def temporalFun(inTime):
    # --------------------
    # CREATE TEMPORAL MODEL
    # --------------------

    #get model name (TDB)
    #SpatModel = inTime[0]
    SpatModel = "Light"

    norm = float(inTime[0])
    fitspath = inTime[1]

    # set text to be put in the xml file

    norm_text = 'parameter scale="' + numdiv(
        norm
    )[1] + '"  name="Normalization"  min="0.0"   max="1000.0"  free="0" value="' + numdiv(
        norm)[0] + '"'

    if (SpatModel == 'Light'):
        temporal = gammalib.GXmlElement(
            'temporal   type="LightCurve"   file="' + fitspath + '"')
        temporal.append(gammalib.GXmlElement(norm_text))
    else:
        print(
            "The only supported temporal model is the one with Normalization and a fits file"
        )
        sys.exit()

    return temporal
Exemplo n.º 2
0
    def _set_response(self, obs, caldb, irf):
        """
        Set response for an observation.
        
        The method creates an XML element so that that the response XML
        writer will write the database and response name into the
        observation definition file.
        """
        # Create XML element
        xml = gammalib.GXmlElement()

        # Append parameter
        parameter = 'parameter name="Calibration" database="'+caldb+\
                    '" response="'+irf+'"'
        xml.append(gammalib.GXmlElement(parameter))

        # Create CTA response
        response = gammalib.GCTAResponseIrf()
        response.read(xml)

        # Attach response to observation
        obs.response(response)

        # Return observation
        return obs
Exemplo n.º 3
0
    def __init__(self, *argv):
        """
        Constructor
        """
        # Initialise application by calling the base class constructor
        self._init_cscript(self.__class__.__name__, ctools.__version__, argv)

        # Initialise some members
        self._obs = gammalib.GObservations()
        self._ebounds = gammalib.GEbounds()
        self._datapath = os.getenv('VHEFITS', '')
        self._prodname = ''
        self._xml = gammalib.GXml()
        self._models = gammalib.GModels()
        self._runlist = []
        self._runlistfile = gammalib.GFilename()
        self._bkgpars = 0
        self._master_indx = ''
        self._use_bkg_scale = False
        self._ev_hiera = ['']
        self._aeff_hiera = ['']
        self._psf_hiera = ['']
        self._bkg_hiera = ['']
        self._edisp_hiera = ['']
        self._bkg_mod_hiera = ['']
        self._bkg_gauss_norm = 1.0
        self._bkg_gauss_index = 0.0
        self._bkg_gauss_sigma = 1.0
        self._bkg_aeff_index = 0.0
        self._bkg_aeff_norm = 1.0
        self._bkg_range_factor = 1.0
        self._hdu_index = ''
        self._obs_index = ''
        self._subdir = ''
        self._debug = False

        # Initialise empty observation definition XML file
        self._xml.append(
            gammalib.GXmlElement('observation_list '
                                 'title="observation list"'))

        # Append an observation list to XML instance
        self._xml.append(
            gammalib.GXmlElement('observation_list title="observation list"'))
        self._xml_obslist = self._xml.element('observation_list', 0)

        # Return
        return
Exemplo n.º 4
0
    def _set_irf(self, obs, caldb, irf):
        """
        Set response for an observation
        
        The method creates an XML element so that that the response XML
        writer will write the database and response name into the
        observation definition file.

        Parameters
        ----------
        obs : `~gammalib.GCTAObservation`
            CTA observation
        caldb : str
            Calibration database
        irf : str
            Instrument response function

        Returns
        obs : `~gammalib.GCTAObservation`
            CTA observation with response attached
        -------
        """
        # Create XML element
        xml = gammalib.GXmlElement()

        # Append parameter
        parameter = 'parameter name="Calibration" database="'+caldb+\
                    '" response="'+irf+'"'
        xml.append(gammalib.GXmlElement(parameter))

        # Create CTA response
        response = gammalib.GCTAResponseIrf()
        response.read(xml)

        # Attach response to observation
        obs.response(response)

        # Return observation
        return obs
Exemplo n.º 5
0
def manipulate_xml(xml):
    """
    Illustrates the manipulation of an XML document.
    
    This function illustrates the manipulation of an XML document by
    using the remove(), insert(), set() and extend() methods.
    """
    # Remove the third child node containing the processing instruction
    # (Note that the third node has the index 2!).
    xml.remove(2)

    # Insert now at the location where we just removed the processing
    # instruction a new child element named 'replacement'. This new
    # child element will have four levels of child nodes.
    level0 = xml.insert(2, gammalib.GXmlElement('replacement'))
    level1 = level0.append('level1')
    level2 = level1.append('level2')
    level3 = level2.append('level3')
    level4 = level3.append('level4')

    # Set now a text node at the place of the level4 child node (the
    # level4 child node was sitting in the first slot of the level3
    # node, hence we have to set the text using the index 0)
    level4 = level3.set(
        0, gammalib.GXmlText('This text replaces the level 4 child node'))

    # We extend the level2 child node by adding four further child nodes
    # containg a text node, one comment and one processing instruction.
    # In total, the level2 child node now has six childs, four of which
    # are elements, one is a comment and one a processing instruction.
    #
    # We could do this simply using the append method, but we illustrate
    # here another case: the extension of a child node using child nodes
    # of another element. For this purpose we create first a fresh element
    # 'ext'. To this fresh element we append four child nodes which all
    # will contain a text node. We furthermore append one comment and one
    # processing instruction. Once this is setup we call the extend() method
    # to extend the level2 child node.
    ext = gammalib.GXmlElement('level2 extension="yes"')
    element1 = ext.append('level3')
    element2 = ext.append('level3')
    element3 = ext.append('level3')
    element4 = ext.append('level3')
    comment = ext.append(gammalib.GXmlComment('This is a comment'))
    pi = ext.append(gammalib.GXmlPI('<?xml-stylesheet type="text/xsl"?>'))
    element1.append(gammalib.GXmlText('This is the first element'))
    element2.append(gammalib.GXmlText('This is the second element'))
    element3.append(gammalib.GXmlText('This is the third element'))
    element4.append(gammalib.GXmlText('This is the forth element'))
    level2.extend(ext)

    # Now we replace the text of the last element in the level2 childs.
    # The emphasis is here on 'element'. The comment and the processing
    # instruction are NOT elements, they are special markup tags. The
    # last 'element' is the forth child node!
    #
    # Instead of explicitly quoting the index of the forth child, we
    # determine the number of elements using the elements() method, and
    # we access the last element by using number-1 as the index in the
    # element() method.
    #
    # The text child is then accessed using the [0] index operator. As
    # there is only a single text node in the last element, we use the
    # index 0.
    number = level2.elements()
    last = level2.element(number - 1)
    text = last[0]
    text.text('This replaces the text of the last element')

    # Now we change the name of the last element in the level2 childs
    # to 'new3' and we benefit to illustrate also how attributes can
    # be set. The name change is done using the name() method, attributes
    # are manipulated using the attribute() method.
    #
    # There are three calls to attribute(). The first adds a new attribute
    # 'type' with a value of 'none'. As this attribute did not exist before,
    # the attribute() method adds it to the element. The same is done by the
    # second call which add the attribute 'case' with value 'mixed'. The
    # third class modifies the attribute 'type' by giving it a new value of
    # 'info'. This illustrates the logic of the attribute() method: if the
    # attribute name does not exist the attribute will be added, otherwise
    # it will be modified.
    #
    # Finally, the 'case' attribute is removed using the remove_attribute()
    # method.
    last.name('new3')
    last.attribute('type', 'none')
    last.attribute('case', 'mixed')
    last.attribute('type', 'info')
    last.remove_attribute('case')

    # Now we make again a text replacement, but instead of chaning the
    # text of the last element we change the text of the last element with
    # name 'level3'. This is not the last in the list as we just changed
    # the name of the last element to 'new3'. This example illustrates
    # how elements can be accessed by name.
    number = level2.elements('level3')
    text = level2.element('level3', number - 1)[0]
    text.text('This replaces the text of the last "level3" element')

    # Return XML document
    return xml
Exemplo n.º 6
0
    def run(self):
        """
        Run the script
        """
        # Switch screen logging on in debug mode
        if self._logDebug():
            self._log.cout(True)

        # Get parameters
        self._get_parameters()

        # Clear models
        self._models.clear()

        # Log output
        msg = 'Looping over %d runs' % len(self._runlist)
        self._log_header1(gammalib.TERSE, msg)

        # Initialise energy range values for logging
        self._ebounds.clear()

        # Loop over runs
        for obs_id in self._runlist:

            # Create selection string
            obs_selection = '[OBS_ID==' + str(obs_id) + ']'

            # Open HDU index file
            hduindx = gammalib.GFits(self._hdu_index + '[HDU_INDEX]' +
                                     obs_selection)
            hduindx_hdu = hduindx['HDU_INDEX']

            # Initialise types and formats
            formats = []
            for i in range(hduindx_hdu.nrows()):
                formats.append(hduindx_hdu['HDU_CLASS'][i])

            # Retrieve filenames
            eventfile = self._get_filename(hduindx_hdu, self._ev_hiera,
                                           formats)
            aefffile = self._get_filename(hduindx_hdu, self._aeff_hiera,
                                          formats)
            psffile = self._get_filename(hduindx_hdu, self._psf_hiera, formats)
            edispfile = self._get_filename(hduindx_hdu, self._edisp_hiera,
                                           formats)
            bkgfile = self._get_filename(hduindx_hdu, self._bkg_hiera, formats)

            # Check for presence of required event file
            if not self._is_present(eventfile, obs_id, "event file"):
                continue

            # Check for presence of required effective area file
            if not self._is_present(aefffile, obs_id, "effective area file"):
                continue

            # Check for presence of required psf file
            if not self._is_present(psffile, obs_id, "PSF file"):
                continue

            # Check for optional energy dispersion file
            if not gammalib.GFilename(edispfile).exists():

                # Print warning that edisp cannot be used for this observation
                msg = ('Warning: observation "%s" has no energy dispersion '
                       'information' % obs_id)
                self._log_string(gammalib.NORMAL, msg)

                # Set energy dispersion file as empty
                edispfile = ''

            # Create a copy of background model hierarchy for this run
            run_bkg_mod_hierarchy = list(self._bkg_mod_hiera)

            # Check if background file is available
            # Remove IRF background from hierarchy if file doesnt exist
            if not gammalib.GFilename(bkgfile).exists():

                # Set background file as empty
                bkgfile = ''

                # Check for IRF background in background model hierarchy
                if 'irf' in run_bkg_mod_hierarchy:

                    # Remove IRF background if file doesnt exist
                    run_bkg_mod_hierarchy.remove('irf')

                    # Print warning that edisp cannot be used for this
                    # observation
                    msg = ('Warning: observation "%s" has no background '
                           'information (IRF background cannot be used)' %
                           obs_id)
                    self._log_string(gammalib.NORMAL, msg)

                # Check if background model hierarchy is empty
                if len(run_bkg_mod_hierarchy) == 0:

                    # Skip observation if no background can be used
                    msg = ('Skipping observation "%s": No background can be '
                           'used' % obs_id)
                    self._log_string(gammalib.NORMAL, msg)
                    continue

                else:
                    # Log if we fall back to next background approach
                    msg = (
                        'Observation "%s": Falling back to background "%s"' %
                        (obs_id, run_bkg_mod_hierarchy[0]))
                    self._log_string(gammalib.NORMAL, msg)

            # Close hdu index file
            hduindx.close()

            # Initialise background scale
            bkg_scale = 1.0

            # Check if background scale should be used
            if self._use_bkg_scale:

                # Read background scale from fits file
                obsindx = gammalib.GFits(self._obs_index + '[OBS_INDEX]' +
                                         obs_selection)
                bkg_scale = obsindx['OBS_INDEX']['BKG_SCALE'][0]
                obsindx.close()

            # Open event FITS file
            fits = gammalib.GFits(eventfile)

            # Get object and telescope strings from event hdu
            events = fits[gammalib.GFilename(eventfile).extname()]
            object_name = events.string('OBJECT')
            telescope = events.string('TELESCOP')

            # Close FITS file
            fits.close()

            # Open effective area file to look for threshold
            aeff_fits = gammalib.GFits(aefffile)
            aeff_table = aeff_fits[gammalib.GFilename(aefffile).extname()]

            # Set energy range from header keyword if present
            if aeff_table.has_card('LO_THRES') and aeff_table.has_card(
                    'HI_THRES'):

                # Get safe energy range
                run_emin = gammalib.GEnergy(aeff_table.real('LO_THRES'), 'TeV')
                run_emax = gammalib.GEnergy(aeff_table.real('HI_THRES'), 'TeV')

                # Append to ebounds
                self._ebounds.append(run_emin, run_emax)

            else:
                # Set default values for energy range
                run_emin = gammalib.GEnergy(10, 'GeV')
                run_emax = gammalib.GEnergy(100, 'TeV')

            # Close Aeff fits file
            aeff_fits.close()

            # Append instrumental background model
            self._models.append(
                self._iact_background(telescope, obs_id, bkg_scale,
                                      run_bkg_mod_hierarchy[0], run_emin.TeV(),
                                      run_emax.TeV()))

            # Append observation to XML and set attributes
            obs = self._xml_obslist.append('observation')
            obs.attribute('name', object_name)
            obs.attribute('id', str(obs_id))
            obs.attribute('instrument', telescope)

            # Append event file
            ev = gammalib.GXmlElement('parameter name="EventList"')
            ev.attribute('file', eventfile)

            # Append effective area
            aeff = gammalib.GXmlElement('parameter name="EffectiveArea"')
            aeff.attribute('file', aefffile)

            # Append PSF
            psf = gammalib.GXmlElement('parameter name="PointSpreadFunction"')
            psf.attribute('file', psffile)

            # Append energy dispersion
            edisp = gammalib.GXmlElement('parameter name="EnergyDispersion"')
            edisp.attribute('file', edispfile)

            # Append background
            bck = gammalib.GXmlElement('parameter name="Background"')
            bck.attribute('file', bkgfile)

            # Assign events and IRFs to observation
            obs.append(ev)
            obs.append(aeff)
            obs.append(psf)
            obs.append(edisp)
            obs.append(bck)

            # Log the observation ID and object name that has been appended
            self._log_value(gammalib.NORMAL, 'Append observation',
                            '%s ("%s")' % (obs_id, object_name))

            # Log the file names of the event and response files
            self._log_value(gammalib.EXPLICIT, ' Event file', eventfile)
            self._log_value(gammalib.EXPLICIT, ' Effective area file',
                            aefffile)
            self._log_value(gammalib.EXPLICIT, ' Point spread function file',
                            psffile)
            self._log_value(gammalib.EXPLICIT, ' Energy dispersion file',
                            edispfile)
            self._log_value(gammalib.EXPLICIT, ' Background file', bkgfile)
            if self._use_bkg_scale:
                self._log_value(gammalib.EXPLICIT, ' Background scale',
                                bkg_scale)

        # Append models provided by "inmodel" to the model container
        self._append_inmodels()

        # Write observation summary
        self._write_summary()

        # Write warning in no observation could be used from runlist
        if self._xml_obslist.size() == 0:
            self._log_string(
                gammalib.NORMAL, 'WARNING: No observation was '
                'appended from specified runlist')

        # Return
        return
Exemplo n.º 7
0
    def run(self):
        """
        Run the script.
        """
        # Switch screen logging on in debug mode
        if self._logDebug():
            self._log.cout(True)

        # Get parameters
        self._get_parameters()

        # Clear models
        self._models.clear()

        # Clear xml file and append an observation list
        self._xml.clear()
        self._xml.append(
            gammalib.GXmlElement('observation_list title="observation list"'))
        lib = self._xml.element('observation_list', 0)

        # Log output
        if self._logTerse():
            self._log('\n')
            self._log.header1('Looping over ' + str(len(self._runlist)) +
                              ' runs')

        # Initialise energy range values for logging
        self._ebounds.clear()

        # Loop over runs
        for obs_id in self._runlist:

            # Create selection string
            obs_selection = '[OBS_ID==' + str(obs_id) + ']'

            # Open HDU index file
            hduindx = gammalib.GFits(self._hdu_index + '[HDU_INDEX]' +
                                     obs_selection)
            hduindx_hdu = hduindx['HDU_INDEX']

            # Initialise files and hdu names
            eventfile = aefffile = psffile = edispfile = bkgfile = ''
            eventhdu = aeffhdu = ''

            types = []
            formats = []
            for i in range(hduindx_hdu.nrows()):
                types.append(hduindx_hdu['HDU_TYPE'][i])
                formats.append(hduindx_hdu['HDU_CLASS'][i])

            # Handle events
            index = -1
            for version in self._ev_hiera:
                n = formats.count(version)
                if n > 0:
                    index = formats.index(version)
                    break
            if index >= 0:
                eventfile = os.path.join(self._subdir,
                                         hduindx_hdu['FILE_DIR'][index],
                                         hduindx_hdu['FILE_NAME'][index])
                eventhdu = hduindx_hdu['HDU_NAME'][index]
                eventfile += '[' + eventhdu + ']'
            if not gammalib.GFilename(eventfile).is_fits():
                if self._logTerse():
                    self._log('Skipping observation ' + str(obs_id) +
                              ': eventfile "' + eventfile + '" not found\n')
                continue

            # Handle Aeff
            index = -1
            for version in self._aeff_hiera:
                n = formats.count(version)
                if n > 0:
                    index = formats.index(version)
                    break
            if index >= 0:
                aefffile = os.path.join(self._subdir,
                                        hduindx_hdu['FILE_DIR'][index],
                                        hduindx_hdu['FILE_NAME'][index])
                aeffhdu = hduindx_hdu['HDU_NAME'][index]
                aefffile += '[' + aeffhdu + ']'
            if not gammalib.GFilename(aefffile).is_fits():
                if self._logTerse():
                    self._log('Skipping observation ' + str(obs_id) +
                              ': effective area "' + aefffile +
                              '" not found\n')
                continue

            # Handle psf
            index = -1
            for version in self._psf_hiera:
                n = formats.count(version)
                if n > 0:
                    index = formats.index(version)
                    break
            if index >= 0:
                psffile = os.path.join(self._subdir,
                                       hduindx_hdu['FILE_DIR'][index],
                                       hduindx_hdu['FILE_NAME'][index])
                psffile += '[' + hduindx_hdu['HDU_NAME'][index] + ']'
            if not gammalib.GFilename(psffile).is_fits():
                if self._logTerse():
                    self._log('Skipping observation ' + str(obs_id) +
                              ': point spread function "' + psffile +
                              '" not found\n')
                continue

            # Handle edisp
            index = -1
            for version in self._edisp_hiera:
                n = formats.count(version)
                if n > 0:
                    index = formats.index(version)
                    break
            if index >= 0:
                edispfile = os.path.join(self._subdir,
                                         hduindx_hdu['FILE_DIR'][index],
                                         hduindx_hdu['FILE_NAME'][index])
                edispfile += '[' + hduindx_hdu['HDU_NAME'][index] + ']'
            if not gammalib.GFilename(edispfile).is_fits():
                if self._logTerse():
                    self._log('Warning: observation ' + str(obs_id) +
                              ' has no energy dispersion "' + edispfile +
                              '" information\n')
                    edispfile = ''

            # Handle background
            index = -1
            bkg_mod_hierarchy = list(self._bkg_mod_hiera)
            for version in self._bkg_hiera:
                n = formats.count(version)
                if n > 0:
                    index = formats.index(version)
                    break
            if index >= 0:
                bkgfile = os.path.join(self._subdir,
                                       hduindx_hdu['FILE_DIR'][index],
                                       hduindx_hdu['FILE_NAME'][index])
                bkgfile += '[' + hduindx_hdu['HDU_NAME'][index] + ']'
            if 'irf' in bkg_mod_hierarchy and not gammalib.GFilename(
                    bkgfile).is_fits():
                bkg_mod_hierarchy.remove('irf')
                if self._logTerse():
                    self._log('Warning: observation ' + str(obs_id) +
                              ' has no background information (file="' +
                              bkgfile + '"). IRF background cannot be used\n')
                    bkgfile = ''
                    if len(bkg_mod_hierarchy) == 0:
                        if self._logTerse():
                            self._log('Skipping observation ' + str(obs_id) +
                                      ': No background can be used\n')
                        continue
                    else:
                        if self._logTerse():
                            self._log('Observation ' + str(obs_id) +
                                      ': Falling back to background "' +
                                      bkg_mod_hierarchy[0] + '"\n')

            # Close hdu index file
            hduindx.close()

            # Handle background scale information if available
            bkg_scale = 1.0
            if self._use_bkg_scale:
                obsindx = gammalib.GFits(self._obs_index + '[OBS_INDEX]' +
                                         obs_selection)
                bkg_scale = obsindx['OBS_INDEX']['BKG_SCALE'][0]
                obsindx.close()

            # Open fits file to determine the observation name
            fits = gammalib.GFits(eventfile)
            events = fits[eventhdu]
            object_name = events.string('OBJECT')
            telescope = events.string('TELESCOP')

            # Close FITS file
            fits.close()

            # Open effective area file to look for threshold
            aeff_fits = gammalib.GFits(aefffile)
            aeff_table = aeff_fits[aeffhdu]

            # Set energy range from header keyword if present
            if aeff_table.has_card('LO_THRES') and aeff_table.has_card(
                    'HI_THRES'):

                # Get safe energy range
                run_emin = gammalib.GEnergy(aeff_table.real('LO_THRES'), 'TeV')
                run_emax = gammalib.GEnergy(aeff_table.real('HI_THRES'), 'TeV')

                # Append to ebounds
                self._ebounds.append(run_emin, run_emax)

            else:
                # Set default values for energy range
                run_emin = gammalib.GEnergy(10, 'GeV')
                run_emax = gammalib.GEnergy(100, 'TeV')

            # Close Aeff fits file
            aeff_fits.close()

            # Append instrumental background model
            self._models.append(
                self._iact_background(telescope, obs_id, bkg_scale,
                                      bkg_mod_hierarchy[0], run_emin.TeV(),
                                      run_emax.TeV()))

            # Logging
            if self._logTerse():
                self._log('Adding observation ' + str(obs_id) + ' ("' +
                          object_name + '")\n')

            if self._logExplicit():
                self._log(' Event file: ' + eventfile + '\n')
                self._log(' Effective area: ' + aefffile + '\n')
                self._log(' Point spread function: ' + psffile + '\n')
                self._log(' Energy dispersion: ' + edispfile + '\n')
                self._log(' Background file: ' + bkgfile + '\n')
                if self._use_bkg_scale:
                    self._log(' Background scale: ' + str(bkg_scale) + '\n')
                self._log('\n')

            # Append observation to XML and set attributes
            obs = lib.append('observation')
            obs.attribute('name', object_name)
            obs.attribute('id', str(obs_id))
            obs.attribute('instrument', telescope)

            # Append event file
            ev = gammalib.GXmlElement('parameter name="EventList"')
            ev.attribute('file', eventfile)

            # Append effective area
            aeff = gammalib.GXmlElement('parameter name="EffectiveArea"')
            aeff.attribute('file', aefffile)

            # Append PSF
            psf = gammalib.GXmlElement('parameter name="PointSpreadFunction"')
            psf.attribute('file', psffile)

            # Append energy dispersion
            edisp = gammalib.GXmlElement('parameter name="EnergyDispersion"')
            edisp.attribute('file', edispfile)

            # Append background
            bck = gammalib.GXmlElement('parameter name="Background"')
            bck.attribute('file', bkgfile)

            # assign events and IRFs to observation
            obs.append(ev)
            obs.append(aeff)
            obs.append(psf)
            obs.append(edisp)
            obs.append(bck)

        # Continue only if there are observations available
        if lib.size():

            # Log header of energy range
            if self._logTerse():
                self._log('\n')
                self._log.header3('Energy range of obervation list')

            # Logging if energy range is available
            if self._ebounds.size() > 0:

                # Write energy range into log file
                self._log(
                    str(self._ebounds.emin()) + ' - ' +
                    str(self._ebounds.emax()))
                self._log('\n')

            else:

                # Write 'not available' into log file
                self._log('not available')
                self._log('\n')

        else:
            self._log.header2(
                'WARNING: No observation from given runlist available')

        # Append models provided by 'inmodels' if necessary
        if not self._inmodels == None:
            if self._logTerse():
                self._log('\n')
                self._log.header1('Appending models')

            # Loop over input models
            for model in self._inmodels:
                if self._logTerse():
                    self._log.header3('Adding model "' + model.name() + '"')
                self._models.append(model)

        # Return
        return
Exemplo n.º 8
0
def sim_select_like(sim_yaml, jobs_in, model_xml, background_fits, counter):
    """

    :param sim_yaml:
    :param jobs_in:
    :param model_xml:
    :param background_fits:
    :param counter:
    :return:
    """
    #print("----------------------------")
    print(model_xml.split('/')[-1], counter)

    config_in = yaml.safe_load(open(jobs_in))
    ctools_pipe_path = create_path(config_in['exe']['software_path'])

    sim_in = yaml.safe_load(open(sim_yaml))
    ctobss_params = sim_in['ctobssim']

    # find proper IRF name
    irf = IRFPicker(sim_in, ctools_pipe_path)
    name_irf = irf.irf_pick()

    if irf.prod_version == "3b" and irf.prod_number == 0:
        caldb = "prod3b"
    else:
        caldb = f'prod{irf.prod_number}-v{irf.prod_version}'

    # loading background (this is a way of doing it without saving any file)
    # output.save("name.xml") to save the file
    obs_def = gammalib.GObservations()

    background_id = f"{str(int(counter) + 1).zfill(6)}"

    output = gammalib.GXml()
    level0 = gammalib.GXmlElement('observation_list title="observation library"')
    level1 = gammalib.GXmlElement(f'observation name="name_source" id="{background_id}" instrument="CTA"')
    level2 = gammalib.GXmlElement(f'parameter name="EventList"  file="{background_fits}"')
    level1.append(level2)
    level0.append(level1)
    output.append(level0)

    obs_def.read(output)

    seed = int(counter)*10

    # do the simulation
    sim = ctools.ctobssim()
    sim['inmodel'] = model_xml
    sim['caldb'] = caldb
    sim['irf'] = name_irf
    sim['ra'] = 0
    sim['dec'] = 0
    sim['rad'] = ctobss_params['radius']
    sim['tmin'] = u.Quantity(ctobss_params['time']['t_min']).to_value(u.s)
    sim['tmax'] = u.Quantity(ctobss_params['time']['t_max']).to_value(u.s)
    sim['emin'] = u.Quantity(ctobss_params['energy']['e_min']).to_value(u.TeV)
    sim['emax'] = u.Quantity(ctobss_params['energy']['e_max']).to_value(u.TeV)
    sim['seed'] = seed
    sim.run()

    obs_def.append(sim.obs()[0])

    # for obs in obs_def:
    #     print(obs.id(), obs.nobserved())

    select = ctools.ctselect(obs_def)
    select['rad'] = 3
    select['tmin'] = 0
    select['tmax'] = 50
    select['emin'] = 0.05
    select['emax'] = 1.0
    select.run()
def sourceDef(info):
    # --------------------
    # CREATE SOURCE BRANCH
    # --------------------
    # spectral and spatial components will be appended to this branch
    # 1 branch for each source in the XML model

    srcname = info[0]
    modelname = info[1]  #extract model name for SOURCE
    ts = info[2]
    #if ver != '': print('--------------------------------')

    pointList = ['Point']
    extendedList = ['RadDisk', 'RadGauss', 'RadShell', 'EllDisk', 'EllGauss']
    diffuseList = ['DiffIso', 'DiffMap', 'DiffMapCube']
    bkg_radial = ['BkgGauss', 'Profile', 'Polynom']
    bkg_irf = ['CTAIrf']
    bkg_cube = ['CTACube']

    if (modelname in pointList):
        source_txt = 'source type="PointSource"  name="' + str(srcname) + '"'
    elif (modelname in extendedList):
        source_txt = 'source type="ExtendedSource"  name="' + str(
            srcname) + '"'
    elif (modelname in diffuseList):
        source_txt = 'source type="DiffuseSource"  name="' + str(srcname) + '"'
    elif (modelname in bkg_radial):
        source_txt = 'source name="Background"  type="RadialAcceptance" instrument="CTA"'
    elif (modelname in bkg_irf):
        source_txt = 'source name="Background" type="CTAIrfBackground" instrument="CTA"'
    elif (modelname in bkg_cube):
        source_txt = 'source name="Background" type="CTACubeBackground" instrument="CTA"'
    else:
        print("Mispelled spatial model, open the .txt and check it!")
        sys.exit()

    if (ts == "1"):
        source_txt = source_txt + ' tscalc="1"'

    source_branch = gammalib.GXmlElement(source_txt)
    if (srcname[0:2] == "BKG"):
        if ver != '': print("-----------background-----------")
        if ver != '': print('The source ' + srcname + ' is a ' + modelname)

        #create SPECTRAL model
        spectral = specFun(info[8:])  #string
        source_branch.append(spectral)
    else:
        if ver != '': print("------source: " + srcname + "-------")
        if ver != '': print('The source ' + srcname + ' is a ' + modelname)

        #create SPECTRAL model
        spectral = specFun(info[8:])  #string
        source_branch.append(spectral)

        if (modelname != 'CTAIrf' and modelname != 'CTACube'):
            #create SPATIAL model
            spatial = spatFun(info[1:])
            source_branch.append(spatial)

        #check if the last item is a file fits for the TEMPORAL evolution
        if (info[-1][-4:] == 'fits'):
            #create TEMPORAL model (use last two item in list, NORMALIZATION and FITS file)
            temporal = temporalFun(info[-2:])
            source_branch.append(temporal)

    if (ts == "1"):
        if ver != '': print("TS calculation: yes")
        #source_txt=source_txt+'  tscalc="1"'
    else:
        if ver != '': print("TS calculation: no")

    return source_branch
def specFun(inSpec):
    # --------------------
    # CREATE SPECTRAL MODEL
    # --------------------
    # CHOOSE BETWEEN = "PowerLaw2", "PowerLaw", "NodeFunction", "LogParabola", "Gaussian", "FileFunction", "ExpCutoff", "ConstantValue", "BrokenPowerLaw"

    #set spectral model name
    SpecModel = inSpec[0]

    if (SpecModel == 'CONST'):
        #CONSTANT MODEL
        if ver != '': print('Spectral model: ' + SpecModel)
        norm = float(inSpec[1])
        norm_text = 'parameter scale="' + numdiv(
            norm
        )[1] + '"  name="Normalization"  min="1e-7"   max="1000"  free="1" value="' + numdiv(
            norm)[0] + '"'
        spectral = gammalib.GXmlElement('spectrum type="ConstantValue"')
        spectral.append(norm_text)

    elif (SpecModel == 'FUNC'):
        # FILE FUNCTION
        if ver != '': print('Spectral model: ' + SpecModel)
        norm = float(inSpec[1])
        filepath = inSpec[2]
        norm_text = 'parameter scale="' + numdiv(
            norm
        )[1] + '"  name="Normalization"  min="1e-7"   max="1000"  free="1" value="' + numdiv(
            norm)[0] + '"'
        spectral = gammalib.GXmlElement(
            'spectrum type="FileFunction"  file="' + filepath + '"')
        spectral.append(norm_text)

    elif (SpecModel == 'NODE'):
        if ver != '': print(SpecModel)
        n_param = int(inSpec[1])  #number of parameters

        if n_param % 2 != 0:
            if ver != '':
                print("Wrong number of parameters in NODE SPECTRAL MODEL")
            sys.exit()

        spectral = gammalib.GXmlElement('spectrum type="NodeFunction"')

        values = []
        for n in range(2, n_param + 2, 2):
            if ver != '': print(inSpec[n])
            if ver != '': print(type(inSpec[n]))
            values.append(EnConv(inSpec[n], "MeV"))  #energy
            values.append(inSpec[n + 1])  #intensity

        val_x = values[0::2]  #select only even characters
        val_y = values[1::2]  #select only odd characters
        if ver != '': print(val_x)
        points = [(val_x[i], val_y[i])
                  for i in range(0, len(val_x))]  #making list of points
        pointss = sorted(points, key=lambda k: k[1])  #sort points by energy
        if ver != '': print(pointss)
        for n in range(0, len(pointss)):
            energy_text = 'parameter scale="' + str(
                pointss[n][0][1]
            ) + '"   name="Energy"    min="0.1"   max="1.0e20" free="0"  value="' + str(
                pointss[n][0][0]) + '"'
            intens_text = 'parameter scale="1e-07" name="Intensity" min="1e-07" max="1000.0" free="1" value="' + pointss[
                n][1] + '"'
            node = spectral.append('node')
            node.append(energy_text)
            node.append(intens_text)

    elif (SpecModel == 'PL'):
        #POWER LAW MODEL
        if ver != '': print('Spectral model: ' + SpecModel)
        pref = float(inSpec[1])
        index = inSpec[2]
        PivotEnergy = EnConv(inSpec[3], "MeV")  #convert the energy in MeV

        pref_text = 'parameter scale="' + numdiv(
            pref
        )[1] + '"  name="Prefactor"  min="1e-7"   max="1000"  free="1" value="' + numdiv(
            pref)[0] + '"'
        index_text = 'parameter scale="-1.0"  name="Index"  min="0.0"   max="+10.0"  free="1" value="' + index + '"'
        energy_text = 'parameter scale="' + str(
            PivotEnergy[1]
        ) + '"  name="Scale"  min="0.0"   max="+10000000.0"  free="0" value="' + str(
            PivotEnergy[0]) + '"'

        spectral = gammalib.GXmlElement('spectrum type="PowerLaw"')
        spectral.append(pref_text)
        spectral.append(index_text)
        spectral.append(energy_text)

    elif (SpecModel == 'PL2'):
        #POWER LAW 2 MODEL
        if ver != '': print('Spectral model: ' + SpecModel)
        pref = float(inSpec[1])
        index = inSpec[2]
        MinEnergy = EnConv(inSpec[3], "MeV")  #convert the energy in MeV
        MaxEnergy = EnConv(inSpec[4], "MeV")  #convert the energy in MeV
        if ver != '': print(MaxEnergy)

        pref_text = 'parameter scale="' + numdiv(
            pref
        )[1] + '"  name="Integral"  min="1e-7"   max="1000"  free="1" value="' + numdiv(
            pref)[0] + '"'
        index_text = 'parameter scale="-1.0"  name="Index"  min="0.0"   max="+10.0"  free="1" value="' + index + '"'
        min_energy_text = 'parameter scale="' + str(
            MinEnergy[1]
        ) + '"  name="LowerLimit"  min="10.0"   max="+100000000.0"  free="0" value="' + str(
            MinEnergy[0]) + '"'
        max_energy_text = 'parameter scale="' + str(
            MaxEnergy[1]
        ) + '"  name="UpperLimit"  min="10.0"   max="+100000000.0"  free="0" value="' + str(
            MaxEnergy[0]) + '"'

        spectral = gammalib.GXmlElement('spectrum type="PowerLaw2"')
        spectral.append(pref_text)
        spectral.append(index_text)
        spectral.append(min_energy_text)
        spectral.append(max_energy_text)

    elif (SpecModel == 'BRPL'):
        # BrokenPowerLaw MODEL
        if ver != '': print('Spectral model: ' + SpecModel)
        pref = float(inSpec[1])
        index1 = inSpec[2]  #must be negative
        CutEnergy = EnConv(inSpec[3], "GeV")  #convert the energy in GeV
        index2 = inSpec[4]  # must be negative

        pref_text = 'parameter scale="' + numdiv(
            pref
        )[1] + '"  name="Prefactor"  min="1e-7"   max="1000"  free="1" value="' + numdiv(
            pref)[0] + '"'
        index1_text = 'parameter scale="-1.0"  name="Index1"  min="0.01"   max="+10.0"  free="1" value="' + index1 + '"'
        cut_energy_text = 'parameter scale="' + str(
            CutEnergy[1]
        ) + '"  name="BreakValue"  min="10.0"   max="+100000000.0"  free="1" value="' + str(
            CutEnergy[0]) + '"'
        index2_text = 'parameter scale="-1.0"  name="Index2"  min="0.01"   max="+10.0"  free="1" value="' + index2 + '"'

        spectral = gammalib.GXmlElement('spectrum type="BrokenPowerLaw"')
        spectral.append(pref_text)
        spectral.append(index1_text)
        spectral.append(cut_energy_text)
        spectral.append(index2_text)

    elif (SpecModel == 'EXPL'):
        #Exponential CUT OFF POWER LAW MODEL
        if ver != '': print('Spectral model: ' + SpecModel)
        pref = float(inSpec[1])
        index = inSpec[2]
        PivotEnergy = EnConv(inSpec[3], "MeV")  #convert the energy in MeV
        CutEnergy = EnConv(inSpec[4], "MeV")  #convert the energy in MeV

        pref_text = 'parameter scale="' + numdiv(
            pref
        )[1] + '"  name="Prefactor"  min="1e-7"   max="1000"  free="1" value="' + numdiv(
            pref)[0] + '"'
        index_text = 'parameter scale="-1.0"  name="Index"  min="0.0"   max="+10.0"  free="1" value="' + index + '"'
        cut_energy_text = 'parameter scale="1.0"  name="Cutoff"  min="0.01"   max="100000000.0"  free="1" value="' + str(
            CutEnergy[0]) + '"'
        piv_energy_text = 'parameter scale="1.0"  name="Scale"  min="0.01"   max="100000000.0"  free="0" value="' + str(
            PivotEnergy[0]) + '"'

        spectral = gammalib.GXmlElement('spectrum type="ExpCutoff"')
        spectral.append(pref_text)
        spectral.append(index_text)
        spectral.append(cut_energy_text)
        spectral.append(piv_energy_text)

    elif (SpecModel == 'SEPL'):
        #SUPER EXPONENTIALY CUY-OFF POWER LAW
        if ver != '': print('Spectral model: ' + SpecModel)
        pref = float(inSpec[1])
        index1 = inSpec[2]
        index2 = inSpec[3]
        PivotEnergy = EnConv(inSpec[4], "MeV")  #convert the energy in MeV
        CutEnergy = EnConv(inSpec[5], "MeV")  #convert the energy in MeV

        pref_text = 'parameter scale="' + numdiv(
            pref
        )[1] + '"  name="Prefactor"  min="1e-7"   max="1000"  free="1" value="' + numdiv(
            pref)[0] + '"'
        index1_text = 'parameter scale="-1.0"  name="Index1"  min="0.0"   max="+10.0"  free="1" value="' + index1 + '"'
        index2_text = 'parameter scale="1.0"   name="Index2"  min="0.1"   max="10.0"   free="1" value="' + index2 + '"'
        cut_energy_text = 'parameter scale="' + str(
            CutEnergy[1]
        ) + '"  name="Cutoff"  min="0.01"   max="100000000.0"  free="1" value="' + str(
            CutEnergy[0]) + '"'
        piv_energy_text = 'parameter scale="' + str(
            PivotEnergy[1]
        ) + '"  name="Scale"   min="0.01"   max="100000000.0"  free="0" value="' + str(
            PivotEnergy[0]) + '"'

        spectral = gammalib.GXmlElement('spectrum type="PLSuperExpCutoff"')
        spectral.append(pref_text)
        spectral.append(index1_text)
        spectral.append(index2_text)
        spectral.append(cut_energy_text)
        spectral.append(piv_energy_text)

    elif (SpecModel == 'LOGPAR'):
        if ver != '': print('Spectral model: ' + SpecModel)
        #LOG PARABOLA
        pref = float(inSpec[1])
        index = inSpec[2]
        curv = inSpec[3]
        E_scale = EnConv(inSpec[4], "MeV")  #convert the energy in MeV

        pref_text = 'parameter scale="' + numdiv(
            pref
        )[1] + '"  name="Prefactor"  min="1e-7"   max="1000"  free="1" value="' + numdiv(
            pref)[0] + '"'
        index_text = 'parameter scale="-1.0"  name="Index"  min="0.0"   max="+10.0"  free="1" value="' + index + '"'
        curv_text = 'parameter scale="-1.0"  name="Curvature"  min="-5.0"   max="+5.0"  free="1" value="' + curv + '"'
        E_scale_text = 'parameter scale="1.0"  name="Scale"  min="0.01"   max="100000000.0"  free="0" value="' + str(
            E_scale[0]) + '"'

        spectral = gammalib.GXmlElement('spectrum type="LogParabola"')

        spectral.append(pref_text)
        spectral.append(index_text)
        spectral.append(curv_text)
        spectral.append(E_scale_text)

    elif (SpecModel == 'GAUSS'):
        if ver != '': print('Spectral model: ' + SpecModel)
        #GAUSSIAN FUNCTION
        norm = float(inSpec[1])
        mean = EnConv(inSpec[2], "GeV")
        sigma = inSpec[3]

        norm_text = 'parameter scale="' + numdiv(
            norm
        )[1] + '"  name="Normalization"  min="1e-7"   max="1000.0"  free="1" value="' + numdiv(
            norm)[0] + '"'
        mean_text = 'parameter scale="1e6"   name="Mean"    value="' + str(
            mean[0]) + '"'
        sigma_text = 'parameter scale="1e6"   name="Sigma"     min="0.01"  max="100.0"  free="1"  value="' + sigma + '"'

        spectral = gammalib.GXmlElement('spectrum type="Gaussian"')
        spectral.append(norm_text)
        spectral.append(mean_text)
        spectral.append(sigma_text)

    else:
        print("Wrong Spectral model!!! CHECK MODEL NAME!!!")
        sys.exit()

    return spectral
def spatFun(inSpat):
    # --------------------
    # CREATE SPATIAL MODEL
    # --------------------

    #get model name
    SpatModel = inSpat[0]

    # set RA and DEC, common for all the spatial models
    ra = inSpat[2]
    dec = inSpat[3]

    # set text to be put in the xml file
    ra_text = 'parameter scale="1.0"  name="RA"  min="-360"   max="360"  free="0" value="' + ra + '"'
    dec_text = 'parameter scale="1.0"  name="DEC"  min="-90"   max="90"  free="0" value="' + dec + '"'

    if (SpatModel == 'Point'):
        spatial = gammalib.GXmlElement('spatialModel type="SkyDirFunction"'
                                       )  #compatibility with Fermi/LAT
        spatial.append(ra_text)
        spatial.append(dec_text)

    elif (SpatModel == 'RadDisk'):
        spatial = gammalib.GXmlElement('spatialModel type="DiskFunction"')
        spatial.append(ra_text)
        spatial.append(dec_text)
        radius = inSpat[4]
        radius_text = 'parameter name="Radius" scale="1.0"  min="0.01" max="10"  free="0"   value="' + radius + '"'
        spatial.append(radius_text)

    elif (SpatModel == 'RadGauss'):
        spatial = gammalib.GXmlElement('spatialModel type="GaussFunction"')
        spatial.append(ra_text)
        spatial.append(dec_text)
        sig = inSpat[4]
        sig_text = 'parameter name="Sigma" scale="1.0"  min="0.01" max="10"  free="0"   value="' + sig + '"'
        spatial.append(sig_text)

    elif (SpatModel == 'RadShell'):
        spatial = gammalib.GXmlElement('spatialModel type="ShellFunction"')
        spatial.append(ra_text)
        spatial.append(dec_text)
        radius = inSpat[4]
        width = inSpat[5]
        radius_text = 'parameter name="Radius" scale="1.0"  min="0.01" max="10"  free="0"  value="' + radius + '"'
        width_text = 'parameter name="Width"  scale="1.0"  min="0.01" max="10"  free="0"  value="' + width + '"'
        spatial.append(radius_text)
        spatial.append(width_text)

    elif (SpatModel == 'EllDisk'):
        spatial = gammalib.GXmlElement('spatialModel type="EllipticalDisk"')
        spatial.append(ra_text)
        spatial.append(dec_text)
        PA = inSpat[4]
        minr = inSpat[5]
        maxr = inSpat[6]
        PA_text = 'parameter name="PA"   scale="1.0"  min="-360"   max="360" free="0"  value="' + PA + '"'
        minr_text = 'parameter name="MinorRadius"  scale="1.0"  min="0.001"  max="10"  free="0"  value="' + minr + '"'
        maxr_text = 'parameter name="MajorRadius"  scale="1.0"  min="0.001"  max="10"  free="0"  value="' + maxr + '"'
        spatial.append(PA_text)
        spatial.append(minr_text)
        spatial.append(maxr_text)

    elif (SpatModel == 'EllGauss'):
        spatial = gammalib.GXmlElement('spatialModel type="EllipticalGauss"')
        spatial.append(ra_text)
        spatial.append(dec_text)
        PA = inSpat[4]
        minr = inSpat[5]
        maxr = inSpat[6]
        PA_text = 'parameter name="PA"           scale="1.0"  min="-360"   max="360" free="0"  value="' + PA + '"'
        minr_text = 'parameter name="MinorRadius"  scale="1.0"  min="0.001"  max="10"  free="0"  value="' + minr + '"'
        maxr_text = 'parameter name="MajorRadius"  scale="1.0"  min="0.001"  max="10"  free="0"  value="' + maxr + '"'
        spatial.append(PA_text)
        spatial.append(minr_text)
        spatial.append(maxr_text)

    elif (SpatModel == 'DiffIso'):
        spatial = gammalib.GXmlElement('spatialModel type="DiffuseSource"')
        value = inSpat[4]
        value_text = 'parameter name="Value" scale="1" min="1"  max="1" free="0" value="' + value + '"'
        spatial.append(value_text)

    elif (SpatModel == 'DiffMap'):
        spatial = gammalib.GXmlElement(
            'spatialModel type="DiffuseSource" file="map.fits"')
        value = inSpat[4]
        value_text = 'parameter name="Prefactor" scale="1" min="0.001"  max="1000.0" free="0" value="' + value + '"'
        spatial.append(value_text)

    elif (SpatModel == 'DiffMapCube'):
        spatial = gammalib.GXmlElement(
            'spatialModel type="MapCubeFunction" file="map_cube.fits"')
        value = inSpat[4]
        value_text = 'parameter name="Normalization" scale="1" min="0.001"  max="1000.0" free="0" value="' + value + '"'
        spatial.append(value_text)

        #---------- Here starts background spatial models

    elif (SpatModel == 'BkgGauss'):
        spatial = gammalib.GXmlElement('radialModel type="Gaussian"')
        sig = inSpat[2]
        sig_text = 'parameter name="Sigma" scale="1.0"  min="0.01" max="10.0"  free="0"   value="' + sig + '"'
        spatial.append(sig_text)

    elif (SpatModel == 'Profile'):
        spatial = gammalib.GXmlElement('radialModel type="Profile"')
        width = inSpat[2]
        core = inSpat[3]
        tail = inSpat[4]
        width_text = 'parameter name="Width" scale="1.0"  min="0.01" max="10000.0"  free="0"   value="' + width + '"'
        core_text = 'parameter name="Core" scale="1.0"  min="0.01" max="10000.0"  free="0"   value="' + core + '"'
        tail_text = 'parameter name="Tail" scale="1.0"  min="0.01" max="10000.0"  free="0"   value="' + tail + '"'

        spatial.append(width_text)
        spatial.append(core_text)
        spatial.append(tail_text)

    elif (SpatModel == 'Polynom'):
        spatial = gammalib.GXmlElement('radialModel type="Polynom"')
        coef = inSpat[2]
        coef = coef.split("_")
        for i in range(0, len(coef)):
            name_coef = 'Coeff' + str(i)
            coef_text = 'parameter name="' + name_coef + '" scale="1.0" value="' + coef[
                i] + '"  min="-10.0" max="10.0" free="0"'
            spatial.append(coef_text)

    else:
        print("Wrong input model")
        sys.exit()
    return spatial