Instruction:
Explain what the following Python 3 code does
def hrd_key(self, key_str):

        pyl.plot(self.data[:,self.cols['log_Teff']-1],\
                 self.data[:,self.cols['log_L']-1],label = key_str)
        pyl.legend()
        pyl.xlabel('log Teff')
        pyl.ylabel('log L')
        x1,x2=pl.xlim()
        if x2 > x1:
            self._xlimrev()

Response: This function plots an HR diagram of the related class.


Instruction:
Can you tell what is the following Python 3 function doing
def hrd_new(self, input_label="", skip=0):
        xl_old=pyl.gca().get_xlim()
        if input_label == "":
            my_label="M="+str(self.header_attr['initial_mass'])+", Z="+str(self.header_attr['initial_z'])
        else:
            my_label="M="+str(self.header_attr['initial_mass'])+", Z="+str(self.header_attr['initial_z'])+"; "+str(input_label)

        pyl.plot(self.data[skip:,self.cols['log_Teff']-1],self.data[skip:,self.cols['log_L']-1],label = my_label)
        pyl.legend(loc=0)
        xl_new=pyl.gca().get_xlim()
        pyl.xlabel('log Teff')
        pyl.ylabel('log L')
        if any(array(xl_old)==0):
            pyl.gca().set_xlim(max(xl_new),min(xl_new))
        elif any(array(xl_new)==0):
            pyl.gca().set_xlim(max(xl_old),min(xl_old))
        else:
            pyl.gca().set_xlim([max(xl_old+xl_new),min(xl_old+xl_new)])

Response: Plot an HR diagram with options to skip the first N lines and add a label string


Instruction:
Explain what the following Python 3 code does
def xche4_teff(self,ifig=None,lims=[1.,0.,3.4,4.7],label=None,colour=None,
                   s2ms=True,dashes=None):
        """
        Plot effective temperature against central helium abundance.

        Parameters
        ----------
        ifig : integer or string
            Figure label, if None the current figure is used
            The default value is None.
        lims : list [x_lower, x_upper, y_lower, y_upper]
        label : string
        Label for the model
            The default value is None
        colour : string
            The colour of the line
            The default value is None
        s2ms : boolean, optional
            "Skip to Main Sequence"
            The default is True
        dashes : list, optional
            Custom dashing style. If None, ignore.
            The default is None.

        """
        fsize=18
        params = {'axes.labelsize':  fsize,
        #    'font.family':       'serif',
        'font.family':        'Times New Roman',
        'figure.facecolor':  'white',
        'text.fontsize':     fsize,
        'legend.fontsize':   fsize,
        'xtick.labelsize':   fsize*0.8,
        'ytick.labelsize':   fsize*0.8,
        'text.usetex':       False}

        try:
            pl.rcParams.update(params)
        except:
            pass

        if s2ms:
            h1=self.get('center_h1')
            idx=np.where(h1[0]-h1>=1.e-3)[0][0]
            skip=idx
        else:
            skip=0

        x = self.get('center_he4')[skip:]
        y = self.get('log_Teff')[skip:]
        if ifig is not None:
            pl.figure(ifig)
        if label is not None:
            if colour is not None:
                line,=pl.plot(x,y,label=label,color=colour)
            else:
                line,=pl.plot(x,y,label=label)
            pl.legend(loc='best').draw_frame(False)
        else:
            if colour is not None:
                line,=pl.plot(x,y,color=colour)
            else:
                line,=pl.plot(x,y)

        if dashes is not None:
            line.set_dashes(dashes)

        if label is not None:
            pl.legend(loc='best').draw_frame(False)

        pl.xlim(lims[:2])
        pl.ylim(lims[2:])
        pl.xlabel('$X_{\\rm c}(\,^4{\\rm He}\,)$')
        pl.ylabel('$\log\,T_{\\rm eff}$')

Response: Plots effective temperature against central helium abundance.


Instruction:
Explain what the following Python 3 code does
def tcrhoc(self,ifig=None,lims=[3.,10.,8.,10.],label=None,colour=None,
               dashes=None):
        """
        Central temperature again central density plot

        Parameters
        ----------
        ifig : integer or string
            Figure label, if None the current figure is used
            The default value is None.
        lims : list [x_lower, x_upper, y_lower, y_upper]
        label : string
            Label for the model
            The default value is None
        colour : string
            The colour of the line
            The default value is None
        dashes : list, optional
            Custom dashing style. If None, ignore.
            The default is None.

        """

#        fsize=18
#
#        params = {'axes.labelsize':  fsize,
#            #    'font.family':       'serif',
#        'font.family':        'Times New Roman',
#        'figure.facecolor':  'white',
#        'text.fontsize':     fsize,
#        'legend.fontsize':   fsize,
#        'xtick.labelsize':   fsize*0.8,
#        'ytick.labelsize':   fsize*0.8,
#        'text.usetex':       False}
#
#        try:
#            pl.rcParams.update(params)
#        except:
#            pass

        if ifig is not None:
            pl.figure(ifig)

        if label is not None:
            if colour is not None:
                line,=pl.plot(self.get('log_center_Rho'),self.get('log_center_T'),label=label,
                        color=colour)
            else:
                line,=pl.plot(self.get('log_center_Rho'),self.get('log_center_T'),label=label)

        else:
            if colour is not None:
                line,=pl.plot(self.get('log_center_Rho'),self.get('log_center_T'),
                        color=colour)
            else:
                line,=pl.plot(self.get('log_center_Rho'),self.get('log_center_T'))
        if dashes is not None:
            line.set_dashes(dashes)
        if label is not None:
            pl.legend(loc='best').draw_frame(False)

        pl.xlim(lims[:2])
        pl.ylim(lims[2:])
        pl.xlabel('log $\\rho_{\\rm c}$')
        pl.ylabel('log $T_{\\rm c}$')

Response: Function to plot the current state of the object.


Instruction:
Can you write a function in Python 3 where it
plots mass loss history as a function of log - time - left.

Response:
def mdot_t(self,ifig=None,lims=[7.4,2.6,-8.5,-4.5],label=None,colour=None,s2ms=False,
               dashes=None):
        """
        Plot mass loss history as a function of log-time-left

        Parameters
        ----------
        ifig : integer or string
            Figure label, if None the current figure is used
            The default value is None.
        lims : list [x_lower, x_upper, y_lower, y_upper]
        label : string
            Label for the model
            The default value is None
        colour : string
            The colour of the line
            The default value is None
        s2ms : boolean, optional
            "skip to main sequence"
        dashes : list, optional
            Custom dashing style. If None, ignore.
            The default is None.

        """

        fsize=18

        params = {'axes.labelsize':  fsize,
        #    'font.family':       'serif',
        'font.family':        'Times New Roman',
        'figure.facecolor':  'white',
        'text.fontsize':     fsize,
        'legend.fontsize':   fsize,
        'xtick.labelsize':   fsize*0.8,
        'ytick.labelsize':   fsize*0.8,
        'text.usetex':       False}

        try:
            pl.rcParams.update(params)
        except:
            pass

        if ifig is not None:
            pl.figure(ifig)

        if s2ms:
            h1=self.get('center_h1')
            idx=np.where(h1[0]-h1>=3.e-3)[0][0]
            skip=idx
        else:
            skip=0

        gage= self.get('star_age')
        lage=np.zeros(len(gage))
        agemin = max(old_div(abs(gage[-1]-gage[-2]),5.),1.e-10)
        for i in np.arange(len(gage)):
            if gage[-1]-gage[i]>agemin:
                lage[i]=np.log10(gage[-1]-gage[i]+agemin)
            else :
                lage[i]=np.log10(agemin)
        x = lage[skip:]
        y = self.get('log_abs_mdot')[skip:]

        if ifig is not None:
            pl.figure(ifig)
        if label is not None:
            if colour is not None:
                line,=pl.plot(x,y,label=label,color=colour)
            else:
                line,=pl.plot(x,y,label=label)
        else:
            if colour is not None:
                line,=pl.plot(x,y,color=colour)
            else:
                line,=pl.plot(x,y)

        if dashes is not None:
            line.set_dashes(dashes)
        if label is not None:
            pl.legend(loc='best').draw_frame(False)

        pl.xlim(lims[:2])
        pl.ylim(lims[2:])
        pl.ylabel('$\mathrm{log}_{10}(\|\dot{M}\|/M_\odot\,\mathrm{yr}^{-1})$')
        pl.xlabel('$\mathrm{log}_{10}(t^*/\mathrm{yr})$')


Instruction:
Can you implement a function in Python 3 that
plots mass of [ oclark01@scandium 15M_led_f_print_nets ]$ cp.. / 15M_led_f_ppcno.

Response:
def mcc_t(self,ifig=None,lims=[0,15,0,25],label=None,colour=None,
              mask=False,s2ms=False,dashes=None):
        """
        Plot mass of [oclark01@scandium 15M_led_f_print_nets]$ cp ../15M_led_f_ppcno/ective core as a function of time.

        Parameters
        ----------
        ifig : integer or string
            Figure label, if None the current figure is used
            The default value is None.
        lims : list [x_lower, x_upper, y_lower, y_upper]
        label : string
            Label for the model
            The default value is None
        colour : string
            The colour of the line
            The default value is None
        mask : boolean, optional
            Do you want to try to hide numerical spikes in the
            plot?
            The default is False
        s2ms : boolean, optional
            skip to main squence?
        dashes : list, optional
            Custom dashing style. If None, ignore.
            The default is None.

        """

        fsize=18

        params = {'axes.labelsize':  fsize,
        #    'font.family':       'serif',
        'font.family':        'Times New Roman',
        'figure.facecolor':  'white',
        'text.fontsize':     fsize,
        'legend.fontsize':   fsize,
        'xtick.labelsize':   fsize*0.8,
        'ytick.labelsize':   fsize*0.8,
        'text.usetex':       False}

        try:
            pl.rcParams.update(params)
        except:
            pass

        if ifig is not None:
            pl.figure(ifig)

        if s2ms:
            h1=self.get('center_h1')
            idx=np.where(h1[0]-h1>=3.e-3)[0][0]
            skip=idx
        else:
            skip=0

        age= self.get('star_age')
        x1 = old_div(age, 1.e6)
        x2 = old_div(age, 1.e6)
        y1 = self.get('mix_qtop_1')*self.get('star_mass')
        y2 = self.get('mix_qtop_2')*self.get('star_mass')
        mt1 = self.get('mix_type_1')
        mt2 = self.get('mix_type_2')

        x1 = x1[skip:]
        x2 = x2[skip:]
        y1 = y1[skip:]
        y2 = y2[skip:]
        mt1 = mt1[skip:]
        mt2 = mt2[skip:]

        # Mask spikes...
        if mask:
            x1 = np.ma.masked_where(mt1 != 1, x1)
            x2 = np.ma.masked_where(mt2 != 1, x2)
            y1 = np.ma.masked_where(mt1 != 1, y1)
            y2 = np.ma.masked_where(mt2 != 1, y2)

        if ifig is not None:
            pl.figure(ifig)
        if label is not None:
            if colour is not None:
                line,=pl.plot(x1,y1,label=label,color=colour)
                line,=pl.plot(x2,y2,color=colour)
            else:
                line,=pl.plot(x1,y1,label=label)
                line,=pl.plot(x2,y2)
        else:
            if colour is not None:
                line,=pl.plot(x1,y1,color=colour)
                line,=pl.plot(x2,y2,color=colour)
            else:
                line,=pl.plot(x1,y1)
                line,=pl.plot(x2,y2)

        if dashes is not None:
            line.set_dashes(dashes)

        if label is not None:
            pl.legend(loc='best').draw_frame(False)

        pl.xlim(lims[:2])
        pl.ylim(lims[2:])
        pl.ylabel('$M/M_\odot}$')
        pl.xlabel('$t/{\\rm Myr}$')


Instruction:
Implement a function in Python 3 to
function to plot a Kippenhahn diagram.

Response:
def kippenhahn_CO(self, num_frame, xax, t0_model=0,
                      title='Kippenhahn diagram', tp_agb=0.,
                      ylim_CO=[0,0]):
        """
        Kippenhahn plot as a function of time or model with CO ratio

        Parameters
        ----------
        num_frame : integer
            Number of frame to plot this plot into.
        xax : string
            Either model or time to indicate what is to be used on the
            x-axis.
        t0_model : integer, optional
            Model for the zero point in time, for AGB plots this would
            be usually the model of the 1st TP, which can be found with
            the Kippenhahn plot.  The default is 0.
        title : string, optional
            Figure title.  The defalut is "Kippenhahn diagram".
        tp_agb : float, optional
            If >= 0 then,
            ylim=[h1_min*1.-tp_agb/100 : h1_max*1.+tp_agb/100] with
            h1_min, h1_max the min and max H-free core mass coordinate.
            The defalut is 0.
        ylim_CO : list
            if ylim_CO is [0,0], then it is automaticly set.  The
            default is [0,0].

        """

        pyl.figure(num_frame)

        if xax == 'time':
            xaxisarray = self.get('star_age')
        elif xax == 'model':
            xaxisarray = self.get('model_number')
        else:
            print('kippenhahn_error: invalid string for x-axis selction.'+\
                  ' needs to be "time" or "model"')

        t0_mod=xaxisarray[t0_model]

        plot_bounds=True
        try:
            h1_boundary_mass  = self.get('h1_boundary_mass')
            he4_boundary_mass = self.get('he4_boundary_mass')
        except:
            try:
                h1_boundary_mass  = self.get('he_core_mass')
                he4_boundary_mass = self.get('c_core_mass')
            except:
                plot_bounds=False

        star_mass         = self.get('star_mass')
        mx1_bot           = self.get('mx1_bot')*star_mass
        mx1_top           = self.get('mx1_top')*star_mass
        mx2_bot           = self.get('mx2_bot')*star_mass
        mx2_top           = self.get('mx2_top')*star_mass
        surface_c12       = self.get('surface_c12')
        surface_o16       = self.get('surface_o16')

        COratio=old_div((surface_c12*4.),(surface_o16*3.))

        pyl.plot(xaxisarray[t0_model:]-t0_mod,COratio[t0_model:],'-k',label='CO ratio')
        pyl.ylabel('C/O ratio')
        pyl.legend(loc=4)
        if ylim_CO[0] is not 0 and  ylim_CO[1] is not 0:
            pyl.ylim(ylim_CO)
        if xax == 'time':
            pyl.xlabel('t / yrs')
        elif xax == 'model':
            pyl.xlabel('model number')

        pyl.twinx()
        if plot_bounds:
            pyl.plot(xaxisarray[t0_model:]-t0_mod,h1_boundary_mass[t0_model:],label='h1_boundary_mass')
            pyl.plot(xaxisarray[t0_model:]-t0_mod,he4_boundary_mass[t0_model:],label='he4_boundary_mass')
        pyl.plot(xaxisarray[t0_model:]-t0_mod,mx1_bot[t0_model:],',r',label='conv bound')
        pyl.plot(xaxisarray[t0_model:]-t0_mod,mx1_top[t0_model:],',r')
        pyl.plot(xaxisarray[t0_model:]-t0_mod,mx2_bot[t0_model:],',r')
        pyl.plot(xaxisarray[t0_model:]-t0_mod,mx2_top[t0_model:],',r')
        pyl.plot(xaxisarray[t0_model:]-t0_mod,star_mass[t0_model:],label='star_mass')
        pyl.ylabel('mass coordinate')
        pyl.legend(loc=2)
        if tp_agb > 0.:
            h1_min = min(h1_boundary_mass[t0_model:])
            h1_max = max(h1_boundary_mass[t0_model:])
            h1_min = h1_min*(1.-old_div(tp_agb,100.))
            h1_max = h1_max*(1.+old_div(tp_agb,100.))
            print('setting ylim to zoom in on H-burning:',h1_min,h1_max)
            pyl.ylim(h1_min,h1_max)


Instruction:
Can you tell what is the following Python 3 function doing
def kippenhahn(self, num_frame, xax, t0_model=0,
                   title='Kippenhahn diagram', tp_agb=0., t_eps=5.e2,
                   plot_star_mass=True, symbol_size=8, c12_bm=False,
                   print_legend=True):
        """Kippenhahn plot as a function of time or model.

        Parameters
        ----------
        num_frame : integer
            Number of frame to plot this plot into, if <0 open no new
            figure.
        xax : string
            Either 'model', 'time' or 'logtimerev' to indicate what is
            to be used on the x-axis.
        t0_model : integer, optional
            If xax = 'time' then model for the zero point in time, for
            AGB plots this would be usually the model of the 1st TP,
            which can be found with the Kippenhahn plot.  The default
            is 0.
        title : string, optional
            The figure title.  The default is "Kippenhahn diagram".
        tp_agb : float, optional
            If > 0. then,
            ylim=[h1_min*1.-tp_agb/100 : h1_max*1.+tp_agb/100] with
            h1_min, h1_max the min and max H-free core mass coordinate.
            The default is 0. .
        t_eps : float, optional
            Final time for logtimerev.  The default is '5.e2'.
        plot_star_mass : boolean, optional
            If True, then plot the stellar mass as a line as well.  The
            default is True.
        symbol_size : integer, optional
            Size of convection boundary marker.  The default is 8.
        c12_bm : boolean, optional
            If we plot c12_boundary_mass or not.  The default is False.
        print_legend : boolean, optionla
            Show or do not show legend.  The defalut is True.

        """

        if num_frame >= 0:
            pyl.figure(num_frame)

        t0_mod=[]

        if xax == 'time':
            xaxisarray = self.get('star_age')
            if t0_model > 0:
                ind=self.get('model_number')
                t0_model=where(ind>t0_model)[0][0]
                t0_mod=xaxisarray[t0_model]
            else:
                t0_mod = 0.
            print('zero time is '+str(t0_mod))
        elif xax == 'model':
            xaxisarray = self.get('model_number')
            #t0_mod=xaxisarray[t0_model]
            t0_mod = 0.
        elif xax == 'logtimerev':
            xaxi    = self.get('star_age')
            xaxisarray = np.log10(np.max(xaxi)+t_eps-xaxi)
            t0_mod = 0.
        else:
            print('kippenhahn_error: invalid string for x-axis selction.'+\
                  ' needs to be "time" or "model"')

        plot_bounds=True
        try:
            h1_boundary_mass  = self.get('h1_boundary_mass')
            he4_boundary_mass = self.get('he4_boundary_mass')
            if c12_bm:
                c12_boundary_mass = self.get('c12_boundary_mass')
        except:
            try:
                h1_boundary_mass  = self.get('he_core_mass')
                he4_boundary_mass = self.get('c_core_mass')
                if c12_bm:
                    c12_boundary_mass = self.get('o_core_mass')
            except:
                plot_bounds=False

        star_mass         = self.get('star_mass')
        mx1_bot           = self.get('mx1_bot')*star_mass
        mx1_top           = self.get('mx1_top')*star_mass
        mx2_bot           = self.get('mx2_bot')*star_mass
        mx2_top           = self.get('mx2_top')*star_mass

        if xax == 'time':
            if t0_model>0:
                pyl.xlabel('$t - t_0$ $\mathrm{[yr]}$')
            else:
                pyl.xlabel('t / yrs')
        elif xax == 'model':
            pyl.xlabel('model number')
        elif xax == 'logtimerev':
            pyl.xlabel('$\log(t_{final} - t)$  $\mathrm{[yr]}$')

        pyl.plot(xaxisarray[t0_model:]-t0_mod,mx1_bot[t0_model:],linestyle='None',color='blue',alpha=0.3,marker='o',markersize=symbol_size,label='convection zones')
        pyl.plot(xaxisarray[t0_model:]-t0_mod,mx1_top[t0_model:],linestyle='None',color='blue',alpha=0.3,marker='o',markersize=symbol_size)
        pyl.plot(xaxisarray[t0_model:]-t0_mod,mx2_bot[t0_model:],linestyle='None',color='blue',alpha=0.3,marker='o',markersize=symbol_size)
        pyl.plot(xaxisarray[t0_model:]-t0_mod,mx2_top[t0_model:],linestyle='None',color='blue',alpha=0.3,marker='o',markersize=symbol_size)

        if plot_bounds:
            pyl.plot(xaxisarray[t0_model:]-t0_mod,h1_boundary_mass[t0_model:],color='red',linewidth=2,label='H-free core')
            pyl.plot(xaxisarray[t0_model:]-t0_mod,he4_boundary_mass[t0_model:],color='green',linewidth=2,linestyle='dashed',label='He-free core')
            if c12_bm:
                pyl.plot(xaxisarray[t0_model:]-t0_mod,c12_boundary_mass[t0_model:],color='purple',linewidth=2,linestyle='dotted',label='C-free core')
        if plot_star_mass is True:
            pyl.plot(xaxisarray[t0_model:]-t0_mod,star_mass[t0_model:],label='$M_\star$')
        pyl.ylabel('$m_\mathrm{r}/\mathrm{M}_\odot$')
        if print_legend:
            pyl.legend(loc=2)
        if tp_agb > 0.:
            h1_min = min(h1_boundary_mass[t0_model:])
            h1_max = max(h1_boundary_mass[t0_model:])
            h1_min = h1_min*(1.-old_div(tp_agb,100.))
            h1_max = h1_max*(1.+old_div(tp_agb,100.))
            print('setting ylim to zoom in on H-burning:',h1_min,h1_max)
            pyl.ylim(h1_min,h1_max)

Response: Function to plot a new Kippenhahn plot.


Instruction:
Implement a Python 3 function for
plotting the luminosity evolution of the current state of the entry.

Response:
def t_lumi(self,num_frame,xax):
        """
        Luminosity evolution as a function of time or model.

        Parameters
        ----------
        num_frame : integer
            Number of frame to plot this plot into.
        xax : string
            Either model or time to indicate what is to be used on the
            x-axis

        """

        pyl.figure(num_frame)

        if xax == 'time':
            xaxisarray = self.get('star_age')
        elif xax == 'model':
            xaxisarray = self.get('model_number')
        else:
            print('kippenhahn_error: invalid string for x-axis selction. needs to be "time" or "model"')

        logLH   = self.get('log_LH')
        logLHe  = self.get('log_LHe')

        pyl.plot(xaxisarray,logLH,label='L_(H)')
        pyl.plot(xaxisarray,logLHe,label='L(He)')
        pyl.ylabel('log L')
        pyl.legend(loc=2)

        if xax == 'time':
            pyl.xlabel('t / yrs')
        elif xax == 'model':
            pyl.xlabel('model number')


Instruction:
Can you tell what is the following Python 3 function doing
def t_surf_parameter(self, num_frame, xax):

        pyl.figure(num_frame)

        if xax == 'time':
            xaxisarray = self.get('star_age')
        elif xax == 'model':
            xaxisarray = self.get('model_number')
        else:
            print('kippenhahn_error: invalid string for x-axis selction. needs to be "time" or "model"')

        logL    = self.get('log_L')
        logTeff    = self.get('log_Teff')

        pyl.plot(xaxisarray,logL,'-k',label='log L')
        pyl.plot(xaxisarray,logTeff,'-k',label='log Teff')
        pyl.ylabel('log L, log Teff')
        pyl.legend(loc=2)

        if xax == 'time':
            pyl.xlabel('t / yrs')
        elif xax == 'model':
            pyl.xlabel('model number')

Response: This function plots the surfaces of the current state of the state of the state of the surfaces of the current state of the surfaces.


Instruction:
Explain what the following Python 3 code does
def kip_cont(self, ifig=110, modstart=0, modstop=-1,t0_model=0,
                 outfile='out.png', xlims=None, ylims=None,
                 xres=1000, yres=1000, ixaxis='model_number',
                 mix_zones=20, burn_zones=20, plot_radius=False,
                 engenPlus=True, engenMinus=False,
                 landscape_plot=False, rad_lines=False, profiles=[],
                 showfig=True, outlines=True, boundaries=True,
                 c12_boundary=False, rasterise=False, yscale='1.',
                 engenlevels=None,CBM=False,fsize=14):
        """
        This function creates a Kippenhahn plot with energy flux using
        contours.

        This plot uses mixing_regions and burning_regions written to
        your history.data or star.log. Set both variables in the
        log_columns.list file to 20 as a start.

        The output log file should then contain columns called
        "mix_type_n", "mix_qtop_n", "burn_type_n" and "burn_qtop_n".
        The number of columns (i.e. the biggest value of n) is what
        goes in the arguments as mix_zones and burn_zones.  DO NOT
        WORRY! if you do not have these columns, just leave the default
        values alone and the script should recognise that you do not
        have these columns and make the most detailed plot that is
        available to you.

        Defaults are set to get some plot, that may not look great if
        you zoom in interactively. Play with xres and yres as well as
        setting the xlims to ylims to the region you are interested in.

        Parameters
        ----------
        ifig : integer, optional
            Figure frame number.  The default is 110.
        modstart : integer, optional
            Model from which you want to plot (be careful if your
            history.data or star.log output is sparse...).  If it is
            0 then it starts from the beginning, works even if
            log_cnt > 1.
            The default is 0.
        modstop : integer, optional
            Model to which you wish to plot, -1 corresponds to end
            [if log_cnt>1, devide modstart and modstop by log_cnt,
            this needs to be improved! SJ: this should be ficed now].
            The defalut is -1.
        t0_model : integer, optional
            Model number from which to reset the time to 0. Typically,
            if modstart!=0, t0_model=modstart is a good choice, but we
            leave the choice to the user in case the time is wished to
            start from 0 at a different key point of the evolution.
            The default value is 0.
        outfile : sting, optional
            'filename + extension' where you want to save the figure.
            The defalut is "out.png".
        xlims, ylims : list, optional
            Plot limits, however these are somewhat obsolete now that
            we have modstart and modstop.  Leaving them as 0. is
            probably no slower, and you can always zoom in afterwards
            in mpl.  ylims is important for well resolved thermal
            pulse etc plots; it's best to get the upper and lower limits
            of he-intershell using s.kippenhahn_CO(1,'model') first.
            The default is [0., 0.].
        xres, yres : integer, optional
            plot resolution. Needless to say that increasing these
            values will yield a nicer plot with some slow-down in
            plotting time.  You will most commonly change xres.  For a
            prelim plot, try xres~200, then bump it up to anywhere from
            1000-10000 for real nicely resolved, publication quality
            plots.  The default is 1000.
        ixaxis : string, optional
            Either 'log_time_left', 'age', or 'model_number'.  The
            default is "model_number".
        mix_zones, burn_zones : integer, optional
            As described above, if you have more detailed output about
            your convection and energy generation boundaries in columns
            mix_type_n, mix_qtop_n, burn_type_n and burn_qtop_n, you
            need to specify the total number of columns for mixing zones
            and burning zones that you have.  Can't work this out from
            your history.data or star.log file?  Check the
            history_columns.list that you used, it'll be the number
            after "mixing regions" and "burning regions".  Can't see
            these columns?  leave it and 2 conv zones and 2 burn zones
            will be drawn using other data that you certainly should
            have in your history.data or star.log file.  The defalut for
            both is 20.
        plot_radius : boolean, optional
            Whether on a second y-axis you want to plot the radius of
            the surface and the he-free core.  The default is False.
        engenPlus : boolean
            Plot energy generation contours for eps_nuc>0.  The default
            is True.
        endgenMinus : boolean, optional
            Plot energy generation contours for eos_nuc<0.  The default
            is True.
        landscape_plot : boolean, optionla
            The default is False.
        rad_lines : boolean, optional
            The deafault is False.
        profiles : list, optional
            The default is [].
        showfig : boolean, optional
            The default is True.
        outlines : boolean, optional
            Whether or not to plot outlines of conv zones in darker
            colour.
        boundaries : boolean, optional
            Whether or not to plot H-, He- and C-free boundaries.
        c12_boundary : boolean, optional
            The default is False.
        rasterise : boolean, optional
            Whether or not to rasterise the contour regions to make
            smaller vector graphics figures.  The default is False.
        yscale : string, optional
            Re-scale the y-axis by this amount
        engenlevels : list
            Give cusstom levels to the engenPlus contour. If None,
            the levels are chosen automatically.
            The default is None.
        CBM : boolean, optional
            plot contours for where CBM is active?

        fsize : integer
            font size for labels

        Notes
        -----
        The parameter xlims is depricated.

        """
        if ylims is None:
            ylims=[0.,0.]
        if xlims is None:
            xlims=[0.,0.]

        # Find correct modstart and modstop:
        mod=np.array([int(i) for i in self.get('model_number')])
        mod1=np.abs(mod-modstart).argmin()
        mod2=np.abs(mod-modstop).argmin()
        if modstart != 0 : modstart=mod1
        if modstop != -1 : modstop=mod2

        xxyy=[self.get('star_age')[modstart:modstop],self.get('star_age')[modstart:modstop]]
        mup = max(float(self.get('star_mass')[0])*1.02,1.0)
        nmodels=len(self.get('model_number')[modstart:modstop])

        if ylims == [0.,0.]:
            mup   = max(float(self.get('star_mass')[0])*1.02,1.0)
            mDOWN = 0.
        else:
            mup = ylims[1]
            mDOWN = ylims[0]

        # y-axis resolution
        ny=yres
        #dy=mup/float(ny)
        dy = old_div((mup-mDOWN),float(ny))

        # x-axis resolution
        maxpoints=xres
        dx=int(max(1,old_div(nmodels,maxpoints)))

        #y = np.arange(0., mup, dy)
        y = np.arange(mDOWN, mup, dy)
        x = np.arange(0, nmodels, dx)
        Msol=1.98892E+33

        engenstyle = 'full'

        B1=np.zeros([len(y),len(x)],float)
        B2=np.zeros([len(y),len(x)],float)
        try:
            self.get('burn_qtop_1')
        except:
            engenstyle = 'twozone'
        if engenstyle == 'full' and (engenPlus == True or engenMinus == True):
            ulimit_array = np.array([self.get('burn_qtop_'+str(j))[modstart:modstop:dx]*\
                           self.get('star_mass')[modstart:modstop:dx] for j in range(1,burn_zones+1)])
            #ulimit_array = np.around(ulimit_array,decimals=len(str(dy))-2)
            llimit_array = np.delete(ulimit_array,-1,0)
            llimit_array = np.insert(ulimit_array,0,0.,0)
            #llimit_array = np.around(llimit_array,decimals=len(str(dy))-2)
            btype_array = np.array([self.get('burn_type_'+str(j))[modstart:modstop:dx] for j in range(1,burn_zones+1)])
            old_percent = 0
            for i in range(len(x)):
                # writing status
                percent = int(i*100/(len(x) - 1))
                if percent >= old_percent + 5:
                    sys.stdout.flush()
                    sys.stdout.write("\r creating color map burn " + "...%d%%" % percent)
                    old_percent = percent

                for j in range(burn_zones):
                    if btype_array[j,i] > 0. and abs(btype_array[j,i]) < 99.:
                        B1[(np.abs(y-llimit_array[j][i])).argmin():(np.abs(y-ulimit_array[j][i])).argmin()+1,i] = 10.0**(btype_array[j,i])
                    elif btype_array[j,i] < 0. and abs(btype_array[j,i]) < 99.:
                        B2[(np.abs(y-llimit_array[j][i])).argmin():(np.abs(y-ulimit_array[j][i])).argmin()+1,i] = 10.0**(abs(btype_array[j,i]))
            print(' \n')

        if engenstyle == 'twozone' and (engenPlus == True or engenMinus == True):
            V=np.zeros([len(y),len(x)],float)
            old_percent = 0
            for i in range(len(x)):
                # writing status
                percent = int(i*100/(len(x) - 1))
                if percent >= old_percent + 5:
                    sys.stdout.flush()
                    sys.stdout.write("\r creating color map1 " + "...%d%%" % percent)
                    old_percent = percent
                llimitl1=old_div(self.get('epsnuc_M_1')[modstart:modstop][i*dx],Msol)
                ulimitl1=old_div(self.get('epsnuc_M_4')[modstart:modstop][i*dx],Msol)
                llimitl2=old_div(self.get('epsnuc_M_5')[modstart:modstop][i*dx],Msol)
                ulimitl2=old_div(self.get('epsnuc_M_8')[modstart:modstop][i*dx],Msol)
                llimith1=old_div(self.get('epsnuc_M_2')[modstart:modstop][i*dx],Msol)
                ulimith1=old_div(self.get('epsnuc_M_3')[modstart:modstop][i*dx],Msol)
                llimith2=old_div(self.get('epsnuc_M_6')[modstart:modstop][i*dx],Msol)
                ulimith2=old_div(self.get('epsnuc_M_7')[modstart:modstop][i*dx],Msol)
                # lower thresh first, then upper thresh:
                if llimitl1!=ulimitl1:
                    for k in range(ny):
                        if llimitl1<=y[k] and ulimitl1>y[k]:
                            V[k,i]=10.
                if llimitl2!=ulimitl2:
                    for k in range(ny):
                        if llimitl2<=y[k] and ulimitl2>y[k]:
                            V[k,i]=10.
                if llimith1!=ulimith1:
                    for k in range(ny):
                        if llimith1<=y[k] and ulimith1>y[k]:
                            V[k,i]=30.
                if llimith2!=ulimith2:
                    for k in range(ny):
                        if llimith2<=y[k] and ulimith2>y[k]:
                            V[k,i]=30.
            print(' \n')

        mixstyle = 'full'
        try:
            self.get('mix_qtop_1')
        except:
            mixstyle = 'twozone'
        if mixstyle == 'full':
            old_percent = 0
            Z=np.zeros([len(y),len(x)],float)
            if CBM:
                Zcbm=np.zeros([len(y),len(x)],float)
            ulimit_array = np.array([self.get('mix_qtop_'+str(j))[modstart:modstop:dx]*self.get('star_mass')[modstart:modstop:dx] for j in range(1,mix_zones+1)])
            llimit_array = np.delete(ulimit_array,-1,0)
            llimit_array = np.insert(ulimit_array,0,0.,0)
            mtype_array = np.array([self.get('mix_type_'+str(j))[modstart:modstop:dx] for j in range(1,mix_zones+1)])
            for i in range(len(x)):
                # writing status
                percent = int(i*100/(len(x) - 1))
                if percent >= old_percent + 5:
                    sys.stdout.flush()
                    sys.stdout.write("\r creating color map mix " + "...%d%%" % percent)
                    old_percent = percent
                for j in range(mix_zones):
                    if mtype_array[j,i] == 1.:
                        Z[(np.abs(y-llimit_array[j][i])).argmin():(np.abs(y-ulimit_array[j][i])).argmin()+1,i] = 1.
                    if CBM:
                        if mtype_array[j,i] == 2.:
                            Zcbm[(np.abs(y-llimit_array[j][i])).argmin():(np.abs(y-ulimit_array[j][i])).argmin()+1,i] = 1.
            print(' \n')

        if mixstyle == 'twozone':
            Z=np.zeros([len(y),len(x)],float)
            old_percent = 0
            for i in range(len(x)):
            # writing reading status
                # writing status
                percent = int(i*100/(len(x) - 1))
                if percent >= old_percent + 5:
                    sys.stdout.flush()
                    sys.stdout.write("\r creating color map mix " + "...%d%%" % percent)
                    old_percent = percent

                ulimit=self.get('conv_mx1_top')[modstart:modstop][i*dx]*self.get('star_mass')[modstart:modstop][i*dx]
                llimit=self.get('conv_mx1_bot')[modstart:modstop][i*dx]*self.get('star_mass')[modstart:modstop][i*dx]
                if llimit!=ulimit:
                    for k in range(ny):
                        if llimit<=y[k] and ulimit>y[k]:
                            Z[k,i]=1.
                ulimit=self.get('conv_mx2_top')[modstart:modstop][i*dx]*self.get('star_mass')[modstart:modstop][i*dx]
                llimit=self.get('conv_mx2_bot')[modstart:modstop][i*dx]*self.get('star_mass')[modstart:modstop][i*dx]
                if llimit!=ulimit:
                    for k in range(ny):
                        if llimit<=y[k] and ulimit>y[k]:
                            Z[k,i]=1.
            print(' \n')

        if rad_lines == True:
            masses = np.arange(0.1,1.5,0.1)
            rads=[[],[],[],[],[],[],[],[],[],[],[],[],[],[]]
            modno=[]
            for i in range(len(profiles)):
                p=mesa_profile('./LOGS',profiles[i])
                modno.append(p.header_attr['model_number'])
                for j in range(len(masses)):
                    idx=np.abs(p.get('mass')-masses[j]).argmin()
                    rads[j].append(p.get('radius')[idx])

        print('engenstyle was ', engenstyle)
        print('mixstyle was ', mixstyle)
        print('\n finished preparing color map')

        ########################################################################
        #----------------------------------plot--------------------------------#
        fig = pyl.figure(ifig)
        #fsize=20
        if landscape_plot == True:
            fig.set_size_inches(9,4)
            pl.gcf().subplots_adjust(bottom=0.2)
            pl.gcf().subplots_adjust(right=0.85)

        params = {'axes.labelsize':  fsize,
          'axes.labelsize': fsize,
          'font.size': fsize,
          'legend.fontsize': fsize,
          'xtick.labelsize': fsize,
          'ytick.labelsize': fsize,
                  'text.usetex': False}
        pyl.rcParams.update(params)

        #ax=pl.axes([0.1,0.1,0.9,0.8])

        #fig=pl.figure()
        ax=pl.axes()

        if ixaxis == 'log_time_left':
        # log of time left until core collapse
            gage= self.get('star_age')
            lage=np.zeros(len(gage))
            agemin = max(old_div(abs(gage[-1]-gage[-2]),5.),1.e-10)
            for i in np.arange(len(gage)):
                if gage[-1]-gage[i]>agemin:
                    lage[i]=np.log10(gage[-1]-gage[i]+agemin)
                else :
                    lage[i]=np.log10(agemin)
            xxx = lage[modstart:modstop]
            print('plot versus time left')
            ax.set_xlabel('$ \\log_{10}(t-t_\mathrm{end})\ /\  \mathrm{[yr]}$',fontsize=fsize)
            if xlims[1] == 0.:
                xlims = [xxx[0],xxx[-1]]
        elif ixaxis =='model_number':
            xxx= self.get('model_number')[modstart:modstop]
            print('plot versus model number')
            ax.set_xlabel('Model number',fontsize=fsize)
            if xlims[1] == 0.:
                xlims = [self.get('model_number')[modstart],self.get('model_number')[modstop]]
        elif ixaxis =='age':
            if t0_model != 0:
                t0_mod=np.abs(mod-t0_model).argmin()
                xxx= self.get('star_age')[modstart:modstop] - self.get('star_age')[t0_mod]
                print('plot versus age')
                ax.set_xlabel('t - %.5e / [yr]' %self.get('star_age')[modstart],fontsize=fsize)
            else:
                xxx= old_div(self.get('star_age')[modstart:modstop],1.e6)
                ax.set_xlabel('t [Myr]',fontsize=fsize)
            if xlims[1] == 0.:
                xlims = [xxx[0],xxx[-1]]

        ax.set_ylabel('$\mathrm{enclosed\ mass\ /\ [M_\odot]}$',fontsize=fsize)

        # some stuff for rasterizing only the contour part of the plot, for nice, but light, eps:
        class ListCollection(Collection):
            def __init__(self, collections, **kwargs):
                Collection.__init__(self, **kwargs)
                self.set_collections(collections)
            def set_collections(self, collections):
                self._collections = collections
            def get_collections(self):
                return self._collections
            @allow_rasterization
            def draw(self, renderer):
                for _c in self._collections:
                    _c.draw(renderer)

        def insert_rasterized_contour_plot(c):
            collections = c.collections
            for _c in collections:
                _c.remove()
            cc = ListCollection(collections, rasterized=True)
            ax = pl.gca()
            ax.add_artist(cc)
            return cc

        cmapMIX = matplotlib.colors.ListedColormap(['w','#8B8386']) # rose grey
        if CBM:
            cmapCBM = matplotlib.colors.ListedColormap(['w','g']) # green
        cmapB1  = pyl.cm.get_cmap('Blues')
        cmapB2  = pl.cm.get_cmap('Reds')

        ylims1=[0.,0.]
        ylims1[0]=ylims[0]
        ylims1[1]=ylims[1]
        if ylims == [0.,0.]:
            ylims[0] = 0.
            ylims[1] = mup
            #print("Setting ylims[1] to mup="+str(mup))
        if ylims[0] != 0.:
            ylab='$(\mathrm{Mass }$ - '+str(ylims[0])
            if yscale!='1.':
                ylab+=') / '+yscale+' $M_\odot$'
            else:
                ylab+=') / $M_\odot$'
            ax.set_ylabel(ylab)
            y = y - ylims[0]
            y = y*float(yscale) # SJONES tweak
            ylims[0] = y[0]
            ylims[1] = y[-1]

        print('plotting contours')
        CMIX    = ax.contourf(xxx[::dx],y,Z, cmap=cmapMIX,alpha=0.6,levels=[0.5,1.5])
        #CMIX    = ax.pcolor(xxx[::dx],y,Z, cmap=cmapMIX,alpha=0.6,vmin=0.5,vmax=1.5)
        if rasterise==True:
            insert_rasterized_contour_plot(CMIX)
        if outlines == True:
            CMIX_outlines    = ax.contour(xxx[::dx],y,Z, cmap=cmapMIX)
            if rasterise==True:
                insert_rasterized_contour_plot(CMIX_outlines)

        if CBM:
            CCBM    = ax.contourf(xxx[::dx],y,Zcbm, cmap=cmapCBM,alpha=0.6,levels=[0.5,1.5])
            if rasterise==True:
                insert_rasterized_contour_plot(CCBM)
            if outlines == True:
                CCBM_outlines    = ax.contour(xxx[::dx],y,Zcbm, cmap=cmapCBM)
                if rasterise==True:
                    insert_rasterized_contour_plot(CCBM_outlines)

        if engenstyle == 'full' and engenPlus == True:
            if engenlevels!= None:
                CBURN1  = ax.contourf(xxx[::dx],y,B1, cmap=cmapB1, alpha=0.5,\
                        locator=matplotlib.ticker.LogLocator(),levels=engenlevels)
                if outlines:
                    CB1_outlines  = ax.contour(xxx[::dx],y,B1, cmap=cmapB1, alpha=0.7, \
                        locator=matplotlib.ticker.LogLocator(),levels=engenlevels)
            else:
                CBURN1  = ax.contourf(xxx[::dx],y,B1, cmap=cmapB1, alpha=0.5, \
                                      locator=matplotlib.ticker.LogLocator())
                if outlines:
                    CB1_outlines  = ax.contour(xxx[::dx],y,B1, cmap=cmapB1, alpha=0.7, \
                                               locator=matplotlib.ticker.LogLocator())
            CBARBURN1 = pyl.colorbar(CBURN1)
            CBARBURN1.set_label('$|\epsilon_\mathrm{nuc}-\epsilon_{\\nu}| \; (\mathrm{erg\,g}^{-1}\mathrm{\,s}^{-1})$',fontsize=fsize)
            if rasterise==True:
                insert_rasterized_contour_plot(CBURN1)
                if outlines:
                    insert_rasterized_contour_plot(CB1_outlines)

        if engenstyle == 'full' and engenMinus == True:
            CBURN2  = ax.contourf(xxx[::dx],y,B2, cmap=cmapB2, alpha=0.5, locator=matplotlib.ticker.LogLocator())
            if outlines:
                CBURN2_outlines  = ax.contour(xxx[::dx],y,B2, cmap=cmapB2, alpha=0.7, locator=matplotlib.ticker.LogLocator())
            CBARBURN2 = pl.colorbar(CBURN2)
            if engenPlus == False:
                CBARBURN2.set_label('$|\epsilon_\mathrm{nuc}-\epsilon_{\\nu}| \; (\mathrm{erg\,g}^{-1}\mathrm{\,s}^{-1})$',fontsize=fsize)
            if rasterise==True:
                insert_rasterized_contour_plot(CBURN2)
                if outlines:
                    insert_rasterized_contour_plot(CB2_outlines)

        if engenstyle == 'twozone' and (engenPlus == True or engenMinus == True):
            ax.contourf(xxx[::dx],y,V, cmap=cmapB1, alpha=0.5)

        print('plotting patches')
        mtot=self.get('star_mass')[modstart:modstop][::dx]
        mtot1=(mtot-ylims1[0])*float(yscale)
        ax.plot(xxx[::dx],mtot1,'k-')

        if boundaries == True:
            print('plotting abund boundaries')
            try:
                bound=self.get('h1_boundary_mass')[modstart:modstop]
                bound1=(bound-ylims1[0])*float(yscale)
                ax.plot(xxx,bound1,label='H boundary',linestyle='-')

                bound=self.get('he4_boundary_mass')[modstart:modstop]
                bound1=(bound-ylims1[0])*float(yscale)
                ax.plot(xxx,bound1,label='He boundary',linestyle='--')

                bound=self.get('c12_boundary_mass')[modstart:modstop]
                bound1=(bound-ylims1[0])*float(yscale)
                ax.plot(xxx,bound1,label='C boundary',linestyle='-.')

            except:
                try:
                    bound=self.get('he_core_mass')[modstart:modstop]
                    bound1=(bound-ylims1[0])*float(yscale)
                    ax.plot(xxx,bound1,label='H boundary',linestyle='-')

                    bound=self.get('c_core_mass')[modstart:modstop]-ylims[0]
                    bound1=(bound-ylims1[0])*float(yscale)
                    ax.plot(xxx,bound1,label='He boundary',linestyle='--')

                    bound=self.get('o_core_mass')[modstart:modstop]-ylims[0]
                    bound1=(bound-ylims1[0])*float(yscale)
                    ax.plot(xxx,bound1,label='C boundary',linestyle='-.')

                    bound=self.get('si_core_mass')[modstart:modstop]-ylims[0]
                    bound1=(bound-ylims1[0])*float(yscale)
                    ax.plot(xxx,bound1,label='C boundary',linestyle='-.')

                    bound=self.get('fe_core_mass')[modstart:modstop]-ylims[0]
                    bound1=(bound-ylims1[0])*float(yscale)
                    ax.plot(xxx,bound1,label='C boundary',linestyle='-.')

                except:
#                    print 'problem to plot boundaries for this plot'
                    pass

        ax.axis([xlims[0],xlims[1],ylims[0],ylims[1]])

        if plot_radius == True:
            ax2=pyl.twinx()
            ax2.plot(xxx,np.log10(self.get('he4_boundary_radius')[modstart:modstop]),label='He boundary radius',color='k',linewidth=1.,linestyle='-.')
            ax2.plot(xxx,self.get('log_R')[modstart:modstop],label='radius',color='k',linewidth=1.,linestyle='-.')
            ax2.set_ylabel('log(radius)')
        if rad_lines == True:
            ax2=pyl.twinx()
            for i in range(len(masses)):
                ax2.plot(modno,np.log10(rads[i]),color='k')

        if outfile[-3:]=='png':
            fig.savefig(outfile,dpi=300)
        elif outfile[-3:]=='eps':
            fig.savefig(outfile,format='eps')
        elif outfile[-3:]=='pdf':
            fig.savefig(outfile,format='pdf')
        if showfig == True:
            pyl.show()

Response: This function creates a Kippenhahn plot with energy flux using the specified contour parameters.


Instruction:
Can you write a function in Python 3 where it
finds the first TP of the TPAGB phase and returns the model that is at its LHe maximum.

Response:
def find_first_TP(self):

        """
        Find first TP of the TPAGB phase and returns the model
        number at its LHe maximum.

        Parameters
        ----------

        """

        star_mass         = self.get('star_mass')
        he_lumi           = self.get('log_LHe')
        h_lumi            = self.get('log_LH')
        mx2_bot           = self.get('mx2_bot')*star_mass
        try:
           h1_boundary_mass  = self.get('h1_boundary_mass')
           he4_boundary_mass = self.get('he4_boundary_mass')
        except:
           try:
                h1_boundary_mass  = self.get('he_core_mass')
                he4_boundary_mass = self.get('c_core_mass')
           except:
                pass

        TP_bot=np.array(self.get('conv_mx2_bot'))*np.array(self.get('star_mass'))
        TP_top=np.array(self.get('conv_mx2_top'))*np.array(self.get('star_mass'))
        lum_array=[]
        activate=False
        models=[]
        pdcz_size=[]
        for i in range(len(h1_boundary_mass)):
            if (h1_boundary_mass[i]-he4_boundary_mass[i] <0.2) and (he4_boundary_mass[i]>0.2):
                if (mx2_bot[i]>he4_boundary_mass[i]) and (he_lumi[i]>h_lumi[i]):
                        if TP_top[i]>he4_boundary_mass[i]:
                                pdcz_size.append(TP_top[i]-TP_bot[i])
                                activate=True
                                lum_array.append(he_lumi[i])
                                models.append(i)
                                #print(TP_bot[i],TP_top[i])
                if (activate == True) and (he_lumi[i]<h_lumi[i]):
                        #if fake tp
                        if max(pdcz_size)<1e-5:
                                active=False
                                lum_array=[]
                                models=[]
                                print('fake tp')
                        else:
                                break
        t0_model = models[np.argmax(lum_array)]
        return t0_model


Instruction:
Write a Python 3 function for
functioning which finds TPs and uses the calc_DUP_parameter function. To calculate DUP parameter evolution dependent of the star or core mass. Parameters ---------- fig : integer Figure number to plot. t0_model : integer First he-shell lum peak. percent : float dredge-up is defined as when the mass dredged up is a certain percent of the total mass dredged up during that event, which is set by the user in this variable. The default is 5. makefig : do you want a figure to be made? Returns ------- TPmods : array model numbers at the peak of each thermal pulse DUPmods : array model numbers at the dredge-up, where dredge-up is defined as when the mass dredged up is a certain percent of the total mass dredged up during that event, which is set by the user TPend : array model numbers at the end of the PDCZ for each TP lambda : array DUP efficiency for each pulse

Response:
def find_TPs_and_DUPs(self, percent=5., makefig=False):
        """
        Function which finds TPs and uses the calc_DUP_parameter
        function.  To calculate DUP parameter evolution dependent of
        the star or core mass.

        Parameters
        ----------
        fig : integer
            Figure number to plot.
        t0_model : integer
            First he-shell lum peak.
        percent : float
            dredge-up is defined as when the mass dredged up is a certain
            percent of the total mass dredged up during that event, which
            is set by the user in this variable.
            The default is 5.
        makefig :
            do you want a figure to be made?

        Returns
        -------
        TPmods : array
            model numbers at the peak of each thermal pulse
        DUPmods : array
            model numbers at the dredge-up, where dredge-up is defined as
            when the mass dredged up is a certain percent of the total mass
            dredged up during that event, which is set by the user
        TPend : array
            model numbers at the end of the PDCZ for each TP
        lambda : array
            DUP efficiency for each pulse
        """

        t0_model=self.find_first_TP()
        t0_idx=(t0_model-self.get("model_number")[0])
        first_TP_he_lum=10**(self.get("log_LHe")[t0_idx])
        he_lum=10**(self.get("log_LHe")[t0_idx:])
        h_lum=10**(self.get("log_LH")[t0_idx:])
        model=self.get("model_number")[t0_idx:]

        try:
           h1_bndry=self.get("h1_boundary_mass")[t0_idx:]
        except:
           try:
                h1_bndry=self.get('he_core_mass')[t0_idx:]
           except:
                pass
        # SJ find TPs by finding local maxima in He-burning luminosity and
        # checking that the he_lum is greater than the h_lum:
        maxima=[0]
        for i in range(2,len(model)-1):
            if he_lum[i] > he_lum[i-1] and he_lum[i] > he_lum[i+1]:
                if he_lum[i-1] > he_lum[i-2] and he_lum[i+1] > he_lum[i+2]:
                    if he_lum[i] > h_lum[i]:
                        maxima.append(i)

        # find DUPs when h-boundary first decreases by more than XX% of the total DUP
        # depth:
        DUPs=[]
        TPend=[]
        maxDUPs=[]
        for i in range(len(maxima)):
            idx1=maxima[i]
            try:
                idx2=maxima[i+1]
            except IndexError:
                idx2=-1
            bound=h1_bndry[idx1:idx2]
            bound0=bound[0]
            if bound0==min(bound) or bound0 < min(bound): # then no DUP
                DUP=idx1
                DUPs.append(DUP)
                maxDUPs.append(DUP)
            else:
                maxDUPs.append(idx1+bound.argmin()) # model number of deepest extend of 3DUP
                maxDUP=bound0-min(bound) # total mass dredged up in DUP
                db=bound - bound[0]
                db_maxDUP = old_div(db, maxDUP)
                DUP=np.where(db_maxDUP <= old_div(-float(percent),100.))[0][0]
                DUPs.append(DUP+idx1)
#                # Alternative definition, where envelope reaches mass coordinate
#                # where top of PDCZ had resided during the TP:
#                top=self.get('mx2_top')[idx1]
#                DUP=np.abs(bound-top).argmin()
#                DUPs.append(DUP+idx1)

        # find end of PDCZ by seeking from TP peak and checking mx2_bot:
            mx2b=self.get('mx2_bot')[t0_idx:][idx1:idx2]
            for i in range(len(mx2b)):
                if mx2b[i]==0.:
                    endTP=i+idx1
                    TPend.append(endTP)
                    break

        # 3DUP efficiency:
        lambd=[0.]
        for i in range(1,len(maxima)):
            dmenv = h1_bndry[maxima[i]] - h1_bndry[maxDUPs[i-1]]
            dmdredge = h1_bndry[maxima[i]] - h1_bndry[maxDUPs[i]]
            lambd.append(old_div(dmdredge,dmenv))

        TPmods = maxima + t0_idx
        DUPmods = DUPs + t0_idx
        TPend = TPend + t0_idx

        return TPmods, DUPmods, TPend, lambd


Instruction:
Write a Python 3 script to
return a list of all properties which are TPAGB parameters which are defined in the nugrid_set. py file.

Response:
def TPAGB_properties(self):

        """
        Temporary, use for now same function in nugrid_set.py!
        Returns many TPAGB parameters which are
        TPstart,TPmods,TP_max_env,TPend,min_m_TP,max_m_TP,DUPmods,DUPm_min_h
        Same function in nugrid_set.py.

        Parameters
        ----------

        """

        peak_lum_model,h1_mass_min_DUP_model=self.find_TP_attributes( 3, t0_model=self.find_first_TP(), color='r', marker_type='o')

        print('first tp')
        print(self.find_first_TP())
        print('peak lum mmmodel')
        print(peak_lum_model)
        print(h1_mass_min_DUP_model)

        TPmods=peak_lum_model

        DUPmods=h1_mass_min_DUP_model
        DUPmods1=[]
        for k in range(len(DUPmods)):
                DUPmods1.append(int(float(DUPmods[k]))+100) #to exclude HBB? effects

        DUPmods=DUPmods1

        TPstart=[]
        #find beginning of TP, goes from TP peak backwards
        # find end of PDCZ by seeking from TP peak and checking mx2_bot:
        models=self.get('model_number')
        mx2b_array=self.get('conv_mx2_bot')
        mx2t_array=self.get('conv_mx2_top')
        massbot=mx2b_array#*self.header_attr['initial_mass']
        masstop=mx2t_array#*self.header_attr['initial_mass']
        massenv=np.array(self.get('conv_mx1_bot'))*np.array(self.get('star_mass'))   #*self.header_attr['initial_mass']

        #h1_bdy=self.get('h1_boundary_mass')

        for k in range(len(TPmods)):
                idx=list(models).index(TPmods[k])
                mx2b=mx2b_array[:idx]
                for i in range(len(mx2b)-1,0,-1):
                        if mx2b[i]==0.:
                            startTP=models[i]
                            TPstart.append(int(float(startTP)))
                            break
        #Find end of TP, goes from TP forwards:
        TPend=[]
        max_m_TP=[]
        min_m_TP=[]
        DUP_m=[]
        TP_max_env=[]
        DUPm_min_h=[]
        flagdecline=False
        for k in range(len(TPmods)):
            idx=list(models).index(TPmods[k])
            mx2b=mx2b_array[idx:]
            mx2t=mx2t_array[idx:]
            refsize=mx2t[0]-mx2b[0]
            for i in range(len(mx2b)):
                if i==0:
                    continue
                if ((mx2t[i]-mx2b[i])<(0.5*refsize)) and (flagdecline==False):
                    flagdecline=True
                    refmasscoord=mx2t[i]
                    print('flagdecline to true')
                    continue
                if flagdecline==True:
                    if (mx2t[i]-mx2b[i])<(0.1*refsize):
                        #for the massive and HDUP AGB's where PDCZ conv zone becomes the Hdup CONV ZONE
                        if refmasscoord<mx2t[i]:
                            endTP=models[idx+i-1]
                            TPend.append(int(float(endTP)))
                            print('HDUp, TP end',endTP)
                            break
                        if (mx2t[i]-mx2b[i])<1e-5:
                            endTP=models[idx+i-1]
                            TPend.append(int(float(endTP)))
                            print('normal TPend',endTP)
                            break

                # if max(mx2t[0:(i-1)])>mx2t[i]:
                #         (max(mx2t[0:(i-1)]) - min(mx2b[0:(i-1)]))
                #         flag=True
                #         continue
                # if flag==True:
                #     endidx=idx+i
                #     endTP=models[endidx]
                #     TPend.append(int(float(endTP)))

                # if (mx2t[i]-mx2b[i])<1e-5:                        #mx2b[i])==0.:
                #     endidx=idx+i
                #     endTP=models[endidx]
                #     TPend.append(int(float(endTP)))
                #     break

            print('found TP boundaries',TPstart[-1],TPend[-1])
        #find max and minimum mass coord of TP at max Lum
            mtot=self.get('star_mass')
            masstop_tot=np.array(masstop)*np.array(mtot)
            idx_tpext=list(masstop_tot).index(max(masstop_tot[TPstart[k]:(TPend[k]-10)]))
            print('TP',k+1,TPmods[k])
            print(TPstart[k],TPend[k])
            print('INDEX',idx_tpext,models[idx_tpext])
            print(max(masstop_tot[TPstart[k]:(TPend[k]-10)]))
            mtot=self.get('star_mass')[idx_tpext]
            max_m_TP.append(masstop[idx_tpext]*mtot)
            min_m_TP.append(massbot[idx_tpext]*mtot)

            TP_max_env.append(massenv[idx_tpext])#*mtot)
            if k> (len(DUPmods)-1):
                    continue
            idx=list(models).index(DUPmods[k])
            mtot=self.get('star_mass')[idx]
            #DUP_m.append(h1_bdy[idx])#*mtot)
        #######identify if it is really a TDUP, Def.
            try:
                h1_bndry=self.get("h1_boundary_mass")[t0_idx:]
            except:
                try:
                    h1_bndry=self.get('he_core_mass')[t0_idx:]
                except:
                    pass

            if h1_bndry[idx]>=max_m_TP[-1]:
                print('Pulse',k+1,'model',TPmods[k],'skip')
                print(h1_bndry[idx],max_m_TP[-1])
                DUPmods[k] = -1
                DUPm_min_h.append( -1)
                continue

            DUPm_min_h.append(h1_bdy[idx])
        for k in range(len(TPmods)):
            print('#############')
            print('TP ',k+1)
            print('Start: ',TPstart[k])
            print('Peak' , TPmods[k],TP_max_env[k])
            print('(conv) PDCZ size: ',min_m_TP[k],' till ',max_m_TP[k])
            print('End',TPend[k])
            if k <=(len(DUPmods)-1):
                print(len(DUPmods),k)
                print('DUP max',DUPmods[k])
                print(DUPm_min_h[k])
            else:
                print('no DUP')

            return TPstart,TPmods,TP_max_env,TPend,min_m_TP,max_m_TP,DUPmods,DUPm_min_h


Instruction:
Can you generate the documentation for the following Python 3 function
def calc_DUP_parameter(self, modeln, label, fig=10, color='r', marker_type='*',
                           h_core_mass=False):
        """
        Method to calculate the DUP parameter evolution for different
        TPs specified specified by their model number.

        Parameters
        ----------
        fig : integer
            Figure number to plot.
        modeln : list
            Array containing pairs of models each corresponding to a
            TP. First model where h boundary mass will be taken before
            DUP, second model where DUP reaches lowest mass.
        leg : string
            Plot label.
        color : string
            Color of the plot.
        marker_type : string
            marker type.
        h_core_mass : boolean, optional
            If True: plot dependence from h free core , else star mass.
            The default is False.

        """
        number_DUP=(old_div(len(modeln),2) -1) #START WITH SECOND
        try:
           h1_bnd_m=self.get('h1_boundary_mass')
        except:
           try:
                h1_bnd_m=self.get('he_core_mass')
           except:
                pass
        star_mass=self.get('star_mass')
        age=self.get("star_age")
        firstTP=h1_bnd_m[modeln[0]]
        first_m_dredge=h1_bnd_m[modeln[1]]
        DUP_parameter=np.zeros(number_DUP)
        DUP_xaxis=np.zeros(number_DUP)
        j=0
        for i in np.arange(2,len(modeln),2):
            TP=h1_bnd_m[modeln[i]]
            m_dredge=h1_bnd_m[modeln[i+1]]
            if i ==2:
                last_m_dredge=first_m_dredge
            #print "testest"
            #print modeln[i]
            if h_core_mass==True:
                DUP_xaxis[j]=h1_bnd_m[modeln[i]]                        #age[modeln[i]] - age[modeln[0]]
            else:
                DUP_xaxis[j]=star_mass[modeln[i]]
            #DUP_xaxis[j]=modeln[i]
            DUP_parameter[j]=old_div((TP-m_dredge),(TP-last_m_dredge))
            last_m_dredge=m_dredge
            j+=1

        pl.figure(fig)
        pl.rcParams.update({'font.size': 18})
        pl.rc('xtick', labelsize=18)
        pl.rc('ytick', labelsize=18)

        pl.plot(DUP_xaxis,DUP_parameter,marker=marker_type,markersize=12,mfc=color,color='k',linestyle='-',label=label)
        if h_core_mass==True:
            pl.xlabel("$M_H$",fontsize=20)
        else:
            pl.xlabel("M/M$_{\odot}$",fontsize=24)
        pl.ylabel("$\lambda_{DUP}$",fontsize=24)
        pl.minorticks_on()
        pl.legend()

Response: Method to calculate the DUP parameter evolution for different types of a single duplicate TPs.


Instruction:
Create a Python 3 function for
creating the UsmUserData object for the given credentials.

Response:
def _create_usm_user_obj(snmp_cred):
    """Creates the UsmUserData obj for the given credentials.

    This method creates an instance for the method hlapi.UsmUserData.
    The UsmUserData() allows the 'auth_protocol' and 'priv_protocol'
    to be undefined by user if their pass phrases are provided.

    :param snmp_cred: Dictionary of SNMP credentials.
           auth_user: SNMP user
           auth_protocol: Auth Protocol
           auth_prot_pp: Pass phrase value for AuthProtocol.
           priv_protocol:Privacy Protocol.
           auth_priv_pp: Pass phrase value for Privacy Protocol.
    :returns UsmUserData object as per given credentials.
    """
    auth_protocol = snmp_cred.get('auth_protocol')
    priv_protocol = snmp_cred.get('priv_protocol')
    auth_user = snmp_cred.get('auth_user')
    auth_prot_pp = snmp_cred.get('auth_prot_pp')
    auth_priv_pp = snmp_cred.get('auth_priv_pp')

    if ((not auth_protocol) and priv_protocol):
        priv_protocol = (
            MAPPED_SNMP_ATTRIBUTES['privProtocol'][priv_protocol])
        usm_user_obj = hlapi.UsmUserData(auth_user, auth_prot_pp,
                                         auth_priv_pp,
                                         privProtocol=priv_protocol)
    elif ((not priv_protocol) and auth_protocol):
        auth_protocol = (
            MAPPED_SNMP_ATTRIBUTES['authProtocol'][auth_protocol])
        usm_user_obj = hlapi.UsmUserData(auth_user, auth_prot_pp,
                                         auth_priv_pp,
                                         authProtocol=auth_protocol)
    elif not all([priv_protocol and auth_protocol]):
        usm_user_obj = hlapi.UsmUserData(auth_user, auth_prot_pp,
                                         auth_priv_pp)
    else:
        auth_protocol = (
            MAPPED_SNMP_ATTRIBUTES['authProtocol'][auth_protocol])
        priv_protocol = (
            MAPPED_SNMP_ATTRIBUTES['privProtocol'][priv_protocol])
        usm_user_obj = hlapi.UsmUserData(auth_user, auth_prot_pp,
                                         auth_priv_pp,
                                         authProtocol=auth_protocol,
                                         privProtocol=priv_protocol)
    return usm_user_obj


Instruction:
Make a summary of the following Python 3 code
def _parse_mibs(iLOIP, snmp_credentials):
    result = {}
    usm_user_obj = _create_usm_user_obj(snmp_credentials)
    try:
        for(errorIndication,
            errorStatus,
            errorIndex,
            varBinds) in hlapi.nextCmd(
                hlapi.SnmpEngine(),
                usm_user_obj,
                hlapi.UdpTransportTarget((iLOIP, 161), timeout=3, retries=3),
                hlapi.ContextData(),
                # cpqida cpqDaPhyDrvTable Drive Array Physical Drive Table
                hlapi.ObjectType(
                    hlapi.ObjectIdentity('1.3.6.1.4.1.232.3.2.5.1')),
                # cpqscsi SCSI Physical Drive Table
                hlapi.ObjectType(
                    hlapi.ObjectIdentity('1.3.6.1.4.1.232.5.2.4.1')),
                # cpqscsi SAS Physical Drive Table
                hlapi.ObjectType(
                    hlapi.ObjectIdentity('1.3.6.1.4.1.232.5.5.2.1')),
                lexicographicMode=False,
                ignoreNonIncreasingOid=True):

            if errorIndication:
                LOG.error(errorIndication)
                msg = "SNMP failed to traverse MIBs %s", errorIndication
                raise exception.IloSNMPInvalidInputFailure(msg)
            else:
                if errorStatus:
                    msg = ('Parsing MIBs failed. %s at %s' % (
                        errorStatus.prettyPrint(),
                        errorIndex and varBinds[-1][int(errorIndex)-1]
                        or '?'
                        )
                    )
                    LOG.error(msg)
                    raise exception.IloSNMPInvalidInputFailure(msg)
                else:
                    for varBindTableRow in varBinds:
                        name, val = tuple(varBindTableRow)
                        oid, label, suffix = (
                            mibViewController.getNodeName(name))
                        key = name.prettyPrint()
                        # Don't traverse outside the tables we requested
                        if not (key.find("SNMPv2-SMI::enterprises.232.3") >= 0
                                or (key.find(
                                    "SNMPv2-SMI::enterprises.232.5") >= 0)):
                            break
                        if key not in result:
                            result[key] = {}
                            result[key][label[-1]] = {}
                        result[key][label[-1]][suffix] = val
    except Exception as e:
        msg = "SNMP library failed with error %s", e
        LOG.error(msg)
        raise exception.IloSNMPExceptionFailure(msg)
    return result

Response: Parses the MIBs from the given iLOIP and returns a dictionary of the parsed MIBs.


Instruction:
Create a Python 3 function to
read the dictionary of parsed MIBs and gets the disk size.

Response:
def _get_disksize_MiB(iLOIP, cred):
    """Reads the dictionary of parsed MIBs and gets the disk size.

    :param iLOIP: IP address of the server on which SNMP discovery
                  has to be executed.
    :param snmp_credentials in a dictionary having following mandatory
           keys.
           auth_user: SNMP user
           auth_protocol: Auth Protocol
           auth_prot_pp: Pass phrase value for AuthProtocol.
           priv_protocol:Privacy Protocol.
           auth_priv_pp: Pass phrase value for Privacy Protocol.

    :returns the dictionary of disk sizes of all physical drives.
    """
    # '1.3.6.1.4.1.232.5.5.1.1',  # cpqscsi SAS HBA Table
    # '1.3.6.1.4.1.232.3.2.3.1',  # cpqida Drive Array Logical Drive Table
    result = _parse_mibs(iLOIP, cred)
    disksize = {}
    for uuid in sorted(result):
        for key in result[uuid]:
            # We only track the Physical Disk Size
            if key.find('PhyDrvSize') >= 0:
                disksize[uuid] = dict()
                for suffix in sorted(result[uuid][key]):
                    size = result[uuid][key][suffix]
                    disksize[uuid][key] = str(size)
    return disksize


Instruction:
Make a summary of the following Python 3 code
def get_local_gb(iLOIP, snmp_credentials):
    disk_sizes = _get_disksize_MiB(iLOIP, snmp_credentials)
    max_size = 0
    for uuid in disk_sizes:
        for key in disk_sizes[uuid]:
            if int(disk_sizes[uuid][key]) > max_size:
                max_size = int(disk_sizes[uuid][key])
    max_size_gb = max_size/1024
    return max_size_gb

Response: Gets the maximum disk size among all disks.


Instruction:
Make a summary of the following Python 3 code
def _http_error_handler(http_error):
    ''' Simple error handler for azure.'''
    message = str(http_error)
    if http_error.respbody is not None:
        message += '\n' + http_error.respbody.decode('utf-8-sig')
    raise AzureHttpError(message, http_error.status)

Response: Simple error handler for azure.


Instruction:
Here you have a function in Python 3, explain what it does
def summary(self):
        mac_dict = {}
        for eth in self.get_members():
            if eth.mac_address is not None:
                if (eth.status is not None and
                        eth.status.health == sys_cons.HEALTH_OK
                        and eth.status.state ==
                        sys_cons.HEALTH_STATE_ENABLED):
                    mac_dict.update(
                        {'Port ' + eth.identity: eth.mac_address})
        return mac_dict

Response: property to return the summary MAC addresses and state


Instruction:
Implement a Python 3 function for
updating the RAID configuration with the details of the physical disks.

Response:
def _update_physical_disk_details(raid_config, server):
    """Adds the physical disk details to the RAID configuration passed."""
    raid_config['physical_disks'] = []
    physical_drives = server.get_physical_drives()
    for physical_drive in physical_drives:
        physical_drive_dict = physical_drive.get_physical_drive_dict()
        raid_config['physical_disks'].append(physical_drive_dict)


Instruction:
Here you have a function in Python 3, explain what it does
def validate(raid_config):
    raid_schema_fobj = open(RAID_CONFIG_SCHEMA, 'r')
    raid_config_schema = json.load(raid_schema_fobj)
    try:
        jsonschema.validate(raid_config, raid_config_schema)
    except json_schema_exc.ValidationError as e:
        raise exception.InvalidInputError(e.message)

    for logical_disk in raid_config['logical_disks']:

        # If user has provided 'number_of_physical_disks' or
        # 'physical_disks', validate that they have mentioned at least
        # minimum number of physical disks required for that RAID level.
        raid_level = logical_disk['raid_level']
        min_disks_reqd = constants.RAID_LEVEL_MIN_DISKS[raid_level]

        no_of_disks_specified = None
        if 'number_of_physical_disks' in logical_disk:
            no_of_disks_specified = logical_disk['number_of_physical_disks']
        elif 'physical_disks' in logical_disk:
            no_of_disks_specified = len(logical_disk['physical_disks'])

        if (no_of_disks_specified and
                no_of_disks_specified < min_disks_reqd):
            msg = ("RAID level %(raid_level)s requires at least %(number)s "
                   "disks." % {'raid_level': raid_level,
                               'number': min_disks_reqd})
            raise exception.InvalidInputError(msg)

Response: Validates the RAID configuration provided against the RAID specification.


Instruction:
Write a Python 3 function that can
filter out the controllers which satisfy the condition.

Response:
def _select_controllers_by(server, select_condition, msg):
    """Filters out the hpssa controllers based on the condition.

    This method updates the server with only the controller which satisfies
    the condition. The controllers which doesn't satisfies the selection
    condition will be removed from the list.

    :param server: The object containing all the supported hpssa controllers
        details.
    :param select_condition: A lambda function to select the controllers based
        on requirement.
    :param msg: A String which describes the controller selection.
    :raises exception.HPSSAOperationError, if all the controller are in HBA
        mode.
    """
    all_controllers = server.controllers
    supported_controllers = [c for c in all_controllers if select_condition(c)]

    if not supported_controllers:
        reason = ("None of the available SSA controllers %(controllers)s "
                  "have %(msg)s"
                  % {'controllers': ', '.join([c.id for c in all_controllers]),
                     'msg': msg})
        raise exception.HPSSAOperationError(reason=reason)

    server.controllers = supported_controllers


Instruction:
Create a Python 3 function for
creating a RAID configuration on this server based on the input passed.

Response:
def create_configuration(raid_config):
    """Create a RAID configuration on this server.

    This method creates the given RAID configuration on the
    server based on the input passed.
    :param raid_config: The dictionary containing the requested
        RAID configuration. This data structure should be as follows:
        raid_config = {'logical_disks': [{'raid_level': 1, 'size_gb': 100},
                                         <info-for-logical-disk-2>
                                        ]}
    :returns: the current raid configuration. This is same as raid_config
        with some extra properties like root_device_hint, volume_name,
        controller, physical_disks, etc filled for each logical disk
        after its creation.
    :raises exception.InvalidInputError, if input is invalid.
    :raises exception.HPSSAOperationError, if all the controllers are in HBA
        mode.
    """
    server = objects.Server()

    select_controllers = lambda x: not x.properties.get('HBA Mode Enabled',
                                                        False)
    _select_controllers_by(server, select_controllers, 'RAID enabled')

    validate(raid_config)

    # Make sure we create the large disks first.  This is avoid the
    # situation that we avoid giving large disks to smaller requests.
    # For example, consider this:
    #   - two logical disks - LD1(50), LD(100)
    #   - have 4 physical disks - PD1(50), PD2(50), PD3(100), PD4(100)
    #
    # In this case, for RAID1 configuration, if we were to consider
    # LD1 first and allocate PD3 and PD4 for it, then allocation would
    # fail. So follow a particular order for allocation.
    #
    # Also make sure we create the MAX logical_disks the last to make sure
    # we allot only the remaining space available.
    logical_disks_sorted = (
        sorted((x for x in raid_config['logical_disks']
                if x['size_gb'] != "MAX"),
               reverse=True,
               key=lambda x: x['size_gb']) +
        [x for x in raid_config['logical_disks'] if x['size_gb'] == "MAX"])

    if any(logical_disk['share_physical_disks']
            for logical_disk in logical_disks_sorted
            if 'share_physical_disks' in logical_disk):
        logical_disks_sorted = _sort_shared_logical_disks(logical_disks_sorted)

    # We figure out the new disk created by recording the wwns
    # before and after the create, and then figuring out the
    # newly found wwn from it.
    wwns_before_create = set([x.wwn for x in
                              server.get_logical_drives()])

    for logical_disk in logical_disks_sorted:

        if 'physical_disks' not in logical_disk:
            disk_allocator.allocate_disks(logical_disk, server,
                                          raid_config)

        controller_id = logical_disk['controller']

        controller = server.get_controller_by_id(controller_id)
        if not controller:
            msg = ("Unable to find controller named '%(controller)s'."
                   " The available controllers are '%(ctrl_list)s'." %
                   {'controller': controller_id,
                    'ctrl_list': ', '.join(
                        [c.id for c in server.controllers])})
            raise exception.InvalidInputError(reason=msg)

        if 'physical_disks' in logical_disk:
            for physical_disk in logical_disk['physical_disks']:
                disk_obj = controller.get_physical_drive_by_id(physical_disk)
                if not disk_obj:
                    msg = ("Unable to find physical disk '%(physical_disk)s' "
                           "on '%(controller)s'" %
                           {'physical_disk': physical_disk,
                            'controller': controller_id})
                    raise exception.InvalidInputError(msg)

        controller.create_logical_drive(logical_disk)

        # Now find the new logical drive created.
        server.refresh()
        wwns_after_create = set([x.wwn for x in
                                 server.get_logical_drives()])

        new_wwn = wwns_after_create - wwns_before_create

        if not new_wwn:
            reason = ("Newly created logical disk with raid_level "
                      "'%(raid_level)s' and size %(size_gb)s GB not "
                      "found." % {'raid_level': logical_disk['raid_level'],
                                  'size_gb': logical_disk['size_gb']})
            raise exception.HPSSAOperationError(reason=reason)

        new_logical_disk = server.get_logical_drive_by_wwn(new_wwn.pop())
        new_log_drive_properties = new_logical_disk.get_logical_drive_dict()
        logical_disk.update(new_log_drive_properties)

        wwns_before_create = wwns_after_create.copy()

    _update_physical_disk_details(raid_config, server)
    return raid_config


Instruction:
Make a summary of the following Python 3 code
def _sort_shared_logical_disks(logical_disks):
    is_shared = (lambda x: True if ('share_physical_disks' in x and
                                    x['share_physical_disks']) else False)
    num_of_disks = (lambda x: x['number_of_physical_disks']
                    if 'number_of_physical_disks' in x else
                    constants.RAID_LEVEL_MIN_DISKS[x['raid_level']])

    # Separate logical disks based on share_physical_disks value.
    # 'logical_disks_shared' when share_physical_disks is True and
    # 'logical_disks_nonshared' when share_physical_disks is False
    logical_disks_shared = []
    logical_disks_nonshared = []
    for x in logical_disks:
        target = (logical_disks_shared if is_shared(x)
                  else logical_disks_nonshared)
        target.append(x)

    # Separete logical disks with raid 1 from the 'logical_disks_shared' into
    # 'logical_disks_shared_raid1' and remaining as
    # 'logical_disks_shared_excl_raid1'.
    logical_disks_shared_raid1 = []
    logical_disks_shared_excl_raid1 = []
    for x in logical_disks_shared:
        target = (logical_disks_shared_raid1 if x['raid_level'] == '1'
                  else logical_disks_shared_excl_raid1)
        target.append(x)

    # Sort the 'logical_disks_shared' in reverse order based on
    # 'number_of_physical_disks' attribute, if provided, otherwise minimum
    # disks required to create the logical volume.
    logical_disks_shared = sorted(logical_disks_shared_excl_raid1,
                                  reverse=True,
                                  key=num_of_disks)

    # Move RAID 1+0 to first in 'logical_disks_shared' when number of physical
    # disks needed to create logical volume cannot be shared with odd number of
    # disks and disks higher than that of RAID 1+0.
    check = True
    for x in logical_disks_shared:
        if x['raid_level'] == "1+0":
            x_num = num_of_disks(x)
            for y in logical_disks_shared:
                if y['raid_level'] != "1+0":
                    y_num = num_of_disks(y)
                    if x_num < y_num:
                        check = (True if y_num % 2 == 0 else False)
                        if check:
                            break
        if not check:
            logical_disks_shared.remove(x)
            logical_disks_shared.insert(0, x)
            check = True

    # Final 'logical_disks_sorted' list should have non shared logical disks
    # first, followed by shared logical disks with RAID 1, and finally by the
    # shared logical disks sorted based on number of disks and RAID 1+0
    # condition.
    logical_disks_sorted = (logical_disks_nonshared +
                            logical_disks_shared_raid1 +
                            logical_disks_shared)
    return logical_disks_sorted

Response: Sort the logical disks based on the conditions that are set in the RAID1 and RAID2.


Instruction:
Can you tell what is the following Python 3 function doing
def delete_configuration():
    server = objects.Server()

    select_controllers = lambda x: not x.properties.get('HBA Mode Enabled',
                                                        False)
    _select_controllers_by(server, select_controllers, 'RAID enabled')

    for controller in server.controllers:
        # Trigger delete only if there is some RAID array, otherwise
        # hpssacli/ssacli will fail saying "no logical drives found.".
        if controller.raid_arrays:
            controller.delete_all_logical_drives()
    return get_configuration()

Response: Delete a RAID configuration on this server.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def get_configuration():
    server = objects.Server()
    logical_drives = server.get_logical_drives()
    raid_config = {}
    raid_config['logical_disks'] = []

    for logical_drive in logical_drives:
        logical_drive_dict = logical_drive.get_logical_drive_dict()
        raid_config['logical_disks'].append(logical_drive_dict)

    _update_physical_disk_details(raid_config, server)
    return raid_config

Response: Get the current RAID configuration.


Instruction:
Here you have a function in Python 3, explain what it does
def erase_devices():
    server = objects.Server()

    for controller in server.controllers:
        drives = [x for x in controller.unassigned_physical_drives
                  if (x.get_physical_drive_dict().get('erase_status', '')
                      == 'OK')]
        if drives:
            controller.erase_devices(drives)

    while not has_erase_completed():
        time.sleep(300)

    server.refresh()

    status = {}
    for controller in server.controllers:
        drive_status = {x.id: x.erase_status
                        for x in controller.unassigned_physical_drives}
        sanitize_supported = controller.properties.get(
            'Sanitize Erase Supported', 'False')
        if sanitize_supported == 'False':
            msg = ("Drives overwritten with zeros because sanitize erase "
                   "is not supported on the controller.")
        else:
            msg = ("Sanitize Erase performed on the disks attached to "
                   "the controller.")

        drive_status.update({'Summary': msg})
        status[controller.id] = drive_status

    return status

Response: Erase all the drives on this server.


Instruction:
Can you generate the documentation for the following Python 3 function
def _parse_metadata_and_message_count(response):
    '''
    Extracts approximate messages count header.
    '''
    metadata = _parse_metadata(response)

    headers = _parse_response_for_dict(response)
    metadata.approximate_message_count = _int_to_str(headers.get('x-ms-approximate-messages-count'))

    return metadata

Response: Extracts approximate messages count header.


Instruction:
Create a Python 3 function for
extracting pop receipt and time next visible from headers.

Response:
def _parse_queue_message_from_headers(response):
    '''
    Extracts pop receipt and time next visible from headers.
    '''
    headers = _parse_response_for_dict(response)

    message = QueueMessage()
    message.pop_receipt = headers.get('x-ms-popreceipt')
    message.time_next_visible = parser.parse(headers.get('x-ms-time-next-visible'))

    return message


Instruction:
Write a Python 3 script to
convert XML response to QueueMessagesList

Response:
def _convert_xml_to_queue_messages(response, decode_function):
    '''
    <?xml version="1.0" encoding="utf-8"?>
    <QueueMessagesList>
        <QueueMessage>
          <MessageId>string-message-id</MessageId>
          <InsertionTime>insertion-time</InsertionTime>
          <ExpirationTime>expiration-time</ExpirationTime>
          <PopReceipt>opaque-string-receipt-data</PopReceipt>
          <TimeNextVisible>time-next-visible</TimeNextVisible>
          <DequeueCount>integer</DequeueCount>
          <MessageText>message-body</MessageText>
        </QueueMessage>
    </QueueMessagesList>
    '''
    if response is None or response.body is None:
        return response

    messages = list()
    list_element = ETree.fromstring(response.body)

    for message_element in list_element.findall('QueueMessage'):
        message = QueueMessage()

        message.id = message_element.findtext('MessageId')
        message.dequeue_count = message_element.findtext('DequeueCount')

        message.content = decode_function(message_element.findtext('MessageText'))

        message.insertion_time = parser.parse(message_element.findtext('InsertionTime'))
        message.expiration_time = parser.parse(message_element.findtext('ExpirationTime'))

        message.pop_receipt = message_element.findtext('PopReceipt')

        time_next_visible = message_element.find('TimeNextVisible')
        if time_next_visible is not None:
            message.time_next_visible = parser.parse(time_next_visible.text)

        # Add message to list
        messages.append(message)

    return messages


Instruction:
Implement a function in Python 3 to
get the list of drives.

Response:
def _drives_list(self):
        """Gets the list of drives

        :return a list of drives.
        """
        drives_list = []
        for member in self.drives:
            drives_list.append(sys_drives.Drive(
                self._conn, member.get('@odata.id'), self.redfish_version))
        return drives_list


Instruction:
Create a Python 3 function to
return true if any of the drives is ssd

Response:
def has_ssd(self):
        """Return true if any of the drive is ssd"""
        for member in self._drives_list():
            if member.media_type == constants.MEDIA_TYPE_SSD:
                return True
        return False


Instruction:
Here you have a function in Python 3, explain what it does
def has_rotational(self):
        for member in self._drives_list():
            if member.media_type == constants.MEDIA_TYPE_HDD:
                return True
        return False

Response: Return True if any of the drives is HDD.


Instruction:
Can you implement a function in Python 3 that
returns True if the drive is SSD and protocol is NVMe

Response:
def has_nvme_ssd(self):
        """Return True if the drive is SSD and protocol is NVMe"""
        for member in self._drives_list():
            if (member.media_type == constants.MEDIA_TYPE_SSD and
                    member.protocol == constants.PROTOCOL_NVMe):
                return True
        return False


Instruction:
How would you explain what the following Python 3 function does
def drive_rotational_speed_rpm(self):

        drv_rot_speed_rpm = set()
        for member in self._drives_list():
            if member.rotation_speed_rpm is not None:
                drv_rot_speed_rpm.add(member.rotation_speed_rpm)
        return drv_rot_speed_rpm

Response: Gets the set of rotational speed of the disks


Instruction:
Make a summary of the following Python 3 code
def volumes_maximum_size_bytes(self):
        return utils.max_safe([member.volumes.maximum_size_bytes
                               for member in self.get_members()])

Response: Gets the biggest logical drive node s maximum size in MiB.


Instruction:
Can you generate the documentation for the following Python 3 function
def drive_rotational_speed_rpm(self):
        drv_rot_speed_rpm = set()
        for member in self.get_members():
            drv_rot_speed_rpm.update(member.drive_rotational_speed_rpm)
        return drv_rot_speed_rpm

Response: Gets the set of rotational speed of the disks


Instruction:
Here you have a function in Python 3, explain what it does
def create_table_service(self):
        '''
        Creates a TableService object with the settings specified in the
        CloudStorageAccount.

        :return: A service object.
        :rtype: :class:`~azure.storage.table.tableservice.TableService`
        '''
        try:
            from ..table.tableservice import TableService
            return TableService(self.account_name, self.account_key,
                                sas_token=self.sas_token,
                                is_emulated=self.is_emulated)
        except ImportError:
            raise Exception('The package azure-storage-table is required. '
                            + 'Please install it using "pip install azure-storage-table"')

Response:
Creates a TableService object with the settings specified in the
        CloudStorageAccount.


Instruction:
Create a Python 3 function to
retrieve the properties of a storage account s Queue service including Azure Storage Account s Queue service logging analytics and CORS rules.

Response:
def get_queue_service_properties(self, timeout=None):
        '''
        Gets the properties of a storage account's Queue service, including
        logging, analytics and CORS rules.

        :param int timeout:
            The server timeout, expressed in seconds.
        :return: The queue service properties.
        :rtype: :class:`~azure.storage.models.ServiceProperties`
        '''
        request = HTTPRequest()
        request.method = 'GET'
        request.host = self._get_host()
        request.path = _get_path()
        request.query = [
            ('restype', 'service'),
            ('comp', 'properties'),
            ('timeout', _int_to_str(timeout)),
        ]
        response = self._perform_request(request)

        return _convert_xml_to_service_properties(response.body)


Instruction:
Given the following Python 3 function, write the documentation
def list_queues(self, prefix=None, num_results=None, include_metadata=False,
                    marker=None, timeout=None):
        '''
        Returns a generator to list the queues. The generator will lazily follow
        the continuation tokens returned by the service and stop when all queues
        have been returned or num_results is reached.

        If num_results is specified and the account has more than that number of
        queues, the generator will have a populated next_marker field once it
        finishes. This marker can be used to create a new generator if more
        results are desired.

        :param str prefix:
            Filters the results to return only queues with names that begin
            with the specified prefix.
        :param int num_results:
            The maximum number of queues to return.
        :param bool include_metadata:
            Specifies that container metadata be returned in the response.
        :param str marker:
            An opaque continuation token. This value can be retrieved from the
            next_marker field of a previous generator object if num_results was
            specified and that generator has finished enumerating results. If
            specified, this generator will begin returning results from the point
            where the previous generator stopped.
        :param int timeout:
            The server timeout, expressed in seconds. This function may make multiple
            calls to the service in which case the timeout value specified will be
            applied to each individual call.
        '''
        include = 'metadata' if include_metadata else None
        kwargs = {'prefix': prefix, 'max_results': num_results, 'include': include,
                  'marker': marker, 'timeout': timeout}
        resp = self._list_queues(**kwargs)

        return ListGenerator(resp, self._list_queues, (), kwargs)

Response: Returns a generator to list the queues in the specified prefix.


Instruction:
Can you tell what is the following Python 3 function doing
def _list_queues(self, prefix=None, marker=None, max_results=None,
                    include=None, timeout=None):
        '''
        Returns a list of queues under the specified account. Makes a single list
        request to the service. Used internally by the list_queues method.

        :param str prefix:
            Filters the results to return only queues with names that begin
            with the specified prefix.
        :param str marker:
            A token which identifies the portion of the query to be
            returned with the next query operation. The operation returns a
            next_marker element within the response body if the list returned
            was not complete. This value may then be used as a query parameter
            in a subsequent call to request the next portion of the list of
            queues. The marker value is opaque to the client.
        :param int max_results:
            The maximum number of queues to return. A single list request may
            return up to 1000 queues and potentially a continuation token which
            should be followed to get additional resutls.
        :param str include:
            Include this parameter to specify that the container's
            metadata be returned as part of the response body.
        :param int timeout:
            The server timeout, expressed in seconds.
        '''
        request = HTTPRequest()
        request.method = 'GET'
        request.host = self._get_host()
        request.path = _get_path()
        request.query = [
            ('comp', 'list'),
            ('prefix', _to_str(prefix)),
            ('marker', _to_str(marker)),
            ('maxresults', _int_to_str(max_results)),
            ('include', _to_str(include)),
            ('timeout', _int_to_str(timeout))
        ]
        response = self._perform_request(request)

        return _convert_xml_to_queues(response)

Response: Returns a list of queues under the specified account.


Instruction:
Here you have a function in Python 3, explain what it does
def create_queue(self, queue_name, metadata=None, fail_on_exist=False, timeout=None):
        '''
        Creates a queue under the given account.

        :param str queue_name:
            The name of the queue to create. A queue name must be from 3 through
            63 characters long and may only contain lowercase letters, numbers,
            and the dash (-) character. The first and last letters in the queue
            must be alphanumeric. The dash (-) character cannot be the first or
            last character. Consecutive dash characters are not permitted in the
            queue name.
        :param metadata:
            A dict containing name-value pairs to associate with the queue as
            metadata. Note that metadata names preserve the case with which they
            were created, but are case-insensitive when set or read.
        :type metadata: a dict mapping str to str
        :param bool fail_on_exist:
            Specifies whether to throw an exception if the queue already exists.
        :param int timeout:
            The server timeout, expressed in seconds.
        :return:
            A boolean indicating whether the queue was created. If fail_on_exist
            was set to True, this will throw instead of returning false.
        :rtype: bool
        '''
        _validate_not_none('queue_name', queue_name)
        request = HTTPRequest()
        request.method = 'PUT'
        request.host = self._get_host()
        request.path = _get_path(queue_name)
        request.query = [('timeout', _int_to_str(timeout))]
        request.headers = [('x-ms-meta-name-values', metadata)]
        if not fail_on_exist:
            try:
                response = self._perform_request(request)
                if response.status == _HTTP_RESPONSE_NO_CONTENT:
                    return False
                return True
            except AzureHttpError as ex:
                _dont_fail_on_exist(ex)
                return False
        else:
            response = self._perform_request(request)
            if response.status == _HTTP_RESPONSE_NO_CONTENT:
                raise AzureConflictHttpError(
                    _ERROR_CONFLICT.format(response.message), response.status)
            return True

Response: Creates a queue under the given account.