Instruction:
Implement a Python 3 function for
localizing a source from its TS map.

Response:
def _fit_position_tsmap(self, name, **kwargs):
        """Localize a source from its TS map."""

        prefix = kwargs.get('prefix', '')
        dtheta_max = kwargs.get('dtheta_max', 0.5)
        zmin = kwargs.get('zmin', -3.0)

        kw = {
            'map_size': 2.0 * dtheta_max,
            'write_fits':  kwargs.get('write_fits', False),
            'write_npy':  kwargs.get('write_npy', False),
            'use_pylike': kwargs.get('use_pylike', True),
            'max_kernel_radius': self.config['tsmap']['max_kernel_radius'],
            'loglevel': logging.DEBUG
        }

        src = self.roi.copy_source(name)

        if src['SpatialModel'] in ['RadialDisk', 'RadialGaussian']:
            kw['max_kernel_radius'] = max(kw['max_kernel_radius'],
                                          2.0 * src['SpatialWidth'])

        skydir = kwargs.get('skydir', src.skydir)
        tsmap = self.tsmap(utils.join_strings([prefix, name.lower().
                                               replace(' ', '_')]),
                           model=src.data,
                           map_skydir=skydir,
                           exclude=[name],
                           make_plots=False, **kw)

        # Find peaks with TS > 4
        peaks = find_peaks(tsmap['ts'], 4.0, 0.2)
        peak_best = None
        o = {}
        for p in sorted(peaks, key=lambda t: t['amp'], reverse=True):
            xy = p['ix'], p['iy']
            ts_value = tsmap['ts'].data[xy[1], xy[0]]
            posfit = fit_error_ellipse(tsmap['ts'], xy=xy, dpix=2,
                                       zmin=max(zmin, -ts_value * 0.5))
            offset = posfit['skydir'].separation(self.roi[name].skydir).deg
            if posfit['fit_success'] and posfit['fit_inbounds']:
                peak_best = p
                break

        if peak_best is None:
            ts_value = np.max(tsmap['ts'].data)
            posfit = fit_error_ellipse(tsmap['ts'], dpix=2,
                                       zmin=max(zmin, -ts_value * 0.5))

        o.update(posfit)
        pix = posfit['skydir'].to_pixel(self.geom.wcs)
        o['xpix'] = float(pix[0])
        o['ypix'] = float(pix[1])
        o['skydir'] = posfit['skydir'].transform_to('icrs')
        o['pos_offset'] = posfit['skydir'].separation(
            self.roi[name].skydir).deg
        o['loglike'] = 0.5 * posfit['zoffset']
        o['tsmap'] = tsmap['ts']

        return o


Instruction:
Here you have a function in Python 3, explain what it does
def make_nfs_path(path):
    if os.path.isabs(path):
        fullpath = path
    else:
        fullpath = os.path.abspath(path)
    if len(fullpath) < 6:
        return fullpath
    if fullpath[0:6] == '/gpfs/':
        fullpath = fullpath.replace('/gpfs/', '/nfs/')
    return fullpath

Response: Make a nfs version of a file path.


Instruction:
How would you implement a function in Python 3 that
makes a gpfs version of a file path.

Response:
def make_gpfs_path(path):
    """Make a gpfs version of a file path.
    This just puts /gpfs at the beginning instead of /nfs"""
    if os.path.isabs(path):
        fullpath = os.path.abspath(path)
    else:
        fullpath = os.path.abspath(path)
    if len(fullpath) < 5:
        return fullpath
    if fullpath[0:5] == '/nfs/':
        fullpath = fullpath.replace('/nfs/', '/gpfs/')
    return fullpath


Instruction:
Write a Python 3 function for
counting and print the number of jobs in various LSF states

Response:
def get_lsf_status():
    """Count and print the number of jobs in various LSF states
    """
    status_count = {'RUN': 0,
                    'PEND': 0,
                    'SUSP': 0,
                    'USUSP': 0,
                    'NJOB': 0,
                    'UNKNWN': 0}

    try:
        subproc = subprocess.Popen(['bjobs'],
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)
        subproc.stderr.close()
        output = subproc.stdout.readlines()
    except OSError:
        return status_count

    for line in output[1:]:
        line = line.strip().split()
        # Protect against format of multiproc jobs
        if len(line) < 5:
            continue

        status_count['NJOB'] += 1

        for k in status_count:
            if line[2] == k:
                status_count[k] += 1

    return status_count


Instruction:
Explain what the following Python 3 code does
def build_bsub_command(command_template, lsf_args):
    if command_template is None:
        return ""
    full_command = 'bsub -o {logfile}'
    for key, value in lsf_args.items():
        full_command += ' -%s' % key
        if value is not None:
            full_command += ' %s' % value
    full_command += ' %s' % command_template
    return full_command

Response: Build and return a lsf batch command template


Instruction:
Can you generate the documentation for the following Python 3 function
def get_slac_default_args(job_time=1500):
    slac_default_args = dict(lsf_args={'W': job_time,
                                       'R': '\"select[rhel60&&!fell]\"'},
                             max_jobs=500,
                             time_per_cycle=15,
                             jobs_per_cycle=20,
                             max_job_age=90,
                             no_batch=False)
    return slac_default_args.copy()

Response: Create a default set of arguments for the batch job interface.


Instruction:
Can you tell what is the following Python 3 function doing
def dispatch_job_hook(self, link, key, job_config, logfile, stream=sys.stdout):
        full_sub_dict = job_config.copy()

        if self._no_batch:
            full_command = "%s >& %s" % (
                link.command_template().format(**full_sub_dict), logfile)
        else:
            full_sub_dict['logfile'] = logfile
            full_command_template = build_bsub_command(
                link.command_template(), self._lsf_args)
            full_command = full_command_template.format(**full_sub_dict)

        logdir = os.path.dirname(logfile)

        print_bsub = True
        if self._dry_run:
            if print_bsub:
                stream.write("%s\n" % full_command)
            return 0

        try:
            os.makedirs(logdir)
        except OSError:
            pass
        proc = subprocess.Popen(full_command.split(),
                                stderr=stream,
                                stdout=stream)
        proc.communicate()
        return proc.returncode

Response: Dispatches a single job to the LSF batch


Instruction:
Create a Python 3 function to
submit all the jobs in job_dict.

Response:
def submit_jobs(self, link, job_dict=None, job_archive=None, stream=sys.stdout):
        """Submit all the jobs in job_dict """
        if link is None:
            return JobStatus.no_job
        if job_dict is None:
            job_keys = link.jobs.keys()
        else:
            job_keys = sorted(job_dict.keys())

        # copy & reverse the keys b/c we will be popping item off the back of
        # the list
        unsubmitted_jobs = job_keys
        unsubmitted_jobs.reverse()

        failed = False
        if unsubmitted_jobs:
            if stream != sys.stdout:
                sys.stdout.write('Submitting jobs (%i): ' %
                                 len(unsubmitted_jobs))
                sys.stdout.flush()
        while unsubmitted_jobs:
            status = get_lsf_status()
            njob_to_submit = min(self._max_jobs - status['NJOB'],
                                 self._jobs_per_cycle,
                                 len(unsubmitted_jobs))

            if self._dry_run:
                njob_to_submit = len(unsubmitted_jobs)

            for i in range(njob_to_submit):
                job_key = unsubmitted_jobs.pop()

                # job_details = job_dict[job_key]
                job_details = link.jobs[job_key]
                job_config = job_details.job_config
                if job_details.status == JobStatus.failed:
                    clean_job(job_details.logfile, {}, self._dry_run)
                    # clean_job(job_details.logfile,
                    #          job_details.outfiles, self.args['dry_run'])

                job_config['logfile'] = job_details.logfile
                new_job_details = self.dispatch_job(
                    link, job_key, job_archive, stream)
                if new_job_details.status == JobStatus.failed:
                    failed = True
                    clean_job(new_job_details.logfile,
                              new_job_details.outfiles, self._dry_run)
                link.jobs[job_key] = new_job_details

            if unsubmitted_jobs:
                if stream != sys.stdout:
                    sys.stdout.write('.')
                    sys.stdout.flush()
                stream.write('Sleeping %.0f seconds between submission cycles\n' %
                             self._time_per_cycle)
                time.sleep(self._time_per_cycle)

        if failed:
            return JobStatus.failed

        if stream != sys.stdout:
            sys.stdout.write('!\n')

        return JobStatus.done


Instruction:
How would you implement a function in Python 3 that
loads an FT2 file from a file or list of files.

Response:
def create_sc_table(scfile, colnames=None):
    """Load an FT2 file from a file or list of files."""

    if utils.is_fits_file(scfile) and colnames is None:
        return create_table_from_fits(scfile, 'SC_DATA')

    if utils.is_fits_file(scfile):
        files = [scfile]
    else:
        files = [line.strip() for line in open(scfile, 'r')]

    tables = [create_table_from_fits(f, 'SC_DATA', colnames)
              for f in files]

    return vstack(tables)


Instruction:
How would you implement a function in Python 3 that
computes the local spectral index of a source.

Response:
def get_spectral_index(src, egy):
    """Compute the local spectral index of a source."""
    delta = 1E-5
    f0 = src.spectrum()(pyLike.dArg(egy * (1 - delta)))
    f1 = src.spectrum()(pyLike.dArg(egy * (1 + delta)))

    if f0 > 0 and f1 > 0:
        gamma = np.log10(f0 / f1) / np.log10((1 - delta) / (1 + delta))
    else:
        gamma = np.nan

    return gamma


Instruction:
Here you have a function in Python 3, explain what it does
def create(cls, infile, config=None, params=None, mask=None):

        infile = os.path.abspath(infile)
        roi_file, roi_data = utils.load_data(infile)

        if config is None:
            config = roi_data['config']
            validate = False
        else:
            validate = True

        gta = cls(config, validate=validate)
        gta.setup(init_sources=False)
        gta.load_roi(infile, params=params, mask=mask)
        return gta

Response: Create a new GTAnalysis from an analysis output file.


Instruction:
Create a Python 3 function to
make a clone of this analysis instance.

Response:
def clone(self, config, **kwargs):
        """Make a clone of this analysis instance."""
        gta = GTAnalysis(config, **kwargs)
        gta._roi = copy.deepcopy(self.roi)
        return gta


Instruction:
Can you generate a brief explanation for the following Python 3 code
def set_random_seed(self, seed):
        self.config['mc']['seed'] = seed
        np.random.seed(seed)

Response: Set the seed for the random number generator


Instruction:
Can you write a function in Python 3 where it
deletes and reload a source in the model.

Response:
def reload_source(self, name, init_source=True):
        """Delete and reload a source in the model.  This will update
        the spatial model of this source to the one defined in the XML
        model."""

        for c in self.components:
            c.reload_source(name)

        if init_source:
            self._init_source(name)

        self.like.model = self.like.components[0].model


Instruction:
How would you code a function in Python 3 to
set the spatial model of a source.

Response:
def set_source_morphology(self, name, **kwargs):
        """Set the spatial model of a source.

        Parameters
        ----------
        name : str
           Source name.

        spatial_model : str
           Spatial model name (PointSource, RadialGaussian, etc.).

        spatial_pars : dict
           Dictionary of spatial parameters (optional).

        use_cache : bool
           Generate the spatial model by interpolating the cached source
           map.

        use_pylike : bool

        """

        name = self.roi.get_source_by_name(name).name
        src = self.roi[name]

        spatial_model = kwargs.get('spatial_model', src['SpatialModel'])
        spatial_pars = kwargs.get('spatial_pars', {})
        use_pylike = kwargs.get('use_pylike', True)
        psf_scale_fn = kwargs.get('psf_scale_fn', None)
        update_source = kwargs.get('update_source', False)

        if hasattr(pyLike.BinnedLikelihood, 'setSourceMapImage') and not use_pylike:
            src.set_spatial_model(spatial_model, spatial_pars)
            self._update_srcmap(src.name, src, psf_scale_fn=psf_scale_fn)
        else:
            src = self.delete_source(name, loglevel=logging.DEBUG,
                                     save_template=False)
            src.set_spatial_model(spatial_model, spatial_pars)
            self.add_source(src.name, src, init_source=False,
                            use_pylike=use_pylike, loglevel=logging.DEBUG)

        if update_source:
            self.update_source(name)


Instruction:
How would you implement a function in Python 3 that
sets the spectral model of a source. This function can be used to change the spectral type of a source or modify its spectral parameters. If called with spectrum_type='FileFunction' and spectrum_pars=None, the source spectrum will be replaced with a FileFunction with the same differential flux distribution as the original spectrum. Parameters ---------- name : str Source name. spectrum_type : str Spectrum type (PowerLaw, etc.). spectrum_pars : dict Dictionary of spectral parameters (optional). update_source : bool Recompute all source characteristics (flux, TS, NPred) using the new spectral model of the source.

Response:
def set_source_spectrum(self, name, spectrum_type='PowerLaw',
                            spectrum_pars=None, update_source=True):
        """Set the spectral model of a source.  This function can be
        used to change the spectral type of a source or modify its
        spectral parameters.  If called with
        spectrum_type='FileFunction' and spectrum_pars=None, the
        source spectrum will be replaced with a FileFunction with the
        same differential flux distribution as the original spectrum.

        Parameters
        ----------

        name : str
           Source name.

        spectrum_type : str
           Spectrum type (PowerLaw, etc.).

        spectrum_pars : dict
           Dictionary of spectral parameters (optional).

        update_source : bool
           Recompute all source characteristics (flux, TS, NPred)
           using the new spectral model of the source.

        """
        name = self.roi.get_source_by_name(name).name
        src = self.roi[name]

        spectrum_pars = {} if spectrum_pars is None else spectrum_pars
        if (self.roi[name]['SpectrumType'] == 'PowerLaw' and
                spectrum_type == 'LogParabola'):
            spectrum_pars.setdefault('beta', {'value': 0.0, 'scale': 1.0,
                                              'min': 0.0, 'max': 1.0})
            spectrum_pars.setdefault('Eb', src.spectral_pars['Scale'])
            spectrum_pars.setdefault('norm', src.spectral_pars['Prefactor'])
            if 'alpha' not in spectrum_pars:
                spectrum_pars['alpha'] = src.spectral_pars['Index']
                spectrum_pars['alpha']['value'] *= -1.0
                if spectrum_pars['alpha']['scale'] == -1.0:
                    spectrum_pars['alpha']['value'] *= -1.0
                    spectrum_pars['alpha']['scale'] *= -1.0

        if spectrum_type == 'FileFunction':
            self._create_filefunction(name, spectrum_pars)
        else:
            fn = gtutils.create_spectrum_from_dict(spectrum_type,
                                                   spectrum_pars)
            self.like.setSpectrum(str(name), fn)

        # Get parameters
        src = self.components[0].like.logLike.getSource(str(name))
        pars_dict = gtutils.get_function_pars_dict(src.spectrum())

        self.roi[name]['SpectrumType'] = spectrum_type
        self.roi[name].set_spectral_pars(pars_dict)
        for c in self.components:
            c.roi[name]['SpectrumType'] = spectrum_type
            c.roi[name].set_spectral_pars(pars_dict)

        if update_source:
            self.update_source(name)


Instruction:
Write a Python 3 function for
setting the differential flux distribution of a source with the FileFunction spectral type.

Response:
def set_source_dnde(self, name, dnde, update_source=True):
        """Set the differential flux distribution of a source with the
        FileFunction spectral type.

        Parameters
        ----------
        name : str
           Source name.

        dnde : `~numpy.ndarray`
           Array of differential flux values (cm^{-2} s^{-1} MeV^{-1}).
        """
        name = self.roi.get_source_by_name(name).name

        if self.roi[name]['SpectrumType'] != 'FileFunction':
            msg = 'Wrong spectral type: %s' % self.roi[name]['SpectrumType']
            self.logger.error(msg)
            raise Exception(msg)

        xy = self.get_source_dnde(name)

        if len(dnde) != len(xy[0]):
            msg = 'Wrong length for dnde array: %i' % len(dnde)
            self.logger.error(msg)
            raise Exception(msg)

        for c in self.components:
            src = c.like.logLike.getSource(str(name))
            spectrum = src.spectrum()
            file_function = pyLike.FileFunction_cast(spectrum)
            file_function.setSpectrum(10**xy[0], dnde)

        if update_source:
            self.update_source(name)


Instruction:
Can you tell what is the following Python 3 function doing
def _create_filefunction(self, name, spectrum_pars):

        spectrum_pars = {} if spectrum_pars is None else spectrum_pars

        if 'loge' in spectrum_pars:
            loge = spectrum_pars.get('loge')
        else:
            ebinsz = (self.log_energies[-1] -
                      self.log_energies[0]) / self.enumbins
            loge = utils.extend_array(self.log_energies, ebinsz, 0.5, 6.5)

        # Get the values
        dnde = np.zeros(len(loge))
        if 'dnde' in spectrum_pars:
            dnde = spectrum_pars.get('dnde')
        else:
            dnde = np.array([self.like[name].spectrum()(pyLike.dArg(10 ** egy))
                             for egy in loge])

        filename = \
            os.path.join(self.workdir,
                         '%s_filespectrum.txt' % (name.lower().replace(' ', '_')))

        # Create file spectrum txt file
        np.savetxt(filename, np.vstack((10**loge, dnde)).T)
        self.like.setSpectrum(name, str('FileFunction'))

        self.roi[name]['Spectrum_Filename'] = filename
        # Update
        for c in self.components:
            src = c.like.logLike.getSource(str(name))
            spectrum = src.spectrum()

            spectrum.getParam(str('Normalization')).setBounds(1E-3, 1E3)

            file_function = pyLike.FileFunction_cast(spectrum)
            file_function.readFunction(str(filename))
            c.roi[name]['Spectrum_Filename'] = filename

Response: Create the file function for an existing source.


Instruction:
Here you have a function in Python 3, explain what it does
def stage_output(self):

        if self.workdir == self.outdir:
            return
        elif not os.path.isdir(self.workdir):
            self.logger.error('Working directory does not exist.')
            return

        regex = self.config['fileio']['outdir_regex']
        savefits = self.config['fileio']['savefits']
        files = os.listdir(self.workdir)
        self.logger.info('Staging files to %s', self.outdir)

        fitsfiles = []
        for c in self.components:
            for f in c.files.values():

                if f is None:
                    continue

                fitsfiles += [os.path.basename(f)]

        for f in files:

            wpath = os.path.join(self.workdir, f)
            opath = os.path.join(self.outdir, f)

            if not utils.match_regex_list(regex, os.path.basename(f)):
                continue
            if os.path.isfile(opath) and filecmp.cmp(wpath, opath, False):
                continue
            if not savefits and f in fitsfiles:
                continue

            self.logger.debug('Copying ' + f)
            self.logger.info('Copying ' + f)
            shutil.copy(wpath, self.outdir)

        self.logger.info('Finished.')

Response: Copy data products to final output directory.


Instruction:
Can you generate the documentation for the following Python 3 function
def stage_input(self):

        if self.workdir == self.outdir:
            return
        elif not os.path.isdir(self.workdir):
            self.logger.error('Working directory does not exist.')
            return

        self.logger.info('Staging files to %s', self.workdir)

        files = [os.path.join(self.outdir, f)
                 for f in os.listdir(self.outdir)]

        regex = copy.deepcopy(self.config['fileio']['workdir_regex'])

        for f in files:

            if not os.path.isfile(f):
                continue
            if not utils.match_regex_list(regex, os.path.basename(f)):
                continue

            self.logger.debug('Copying ' + os.path.basename(f))
            shutil.copy(f, self.workdir)

        for c in self.components:
            for f in c.files.values():

                if f is None:
                    continue

                wpath = os.path.join(self.workdir, os.path.basename(f))
                opath = os.path.join(self.outdir, os.path.basename(f))

                if os.path.isfile(wpath):
                    continue
                elif os.path.isfile(opath):
                    self.logger.debug('Copying ' + os.path.basename(f))
                    shutil.copy(opath, self.workdir)

        self.logger.info('Finished.')

Response: Copy input files to working directory.


Instruction:
Can you generate the documentation for the following Python 3 function
def setup(self, init_sources=True, overwrite=False, **kwargs):

        loglevel = kwargs.get('loglevel', self.loglevel)

        self.logger.log(loglevel, 'Running setup.')

        # Make spatial maps for extended sources
        for s in self.roi.sources:
            if s.diffuse:
                continue
            if not s.extended:
                continue
            self.make_template(s)

        # Run setup for each component
        for i, c in enumerate(self.components):
            c.setup(overwrite=overwrite)

        # Create likelihood
        self._create_likelihood()

        # Determine tmin, tmax
        for i, c in enumerate(self._components):
            self._tmin = (c.tmin if self._tmin is None
                          else min(self._tmin, c.tmin))
            self._tmax = (c.tmax if self._tmax is None
                          else min(self._tmax, c.tmax))

        if init_sources:

            self.logger.log(loglevel, 'Initializing source properties')
            for name in self.like.sourceNames():
                self.logger.debug('Initializing source %s', name)
                self._init_source(name)
            self._update_roi()

        self.logger.log(loglevel, 'Finished setup.')

Response: This function performs pre - processing for each analysis component and construct a joint likelihood object.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def _create_likelihood(self, srcmdl=None):

        self._like = SummedLikelihood()
        for c in self.components:
            c._create_binned_analysis(srcmdl)
            self._like.addComponent(c.like)

        self.like.model = self.like.components[0].model
        self._fitcache = None
        self._init_roi_model()

Response: Instantiate the likelihood object for each component and create a SummedLikelihood object.


Instruction:
Can you tell what is the following Python 3 function doing
def generate_model(self, model_name=None):

        for i, c in enumerate(self._components):
            c.generate_model(model_name=model_name)

Response: Generate model maps for all components.


Instruction:
Write a Python 3 function for
setting the energy bounds of the analysis. This restricts the evaluation of the likelihood to the data that falls in this range. Input values will be rounded to the closest bin edge value. If either argument is None then the lower or upper bound of the analysis instance will be used. Parameters ---------- logemin : float Lower energy bound in log10(E/MeV). logemax : float Upper energy bound in log10(E/MeV). Returns ------- eminmax : array Minimum and maximum energy in log10(E/MeV).

Response:
def set_energy_range(self, logemin, logemax):
        """Set the energy bounds of the analysis.  This restricts the
        evaluation of the likelihood to the data that falls in this
        range.  Input values will be rounded to the closest bin edge
        value.  If either argument is None then the lower or upper
        bound of the analysis instance will be used.

        Parameters
        ----------

        logemin : float
           Lower energy bound in log10(E/MeV).

        logemax : float
           Upper energy bound in log10(E/MeV).

        Returns
        -------

        eminmax : array
           Minimum and maximum energy in log10(E/MeV).

        """

        if logemin is None:
            logemin = self.log_energies[0]
        else:
            imin = int(utils.val_to_edge(self.log_energies, logemin)[0])
            logemin = self.log_energies[imin]

        if logemax is None:
            logemax = self.log_energies[-1]
        else:
            imax = int(utils.val_to_edge(self.log_energies, logemax)[0])
            logemax = self.log_energies[imax]

        self._loge_bounds = np.array([logemin, logemax])
        self._roi_data['loge_bounds'] = np.copy(self.loge_bounds)
        for c in self.components:
            c.set_energy_range(logemin, logemax)

        return self._loge_bounds


Instruction:
Write a Python 3 function for
returning the model counts map for a single source a list of sources or for the sum of all sources in the ROI.

Response:
def model_counts_map(self, name=None, exclude=None, use_mask=False):
        """Return the model counts map for a single source, a list of
        sources, or for the sum of all sources in the ROI.  The
        exclude parameter can be used to exclude one or more
        components when generating the model map.

        Parameters
        ----------
        name : str or list of str

           Parameter controlling the set of sources for which the
           model counts map will be calculated.  If name=None the
           model map will be generated for all sources in the ROI.

        exclude : str or list of str

           List of sources that will be excluded when calculating the
           model map.

        use_mask : bool

           Parameter that specifies in the model counts map should include
           mask pixels (i.e., ones whose weights are <= 0)

        Returns
        -------
        map : `~gammapy.maps.Map`
        """
        maps = [c.model_counts_map(name, exclude, use_mask=use_mask)
                for c in self.components]
        return skymap.coadd_maps(self.geom, maps)


Instruction:
Implement a Python 3 function for
returning the predicted number of model counts versus energy for a given source and energy range.

Response:
def model_counts_spectrum(self, name, logemin=None, logemax=None,
                              summed=False, weighted=False):
        """Return the predicted number of model counts versus energy
        for a given source and energy range.  If summed=True return
        the counts spectrum summed over all components otherwise
        return a list of model spectra.   If weighted=True return
        the weighted version of the counts spectrum
        """

        if logemin is None:
            logemin = self.log_energies[0]
        if logemax is None:
            logemax = self.log_energies[-1]

        if summed:
            cs = np.zeros(self.enumbins)
            imin = utils.val_to_bin_bounded(self.log_energies,
                                            logemin + 1E-7)[0]
            imax = utils.val_to_bin_bounded(self.log_energies,
                                            logemax - 1E-7)[0] + 1

            for c in self.components:
                ecenter = 0.5 * (c.log_energies[:-1] + c.log_energies[1:])
                counts = c.model_counts_spectrum(name, self.log_energies[0],
                                                 self.log_energies[-1], weighted)
                cs += np.histogram(ecenter,
                                   weights=counts,
                                   bins=self.log_energies)[0]

            return cs[imin:imax]
        else:
            cs = []
            for c in self.components:
                cs += [c.model_counts_spectrum(name, logemin,
                                               logemax, weighted=weighted)]
            return cs


Instruction:
Write a Python 3 script for
retrieving list of sources in the ROI satisfying the given cuts distance skydir and exclude.

Response:
def get_sources(self, cuts=None, distance=None, skydir=None,
                    minmax_ts=None, minmax_npred=None, exclude=None,
                    square=False):
        """Retrieve list of sources in the ROI satisfying the given
        selections.

        Returns
        -------
        srcs : list
            A list of `~fermipy.roi_model.Model` objects.

        """

        coordsys = self.config['binning']['coordsys']
        return self.roi.get_sources(skydir, distance, cuts,
                                    minmax_ts, minmax_npred,
                                    exclude, square,
                                    coordsys=coordsys)


Instruction:
Implement a Python 3 function for
adding a source to the ROI model.

Response:
def add_source(self, name, src_dict, free=None, init_source=True,
                   save_source_maps=True, use_pylike=True,
                   use_single_psf=False, **kwargs):
        """Add a source to the ROI model.  This function may be called
        either before or after `~fermipy.gtanalysis.GTAnalysis.setup`.

        Parameters
        ----------
        name : str
            Source name.

        src_dict : dict or `~fermipy.roi_model.Source` object
            Dictionary or source object defining the source properties
            (coordinates, spectral parameters, etc.).

        free : bool
            Initialize the source with a free normalization parameter.

        use_pylike : bool
            Create source maps with pyLikelihood.

        use_single_psf : bool
            Use the PSF model calculated for the ROI center.  If false
            then a new model will be generated using the position of
            the source.

        """

        if self.roi.has_source(name):
            msg = 'Source %s already exists.' % name
            self.logger.error(msg)
            raise Exception(msg)

        loglevel = kwargs.pop('loglevel', self.loglevel)

        self.logger.log(loglevel, 'Adding source ' + name)

        src = self.roi.create_source(name, src_dict, rescale=True)
        self.make_template(src)

        for c in self.components:
            c.add_source(name, src_dict, free=free,
                         save_source_maps=save_source_maps,
                         use_pylike=use_pylike,
                         use_single_psf=use_single_psf)

        if self._like is None:
            return

        if self.config['gtlike']['edisp'] and src.name not in \
                self.config['gtlike']['edisp_disable']:
            self.set_edisp_flag(src.name, True)

        self.like.syncSrcParams(str(name))
        self.like.model = self.like.components[0].model
        # if free is not None:
        #    self.free_norm(name, free, loglevel=logging.DEBUG)

        if init_source:
            self._init_source(name)
            self._update_roi()

        if self._fitcache is not None:
            self._fitcache.update_source(name)


Instruction:
Explain what the following Python 3 code does
def add_sources_from_roi(self, names, roi, free=False, **kwargs):

        for name in names:
            self.add_source(name, roi[name].data, free=free, **kwargs)

Response: Add multiple sources to the current ROI model copied from another ROI model.


Instruction:
Make a summary of the following Python 3 code
def delete_source(self, name, save_template=True, delete_source_map=False,
                      build_fixed_wts=True, **kwargs):
        """Delete a source from the ROI model.

        Parameters
        ----------
        name : str
            Source name.

        save_template : bool
            Keep the SpatialMap FITS template associated with this
            source.

        delete_source_map : bool
            Delete the source map associated with this source from the
            source maps file.

        Returns
        -------
        src : `~fermipy.roi_model.Model`
            The deleted source object.

        """

        if not self.roi.has_source(name):
            self.logger.error('No source with name: %s', name)
            return

        loglevel = kwargs.pop('loglevel', self.loglevel)

        self.logger.log(loglevel, 'Deleting source %s', name)

        # STs require a source to be freed before deletion
        if self.like is not None:
            self.free_norm(name, loglevel=logging.DEBUG)

        for c in self.components:
            c.delete_source(name, save_template=save_template,
                            delete_source_map=delete_source_map,
                            build_fixed_wts=build_fixed_wts)

        src = self.roi.get_source_by_name(name)
        self.roi.delete_sources([src])
        if self.like is not None:
            self.like.model = self.like.components[0].model
            self._update_roi()
        return src

Response: Delete a source from the ROI model.


Instruction:
Create a Python 3 function for
deleting sources in the ROI model satisfying the given selection criteria.

Response:
def delete_sources(self, cuts=None, distance=None,
                       skydir=None, minmax_ts=None, minmax_npred=None,
                       exclude=None, square=False, names=None):
        """Delete sources in the ROI model satisfying the given
        selection criteria.

        Parameters
        ----------
        cuts : dict
            Dictionary of [min,max] selections on source properties.

        distance : float
            Cut on angular distance from ``skydir``.  If None then no
            selection will be applied.

        skydir : `~astropy.coordinates.SkyCoord`
            Reference sky coordinate for ``distance`` selection.  If
            None then the distance selection will be applied with
            respect to the ROI center.

        minmax_ts : list
            Select sources that have TS in the range [min,max].  If
            either min or max are None then only a lower (upper) bound
            will be applied.  If this parameter is none no selection
            will be applied.

        minmax_npred : list
            Select sources that have npred in the range [min,max].  If
            either min or max are None then only a lower (upper) bound
            will be applied.  If this parameter is none no selection
            will be applied.

        square : bool
            Switch between applying a circular or square (ROI-like)
            selection on the maximum projected distance from the ROI
            center.

        names : list
            Select sources matching a name in this list.

        Returns
        -------
        srcs : list
            A list of `~fermipy.roi_model.Model` objects.

        """

        srcs = self.roi.get_sources(skydir=skydir, distance=distance, cuts=cuts,
                                    minmax_ts=minmax_ts, minmax_npred=minmax_npred,
                                    exclude=exclude, square=square,
                                    coordsys=self.config[
                                        'binning']['coordsys'],
                                    names=names)

        for s in srcs:
            self.delete_source(s.name, build_fixed_wts=False)

        if self.like is not None:
            # Build fixed model weights in one pass
            for c in self.components:
                c.like.logLike.buildFixedModelWts()

            self._update_roi()

        return srcs


Instruction:
Make a summary of the following Python 3 code
def free_sources_by_name(self, names, free=True, pars=None,
                             **kwargs):
        """Free all sources with names matching ``names``.

        Parameters
        ----------
        names : list
            List of source names.

        free : bool
            Choose whether to free (free=True) or fix (free=False)
            source parameters.

        pars : list
            Set a list of parameters to be freed/fixed for each
            source.  If none then all source parameters will be
            freed/fixed.  If pars='norm' then only normalization
            parameters will be freed.

        Returns
        -------
        srcs : list
            A list of `~fermipy.roi_model.Model` objects.
        """

        if names is None:
            return

        names = [names] if not isinstance(names, list) else names
        names = [self.roi.get_source_by_name(t).name for t in names]
        srcs = [s for s in self.roi.sources if s.name in names]
        for s in srcs:
            self.free_source(s.name, free=free, pars=pars, **kwargs)

        return srcs

Response: Free all sources with names matching names.


Instruction:
Can you generate the documentation for the following Python 3 function
def free_sources(self, free=True, pars=None, cuts=None,
                     distance=None, skydir=None, minmax_ts=None, minmax_npred=None,
                     exclude=None, square=False, **kwargs):
        """Free or fix sources in the ROI model satisfying the given
        selection.  When multiple selections are defined, the selected
        sources will be those satisfying the logical AND of all
        selections (e.g. distance < X && minmax_ts[0] < ts <
        minmax_ts[1] && ...).

        Parameters
        ----------

        free : bool
            Choose whether to free (free=True) or fix (free=False)
            source parameters.

        pars : list
            Set a list of parameters to be freed/fixed for each
            source.  If none then all source parameters will be
            freed/fixed.  If pars='norm' then only normalization
            parameters will be freed.

        cuts : dict
            Dictionary of [min,max] selections on source properties.

        distance : float
            Cut on angular distance from ``skydir``.  If None then no
            selection will be applied.

        skydir : `~astropy.coordinates.SkyCoord`
            Reference sky coordinate for ``distance`` selection.  If
            None then the distance selection will be applied with
            respect to the ROI center.

        minmax_ts : list
            Free sources that have TS in the range [min,max].  If
            either min or max are None then only a lower (upper) bound
            will be applied.  If this parameter is none no selection
            will be applied.

        minmax_npred : list
            Free sources that have npred in the range [min,max].  If
            either min or max are None then only a lower (upper) bound
            will be applied.  If this parameter is none no selection
            will be applied.

        exclude : list
            Names of sources that will be excluded from the selection.

        square : bool
            Switch between applying a circular or square (ROI-like)
            selection on the maximum projected distance from the ROI
            center.

        Returns
        -------
        srcs : list
            A list of `~fermipy.roi_model.Model` objects.

        """

        srcs = self.roi.get_sources(skydir=skydir, distance=distance,
                                    cuts=cuts, minmax_ts=minmax_ts,
                                    minmax_npred=minmax_npred, exclude=exclude,
                                    square=square,
                                    coordsys=self.config['binning']['coordsys'])

        for s in srcs:
            self.free_source(s.name, free=free, pars=pars, **kwargs)

        return srcs

Response:
Free or fix sources in the ROI model satisfying the given
            selection.


Instruction:
Here you have a function in Python 3, explain what it does
def set_parameter(self, name, par, value, true_value=True, scale=None,
                      bounds=None, error=None, update_source=True):
        """
        Update the value of a parameter.  Parameter bounds will
        automatically be adjusted to encompass the new parameter
        value.

        Parameters
        ----------

        name : str
            Source name.

        par : str
            Parameter name.

        value : float
            Parameter value.  By default this argument should be the
            unscaled (True) parameter value.

        scale : float
            Parameter scale (optional).  Value argument is interpreted
            with respect to the scale parameter if it is provided.

        error : float
            Parameter error (optional).  By default this argument should be the
            unscaled (True) parameter value.

        update_source : bool
            Update the source dictionary for the object.

        """
        name = self.roi.get_source_by_name(name).name
        idx = self.like.par_index(name, par)
        current_bounds = list(self.like.model[idx].getBounds())

        if scale is not None:
            self.like[idx].setScale(scale)
        else:
            scale = self.like.model[idx].getScale()

        if true_value:
            current_bounds[0] = min(current_bounds[0], value / scale)
            current_bounds[1] = max(current_bounds[1], value / scale)
            if error is not None:
                error = error / scale
        else:
            current_bounds[0] = min(current_bounds[0], value)
            current_bounds[1] = max(current_bounds[1], value)

        # update current bounds to encompass new value
        self.like[idx].setBounds(*current_bounds)

        if true_value:
            for p in self.like[idx].pars:
                p.setTrueValue(value)
        else:
            self.like[idx].setValue(value)

        if bounds is not None:
            if true_value:
                bounds[0] = min(bounds[0], value / scale)
                bounds[1] = max(bounds[1], value / scale)
            else:
                bounds[0] = min(bounds[0], value)
                bounds[1] = max(bounds[1], value)

        # For some reason the numerical accuracy is causing this to throw exceptions.
        try:
            if bounds is not None:
                self.like[idx].setBounds(*bounds)
        except RuntimeError:
            self.logger.warning(
                "Caught failure on setBounds for %s::%s." % (name, par))
            pass

        if error is not None:
            self.like[idx].setError(error)

        self._sync_params(name)

        if update_source:
            self.update_source(name)

Response: Set the value of a parameter in the source dictionary.


Instruction:
Make a summary of the following Python 3 code
def set_parameter_scale(self, name, par, scale):
        name = self.roi.get_source_by_name(name).name
        idx = self.like.par_index(name, par)
        current_bounds = list(self.like.model[idx].getBounds())
        current_scale = self.like.model[idx].getScale()
        current_value = self.like[idx].getValue()

        self.like[idx].setScale(scale)
        self.like[idx].setValue(current_value * current_scale / scale)
        self.like[idx].setBounds(current_bounds[0] * current_scale / scale,
                                 current_bounds[1] * current_scale / scale)
        self._sync_params(name)

Response: Update the scale of a parameter while keeping its value constant.


Instruction:
How would you explain what the following Python 3 function does
def set_parameter_bounds(self, name, par, bounds):
        idx = self.like.par_index(name, par)
        self.like[idx].setBounds(*bounds)
        self._sync_params(name)

Response: Set the bounds on the scaled value of a parameter.


Instruction:
Can you create a Python 3 function that
sets the error on the value of a parameter.

Response:
def set_parameter_error(self, name, par, error):
        """Set the error on the value of a parameter.

        Parameters
        ----------

        name : str
            Source name.

        par : str
            Parameter name.

        error : float
            The value for the parameter error
        """
        idx = self.like.par_index(name, par)
        self.like[idx].setError(error)
        self._sync_params(name)


Instruction:
Write a Python 3 function for
locking the specified parameter in the specified source.

Response:
def lock_parameter(self, name, par, lock=True):
        """Set parameter to locked/unlocked state.  A locked parameter
        will be ignored when running methods that free/fix sources or
        parameters.

        Parameters
        ----------
        name : str
            Source name.

        par : str
            Parameter name.

        lock : bool
            Set parameter to locked (True) or unlocked (False) state.
        """
        name = self.roi.get_source_by_name(name).name
        lck_params = self._lck_params.setdefault(name, [])

        if lock:
            self.free_parameter(name, par, False)
            if not par in lck_params:
                lck_params += [par]
        else:
            if par in lck_params:
                lck_params.remove(par)


Instruction:
Can you tell what is the following Python 3 function doing
def free_parameter(self, name, par, free=True):
        name = self.get_source_name(name)
        if par in self._lck_params.get(name, []):
            return
        idx = self.like.par_index(name, par)
        self.like[idx].setFree(free)
        self._sync_params(name)

Response: Free a parameter of a source by name.


Instruction:
Explain what the following Python 3 code does
def lock_source(self, name, lock=True):
        name = self.get_source_name(name)
        if lock:
            par_names = self.get_source_params(name)
            self.free_source(name, False, pars=par_names)
            self._lck_params[name] = par_names
        else:
            self._lck_params[name] = []

Response: Locks the source with the specified name.


Instruction:
Make a summary of the following Python 3 code
def free_source(self, name, free=True, pars=None, **kwargs):

        free_pars = self.get_free_param_vector()

        loglevel = kwargs.pop('loglevel', self.loglevel)

        # Find the source
        src = self.roi.get_source_by_name(name)
        name = src.name

        if pars is None or (isinstance(pars, list) and not pars):
            pars = []
            pars += norm_parameters.get(src['SpectrumType'], [])
            pars += shape_parameters.get(src['SpectrumType'], [])
        elif pars == 'norm':
            pars = []
            pars += norm_parameters.get(src['SpectrumType'], [])
        elif pars == 'shape':
            pars = []
            pars += shape_parameters.get(src['SpectrumType'], [])
        elif isinstance(pars, list):
            pass
        else:
            raise Exception('Invalid parameter list.')

        # Remove locked parameters
        lck_params = self._lck_params.get(name, [])
        pars = [p for p in pars if p not in lck_params]

        # Deduce here the names of all parameters from the spectral type
        src_par_names = pyLike.StringVector()
        self.like[name].src.spectrum().getParamNames(src_par_names)

        par_indices = []
        par_names = []
        for p in src_par_names:
            if pars is not None and p not in pars:
                continue

            idx = self.like.par_index(name, p)
            if free == free_pars[idx]:
                continue

            par_indices.append(idx)
            par_names.append(p)

        if len(par_names) == 0:
            return

        if free:
            self.logger.log(loglevel, 'Freeing parameters for %-22s: %s',
                            name, par_names)
        else:
            self.logger.log(loglevel, 'Fixing parameters for %-22s: %s',
                            name, par_names)

        for (idx, par_name) in zip(par_indices, par_names):
            self.like[idx].setFree(free)
        self._sync_params_state(name)

Response: Free a source and its parameters.


Instruction:
Implement a function in Python 3 to
free normalization of a source.

Response:
def free_norm(self, name, free=True, **kwargs):
        """Free/Fix normalization of a source.

        Parameters
        ----------

        name : str
            Source name.

        free : bool
            Choose whether to free (free=True) or fix (free=False).

        """
        name = self.get_source_name(name)
        normPar = self.like.normPar(name).getName()
        self.free_source(name, pars=[normPar], free=free, **kwargs)


Instruction:
Can you implement a function in Python 3 that
frees index of a source.

Response:
def free_index(self, name, free=True, **kwargs):
        """Free/Fix index of a source.

        Parameters
        ----------

        name : str
            Source name.

        free : bool
            Choose whether to free (free=True) or fix (free=False).

        """
        src = self.roi.get_source_by_name(name)
        self.free_source(name, free=free,
                         pars=index_parameters.get(src['SpectrumType'], []),
                         **kwargs)


Instruction:
How would you code a function in Python 3 to
free shape parameters of a source.

Response:
def free_shape(self, name, free=True, **kwargs):
        """Free/Fix shape parameters of a source.

        Parameters
        ----------

        name : str
            Source name.

        free : bool
            Choose whether to free (free=True) or fix (free=False).
        """
        src = self.roi.get_source_by_name(name)
        self.free_source(name, free=free,
                         pars=shape_parameters[src['SpectrumType']],
                         **kwargs)


Instruction:
Explain what the following Python 3 code does
def get_source_name(self, name):
        if name not in self.like.sourceNames():
            name = self.roi.get_source_by_name(name).name
        return name

Response:
Return the name of a source as it is defined in the
            pyLikelihood model object.


Instruction:
How would you explain what the following Python 3 function does
def optimize(self, **kwargs):

        loglevel = kwargs.pop('loglevel', self.loglevel)
        timer = Timer.create(start=True)
        self.logger.log(loglevel, 'Starting')

        loglike0 = -self.like()
        self.logger.debug('LogLike: %f' % loglike0)

        # Extract options from kwargs
        config = copy.deepcopy(self.config['roiopt'])
        config['optimizer'] = copy.deepcopy(self.config['optimizer'])
        fermipy.config.validate_config(kwargs, config)
        config = merge_dict(config, kwargs)

        # Extract options from kwargs
        npred_frac_threshold = config['npred_frac']
        npred_threshold = config['npred_threshold']
        shape_ts_threshold = config['shape_ts_threshold']
        max_free_sources = config['max_free_sources']
        skip = copy.deepcopy(config['skip'])

        o = defaults.make_default_dict(defaults.roiopt_output)
        o['config'] = config
        o['loglike0'] = loglike0

        # preserve free parameters
        free = self.get_free_param_vector()

        # Fix all parameters
        self.free_sources(free=False, loglevel=logging.DEBUG)

        # Free norms of sources for which the sum of npred is a
        # fraction > npred_frac of the total model counts in the ROI
        npred_sum = 0
        skip_sources = skip if skip != None else []
        joint_norm_fit = []

        # EAC, we need this try block by older version of the ST don't have has_weights function
        try:
            if self.like.logLike.has_weights():
                npred_str = 'npred_wt'
            else:
                npred_str = 'npred'
        except AttributeError:
            npred_str = 'npred'

        # FIXME, EAC, use npred_wt here
        for s in sorted(self.roi.sources, key=lambda t: t[npred_str],
                        reverse=True):

            npred_sum += s[npred_str]
            npred_frac = npred_sum / self._roi_data[npred_str]

            if s.name in skip_sources:
                continue

            self.free_norm(s.name, loglevel=logging.DEBUG)
            joint_norm_fit.append(s.name)

            if npred_frac > npred_frac_threshold:
                break
            if s[npred_str] < npred_threshold:
                break
            if len(joint_norm_fit) >= max_free_sources:
                break

        print ("Joint fit ", joint_norm_fit)
        self.fit(loglevel=logging.DEBUG, **config['optimizer'])
        self.free_sources(free=False, loglevel=logging.DEBUG)

        # Step through remaining sources and re-fit normalizations
        # FIXME, EAC, use npred_wt here
        for s in sorted(self.roi.sources, key=lambda t: t[npred_str],
                        reverse=True):

            if s.name in skip_sources or s.name in joint_norm_fit:
                continue

            if s[npred_str] < npred_threshold:
                self.logger.debug(
                    'Skipping %s with npred %10.3f', s.name, s[npred_str])
                continue

            self.logger.debug('Fitting %s npred: %10.3f TS: %10.3f',
                              s.name, s[npred_str], s['ts'])
            self.free_norm(s.name, loglevel=logging.DEBUG)
            self.fit(loglevel=logging.DEBUG, **config['optimizer'])
            self.logger.debug('Post-fit Results npred: %10.3f TS: %10.3f',
                              s[npred_str], s['ts'])
            self.free_norm(s.name, free=False, loglevel=logging.DEBUG)

        # Refit spectral shape parameters for sources with TS >
        # shape_ts_threshold
        for s in sorted(self.roi.sources,
                        key=lambda t: t['ts'] if np.isfinite(t['ts']) else 0,
                        reverse=True):

            if s.name in skip_sources:
                continue

            if s['ts'] < shape_ts_threshold or not np.isfinite(s['ts']):
                continue

            print ('Fitting shape %s TS: %10.3f' % (s.name, s['ts']))
            self.logger.debug('Fitting shape %s TS: %10.3f', s.name, s['ts'])
            self.free_source(s.name, loglevel=logging.DEBUG)
            self.fit(loglevel=logging.DEBUG, **config['optimizer'])
            self.free_source(s.name, free=False, loglevel=logging.DEBUG)

        self.set_free_param_vector(free)

        loglike1 = -self.like()

        o['loglike1'] = loglike1
        o['dloglike'] = loglike1 - loglike0

        self.logger.log(loglevel, 'Finished')
        self.logger.log(loglevel, 'LogLike: %f Delta-LogLike: %f',
                        loglike1, loglike1 - loglike0)
        self.logger.log(loglevel, 'Execution time: %.2f s', timer.elapsed_time)
        return o

Response: Iteratively optimize the ROI model.


Instruction:
Implement a function in Python 3 to
profile the normalization of a source.

Response:
def profile_norm(self, name, logemin=None, logemax=None, reoptimize=False,
                     xvals=None, npts=None, fix_shape=True, savestate=True,
                     **kwargs):
        """Profile the normalization of a source.

        Parameters
        ----------

        name : str
            Source name.

        reoptimize : bool
            Re-optimize free parameters in the model at each point
            in the profile likelihood scan.

        """

        self.logger.debug('Profiling %s', name)

        if savestate:
            saved_state = LikelihoodState(self.like)

        if fix_shape:
            self.free_sources(False, pars='shape', loglevel=logging.DEBUG)

        if npts is None:
            npts = self.config['gtlike']['llscan_npts']

        # Find the source
        name = self.roi.get_source_by_name(name).name
        parName = self.like.normPar(name).getName()

        loge_bounds = self.loge_bounds
        if logemin is not None or logemax is not None:
            self.set_energy_range(logemin, logemax)

        # Find a sequence of values for the normalization scan
        if xvals is None:
            if reoptimize:
                xvals = self._find_scan_pts_reopt(name, npts=npts,
                                                  **kwargs)
            else:
                xvals = self._find_scan_pts(name, npts=9)
                lnlp = self.profile(name, parName,
                                    reoptimize=False, xvals=xvals)
                lims = utils.get_parameter_limits(lnlp['xvals'],
                                                  lnlp['dloglike'],
                                                  cl_limit=0.99)

                if not np.isfinite(lims['ul']):
                    self.logger.warning('Upper limit not found.  '
                                        'Refitting normalization.')
                    self.like.optimize(0)
                    xvals = self._find_scan_pts(name, npts=npts)
                    lnlp = self.profile(name, parName,
                                        reoptimize=False,
                                        xvals=xvals)
                    lims = utils.get_parameter_limits(lnlp['xvals'],
                                                      lnlp['dloglike'],
                                                      cl_limit=0.99)

                if np.isfinite(lims['ll']):
                    xhi = np.linspace(lims['x0'], lims['ul'], npts - npts // 2)
                    xlo = np.linspace(lims['ll'], lims['x0'], npts // 2)
                    xvals = np.concatenate((xlo[:-1], xhi))
                    xvals = np.insert(xvals, 0, 0.0)
                elif np.abs(lnlp['dloglike'][0] - lims['lnlmax']) > 0.1:
                    lims['ll'] = 0.0
                    xhi = np.linspace(lims['x0'], lims['ul'],
                                      (npts + 1) - (npts + 1) // 2)
                    xlo = np.linspace(lims['ll'], lims['x0'], (npts + 1) // 2)
                    xvals = np.concatenate((xlo[:-1], xhi))
                else:
                    xvals = np.linspace(0, lims['ul'], npts)

        o = self.profile(name, parName,
                         reoptimize=reoptimize, xvals=xvals,
                         savestate=savestate, **kwargs)

        if savestate:
            saved_state.restore()

        if logemin is not None or logemax is not None:
            self.set_energy_range(*loge_bounds)

        self.logger.debug('Finished')

        return o


Instruction:
Given the following Python 3 function, write the documentation
def profile(self, name, parName, logemin=None, logemax=None,
                reoptimize=False,
                xvals=None, npts=None, savestate=True, **kwargs):
        """Profile the likelihood for the given source and parameter.

        Parameters
        ----------

        name : str
           Source name.

        parName : str
           Parameter name.

        reoptimize : bool
           Re-fit nuisance parameters at each step in the scan.  Note
           that enabling this option will only re-fit parameters that
           were free when the method was executed.

        Returns
        -------

        lnlprofile : dict
           Dictionary containing results of likelihood scan.

        """
        # Find the source
        name = self.roi.get_source_by_name(name).name

        par = self.like.normPar(name)
        parName = self.like.normPar(name).getName()
        idx = self.like.par_index(name, parName)
        bounds = self.like.model[idx].getBounds()
        value = self.like.model[idx].getValue()
        loge_bounds = self.loge_bounds

        optimizer = kwargs.get('optimizer', self.config['optimizer'])

        if savestate:
            saved_state = self._latch_state()

        # If parameter is fixed temporarily free it
        par.setFree(True)
        if optimizer['optimizer'] == 'NEWTON':
            self._create_fitcache()

        if logemin is not None or logemax is not None:
            loge_bounds = self.set_energy_range(logemin, logemax)
        else:
            loge_bounds = self.loge_bounds

        loglike0 = -self.like()

        if xvals is None:

            err = par.error()
            val = par.getValue()
            if err <= 0 or val <= 3 * err:
                xvals = 10 ** np.linspace(-2.0, 2.0, 51)
                if val < xvals[0]:
                    xvals = np.insert(xvals, val, 0)
            else:
                xvals = np.linspace(0, 1, 25)
                xvals = np.concatenate((-1.0 * xvals[1:][::-1], xvals))
                xvals = val * 10 ** xvals

        if np.isnan(xvals).any():
            raise RuntimeError(
                "Parameter scan points for %s::%s include infinite value." % (name, parName))

        # Update parameter bounds to encompass scan range
        try:
            self.like[idx].setBounds(min(min(xvals), value, bounds[0]),
                                     max(max(xvals), value, bounds[1]))
        except RuntimeError:
            self.logger.warning(
                "Caught failure on setBounds for %s::%s." % (name, parName))

        o = {'xvals': xvals,
             'npred': np.zeros(len(xvals)),
             'npred_wt': np.zeros(len(xvals)),
             'dnde': np.zeros(len(xvals)),
             'flux': np.zeros(len(xvals)),
             'eflux': np.zeros(len(xvals)),
             'dloglike': np.zeros(len(xvals)),
             'loglike': np.zeros(len(xvals))
             }

        if reoptimize and hasattr(self.like.components[0].logLike,
                                  'setUpdateFixedWeights'):

            for c in self.components:
                c.like.logLike.setUpdateFixedWeights(False)

        for i, x in enumerate(xvals):

            try:
                self.like[idx] = x
            except RuntimeError:
                self.logger.warning(
                    "Caught failure on set for %s::%s: %.2f" % (name, parName, x))

            if self.like.nFreeParams() > 1 and reoptimize:
                # Only reoptimize if not all frozen
                self.like.freeze(idx)
                fit_output = self._fit(errors=False, **optimizer)
                loglike1 = fit_output['loglike']
                self.like.thaw(idx)
            else:
                loglike1 = -self.like()

            flux = self.like[name].flux(10 ** loge_bounds[0],
                                        10 ** loge_bounds[1])
            eflux = self.like[name].energyFlux(10 ** loge_bounds[0],
                                               10 ** loge_bounds[1])
            prefactor = self.like[idx]

            o['dloglike'][i] = loglike1 - loglike0
            o['loglike'][i] = loglike1
            o['dnde'][i] = prefactor.getTrueValue()
            o['flux'][i] = flux
            o['eflux'][i] = eflux

            cs = self.model_counts_spectrum(name,
                                            loge_bounds[0],
                                            loge_bounds[1], summed=True)
            o['npred'][i] += np.sum(cs)
            cs_wt = self.model_counts_spectrum(name,
                                               loge_bounds[0],
                                               loge_bounds[1], summed=True, weighted=True)
            o['npred_wt'][i] += np.sum(cs_wt)

        self.like[idx] = value

        if reoptimize and hasattr(self.like.components[0].logLike,
                                  'setUpdateFixedWeights'):

            for c in self.components:
                c.like.logLike.setUpdateFixedWeights(True)

        # Restore model parameters to original values
        if savestate:
            saved_state.restore()

        self.like[idx].setBounds(*bounds)
        if logemin is not None or logemax is not None:
            self.set_energy_range(*loge_bounds)

        return o

Response: Profile the likelihood for the given source and parameter.


Instruction:
How would you code a function in Python 3 to
constrain the normalizations of one or more sources by adding gaussian priors with sigma equal to the parameter error times a scaling factor.

Response:
def constrain_norms(self, srcNames, cov_scale=1.0):
        """Constrain the normalizations of one or more sources by
        adding gaussian priors with sigma equal to the parameter
        error times a scaling factor."""

        # Get the covariance matrix

        for name in srcNames:
            par = self.like.normPar(name)

            err = par.error()
            val = par.getValue()

            if par.error() == 0.0 or not par.isFree():
                continue

            self.add_gauss_prior(name, par.getName(),
                                 val, err * cov_scale)


Instruction:
Can you create a Python 3 function that
creates an object of type MINUIT or NewMinuit type optimizer object

Response:
def _create_optObject(self, **kwargs):
        """ Make MINUIT or NewMinuit type optimizer object """

        optimizer = kwargs.get('optimizer',
                               self.config['optimizer']['optimizer'])

        if optimizer.upper() == 'MINUIT':
            optObject = pyLike.Minuit(self.like.logLike)
        elif optimizer.upper() == 'NEWMINUIT':
            optObject = pyLike.NewMinuit(self.like.logLike)
        else:
            optFactory = pyLike.OptimizerFactory_instance()
            optObject = optFactory.create(str(optimizer), self.like.logLike)
        return optObject


Instruction:
How would you implement a function in Python 3 that
executes a fit of all sources with the specified parameters.

Response:
def fit(self, update=True, **kwargs):
        """Run the likelihood optimization.  This will execute a fit of all
        parameters that are currently free in the model and update the
        charateristics of the corresponding model components (TS,
        npred, etc.).  The fit will be repeated N times (set with the
        `retries` parameter) until a fit quality greater than or equal
        to `min_fit_quality` and a fit status code of 0 is obtained.
        If the fit does not succeed after N retries then all parameter
        values will be reverted to their state prior to the execution
        of the fit.

        Parameters
        ----------

        update : bool
           Update the model dictionary for all sources with free
           parameters.

        tol : float
           Set the optimizer tolerance.

        verbosity : int
           Set the optimizer output level.

        optimizer : str
           Set the likelihood optimizer (e.g. MINUIT or NEWMINUIT).

        retries : int
           Set the number of times to rerun the fit when the fit quality
           is < 3.

        min_fit_quality : int
           Set the minimum fit quality.  If the fit quality is smaller
           than this value then all model parameters will be
           restored to their values prior to the fit.

        reoptimize : bool
           Refit background sources when updating source properties
           (TS and likelihood profiles).

        Returns
        -------

        fit : dict
           Dictionary containing diagnostic information from the fit
           (fit quality, parameter covariances, etc.).

        """

        loglevel = kwargs.pop('loglevel', self.loglevel)
        self.logger.log(loglevel, "Starting fit.")

        # Extract options from kwargs
        config = copy.deepcopy(self.config['optimizer'])
        config.setdefault('covar', True)
        config.setdefault('reoptimize', False)
        config = utils.merge_dict(config, kwargs)

        num_free = self.like.nFreeParams()

        loglike0 = -self.like()

        # Initialize output dict
        o = {'fit_quality': 3,
             'fit_status': 0,
             'fit_success': True,
             'dloglike': 0.0,
             'edm': 0.0,
             'loglike': loglike0,
             'covariance': None,
             'correlation': None,
             'values': np.ones(num_free) * np.nan,
             'errors': np.ones(num_free) * np.nan,
             'indices': np.zeros(num_free, dtype=int),
             'is_norm': np.empty(num_free, dtype=bool),
             'src_names': num_free * [None],
             'par_names': num_free * [None],
             'config': config
             }

        if not num_free:
            self.logger.log(loglevel, "Skipping fit.  No free parameters.")
            return o

        saved_state = LikelihoodState(self.like)

        fit_output = self._fit(**config)
        o.update(fit_output)

        self.logger.debug("Fit complete.")
        o['dloglike'] = o['loglike'] - loglike0

        if not o['fit_success']:
            self.logger.error('%s failed with status code %i fit quality %i',
                              config['optimizer'], o['fit_status'],
                              o['fit_quality'])
            saved_state.restore()
            return o

        if update:

            free_params = self.get_params(True)
            self._extract_correlation(o, free_params)
            for name in self.like.sourceNames():
                freePars = self.get_free_source_params(name)
                if len(freePars) == 0:
                    continue
                self.update_source(name, reoptimize=config['reoptimize'])

            # Update roi model counts
            self._update_roi()

        self.logger.log(loglevel, "Fit returned successfully. " +
                        "Quality: %3i Status: %3i",
                        o['fit_quality'], o['fit_status'])
        self.logger.log(loglevel, "LogLike: %12.3f DeltaLogLike: %12.3f ",
                        o['loglike'], o['dloglike'])
        return o


Instruction:
Given the following Python 3 function, write the documentation
def _fit_newton(self, fitcache=None, ebin=None, **kwargs):

        tol = kwargs.get('tol', self.config['optimizer']['tol'])
        max_iter = kwargs.get('max_iter',
                              self.config['optimizer']['max_iter'])
        init_lambda = kwargs.get('init_lambda',
                                 self.config['optimizer']['init_lambda'])
        use_reduced = kwargs.get('use_reduced', True)

        free_params = self.get_params(True)
        free_norm_params = [p for p in free_params if p['is_norm'] is True]

        if len(free_params) != len(free_norm_params):
            msg = 'Executing Newton fitter with one ' + \
                'or more free shape parameters.'
            self.logger.error(msg)
            raise Exception(msg)

        verbosity = kwargs.get('verbosity', 0)
        if fitcache is None:
            fitcache = self._create_fitcache(**kwargs)

        fitcache.update(self.get_params(),
                        tol, max_iter, init_lambda, use_reduced)

        logemin = self.loge_bounds[0]
        logemax = self.loge_bounds[1]
        imin = int(utils.val_to_edge(self.log_energies, logemin)[0])
        imax = int(utils.val_to_edge(self.log_energies, logemax)[0])

        if ebin is not None:
            fitcache.fitcache.setEnergyBin(ebin)
        elif imin == 0 and imax == self.enumbins:
            fitcache.fitcache.setEnergyBin(-1)
        else:
            fitcache.fitcache.setEnergyBins(imin, imax)

        num_free = len(free_norm_params)

        o = {'fit_status': 0,
             'fit_quality': 3,
             'fit_success': True,
             'edm': 0,
             'loglike': None,
             'values': np.ones(num_free) * np.nan,
             'errors': np.ones(num_free) * np.nan,
             'indices': np.zeros(num_free, dtype=int),
             'is_norm': np.empty(num_free, dtype=bool),
             'src_names': num_free * [None],
             'par_names': num_free * [None],
             }

        if num_free == 0:
            return o

        ref_vals = np.array(fitcache.fitcache.refValues())
        free = np.array(fitcache.fitcache.currentFree())
        norm_vals = ref_vals[free]

        norm_idxs = []
        for i, p in enumerate(free_norm_params):

            norm_idxs += [p['idx']]
            o['indices'][i] = p['idx']
            o['src_names'][i] = p['src_name']
            o['par_names'][i] = p['par_name']
            o['is_norm'][i] = p['is_norm']

        o['fit_status'] = fitcache.fit(verbose=verbosity)
        o['edm'] = fitcache.fitcache.currentEDM()

        pars, errs, cov = fitcache.get_pars()
        pars *= norm_vals
        errs *= norm_vals
        cov = cov * np.outer(norm_vals, norm_vals)

        o['values'] = pars
        o['errors'] = errs
        o['covariance'] = cov
        errinv = np.zeros_like(o['errors'])
        m = o['errors'] > 0
        errinv[m] = 1. / o['errors'][m]
        o['correlation'] = o['covariance'] * np.outer(errinv, errinv)

        if o['fit_status'] in [-2, 0]:
            for idx, val, err in zip(norm_idxs, pars, errs):
                self._set_value_bounded(idx, val)
                self.like[idx].setError(err)
            self.like.syncSrcParams()
            o['fit_success'] = True
        else:
            o['fit_success'] = False

        if o['fit_status']:
            self.logger.error('Error in NEWTON fit. Fit Status: %i',
                              o['fit_status'])

        # FIXME: Figure out why currentLogLike gets out of sync
        #loglike = fitcache.fitcache.currentLogLike()
        #prior_vals, prior_errs, has_prior = gtutils.get_priors(self.like)
        #loglike -= np.sum(has_prior) * np.log(np.sqrt(2 * np.pi))
        loglike = -self.like()
        o['loglike'] = loglike

        return o

Response: Fast fitting method using Newton fitter.


Instruction:
Here you have a function in Python 3, explain what it does
def load_xml(self, xmlfile):

        self.logger.info('Loading XML')

        for c in self.components:
            c.load_xml(xmlfile)

        for name in self.like.sourceNames():
            self.update_source(name)

        self._fitcache = None

        self.logger.info('Finished Loading XML')

Response: Load model definition from XML file.


Instruction:
Make a summary of the following Python 3 code
def load_parameters_from_yaml(self, yamlfile, update_sources=False):
        d = utils.load_yaml(yamlfile)
        for src, src_pars in d.items():
            for par_name, par_dict in src_pars.items():
                if par_name in ['SpectrumType']:
                    continue
                par_value = par_dict.get('value', None)
                par_error = par_dict.get('error', None)
                par_scale = par_dict.get('scale', None)
                par_min = par_dict.get('min', None)
                par_max = par_dict.get('max', None)
                par_free = par_dict.get('free', None)
                if par_min is not None and par_max is not None:
                    par_bounds = [par_min, par_max]
                else:
                    par_bounds = None
                try:
                    self.set_parameter(src, par_name, par_value, true_value=False,
                                       scale=par_scale, bounds=par_bounds, error=par_error,
                                       update_source=update_sources)
                except RuntimeError as msg:
                    self.logger.warn(msg)
                    self.logger.warn("Did not set parameter %s:%s"%(src,par_name))
                    continue
                except Exception as msg:
                    self.logger.warn(msg)
                    continue
                if par_free is not None:
                    self.free_parameter(src, par_name, par_free)
        self._sync_params_state()

Response: Load model parameters from a yaml file.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def _restore_counts_maps(self):

        for c in self.components:
            c.restore_counts_maps()

        if hasattr(self.like.components[0].logLike, 'setCountsMap'):
            self._init_roi_model()
        else:
            self.write_xml('tmp')
            self._like = SummedLikelihood()
            for i, c in enumerate(self._components):
                c._create_binned_analysis()
                self._like.addComponent(c.like)
            self._init_roi_model()
            self.load_xml('tmp')

Response:
Revert counts maps to their state prior to injecting any simulated
        components.


Instruction:
Explain what the following Python 3 code does
def simulate_source(self, src_dict=None):

        self._fitcache = None

        if src_dict is None:
            src_dict = {}
        else:
            src_dict = copy.deepcopy(src_dict)

        skydir = wcs_utils.get_target_skydir(src_dict, self.roi.skydir)

        src_dict.setdefault('ra', skydir.ra.deg)
        src_dict.setdefault('dec', skydir.dec.deg)
        src_dict.setdefault('SpatialModel', 'PointSource')
        src_dict.setdefault('SpatialWidth', 0.3)
        src_dict.setdefault('Index', 2.0)
        src_dict.setdefault('Prefactor', 1E-13)

        self.add_source('mcsource', src_dict, free=True,
                        init_source=False)
        for c in self.components:
            c.simulate_roi('mcsource', clear=False)

        self.delete_source('mcsource')

        if hasattr(self.like.components[0].logLike, 'setCountsMap'):
            self._init_roi_model()
        else:
            self.write_xml('tmp')
            self._like = SummedLikelihood()
            for i, c in enumerate(self._components):
                c._create_binned_analysis('tmp.xml')
                self._like.addComponent(c.like)
            self._init_roi_model()
            self.load_xml('tmp')

Response: Simulate a source and inject the simulated source counts into the data.


Instruction:
Can you create a Python 3 function that
simulates the current model and replace the data counts cube with the simulation of the ROI.

Response:
def simulate_roi(self, name=None, randomize=True, restore=False):
        """Generate a simulation of the ROI using the current best-fit model
        and replace the data counts cube with this simulation.  The
        simulation is created by generating an array of Poisson random
        numbers with expectation values drawn from the model cube of
        the binned analysis instance.  This function will update the
        counts cube both in memory and in the source map file.  The
        counts cube can be restored to its original state by calling
        this method with ``restore`` = True.

        Parameters
        ----------
        name : str
           Name of the model component to be simulated.  If None then
           the whole ROI will be simulated.

        restore : bool
           Restore the data counts cube to its original state.
        """

        self.logger.info('Simulating ROI')

        self._fitcache = None

        if restore:
            self.logger.info('Restoring')
            self._restore_counts_maps()
            self.logger.info('Finished')
            return

        for c in self.components:
            c.simulate_roi(name=name, clear=True, randomize=randomize)

        if hasattr(self.like.components[0].logLike, 'setCountsMap'):
            self._init_roi_model()
        else:
            self.write_xml('tmp')
            self._like = SummedLikelihood()
            for i, c in enumerate(self._components):
                c._create_binned_analysis('tmp.xml')
                self._like.addComponent(c.like)
            self._init_roi_model()
            self.load_xml('tmp')

        self.logger.info('Finished')


Instruction:
Make a summary of the following Python 3 code
def write_model_map(self, model_name, name=None):
        maps = [c.write_model_map(model_name, name) for c in self.components]

        outfile = os.path.join(self.workdir,
                               'mcube_%s.fits' % (model_name))

        mmap = Map.from_geom(self.geom)
        for m in maps:
            mmap.coadd(m)
        mmap.write(outfile, overwrite=True, conv='fgst-ccube')
        return [mmap] + maps

Response: Save the counts model map to a FITS file.


Instruction:
How would you explain what the following Python 3 function does
def write_weight_map(self, model_name):
        maps = [c.write_weight_map(model_name) for c in self.components]

        outfile = os.path.join(self.workdir,
                               'wcube_%s.fits' % (model_name))

        wmap = Map.from_geom(self.geom)
        # FIXME: Should we average weights maps rather than coadding?
        for m in maps:
            wmap.coadd(m)
        wmap.write(outfile, overwrite=True, conv='fgst-ccube')
        return [wmap] + maps

Response: Save the counts model map to a FITS file.


Instruction:
Can you implement a function in Python 3 that
prints information about the spectral and spatial properties of the ROI.

Response:
def print_roi(self, loglevel=logging.INFO):
        """Print information about the spectral and spatial properties
        of the ROI (sources, diffuse components)."""
        self.logger.log(loglevel, '\n' + str(self.roi))


Instruction:
Can you generate a brief explanation for the following Python 3 code
def print_params(self, allpars=False, loglevel=logging.INFO):

        pars = self.get_params()

        o = '\n'
        o += '%4s %-20s%10s%10s%10s%10s%10s%5s\n' % (
            'idx', 'parname', 'value', 'error',
            'min', 'max', 'scale', 'free')

        o += '-' * 80 + '\n'

        src_pars = collections.OrderedDict()
        for p in pars:

            src_pars.setdefault(p['src_name'], [])
            src_pars[p['src_name']] += [p]

        free_sources = []
        for k, v in src_pars.items():

            for p in v:
                if not p['free']:
                    continue

                free_sources += [k]

        for k, v in src_pars.items():

            if not allpars and k not in free_sources:
                continue

            o += '%s\n' % k
            for p in v:

                o += '%4i %-20.19s' % (p['idx'], p['par_name'])
                o += '%10.3g%10.3g' % (p['value'], p['error'])
                o += '%10.3g%10.3g%10.3g' % (p['min'], p['max'],
                                             p['scale'])

                if p['free']:
                    o += '    *'
                else:
                    o += '     '

                o += '\n'

        self.logger.log(loglevel, o)

Response: Print information about the model parameters.


Instruction:
Create a Python 3 function to
write current state of the analysis to a file. This method writes an XML model definition, a ROI dictionary, and a FITS source catalog file. A previously saved analysis state can be reloaded from the ROI dictionary file with the `~fermipy.gtanalysis.GTAnalysis.load_roi` method. Parameters ---------- outfile : str String prefix of the output files. The extension of this string will be stripped when generating the XML, YAML and npy filenames. make_plots : bool Generate diagnostic plots. save_model_map : bool Save the current counts model to a FITS file.

Response:
def write_roi(self, outfile=None,
                  save_model_map=False, **kwargs):
        """Write current state of the analysis to a file.  This method
        writes an XML model definition, a ROI dictionary, and a FITS
        source catalog file.  A previously saved analysis state can be
        reloaded from the ROI dictionary file with the
        `~fermipy.gtanalysis.GTAnalysis.load_roi` method.

        Parameters
        ----------

        outfile : str
            String prefix of the output files.  The extension of this
            string will be stripped when generating the XML, YAML and
            npy filenames.

        make_plots : bool
            Generate diagnostic plots.

        save_model_map : bool
            Save the current counts model to a FITS file.

        """
        # extract the results in a convenient format

        make_plots = kwargs.get('make_plots', False)
        save_weight_map = kwargs.get('save_weight_map', False)

        if outfile is None:
            pathprefix = os.path.join(self.config['fileio']['workdir'],
                                      'results')
        elif not os.path.isabs(outfile):
            pathprefix = os.path.join(self.config['fileio']['workdir'],
                                      outfile)
        else:
            pathprefix = outfile

        pathprefix = utils.strip_suffix(pathprefix,
                                        ['fits', 'yaml', 'npy'])
#        pathprefix, ext = os.path.splitext(pathprefix)
        prefix = os.path.basename(pathprefix)

        xmlfile = pathprefix + '.xml'
        fitsfile = pathprefix + '.fits'
        npyfile = pathprefix + '.npy'

        self.write_xml(xmlfile)
        self.write_fits(fitsfile)

        if not self.config['gtlike']['use_external_srcmap']:
            for c in self.components:
                c.like.logLike.saveSourceMaps(str(c.files['srcmap']))

        if save_model_map:
            self.write_model_map(prefix)

        if save_weight_map:
            self.write_weight_map(prefix)

        o = {}
        o['roi'] = copy.deepcopy(self._roi_data)
        o['config'] = copy.deepcopy(self.config)
        o['version'] = fermipy.__version__
        o['stversion'] = fermipy.get_st_version()
        o['sources'] = {}

        for s in self.roi.sources:
            o['sources'][s.name] = copy.deepcopy(s.data)

        for i, c in enumerate(self.components):
            o['roi']['components'][i][
                'src_expscale'] = copy.deepcopy(c.src_expscale)

        self.logger.info('Writing %s...', npyfile)
        np.save(npyfile, o)

        if make_plots:
            self.make_plots(prefix, None,
                            **kwargs.get('plotting', {}))


Instruction:
How would you code a function in Python 3 to
make diagnostic plots using the current ROI model.

Response:
def make_plots(self, prefix, mcube_map=None, **kwargs):
        """Make diagnostic plots using the current ROI model."""

        #mcube_maps = kwargs.pop('mcube_maps', None)
        if mcube_map is None:
            mcube_map = self.model_counts_map()

        plotter = plotting.AnalysisPlotter(self.config['plotting'],
                                           fileio=self.config['fileio'],
                                           logging=self.config['logging'])
        plotter.run(self, mcube_map, prefix=prefix, **kwargs)


Instruction:
How would you code a function in Python 3 to
test whether a source shows spectral curvature by comparing the likelihood ratio of PowerLaw and LogParabola spectral curvature.

Response:
def curvature(self, name, **kwargs):
        """Test whether a source shows spectral curvature by comparing
        the likelihood ratio of PowerLaw and LogParabola spectral
        models.

        Parameters
        ----------
        name : str
            Source name.

        """

        name = self.roi.get_source_by_name(name).name

        saved_state = LikelihoodState(self.like)
        source = self.components[0].like.logLike.getSource(str(name))

        old_spectrum = source.spectrum()
        old_pars = copy.deepcopy(self.roi[name].spectral_pars)
        old_type = self.roi[name]['SpectrumType']

        if old_type != 'PowerLaw':

            dnde = self.like[name].spectrum()(pyLike.dArg(1000.))
            value, scale = utils.scale_parameter(dnde)
            pars0 = {
                'Prefactor':
                    {'value': value, 'scale': scale,
                        'min': 1E-5, 'max': 1000., 'free': True},
                'Index':
                    {'value': 2.0, 'scale': -1.0, 'min': 0.0,
                        'max': 5.0, 'free': False},
                'Scale':
                    {'value': 1E3, 'scale': 1.0, 'min': 1.,
                        'max': 1E6, 'free': False},
            }
            self.set_source_spectrum(str(name), 'PowerLaw',
                                     spectrum_pars=pars0,
                                     update_source=False)

        self.free_source(name, loglevel=logging.DEBUG)
        fit_pl = self._fit(loglevel=logging.DEBUG)

        prefactor = self._get_param(name, 'Prefactor')
        index = self._get_param(name, 'Index')
        scale = self._get_param(name, 'Scale')

        pars1 = {
            'norm': copy.deepcopy(prefactor),
            'alpha': copy.deepcopy(index),
            'Eb': copy.deepcopy(scale),
        }
        pars1['alpha']['scale'] *= -1
        pars1['alpha']['min'] = -5.0
        pars1['alpha']['max'] = 5.0

        self.set_source_spectrum(str(name), 'LogParabola',
                                 spectrum_pars=pars1,
                                 update_source=False)

        self.free_source(name, loglevel=logging.DEBUG)
        fit_lp = self._fit(loglevel=logging.DEBUG)

        self.set_source_spectrum(str(name), old_type,
                                 spectrum_pars=old_pars,
                                 update_source=False)

        pars2 = {
            'Prefactor': copy.deepcopy(prefactor),
            'Index1': copy.deepcopy(index),
            'Cutoff': {'value': 1000.0, 'scale': 1E3,
                       'min': 10.0, 'max': 1E4, 'free': True},
            'Index2': {'value': 1.0, 'scale': 1.0,
                       'min': 1.0, 'max': 1.0, 'free': False},
            'Scale': copy.deepcopy(scale)
        }

        self.set_source_spectrum(str(name), 'PLSuperExpCutoff',
                                 spectrum_pars=pars2,
                                 update_source=False)

        self.free_source(name, loglevel=logging.DEBUG)
        fit_ple = self._fit(loglevel=logging.DEBUG)

        # Revert to initial spectral model
        self.set_source_spectrum(str(name), old_type,
                                 spectrum_pars=old_pars,
                                 update_source=False)
        saved_state.restore()

        lp_ts_curv = 2.0 * (fit_lp['loglike'] - fit_pl['loglike'])
        ple_ts_curv = 2.0 * (fit_ple['loglike'] - fit_pl['loglike'])
        o = MutableNamedTuple(ts_curv=lp_ts_curv,
                              lp_ts_curv=lp_ts_curv,
                              ple_ts_curv=ple_ts_curv,
                              loglike_pl=fit_pl['loglike'],
                              loglike_lp=fit_lp['loglike'],
                              loglike_ple=fit_ple['loglike'])

        self.logger.info('LogLike_PL: %12.3f LogLike_LP: %12.3f LogLike_PLE: %12.3f',
                         o.loglike_pl, o.loglike_lp, o.loglike_ple)
        self.logger.info('TS_curv:        %.3f (LP)', o.lp_ts_curv)
        self.logger.info('TS_curv:        %.3f (PLE)', o.ple_ts_curv)
        return o


Instruction:
Can you generate the documentation for the following Python 3 function
def bowtie(self, name, fd=None, loge=None):

        if loge is None:
            logemin = self.log_energies[0]
            logemax = self.log_energies[-1]
            loge = np.linspace(logemin, logemax, 50)

        o = {'energies': 10**loge,
             'log_energies': loge,
             'dnde': np.zeros(len(loge)) * np.nan,
             'dnde_lo': np.zeros(len(loge)) * np.nan,
             'dnde_hi': np.zeros(len(loge)) * np.nan,
             'dnde_err': np.zeros(len(loge)) * np.nan,
             'dnde_ferr': np.zeros(len(loge)) * np.nan,
             'pivot_energy': np.nan}

        try:
            if fd is None:
                fd = FluxDensity.FluxDensity(self.like, name)
        except RuntimeError:
            self.logger.error('Failed to create FluxDensity',
                              exc_info=True)
            return o

        dnde = [fd.value(10 ** x) for x in loge]
        dnde_err = [fd.error(10 ** x) for x in loge]

        dnde = np.array(dnde)
        dnde_err = np.array(dnde_err)
        m = dnde > 0

        fhi = np.zeros_like(dnde)
        flo = np.zeros_like(dnde)
        ferr = np.zeros_like(dnde)

        fhi[m] = dnde[m] * (1.0 + dnde_err[m] / dnde[m])
        flo[m] = dnde[m] / (1.0 + dnde_err[m] / dnde[m])
        ferr[m] = 0.5 * (fhi[m] - flo[m]) / dnde[m]
        fhi[~m] = dnde_err[~m]

        o['dnde'] = dnde
        o['dnde_lo'] = flo
        o['dnde_hi'] = fhi
        o['dnde_err'] = dnde_err
        o['dnde_ferr'] = ferr

        try:
            o['pivot_energy'] = 10 ** utils.interpolate_function_min(loge, o[
                                                                     'dnde_ferr'])
        except Exception:
            self.logger.error('Failed to compute pivot energy',
                              exc_info=True)

        return o

Response: This method generates a spectral uncertainty band for the given source.


Instruction:
Can you create a Python 3 function that
updates the dictionary for this source.

Response:
def update_source(self, name, paramsonly=False, reoptimize=False, **kwargs):
        """Update the dictionary for this source.

        Parameters
        ----------

        name : str

        paramsonly : bool

        reoptimize : bool
           Re-fit background parameters in likelihood scan.

        """

        npts = self.config['gtlike']['llscan_npts']
        optimizer = kwargs.get('optimizer', self.config['optimizer'])

        sd = self.get_src_model(name, paramsonly, reoptimize, npts,
                                optimizer=optimizer)
        src = self.roi.get_source_by_name(name)
        src.update_data(sd)