Example #1
0
    def _compute_ulimit(self, obs):
        """
        Computes upper limit

        Parameters
        ----------
        obs : `~gammalib.GObservations`
            Observation container

        Returns
        -------
        ul_diff, ul_flux, ul_eflux : tuple of float
            Upper limits, -1.0 of not computed
        """
        # Initialise upper flux limit
        ul_diff  = -1.0
        ul_flux  = -1.0
        ul_eflux = -1.0

        # Perform computation only if requested
        if self['calc_ulim'].boolean():

            # Write header in logger
            self._log_header3(gammalib.EXPLICIT, 'Computing upper limit')

            # Create copy of observations
            cpy_obs = obs.copy()

            # Fix parameters of source of interest in copy of observations.
            # This assures that the original spectral parameters and position
            # are used in the upper limit search. The ctulimit tool makes sure
            # that the flux parameter is freed when needed.
            source = cpy_obs.models()[self._srcname]
            for par in source:
                if par.is_free():
                    par.fix()

            # Create instance of upper limit tool
            ulimit = ctools.ctulimit(cpy_obs)
            ulimit['srcname']   = self._srcname
            ulimit['eref']      = 1.0
            ulimit['emin']      = self['emin'].real()
            ulimit['emax']      = self['emax'].real()
            ulimit['sigma_min'] = 0.0
            ulimit['sigma_max'] = 3.0

            # Try to run upper limit tool and catch any exceptions
            try:
                ulimit.run()
                ul_diff  = ulimit.diff_ulimit()
                ul_flux  = ulimit.flux_ulimit()
                ul_eflux = ulimit.eflux_ulimit()
            except:
                self._log_string(gammalib.TERSE, 'Upper limit calculation failed.')
                ul_diff  = -1.0
                ul_flux  = -1.0
                ul_eflux = -1.0

        # Return upper limit tuple
        return ul_diff, ul_flux, ul_eflux
Example #2
0
    def test_functional(self):
        """
        Test cttsmap functionnality.
        """
        # Set-up cttsmap
        ulimit = ctools.ctulimit()
        ulimit["inobs"].filename(self.events_name)
        ulimit["inmodel"].filename(self.model_name)
        ulimit["srcname"].string("Crab")
        ulimit["caldb"].string(self.caldb)
        ulimit["irf"].string(self.irf)
        
        # Run tool
        self.test_try("Run ctulimit")
        try:
            ulimit.run()
            self.test_try_success()
        except:
            self.test_try_failure("Exception occured in ctulimit.")

        # Save results
        self.test_try("Save results")
        try:
            ulimit.save()
            self.test_try_success()
        except:
            self.test_try_failure("Exception occured in saving results.")
        
        # Return
        return
Example #3
0
    def _test_python(self):
        """
        Test ctulimit from Python
        """
        # Set-up ctulimit
        ulimit = ctools.ctulimit()
        ulimit['inobs'] = self._events
        ulimit['inmodel'] = self._model
        ulimit['srcname'] = 'Crab'
        ulimit['caldb'] = self._caldb
        ulimit['irf'] = self._irf
        ulimit['logfile'] = 'ctulimit_py1.log'
        ulimit['chatter'] = 2

        # Run ctulimit tool
        ulimit.logFileOpen()  # Make sure we get a log file
        ulimit.run()
        ulimit.save()

        # Check result file
        self._check_result_file('ctulimit_py1.log')

        # Return
        return
Example #4
0
    def _compute_ulimit(self, obs):
        """
        Computes upper flux limit.

        Args:
            obs: Observation container.

        Returns:
            Upper flux limit (-1 of not computed).
        """
        # Initialise upper flux limit
        ulimit_value = -1.0

        # Perform computation only if requested
        if self["calc_ulim"].boolean():

            # Write header in logger
            if self._logExplicit():
                self._log.header3("Computing upper flux limit")

            # Create upper limit object
            ulimit = ctools.ctulimit(obs)
            ulimit["srcname"] = self._srcname
            ulimit["eref"] = 1.0

            # Try to run upper limit and catch exceptions
            try:
                ulimit.run()
                ulimit_value = ulimit.flux_ulimit()
            except:
                if self._logTerse():
                    self._log("Upper limit flux calculation failed.s\n")
                ulimit_value = -1.0

        # Return upper limit
        return ulimit_value
Example #5
0
    def _fit_model(self):
        """
        Fit model to observations

        Returns
        -------
        results : list of dict
            List of dictionaries with fit results
        """
        # Write header
        self._log_header1(gammalib.TERSE, 'Generate spectrum')

        # Write header for fitting
        self._log_header3(gammalib.EXPLICIT, 'Performing model fit')

        # Perform maximum likelihood fit
        like = ctools.ctlike(self.obs())
        like['edisp'] = self['edisp'].boolean()
        like.run()

        # Initialise fit results
        results = []

        # Extract fit results
        model = like.obs().models()[self['srcname'].string()]
        spectrum = model.spectral()
        logL0 = like.obs().logL()

        # Write model results for explicit chatter level
        self._log_string(gammalib.EXPLICIT, str(like.obs().models()))

        # Loop over all nodes
        for i in range(spectrum.nodes()):

            # Get energy boundaries
            emin = self._ebounds.emin(i)
            emax = self._ebounds.emax(i)
            elogmean = self._ebounds.elogmean(i)

            # Initialise dictionary
            result = {
                'energy': elogmean.TeV(),
                'energy_low': (elogmean - emin).TeV(),
                'energy_high': (emax - elogmean).TeV(),
                'flux': 0.0,
                'flux_err': 0.0,
                'TS': 0.0,
                'ulimit': 0.0,
                'Npred': 0.0
            }

            # Convert differential flux and flux error to nuFnu
            norm = elogmean.MeV() * elogmean.MeV() * gammalib.MeV2erg
            result['flux'] = spectrum[i * 2 + 1].value() * norm
            result['flux_err'] = spectrum[i * 2 + 1].error() * norm

            # Compute upper flux limit
            ulimit_value = -1.0
            if self['calc_ulim'].boolean():

                # Logging information
                self._log_header3(
                    gammalib.EXPLICIT,
                    'Computing upper limit for node energy %f TeV' %
                    result['energy'])

                # Copy observation container
                obs = like.obs().copy()

                # Fix intensities of all nodes
                spectral = obs.models()[self['srcname'].string()].spectral()
                for par in spectral:
                    par.fix()

                # Create upper limit object
                ulimit = ctools.ctulimit(obs)
                ulimit['srcname'] = self['srcname'].string()
                ulimit['parname'] = 'Intensity%d' % i
                ulimit['eref'] = elogmean.TeV()
                ulimit['tol'] = 1.0e-3

                # Try to run upper limit and catch exceptions
                try:
                    ulimit.run()
                    ulimit_value = ulimit.diff_ulimit()
                except:
                    self._log_string(gammalib.EXPLICIT, 'Upper limit '
                                     'calculation failed.')
                    ulimit_value = -1.0

                # Compute upper limit
                if ulimit_value > 0.0:
                    result['ulimit'] = ulimit_value * elogmean.MeV() * \
                                       elogmean.MeV() * gammalib.MeV2erg

            # Compute TS
            if self['calc_ts'].boolean():

                # Copy observation container
                obs = like.obs().copy()

                # Set intensity of node to tiny value by scaling the value
                # by a factor 1e-8.
                par = obs.models()[self['srcname'].string()].spectral()[i * 2 +
                                                                        1]
                par.autoscale()
                par.factor_min(1.0e-8)
                par.factor_value(1.0e-8)
                par.autoscale()
                par.fix()

                # Perform maximum likelihood fit
                tslike = ctools.ctlike(obs)
                tslike['edisp'] = self['edisp'].boolean()
                tslike.run()

                # Store Test Statistic
                model = tslike.obs().models()[self['srcname'].string()]
                logL1 = tslike.obs().logL()
                result['TS'] = 2.0 * (logL1 - logL0)

            # Log information
            value = '%e +/- %e' % (result['flux'], result['flux_err'])
            if self['calc_ulim'].boolean() and result['ulimit'] > 0.0:
                value += ' [< %e]' % (result['ulimit'])
            value += ' erg/cm2/s'
            if self['calc_ts'].boolean() and result['TS'] > 0.0:
                value += ' (TS = %.3f)' % (result['TS'])
            self._log_value(gammalib.TERSE, 'Bin ' + str(i + 1), value)

            # Append results
            results.append(result)

        # Return results
        return results
Example #6
0
    def _fit_energy_bin(self, i):
        """
        Fit data for one energy bin

        Parameters
        ----------
        i : int
            Energy bin index

        Returns
        -------
        result : dict
            Dictionary with fit results
        """

        # Write header for energy bin
        self._log_header2(gammalib.EXPLICIT, 'Energy bin ' + str(i + 1))

        # Get energy boundaries
        emin = self._ebounds.emin(i)
        emax = self._ebounds.emax(i)
        elogmean = self._ebounds.elogmean(i)

        # Select observations for energy bin
        obs = self._select_obs(emin, emax)

        # Initialise dictionary
        result = {
            'energy': elogmean.TeV(),
            'energy_low': (elogmean - emin).TeV(),
            'energy_high': (emax - elogmean).TeV(),
            'flux': 0.0,
            'flux_err': 0.0,
            'TS': 0.0,
            'ulimit': 0.0,
            'Npred': 0.0
        }

        # Write header for fitting
        self._log_header3(gammalib.EXPLICIT, 'Performing fit in energy bin')

        # Setup maximum likelihood fit
        like = ctools.ctlike(obs)
        like['edisp'] = self['edisp'].boolean()
        like['nthreads'] = 1  # Avoids OpenMP conflict

        # If chatter level is verbose and debugging is requested then
        # switch also on the debug model in ctlike
        if self._logVerbose() and self._logDebug():
            like['debug'] = True

        # Perform maximum likelihood fit
        like.run()

        # Write model results for explicit chatter level
        self._log_string(gammalib.EXPLICIT, str(like.obs().models()))

        # Continue only if log-likelihood is non-zero
        if like.obs().logL() != 0.0:

            # Get results
            fitted_models = like.obs().models()
            source = fitted_models[self['srcname'].string()]

            # Extract Test Statistic value
            if self['calc_ts'].boolean():
                result['TS'] = source.ts()

            # Compute Npred value (only works for unbinned analysis)
            if not self._binned_mode and not self._onoff_mode:
                for observation in like.obs():
                    result['Npred'] += observation.npred(source)

            # Compute upper flux limit
            ulimit_value = -1.0
            if self['calc_ulim'].boolean():

                # Logging information
                self._log_header3(gammalib.EXPLICIT,
                                  'Computing upper limit for energy bin')

                # Create upper limit object
                ulimit = ctools.ctulimit(like.obs())
                ulimit['srcname'] = self['srcname'].string()
                ulimit['eref'] = elogmean.TeV()

                # If chatter level is verbose and debugging is requested
                # then switch also on the debug model in ctulimit
                if self._logVerbose() and self._logDebug():
                    ulimit['debug'] = True

                # Try to run upper limit and catch exceptions
                try:
                    ulimit.run()
                    ulimit_value = ulimit.diff_ulimit()
                except:
                    self._log_string(gammalib.EXPLICIT, 'Upper limit '
                                     'calculation failed.')
                    ulimit_value = -1.0

                # Compute upper limit
                if ulimit_value > 0.0:
                    result['ulimit'] = ulimit_value * elogmean.MeV() * \
                                       elogmean.MeV() * gammalib.MeV2erg

            # Compute differential flux and flux error
            fitted_flux = source.spectral().eval(elogmean)
            parvalue = source.spectral()[0].value()
            if parvalue != 0.0:
                rel_error = source.spectral()[0].error() / parvalue
                e_flux = fitted_flux * rel_error
            else:
                e_flux = 0.0

            # If the source model is a cube then multiply-in the cube
            # spectrum
            if source.spatial().classname() == 'GModelSpatialDiffuseCube':
                dir = gammalib.GSkyDir()
                source.spatial().set_mc_cone(dir, 180.0)
                norm = source.spatial().spectrum().eval(elogmean)
                fitted_flux *= norm
                e_flux *= norm

            # Convert differential flux and flux error to nuFnu
            elogmean2 = elogmean.MeV() * elogmean.MeV()
            result['flux'] = fitted_flux * elogmean2 * gammalib.MeV2erg
            result['flux_err'] = e_flux * elogmean2 * gammalib.MeV2erg

            # Log information
            value = '%e +/- %e' % (result['flux'], result['flux_err'])
            if self['calc_ulim'].boolean() and result['ulimit'] > 0.0:
                value += ' [< %e]' % (result['ulimit'])
            value += ' erg/cm2/s'
            if self['calc_ts'].boolean() and result['TS'] > 0.0:
                value += ' (TS = %.3f)' % (result['TS'])
            self._log_value(gammalib.TERSE, 'Bin ' + str(i + 1), value)

        # ... otherwise if logL is zero then signal that bin is
        # skipped
        else:
            value = 'Likelihood is zero. Bin is skipped.'
            self._log_value(gammalib.TERSE, 'Bin ' + str(i + 1), value)

        # Return result
        return result
Example #7
0
    def _test_python(self):
        """
        Test ctulimit from Python
        """
        # Allocate ctulimit
        ulimit = ctools.ctulimit()

        # Check that empty ctulimit tool holds zero upper limits
        self.test_value(ulimit.diff_ulimit(), 0.0, 1.0e-21,
                        'Check differential upper limit')
        self.test_value(ulimit.flux_ulimit(), 0.0, 1.0e-16,
                        'Check upper limit on photon flux')
        self.test_value(ulimit.eflux_ulimit(), 0.0, 1.0e-16,
                        'Check upper limit on energy flux')

        # Check that saving does not nothing
        ulimit['logfile'] = 'ctulimit_py0.log'
        ulimit.logFileOpen()
        ulimit.save()

        # Check that clearing does not lead to an exception or segfault
        ulimit.clear()

        # Now set ctulimit parameters
        ulimit['inobs']   = self._events
        ulimit['inmodel'] = self._model
        ulimit['srcname'] = 'Crab'
        ulimit['caldb']   = self._caldb
        ulimit['irf']     = self._irf
        ulimit['tol']     = 0.1
        ulimit['logfile'] = 'ctulimit_py1.log'
        ulimit['chatter'] = 2

        # Run ctulimit tool
        ulimit.logFileOpen()   # Make sure we get a log file
        ulimit.run()
        ulimit.save()

        # Set reference value
        ref_diff  = 2.75359655874408e-17
        ref_flux  = 1.66942609234064e-11
        ref_eflux = 6.4588860064421e-11

        # Check results
        self.test_value(ulimit.diff_ulimit(), ref_diff, 1.0e-21,
                        'Check differential upper limit')
        self.test_value(ulimit.flux_ulimit(), ref_flux, 1.0e-16,
                        'Check upper limit on photon flux')
        self.test_value(ulimit.eflux_ulimit(), ref_eflux, 1.0e-16,
                        'Check upper limit on energy flux')

        # Check obs() method
        self.test_value(ulimit.obs().size(), 1,
                        'Check number of observations in container')

        # Check opt() method
        self.test_value(ulimit.opt().status(), 0, 'Check optimizer status')

        # Copy ctulimit tool
        cpy_ulimit = ulimit.copy()

        # Check results of copy
        self.test_value(cpy_ulimit.diff_ulimit(), ref_diff, 1.0e-21,
                        'Check differential upper limit')
        self.test_value(cpy_ulimit.flux_ulimit(), ref_flux, 1.0e-16,
                        'Check upper limit on photon flux')
        self.test_value(cpy_ulimit.eflux_ulimit(), ref_eflux, 1.0e-16,
                        'Check upper limit on energy flux')

        # Check results
        self.test_value(cpy_ulimit.diff_ulimit(), ref_diff, 1.0e-21,
                        'Check differential upper limit')
        self.test_value(cpy_ulimit.flux_ulimit(), ref_flux, 1.0e-16,
                        'Check upper limit on photon flux')
        self.test_value(cpy_ulimit.eflux_ulimit(), ref_eflux, 1.0e-16,
                        'Check upper limit on energy flux')

        # Now clear copy of ctulimit tool
        cpy_ulimit.clear()

        # Check that empty ctulimit tool holds zero upper limits
        self.test_value(cpy_ulimit.diff_ulimit(), 0.0, 1.0e-21,
                        'Check differential upper limit')
        self.test_value(cpy_ulimit.flux_ulimit(), 0.0, 1.0e-16,
                        'Check upper limit on photon flux')
        self.test_value(cpy_ulimit.eflux_ulimit(), 0.0, 1.0e-16,
                        'Check upper limit on energy flux')

        # Run ctlike to get an initial log-likelihood solution
        like = ctools.ctlike()
        like['inobs']    = self._events
        like['inmodel']  = self._model
        like['caldb']    = self._caldb
        like['irf']      = self._irf
        like.run()

        # Now set ctulimit tool using the observation container from the
        # previous run. This should avoid the necessity to recompute the
        # maximum likelihood
        ulimit = ctools.ctulimit(like.obs())
        ulimit['srcname'] = 'Crab'
        ulimit['tol']     = 0.1
        ulimit['logfile'] = 'ctulimit_py2.log'
        ulimit['chatter'] = 3

        # Execute ctulimit tool
        ulimit.logFileOpen()  # Needed to get a new log file
        ulimit.execute()

        # Check results
        self.test_value(ulimit.diff_ulimit(), ref_diff, 1.0e-21,
                        'Check differential upper limit')
        self.test_value(ulimit.flux_ulimit(), ref_flux, 1.0e-16,
                        'Check upper limit on photon flux')
        self.test_value(ulimit.eflux_ulimit(), ref_eflux, 1.0e-16,
                        'Check upper limit on energy flux')

        # Test invalid model name
        ulimit['srcname'] = 'Weihnachtsstern'
        ulimit['logfile'] = 'ctulimit_py3.log'
        ulimit.logFileOpen()
        self.test_try('Test invalid model name')
        try:
            ulimit.execute()
            self.test_try_failure('Exception not thrown')
        except ValueError:
            self.test_try_success()

        # Test specification of background model
        ulimit['srcname'] = 'Background'
        ulimit['logfile'] = 'ctulimit_py4.log'
        ulimit.logFileOpen()
        self.test_try('Test invalid model name')
        try:
            ulimit.execute()
            self.test_try_failure('Exception not thrown')
        except ValueError:
            self.test_try_success()

        # Test run with too few iterations
        ulimit['srcname']  = 'Crab'
        ulimit['max_iter'] = 1
        ulimit['logfile']  = 'ctulimit_py5.log'
        ulimit.logFileOpen()
        self.test_try('Test ctulimit with too few iterations')
        try:
            ulimit.execute()
            self.test_try_failure('Exception not thrown')
        except ValueError:
            self.test_try_success()

        # Return
        return
Example #8
0
                        'logs/enhist.png',
                        ebins=60,
                        title='Energy Histogram - %d Events' % nevents)

printstat('pointing elevation minutes')
runs = veripy.obs2runs(obs)
db.plot_elev_bins(runs,
                  'logs/pelev.png',
                  elmin=elmin - 0.5,
                  elmax=elmax + 0.5,
                  nelbins=80)

printstat('starting ctulimit')
eref = gammalib.GEnergy(10, 'TeV')
t3 = time.time()
ul = ctools.ctulimit(obs)
ul['srcname'] = dmhalo
ul['edisp'] = True
ul['confidence'] = 0.68
ul['eref'] = eref.TeV()  # reference energy for differential limit
ul['emin'] = emin
ul['emax'] = emax
ul['tol'] = 1e-5
ul['max_iter'] = 50
ul['sigma_min'] = 0.0
ul['sigma_max'] = 10.0
ul['debug'] = True
ul['chatter'] = 4
ul['logfile'] = 'logs/ctulimit.log'
ul.logFileOpen()
ul.run()
Example #9
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()
        
        #  Write input parameters into logger
        if self.logTerse():
            self.log_parameters()
            self.log("\n")
        
        # Write observation into logger
        if self.logTerse():
            self.log("\n")
            self.log.header1("Observation")
            self.log(str(self.obs))
            self.log("\n")

        # Write header
        if self.logTerse():
            self.log("\n")
            self.log.header1("Adjust model parameters")

        # Adjust model parameters dependent on input user parameters
        for model in self.obs.models():
            
            # Set TS flag for all models to false.
            # Source of interest will be set to true later
            model.tscalc(False)
            
            # Log model name
            if self.logExplicit():
                self.log.header3(model.name())
            
            # Deal with the source of interest    
            if model.name() == self.m_srcname:
                if self.m_calc_ts:
                    model.tscalc(True)
                
            elif self.m_fix_bkg and not model.classname() == "GModelSky":
                for par in model:
                    if par.is_free() and self.logExplicit():
                        self.log(" Fixing \""+par.name()+"\"\n")
                    par.fix()
        
            elif self.m_fix_srcs and model.classname() == "GModelSky":
                for par in model:
                    if par.is_free() and self.logExplicit():
                        self.log(" Fixing \""+par.name()+"\"\n")
                    par.fix()
        
        # Write header
        if self.logTerse():
            self.log("\n")
            self.log.header1("Generate lightcurve")      
        
        # Initialise FITS Table with extension "LIGHTCURVE"
        table = gammalib.GFitsBinTable(self.m_tbins.size())
        table.extname("LIGHTCURVE")
        
        # Add Header for compatibility with gammalib.GMWLSpectrum
        table.card("INSTRUME", "CTA", "Name of Instrument")
        table.card("TELESCOP", "CTA", "Name of Telescope")
             
        # Create FITS table columns        
        MJD = gammalib.GFitsTableDoubleCol("MJD", self.m_tbins.size())
        MJD.unit("days")
        e_MJD = gammalib.GFitsTableDoubleCol("e_MJD", self.m_tbins.size())
        e_MJD.unit("days")
        
        # Create a FITS column for every free parameter
        columns = []
        for par in self.obs.models()[self.m_srcname]:
            if par.is_free():
                col = gammalib.GFitsTableDoubleCol(par.name(), self.m_tbins.size())
                col.unit(par.unit())
                columns.append(col)
                e_col = gammalib.GFitsTableDoubleCol("e_"+par.name(), self.m_tbins.size())
                e_col.unit(par.unit())
                columns.append(e_col)
        
        # Create TS and upper limit columns
        TSvalues    = gammalib.GFitsTableDoubleCol("TS", self.m_tbins.size())
        ulim_values = gammalib.GFitsTableDoubleCol("UpperLimit", self.m_tbins.size())
        ulim_values.unit("ph/cm2/s")

        # Loop over energy bins
        for i in range(self.m_tbins.size()):

            # Log information
            if self.logTerse():
                self.log("\n")
                self.log.header2("Time bin "+str(i))

            # Get time boundaries
            tmin = self.m_tbins.tstart(i)
            tmax = self.m_tbins.tstop(i)
            
            # Compute time bin center and time width
            tmean   = (tmin + tmax)
            tmean  *= 0.5
            twidth  = (tmax - tmin)
            twidth *= 0.5 

            # Store time as MJD
            MJD[i] = tmean.mjd()
            e_MJD[i] = twidth.days()
            
            # Log information
            if self.logExplicit():
                self.log.header3("Selecting events")
                     
            # Select events
            select = ctools.ctselect(self.obs)
            select["emin"].real(self.m_emin)    
            select["emax"].real(self.m_emax) 
            select["tmin"].real(tmin.convert(select.time_reference()))
            select["tmax"].real(tmax.convert(select.time_reference()))
            select["rad"].value("UNDEFINED")
            select["ra"].value("UNDEFINED")
            select["dec"].value("UNDEFINED")
            select.run()  

            # Retrieve observation
            obs = select.obs()
             
            # Binned analysis
            if self.m_binned:

                # Header
                if self.logTerse():
                    self.log.header3("Binning events")
                
                # Bin events
                bin = ctools.ctbin(select.obs())
                bin["usepnt"].boolean(False)
                bin["ebinalg"].string("LOG")
                bin["xref"].real(self.m_xref)
                bin["yref"].real(self.m_yref)
                bin["binsz"].real(self.m_binsz)
                bin["nxpix"].integer(self.m_nxpix)
                bin["nypix"].integer(self.m_nypix)
                bin["enumbins"].integer(self.m_ebins)
                bin["emin"].real(self.m_emin)
                bin["emax"].real(self.m_emax)        
                bin["coordsys"].string(self.m_coordsys)
                bin["proj"].string(self.m_proj)            
                bin.run()
                
                # Header
                if self.logTerse():
                    self.log.header3("Creating exposure cube")
                
                # Create exposure cube
                expcube = ctools.ctexpcube(select.obs())
                expcube["incube"].filename("NONE")
                expcube["usepnt"].boolean(False)
                expcube["ebinalg"].string("LOG")
                expcube["xref"].real(self.m_xref)
                expcube["yref"].real(self.m_yref)
                expcube["binsz"].real(self.m_binsz)
                expcube["nxpix"].integer(self.m_nxpix)
                expcube["nypix"].integer(self.m_nypix)
                expcube["enumbins"].integer(self.m_ebins)
                expcube["emin"].real(self.m_emin)
                expcube["emax"].real(self.m_emax)   
                expcube["coordsys"].string(self.m_coordsys)
                expcube["proj"].string(self.m_proj)               
                expcube.run()
                
                # Header
                if self.logTerse():
                    self.log.header3("Creating PSF cube")
                
                # Create psf cube
                psfcube = ctools.ctpsfcube(select.obs())
                psfcube["incube"].filename("NONE")
                psfcube["usepnt"].boolean(False)
                psfcube["ebinalg"].string("LOG")
                psfcube["xref"].real(self.m_xref)
                psfcube["yref"].real(self.m_yref)
                psfcube["binsz"].real(self.m_binsz)
                psfcube["nxpix"].integer(self.m_nxpix)
                psfcube["nypix"].integer(self.m_nypix)
                psfcube["enumbins"].integer(self.m_ebins)
                psfcube["emin"].real(self.m_emin)
                psfcube["emax"].real(self.m_emax)    
                psfcube["coordsys"].string(self.m_coordsys)
                psfcube["proj"].string(self.m_proj)               
                psfcube.run()
                
                # Header
                if self.logTerse():
                    self.log.header3("Creating background cube")
                
                # Create background cube
                bkgcube = ctools.ctbkgcube(select.obs())
                bkgcube["incube"].filename("NONE")
                bkgcube["usepnt"].boolean(False)
                bkgcube["ebinalg"].string("LOG")
                bkgcube["xref"].real(self.m_xref)
                bkgcube["yref"].real(self.m_yref)
                bkgcube["binsz"].real(self.m_binsz)
                bkgcube["nxpix"].integer(self.m_nxpix)
                bkgcube["nypix"].integer(self.m_nypix)
                bkgcube["enumbins"].integer(self.m_ebins)
                bkgcube["emin"].real(self.m_emin)
                bkgcube["emax"].real(self.m_emax)   
                bkgcube["coordsys"].string(self.m_coordsys)
                bkgcube["proj"].string(self.m_proj)                
                bkgcube.run()
                
                # Set new binned observation
                obs = bin.obs()
                
                # Set precomputed binned response
                obs[0].response(expcube.expcube(), psfcube.psfcube(), bkgcube.bkgcube())

                # Get new models
                models = bkgcube.models()
                
                # Fix background models if required
                if self.m_fix_bkg:
                    for model in models:
                        if not model.classname() == "GModelSky":
                            for par in model:
                                par.fix()
                                
                # Set new models to binned observation           
                obs.models(models)
                
            # Header
            if self.logTerse():
                self.log.header3("Performing fit")
                             
            # Likelihood
            like = ctools.ctlike(obs)
            like.run()
            
            # Skip bin if no event was present
            if like.obs().logL() == 0.0:
                
                # Log information
                if self.logTerse():
                    self.log("No event in this time bin. Bin is skipped\n")

                # Set all values to 0
                for col in columns:
                    col[i] = 0.0
                TSvalues[i]    = 0.0
                ulim_values[i] = 0.0
                continue
                         
            # Get results
            fitted_models = like.obs().models()
            source        = fitted_models[self.m_srcname]

            # Calculate Upper Limit            
            ulimit_value = -1.0
            if self.m_calc_ulimit:
                
                # Logging information
                if self.logTerse():
                    self.log.header3("Computing upper limit")
                  
                # Create upper limit object  
                ulimit = ctools.ctulimit(like.obs())
                ulimit["srcname"].string(self.m_srcname)
                ulimit["eref"].real(1.0)
                
                # Try to run upper limit and catch exceptions
                try:
                    ulimit.run()
                    ulimit_value = ulimit.flux_ulimit()
                except:
                    if self.logTerse():
                        self.log("Upper limit calculation failed\n")
                    ulimit_value = -1.0
            
            # Get TS value
            TS = -1.0
            if self.m_calc_ts:
                TS = source.ts() 
            
            # Set values for storage
            TSvalues[i] = TS
            
            # Set FITS column values
            for col in columns:
                if "e_" == col.name()[:2]:
                    col[i] = source.spectral()[col.name()[2:]].error()
                else:
                    col[i] = source.spectral()[col.name()].value()
            
            # Store upper limit value if available
            if ulimit_value > 0.0:
                ulim_values[i] = ulimit_value
         
            # Log information
            if self.logExplicit(): 
                self.log.header3("Results of bin "+str(i)+": MJD "+str(tmin.mjd())+"-"+str(tmax.mjd()))
                for col in columns:
                    if "e_" == col.name()[:2]:
                        continue
                    value = source.spectral()[col.name()].value()
                    error = source.spectral()[col.name()].error()
                    unit = source.spectral()[col.name()].unit()
                    self.log(" > "+col.name()+": "+str(value)+" +- "+str(error)+" "+unit+"\n")
                if self.m_calc_ts and TSvalues[i] > 0.0:
                    self.log(" > TS = "+str(TS)+" \n")
                if self.m_calc_ulimit and ulim_values[i] > 0.0:
                    self.log(" > UL = "+str(ulim_values[i])+" [ph/cm2/s]")
                self.log("\n")

        # Append filles columns to fits table    
        table.append(MJD)
        table.append(e_MJD)
        for col in columns:
            table.append(col)
        table.append(TSvalues)
        table.append(ulim_values)
        
        # Create the FITS file now
        self.fits = gammalib.GFits()
        self.fits.append(table)
            
        # Return
        return
Example #10
0
    def _compute_ulimit(self, obs):
        """
        Computes upper limit

        Parameters
        ----------
        obs : `~gammalib.GObservations`
            Observation container

        Returns
        -------
        ul_diff, ul_flux, ul_eflux : tuple of float
            Upper limits, -1.0 of not computed
        """
        # Initialise upper flux limit
        ul_diff = -1.0
        ul_flux = -1.0
        ul_eflux = -1.0

        # Perform computation only if requested
        if self['calc_ulim'].boolean():

            # Write header in logger
            self._log_header3(gammalib.EXPLICIT, 'Computing upper limit')

            # Create copy of observations
            cpy_obs = obs.copy()

            # Fix parameters of source of interest in copy of observations.
            # This assures that the original spectral parameters and position
            # are used in the upper limit search. The ctulimit tool makes sure
            # that the flux parameter is freed when needed.
            source = cpy_obs.models()[self._srcname]
            for par in source:
                if par.is_free():
                    par.fix()

            # Create instance of upper limit tool
            ulimit = ctools.ctulimit(cpy_obs)
            ulimit['srcname'] = self._srcname
            ulimit['eref'] = 1.0
            ulimit['emin'] = self['emin'].real()
            ulimit['emax'] = self['emax'].real()
            ulimit['sigma_min'] = 0.0
            ulimit['sigma_max'] = 3.0

            # Try to run upper limit tool and catch any exceptions
            try:
                ulimit.run()
                ul_diff = ulimit.diff_ulimit()
                ul_flux = ulimit.flux_ulimit()
                ul_eflux = ulimit.eflux_ulimit()
            except:
                self._log_string(gammalib.TERSE,
                                 'Upper limit calculation failed.')
                ul_diff = -1.0
                ul_flux = -1.0
                ul_eflux = -1.0

        # Return upper limit tuple
        return ul_diff, ul_flux, ul_eflux
Example #11
0
    def _fit_model(self):
        """
        Fit Model to DATA in the observation

        Return
        ------
        Result , dictionary with relevant fit results
        """

        #   Set reference energy for calculations
        eref = gammalib.GEnergy(self['dmass'].real() / 2.0, 'TeV')

        #   Get expected dmflux at reference energy
        #   for the source of interest
        srcmodel = self.obs().models()[self['srcname'].string()]
        srcspec = srcmodel.spectral()
        theoflux = srcspec.eval(eref)

        #   Header
        self._log_header1(gammalib.TERSE, 'Fitting DM Model')

        #   So, at this moment interesting results to save are:
        #       - Reference Energy
        #       - Differential flux obtained in the fit
        #       - Error
        #       - TS
        #       - Upper-limit on the differential flux
        #       - Reference value of sigmav
        #       - UL computed of sigmav
        #       - Scale factor computed to obtain the UL on sigmav
        #   This may be change when including Spectral class
        #   for DM annihilation
        result = {
            'energy': eref.TeV(),
            'flux': 0.0,
            'flux_err': 0.0,
            'TS': 0.0,
            'ulimit': 0.0,
            # 'sigma_ref' : self[ 'sigmav' ] ,
            # 'sigma_lim' : 0.0 ,
            'sc_factor': 0.0
        }

        #   Header for ctlike instance :)
        self._log_header3(gammalib.EXPLICIT, 'ctlike instance')

        #   Maximum likelihood fit via ctlike
        like = ctools.ctlike(self.obs())
        like['edisp'] = self['edisp'].boolean()
        like['nthreads'] = 1

        #   Chatter
        if self._logVerbose() and self._logDebug():

            like['debug'] = True

        like.run()

        #   Extract fit results
        model = like.obs().models()[self['srcname'].string()]
        spectrum = model.spectral()
        logL0 = like.obs().logL()

        #   Write models results
        self._log_string(gammalib.EXPLICIT, str(like.obs().models()))

        #   Continue only if logL0 is different from zero
        if logL0 != 0.0:

            #   Extract TS value
            result['TS'] = model.ts()

            #   Calculation of upper-limit via ctulimit
            ulimit_value = -1.0

            if self['calc_ulim'].boolean():

                #   Print to log
                self._log_header3(gammalib.EXPLICIT, 'Computing Upper Limit')

                #   Instance for ctulimit
                ulimit = ctools.ctulimit(like.obs())
                ulimit['srcname'] = self['srcname'].string()
                ulimit['eref'] = eref.TeV()

                #   Set chatter
                if self._logVerbose() and self._logDebug():

                    ulimit['debug'] = True

                #    Catching exceptions

                try:

                    ulimit.run()
                    ulimit_value = ulimit.diff_ulimit()

                except:

                    self._log_string(gammalib.EXPLICIT,
                                     'UL Calculation failed :(')
                    ulimit_value = -1.0

                #   Compute quantities related to ulimit
                if ulimit_value > 0.0:

                    result[ 'ulimit' ]    = ulimit_value * eref.MeV() * \
                                            eref.MeV() * gammalib.MeV2erg
                    result['sc_factor'] = ulimit_value / theoflux
                    # result[ 'sigma_lim' ] = ulimit_value / theoflux * \
                    #                         self[ 'sigmav' ]

                #   Get flux and error
                fitted_flux = spectrum.eval(eref)
                parvalue = spectrum[0].value()

                if parvalue != 0.0:

                    rel_error = spectrum[0].error() / parvalue
                    e_flux = fitted_flux * rel_error

                else:

                    e_flux = 0.0

                # If a cube, then compute corresponding weight
                if model.spatial().classname() == 'GModelSpatialDiffuseCube':

                    dir = gammalib.GSkyDir()
                    model.spatial().set_mc_cone(dir, 180)
                    norm = model.spatial().spectrum().eval(eref)
                    fitted_flux *= norm
                    e_flux *= norm

                #   Convert to nuFnu
                eref2 = eref.MeV() * eref.MeV()
                result['flux'] = fitted_flux * eref2 * gammalib.MeV2erg
                result['flux_err'] = e_flux * eref2 * gammalib.MeV2erg

                #   Logging
                value = '%e +/- %e' % (result['flux'], result['flux_err'])
                svmsg = ''

                if self['calc_ulim'].boolean() and result['ulimit'] > 0.0:

                    value += ' [< %e]' % (result['ulimit'])
                    svmsg += ' [%e]' % (result['sc_factor'])

                value += ' erg/cm**2/s'

                if self['calc_ts'].boolean() and result['TS'] > 0.0:

                    value += ' (TS = %.3f)' % (result['TS'])

                self._log_value(gammalib.TERSE, 'Flux', value)

                if len(svmsg) > 0:

                    self._log_value(gammalib.TERSE, 'ScaleFactor', svmsg)

        #   If logL0 == 0, then failed :(
        #   but, this does not raise any error
        else:

            value = 'Likelihood is zero. Something is weird. Check model'
            self._log_value(gammalib.TERSE, 'Warning: ', value)

        #   Return
        #   At this moment, only save for individual mass and channel
        #   Later, include loop to compute over several masses and channels
        return result
Example #12
0
    model["Prefactor"].scale(1)
    model["Prefactor"].fix()
    model["Index"].value(p[1])
    model["Index"].scale(-1)
    model["Index"].fix()
    model["PivotEnergy"].value(p[2])
    model["PivotEnergy"].scale(1)
    model["PivotEnergy"].fix()
    '''
    model = gammalib.GModelSky(spatial, spectral)
    model.name('DM')
    bkgmodel.append(model)

    bkgmodel.save("fitmodel.xml")

    ulimit = ctools.ctulimit()
    ulimit["inobs"] = cntcube
    ulimit["expcube"] = expcube
    ulimit["psfcube"] = psfcube
    ulimit["bkgcube"] = bkgcube
    ulimit["inmodel"] = "fitmodel.xml"
    ulimit["caldb"] = caldb_
    ulimit["irf"] = irf_
    ulimit["srcname"] = 'DM'
    ulimit["eref"] = eref
    ulimit["emin"] = emin
    ulimit["emax"] = emax
    ulimit["debug"] = True
    ulimit.execute()

    print >> f, mass, eref, ulimit.diff_ulimit(), ulimit.flux_ulimit(
Example #13
0
    def _fit_energy_bin(self, i ):
        """
        Fit data for one energy bin

        Parameters
        ----------
        i : int
            Energy bin index

        Returns
        -------
        result : dict
            Dictionary with fit results
        """
        # Write header for energy bin
        self._log_header2(gammalib.EXPLICIT, 'Energy bin ' + str(i + 1))

        # Get energy boundaries
        emin      = self._ebounds.emin(i)
        emax      = self._ebounds.emax(i)
        elogmean  = self._ebounds.elogmean(i)

        # Select observations for energy bin
        obs = self._select_obs(emin, emax)

        # Initialise dictionary
        result = {'energy':      elogmean.TeV(),
                  'energy_low':  (elogmean - emin).TeV(),
                  'energy_high': (emax - elogmean).TeV(),
                  'flux':        0.0,
                  'flux_err':    0.0,
                  'TS':          0.0,
                  'ulimit':      0.0,
                  'Npred':       0.0}
        # Write header for fitting
        self._log_header3(gammalib.EXPLICIT, 'Performing fit in energy bin')

        # Setup maximum likelihood fit
        like = ctools.ctlike(obs)
        like['edisp']    = self['edisp'].boolean()
        like['nthreads'] = 1  # Avoids OpenMP conflict

        # If chatter level is verbose and debugging is requested then
        # switch also on the debug model in ctlike
        if self._logVerbose() and self._logDebug():
            like['debug'] = True

        # Perform maximum likelihood fit
        like.run()

        # plotfile = self[ 'srcname' ].string() + 'AfterLike{:d}.png'.format( i + 1 )
        # ctamap( obs , 'CEL' , self[ 'srcname' ].string() , plotfile )

        # Write model results for explicit chatter level
        self._log_string(gammalib.EXPLICIT, str(like.obs().models()))

        obs2 = obs.copy()
        obs2.models().remove( self[ 'srcname' ].string() )

        likeNoSrc = ctools.ctlike( obs2 )
        likeNoSrc[ 'edisp' ] = self[ 'edisp' ].boolean()
        likeNoSrc[ 'nthreads' ] = 1
        likeNoSrc.run()

        logLNoSrc = likeNoSrc.obs().logL()
        # print( 'The LogL(No-Src) is {:.7e}'.format( logLNoSrc ) )

        binNorm    = obs.models()[ self[ 'srcname' ].string() ].spectral()[ 'Prefactor' ].value()
        scaleNorm  = obs.models()[ self[ 'srcname' ].string() ].spectral()[ 'Prefactor' ].scale()
        binNorm    = binNorm / scaleNorm
        logbinNorm = np.log10( binNorm )

        lognorms = np.logspace( logbinNorm - 5 , logbinNorm + 5 , 10000 )

        # Continue only if log-likelihood is non-zero
        logL0 = like.obs().logL() 
        # print( 'The LogL(Src) is {:.7e}'.format( logL0 ) )
        thisTS = []
        NormsScan = []

        if logL0 != 0.0:

            # Get results
            fitted_models = like.obs().models()
            source        = fitted_models[self['srcname'].string()]
            # print( source )

            # Extract Test Statistic value
            if self['calc_ts'].boolean():
                result['TS'] = source.ts()

                for norm in lognorms :
                    thisobs = like.obs().copy()
                    pars = thisobs.models()[ self[ 'srcname' ].string() ].spectral()[ 'Prefactor' ]
                    pars.factor_min( obs.models()[ self[ 'srcname' ].string() ].spectral()[ 'Prefactor' ].min() )
                    pars.factor_max( 1.0e+12 )
                    pars.factor_value( norm )
                    pars.fix()

                    this_like            = ctools.ctlike( thisobs )
                    this_like[ 'edisp' ] = self[ 'edisp' ].boolean()
                    this_like.run()

                    thismodel = this_like.obs().models()[ self[ 'srcname' ].string() ]
                    thislogL  = this_like.obs().logL()
                    thisnorm  = thismodel.spectral().eval( elogmean )
                    # print( thismodel.ts() )
                    # print( 'Norm {:.7e} with LogL {:.7e}'.format( thisnorm , thislogL ) )

                    ts = - ( source.ts() - thismodel.ts() )
                    if abs( ts ) <= 4.1 :
                        thisTS.append( ts )
                        NormsScan.append( thisnorm * elogmean.MeV() * elogmean.MeV() * gammalib.MeV2erg )

                data = np.array( ( NormsScan , thisTS ) ).transpose()
                filename = self[ 'outfile' ].filename().path() + self[ 'outfile' ].filename().file()
                filename = filename[ : -5 ] + 'ScanDataForBin{:d}.txt'.format( i + 1 )
                np.savetxt( filename , data , fmt='%.5e\t%.5e' , header='Normalization\tTS' )


            # Compute Npred value (only works for unbinned analysis)
            if not self._binned_mode and not self._onoff_mode:
                for observation in like.obs():
                    result['Npred'] += observation.npred(source)

            # Compute upper flux limit
            ulimit_value = -1.0
            if self['calc_ulim'].boolean():

                # Logging information
                self._log_header3(gammalib.EXPLICIT,
                                  'Computing upper limit for energy bin')

                # Create upper limit object  
                ulimit = ctools.ctulimit(like.obs())
                ulimit['srcname'] = self['srcname'].string()
                ulimit['eref']    = elogmean.TeV()

                # If chatter level is verbose and debugging is requested
                # then switch also on the debug model in ctulimit
                if self._logVerbose() and self._logDebug():
                    ulimit['debug'] = True

                # Try to run upper limit and catch exceptions
                try:
                    ulimit.run()
                    ulimit_value = ulimit.diff_ulimit()
                except:
                    self._log_string(gammalib.EXPLICIT, 'Upper limit '
                                     'calculation failed.')
                    ulimit_value = -1.0

                # Compute upper limit
                if ulimit_value > 0.0:
                    result['ulimit'] = ulimit_value * elogmean.MeV() * \
                                       elogmean.MeV() * gammalib.MeV2erg

            # Compute differential flux and flux error
            fitted_flux = source.spectral().eval(elogmean)
            parvalue    = source.spectral()[0].value()
            if parvalue != 0.0:
                rel_error = source.spectral()[0].error() / parvalue
                e_flux    = fitted_flux * rel_error
            else:
                e_flux = 0.0

            # If the source model is a cube then multiply-in the cube
            # spectrum
            if source.spatial().classname() == 'GModelSpatialDiffuseCube':
                dir          = gammalib.GSkyDir()
                source.spatial().set_mc_cone(dir, 180.0)
                norm         = source.spatial().spectrum().eval(elogmean)
                fitted_flux *= norm
                e_flux      *= norm

            # Convert differential flux and flux error to nuFnu
            elogmean2          = elogmean.MeV() * elogmean.MeV()
            result['flux']     = fitted_flux * elogmean2 * gammalib.MeV2erg
            result['flux_err'] = e_flux      * elogmean2 * gammalib.MeV2erg

            # Log information
            value = '%e +/- %e' % (result['flux'], result['flux_err'])
            if self['calc_ulim'].boolean() and result['ulimit'] > 0.0:
                value += ' [< %e]' % (result['ulimit'])
            value += ' erg/cm2/s'
            if self['calc_ts'].boolean() and result['TS'] > 0.0:
                value += ' (TS = %.3f)' % (result['TS'])
            self._log_value(gammalib.TERSE, 'Bin '+str(i+1), value)

        # ... otherwise if logL is zero then signal that bin is
        # skipped
        else:
            value = 'Likelihood is zero. Bin is skipped.'
            self._log_value(gammalib.TERSE, 'Bin '+str(i+1), value)

        # Return result
        return result
Example #14
0
    def _fit_energy_bin(self, i):
        """
        Fit data for one energy bin

        Parameters
        ----------
        i : int
            Energy bin index

        Returns
        -------
        result : dict
            Dictionary with fit results
        """
        # Get energy boundaries
        emin      = self._ebounds.emin(i)
        emax      = self._ebounds.emax(i)
        elogmean  = self._ebounds.elogmean(i)

        # Select observations for energy bin
        obs = self._select_obs(emin, emax)

        # Initialise dictionary
        result = {'energy':      elogmean.TeV(),
                  'energy_low':  (elogmean - emin).TeV(),
                  'energy_high': (emax - elogmean).TeV(),
                  'flux':        0.0,
                  'flux_err':    0.0,
                  'TS':          0.0,
                  'ulimit':      0.0,
                  'Npred':       0.0}

        # Write header for fitting
        self._log_header3(gammalib.EXPLICIT, 'Performing fit')

        # Perform maximum likelihood fit
        like          = ctools.ctlike(obs)
        like['edisp'] = self['edisp'].boolean()
        like.run()

        # Continue only if log-likelihood is non-zero
        if like.obs().logL() != 0.0:

            # Get results
            fitted_models = like.obs().models()
            source        = fitted_models[self['srcname'].string()]

            # Extract Test Statistic value
            if self['calc_ts'].boolean():
                result['TS'] = source.ts()

            # Compute Npred value (only works for unbinned analysis)
            if not self._binned_mode and not self._onoff_mode:
                for observation in like.obs():
                    result['Npred'] += observation.npred(source)

            # Compute upper flux limit
            ulimit_value = -1.0
            if self['calc_ulim'].boolean():

                # Logging information
                self._log_header3(gammalib.EXPLICIT, 'Computing upper limit')

                # Create upper limit object  
                ulimit = ctools.ctulimit(like.obs())
                ulimit['srcname'] = self['srcname'].string()
                ulimit['eref']    = elogmean.TeV()

                # Try to run upper limit and catch exceptions
                try:
                    ulimit.run()
                    ulimit_value = ulimit.diff_ulimit()
                except:
                    self._log_string(gammalib.EXPLICIT, 'Upper limit '
                                     'calculation failed.')
                    ulimit_value = -1.0

                # Compute upper limit
                if ulimit_value > 0.0:
                    result['ulimit'] = ulimit_value * elogmean.MeV() * \
                                       elogmean.MeV() * gammalib.MeV2erg

            # Compute differential flux and flux error
            fitted_flux = source.spectral().eval(elogmean)
            parvalue    = source.spectral()[0].value()
            if parvalue != 0.0:
                rel_error = source.spectral()[0].error() / parvalue
                e_flux    = fitted_flux * rel_error
            else:
                e_flux = 0.0

            # Convert differential flux and flux error to nuFnu
            elogmean2          = elogmean.MeV() * elogmean.MeV()
            result['flux']     = fitted_flux * elogmean2 * gammalib.MeV2erg
            result['flux_err'] = e_flux      * elogmean2 * gammalib.MeV2erg

            # Log information
            value = '%e +/- %e' % (result['flux'], result['flux_err'])
            if self['calc_ulim'].boolean() and result['ulimit'] > 0.0:
                value += ' [< %e]' % (result['ulimit'])
            value += ' erg/cm2/s'
            if self['calc_ts'].boolean() and result['TS'] > 0.0:
                value += ' (TS = %.3f)' % (result['TS'])
            self._log_value(gammalib.TERSE, 'Bin '+str(i+1), value)

        # ... otherwise if logL is zero then signal that bin is
        # skipped
        else:
            value = 'No event in this bin. Likelihood is zero. Bin is skipped.'
            self._log_value(gammalib.TERSE, 'Bin '+str(i+1), value)

        # Return result
        return result
Example #15
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()

        #  Write input parameters into logger
        if self.logTerse():
            self.log_parameters()
            self.log("\n")

        # Write spectral binning into header
        if self.logTerse():
            self.log("\n")
            self.log.header1("Spectral binning")
            if self.m_binned_mode:
                cube_ebounds = self.obs[0].events().ebounds()
                self.log.parformat("Counts cube energy range")
                self.log(str(cube_ebounds.emin()))
                self.log(" - ")
                self.log(str(cube_ebounds.emax()))
                self.log("\n")
            for i in range(self.m_ebounds.size()):
                self.log.parformat("Bin "+str(i+1))
                self.log(str(self.m_ebounds.emin(i)))
                self.log(" - ")
                self.log(str(self.m_ebounds.emax(i)))
                self.log("\n")

        # Write observation into logger
        if self.logTerse():
            self.log("\n")
            self.log.header1("Observation")
            self.log(str(self.obs))
            self.log("\n")

        # Write header
        if self.logTerse():
            self.log("\n")
            self.log.header1("Adjust model parameters")

        # Adjust model parameters dependent on input user parameters
        for model in self.obs.models():

            # Set TS flag for all models to false.
            # Source of interest will be set to true later
            model.tscalc(False)

            # Log model name
            if self.logExplicit():
                self.log.header3(model.name())

            # Deal with the source of interest    
            if model.name() == self.m_srcname:
                for par in model:
                    if par.is_free() and self.logExplicit():
                        self.log(" Fixing \""+par.name()+"\"\n")
                    par.fix()
                normpar = model.spectral()[0]
                if normpar.is_fixed() and self.logExplicit():
                    self.log(" Freeing \""+normpar.name()+"\"\n")
                normpar.free()
                if self.m_calc_ts:
                    model.tscalc(True)

            elif self.m_fix_bkg and not model.classname() == "GModelSky":
                for par in model:
                    if par.is_free() and self.logExplicit():
                        self.log(" Fixing \""+par.name()+"\"\n")
                    par.fix()

            elif self.m_fix_srcs and model.classname() == "GModelSky":
                for par in model:
                    if par.is_free() and self.logExplicit():
                        self.log(" Fixing \""+par.name()+"\"\n")
                    par.fix()

        # Write header
        if self.logTerse():
            self.log("\n")
            self.log.header1("Generate spectrum")  
            self.log(str(self.m_ebounds))    

        # Initialise FITS Table with extension "SPECTRUM"
        table = gammalib.GFitsBinTable(self.m_ebounds.size())
        table.extname("SPECTRUM")

        # Add Header for compatibility with gammalib.GMWLSpectrum
        table.card("INSTRUME", "CTA", "Name of Instrument")
        table.card("TELESCOP", "CTA", "Name of Telescope")

        # Create FITS table columns
        energy       = gammalib.GFitsTableDoubleCol("Energy", self.m_ebounds.size())
        energy_low   = gammalib.GFitsTableDoubleCol("ed_Energy", self.m_ebounds.size())
        energy_high  = gammalib.GFitsTableDoubleCol("eu_Energy", self.m_ebounds.size())
        flux         = gammalib.GFitsTableDoubleCol("Flux", self.m_ebounds.size())
        flux_err     = gammalib.GFitsTableDoubleCol("e_Flux", self.m_ebounds.size())
        TSvalues     = gammalib.GFitsTableDoubleCol("TS", self.m_ebounds.size())
        ulim_values  = gammalib.GFitsTableDoubleCol("UpperLimit", self.m_ebounds.size())
        Npred_values = gammalib.GFitsTableDoubleCol("Npred", self.m_ebounds.size())
        energy.unit("TeV")
        energy_low.unit("TeV")
        energy_high.unit("TeV")
        flux.unit("erg/cm2/s")
        flux_err.unit("erg/cm2/s")
        ulim_values.unit("erg/cm2/s")

        # Loop over energy bins
        for i in range(self.m_ebounds.size()):

            # Log information
            if self.logExplicit():
                self.log("\n")
                self.log.header2("Energy bin "+str(i+1))

            # Get energy boundaries
            emin      = self.m_ebounds.emin(i)
            emax      = self.m_ebounds.emax(i)
            elogmean  = self.m_ebounds.elogmean(i)
            elogmean2 = elogmean.MeV() * elogmean.MeV()    

            # Store energy as TeV
            energy[i] = elogmean.TeV()

            # Store energy errors
            energy_low[i]  = (elogmean - emin).TeV()
            energy_high[i] = (emax - elogmean).TeV()

            # use ctselect for unbinned analysis
            if not self.m_binned_mode:
                
                # Log information
                if self.logExplicit():
                    self.log.header3("Selecting events")
    
                # Select events
                select = ctools.ctselect(self.obs)
                select["emin"] = emin.TeV()    
                select["emax"] = emax.TeV() 
                select["tmin"] = "UNDEFINED"
                select["tmax"] = "UNDEFINED"
                select["rad"]  = "UNDEFINED"
                select["ra"]   = "UNDEFINED"
                select["dec"]  = "UNDEFINED"
                select.run()  
    
                # Retrieve observation
                obs = select.obs()

            # use ctcubemask for binned analysis
            else:

                # Header
                if self.logExplicit():
                    self.log.header3("Filtering cube")

                # Select layers
                cubemask            = ctools.ctcubemask(self.obs)
                cubemask["regfile"] = "NONE"
                cubemask["ra"]      = "UNDEFINED"
                cubemask["dec"]     = "UNDEFINED"
                cubemask["rad"]     = "UNDEFINED"
                cubemask["emin"]    = emin.TeV() 
                cubemask["emax"]    = emax.TeV()
                cubemask.run() 
                
                # Set new binned observation
                obs = cubemask.obs()

            # Header
            if self.logExplicit():
                self.log.header3("Performing fit")

            # Likelihood
            like          = ctools.ctlike(obs)
            like["edisp"] = self.m_edisp
            like.run()

            # Skip bin if no event was present
            if like.obs().logL() == 0.0:

                # Log information
                if self.logExplicit():
                    self.log("No event in this bin. ")
                    self.log("Likelihood is zero. ")
                    self.log("Bin is skipped.")

                # Set all values to 0
                flux[i]         = 0.0
                flux_err[i]     = 0.0
                TSvalues[i]     = 0.0
                ulim_values[i]  = 0.0
                Npred_values[i] = 0.0
                continue

            # Get results
            fitted_models = like.obs().models()
            source        = fitted_models[self.m_srcname]

            # Calculate Upper Limit            
            ulimit_value = -1.0
            if self.m_calc_ulimit:

                # Logging information
                if self.logExplicit():
                    self.log.header3("Computing upper limit")

                # Create upper limit object  
                ulimit = ctools.ctulimit(like.obs())
                ulimit["srcname"] = self.m_srcname
                ulimit["eref"]    = elogmean.TeV()

                # Try to run upper limit and catch exceptions
                try:
                    ulimit.run()
                    ulimit_value = ulimit.diff_ulimit()
                except:
                    if self.logExplicit():
                        self.log("Upper limit calculation failed.")
                    ulimit_value = -1.0

            # Get TS value
            TS = -1.0
            if self.m_calc_ts:
                TS = source.ts() 

            # Compute Npred value (only works for unbinned analysis)
            Npred = 0.0
            if not self.m_binned_mode:
                for observation in like.obs():
                    Npred += observation.npred(source)  

            # Get differential flux    
            fitted_flux = source.spectral().eval(elogmean,gammalib.GTime())

            # Compute flux error
            parvalue  = source.spectral()[0].value()
            rel_error = source.spectral()[0].error() / parvalue        
            e_flux    = fitted_flux * rel_error

            # Set values for storage
            TSvalues[i] = TS

            # Set npred values 
            Npred_values[i] = Npred

            # Convert fluxes to nuFnu
            flux[i]     = fitted_flux * elogmean2 * gammalib.MeV2erg
            flux_err[i] = e_flux      * elogmean2 * gammalib.MeV2erg
            if ulimit_value > 0.0:
                ulim_values[i] = ulimit_value * elogmean2 * gammalib.MeV2erg

            # Log information
            if self.logTerse(): 
                self.log("\n")
                self.log.parformat("Bin "+str(i+1))
                self.log(str(flux[i]))
                self.log(" +/- ")
                self.log(str(flux_err[i]))
                if self.m_calc_ulimit and ulim_values[i] > 0.0:
                    self.log(" [< "+str(ulim_values[i])+"]")
                self.log(" erg/cm2/s")
                if self.m_calc_ts and TSvalues[i] > 0.0:
                    self.log(" (TS = "+str(TS)+")")

        # Append filled columns to fits table    
        table.append(energy)
        table.append(energy_low)
        table.append(energy_high)
        table.append(flux)
        table.append(flux_err)
        table.append(TSvalues)
        table.append(ulim_values)
        table.append(Npred_values)

        # Create the FITS file now
        self.fits = gammalib.GFits()
        self.fits.append(table)

        # Return
        return
Example #16
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()

        # Write spectral binning into header
        if self._logTerse():
            self._log("\n")
            self._log.header1("Spectral binning")
            if self._binned_mode:
                cube_ebounds = self._obs[0].events().ebounds()
                self._log.parformat("Counts cube energy range")
                self._log(str(cube_ebounds.emin()))
                self._log(" - ")
                self._log(str(cube_ebounds.emax()))
                self._log("\n")
            for i in range(self._ebounds.size()):
                self._log.parformat("Bin " + str(i + 1))
                self._log(str(self._ebounds.emin(i)))
                self._log(" - ")
                self._log(str(self._ebounds.emax(i)))
                self._log("\n")

        # Write observation into logger
        if self._logTerse():
            self._log("\n")
            self._log.header1("Observation")
            self._log(str(self._obs))
            self._log("\n")

        # Write header
        if self._logTerse():
            self._log("\n")
            self._log.header1("Adjust model parameters")

        # Adjust model parameters dependent on input user parameters
        for model in self._obs.models():

            # Set TS flag for all models to false.
            # Source of interest will be set to true later
            model.tscalc(False)

            # Log model name
            if self._logExplicit():
                self._log.header3(model.name())

            # Deal with the source of interest
            if model.name() == self._srcname:
                for par in model:
                    if par.is_free() and self._logExplicit():
                        self._log(" Fixing \"" + par.name() + "\"\n")
                    par.fix()
                normpar = model.spectral()[0]
                if normpar.is_fixed() and self._logExplicit():
                    self._log(" Freeing \"" + normpar.name() + "\"\n")
                normpar.free()
                if self._calc_ts:
                    model.tscalc(True)

            elif self._fix_bkg and not model.classname() == "GModelSky":
                for par in model:
                    if par.is_free() and self._logExplicit():
                        self._log(" Fixing \"" + par.name() + "\"\n")
                    par.fix()

            elif self._fix_srcs and model.classname() == "GModelSky":
                for par in model:
                    if par.is_free() and self._logExplicit():
                        self._log(" Fixing \"" + par.name() + "\"\n")
                    par.fix()

        # Write header
        if self._logTerse():
            self._log("\n")
            self._log.header1("Generate spectrum")
            self._log(str(self._ebounds))

        # Initialise FITS Table with extension "SPECTRUM"
        table = gammalib.GFitsBinTable(self._ebounds.size())
        table.extname("SPECTRUM")

        # Add Header for compatibility with gammalib.GMWLSpectrum
        table.card("INSTRUME", "CTA", "Name of Instrument")
        table.card("TELESCOP", "CTA", "Name of Telescope")

        # Create FITS table columns
        nrows = self._ebounds.size()
        energy = gammalib.GFitsTableDoubleCol("Energy", nrows)
        energy_low = gammalib.GFitsTableDoubleCol("ed_Energy", nrows)
        energy_high = gammalib.GFitsTableDoubleCol("eu_Energy", nrows)
        flux = gammalib.GFitsTableDoubleCol("Flux", nrows)
        flux_err = gammalib.GFitsTableDoubleCol("e_Flux", nrows)
        TSvalues = gammalib.GFitsTableDoubleCol("TS", nrows)
        ulim_values = gammalib.GFitsTableDoubleCol("UpperLimit", nrows)
        Npred_values = gammalib.GFitsTableDoubleCol("Npred", nrows)
        energy.unit("TeV")
        energy_low.unit("TeV")
        energy_high.unit("TeV")
        flux.unit("erg/cm2/s")
        flux_err.unit("erg/cm2/s")
        ulim_values.unit("erg/cm2/s")

        # Loop over energy bins
        for i in range(nrows):

            # Log information
            if self._logExplicit():
                self._log("\n")
                self._log.header2("Energy bin " + str(i + 1))

            # Get energy boundaries
            emin = self._ebounds.emin(i)
            emax = self._ebounds.emax(i)
            elogmean = self._ebounds.elogmean(i)
            elogmean2 = elogmean.MeV() * elogmean.MeV()

            # Store energy as TeV
            energy[i] = elogmean.TeV()

            # Store energy errors
            energy_low[i] = (elogmean - emin).TeV()
            energy_high[i] = (emax - elogmean).TeV()

            # Use ctselect for unbinned analysis
            if not self._binned_mode:

                # Log information
                if self._logExplicit():
                    self._log.header3("Selecting events")

                # Select events
                select = ctools.ctselect(self._obs)
                select["emin"] = emin.TeV()
                select["emax"] = emax.TeV()
                select["tmin"] = "UNDEFINED"
                select["tmax"] = "UNDEFINED"
                select["rad"] = "UNDEFINED"
                select["ra"] = "UNDEFINED"
                select["dec"] = "UNDEFINED"
                select.run()

                # Retrieve observation
                obs = select.obs()

            # Use ctcubemask for binned analysis
            else:

                # Header
                if self._logExplicit():
                    self._log.header3("Filtering cube")

                # Select layers
                cubemask = ctools.ctcubemask(self._obs)
                cubemask["regfile"] = "NONE"
                cubemask["ra"] = "UNDEFINED"
                cubemask["dec"] = "UNDEFINED"
                cubemask["rad"] = "UNDEFINED"
                cubemask["emin"] = emin.TeV()
                cubemask["emax"] = emax.TeV()
                cubemask.run()

                # Set new binned observation
                obs = cubemask.obs()

            # Header
            if self._logExplicit():
                self._log.header3("Performing fit")

            # Likelihood
            like = ctools.ctlike(obs)
            like["edisp"] = self._edisp
            like.run()

            # Skip bin if no event was present
            if like.obs().logL() == 0.0:

                # Log information
                if self._logExplicit():
                    self._log("No event in this bin. ")
                    self._log("Likelihood is zero. ")
                    self._log("Bin is skipped.")

                # Set all values to 0
                flux[i] = 0.0
                flux_err[i] = 0.0
                TSvalues[i] = 0.0
                ulim_values[i] = 0.0
                Npred_values[i] = 0.0
                continue

            # Get results
            fitted_models = like.obs().models()
            source = fitted_models[self._srcname]

            # Calculate Upper Limit
            ulimit_value = -1.0
            if self._calc_ulimit:

                # Logging information
                if self._logExplicit():
                    self._log.header3("Computing upper limit")

                # Create upper limit object
                ulimit = ctools.ctulimit(like.obs())
                ulimit["srcname"] = self._srcname
                ulimit["eref"] = elogmean.TeV()

                # Try to run upper limit and catch exceptions
                try:
                    ulimit.run()
                    ulimit_value = ulimit.diff_ulimit()
                except:
                    if self._logExplicit():
                        self._log("Upper limit calculation failed.")
                    ulimit_value = -1.0

            # Get TS value
            TS = -1.0
            if self._calc_ts:
                TS = source.ts()

            # Compute Npred value (only works for unbinned analysis)
            Npred = 0.0
            if not self._binned_mode:
                for observation in like.obs():
                    Npred += observation.npred(source)

            # Get differential flux
            fitted_flux = source.spectral().eval(elogmean)

            # Compute flux error
            parvalue = source.spectral()[0].value()
            rel_error = source.spectral()[0].error() / parvalue
            e_flux = fitted_flux * rel_error

            # Set values for storage
            TSvalues[i] = TS

            # Set npred values
            Npred_values[i] = Npred

            # Convert fluxes to nuFnu
            flux[i] = fitted_flux * elogmean2 * gammalib.MeV2erg
            flux_err[i] = e_flux * elogmean2 * gammalib.MeV2erg
            if ulimit_value > 0.0:
                ulim_values[i] = ulimit_value * elogmean2 * gammalib.MeV2erg

            # Log information
            if self._logTerse():
                self._log("\n")
                self._log.parformat("Bin " + str(i + 1))
                self._log(str(flux[i]))
                self._log(" +/- ")
                self._log(str(flux_err[i]))
                if self._calc_ulimit and ulim_values[i] > 0.0:
                    self._log(" [< " + str(ulim_values[i]) + "]")
                self._log(" erg/cm2/s")
                if self._calc_ts and TSvalues[i] > 0.0:
                    self._log(" (TS = " + str(TS) + ")")

        # Append filled columns to fits table
        table.append(energy)
        table.append(energy_low)
        table.append(energy_high)
        table.append(flux)
        table.append(flux_err)
        table.append(TSvalues)
        table.append(ulim_values)
        table.append(Npred_values)

        # Create the FITS file now
        self._fits = gammalib.GFits()
        self._fits.append(table)

        # Return
        return
Example #17
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()
        
        #  Write input parameters into logger
        if self.logTerse():
            self.log_parameters()
            self.log("\n")
        
        # Write observation into logger
        if self.logTerse():
            self.log("\n")
            self.log.header1("Observation")
            self.log(str(self.obs))
            self.log("\n")

        # Write header
        if self.logTerse():
            self.log("\n")
            self.log.header1("Adjust model parameters")

        # Adjust model parameters dependent on input user parameters
        for model in self.obs.models():
            
            # Set TS flag for all models to false.
            # Source of interest will be set to true later
            model.tscalc(False)
            
            # Log model name
            if self.logExplicit():
                self.log.header3(model.name())
            
            # Deal with the source of interest    
            if model.name() == self.m_srcname:
                for par in model:
                    if par.is_free() and self.logExplicit():
                        self.log(" Fixing \""+par.name()+"\"\n")
                    par.fix()
                if par.is_fixed() and self.logExplicit():
                    self.log(" Freeing \""+par.name()+"\"\n")
                model.spectral()[0].free()
                if self.m_calc_ts:
                    model.tscalc(True)
                
            elif self.m_fix_bkg and not model.classname() == "GModelSky":
                for par in model:
                    if par.is_free() and self.logExplicit():
                        self.log(" Fixing \""+par.name()+"\"\n")
                    par.fix()
        
            elif self.m_fix_srcs and model.classname() == "GModelSky":
                for par in model:
                    if par.is_free() and self.logExplicit():
                        self.log(" Fixing \""+par.name()+"\"\n")
                    par.fix()
        
        # Write header
        if self.logTerse():
            self.log("\n")
            self.log.header1("Generate spectrum")      
        
        # Initialise FITS Table with extension "SPECTRUM"
        table = gammalib.GFitsBinTable(self.m_ebounds.size())
        table.extname("SPECTRUM")
        
        # Add Header for compatibility with gammalib.GMWLSpectrum
        table.card("INSTRUME", "CTA", "Name of Instrument")
        table.card("TELESCOP", "CTA", "Name of Telescope")
        
        # Create FITS table columns
        energy      = gammalib.GFitsTableDoubleCol("Energy", self.m_ebounds.size())
        energy.unit("TeV")
        energy_low  = gammalib.GFitsTableDoubleCol("ed_Energy", self.m_ebounds.size())
        energy_low.unit("TeV")
        energy_high  = gammalib.GFitsTableDoubleCol("eu_Energy", self.m_ebounds.size())
        energy_high.unit("TeV")
        flux        = gammalib.GFitsTableDoubleCol("Flux", self.m_ebounds.size())
        flux.unit("erg/cm2/s")
        flux_err    = gammalib.GFitsTableDoubleCol("e_Flux", self.m_ebounds.size())
        flux_err.unit("erg/cm2/s")
        TSvalues    = gammalib.GFitsTableDoubleCol("TS", self.m_ebounds.size())
        ulim_values = gammalib.GFitsTableDoubleCol("UpperLimit", self.m_ebounds.size())
        ulim_values.unit("erg/cm2/s")

        # Loop over energy bins
        for i in range(self.m_ebounds.size()):

            # Log information
            if self.logTerse():
                self.log("\n")
                self.log.header2("Energy bin "+str(i))

            # Get energy boundaries
            emin      = self.m_ebounds.emin(i)
            emax      = self.m_ebounds.emax(i)
            elogmean  = self.m_ebounds.elogmean(i)
            elogmean2 = elogmean.MeV() * elogmean.MeV()    
                        
            # Store energy as TeV
            energy[i] = elogmean.TeV()
            
            # Store energy errors
            energy_low[i]  = (elogmean - emin).TeV()
            energy_high[i] = (emax - elogmean).TeV()
            
            # Log information
            if self.logExplicit():
                    self.log.header3("Selecting events")
            
            # Select events
            select = ctools.ctselect(self.obs)
            select["emin"].real(emin.TeV())    
            select["emax"].real(emax.TeV()) 
            select["tmin"].value("UNDEFINED")
            select["tmax"].value("UNDEFINED")
            select["rad"].value("UNDEFINED")
            select["ra"].value("UNDEFINED")
            select["dec"].value("UNDEFINED")
            select.run()  

            # Retrieve observation
            obs = select.obs()

            # Binned analysis
            if self.m_binned:

                # Header
                if self.logTerse():
                    self.log.header3("Binning events")
                
                # Bin events
                bin = ctools.ctbin(select.obs())
                bin["usepnt"].boolean(False)
                bin["ebinalg"].string("LOG")
                bin["xref"].real(self.m_xref)
                bin["yref"].real(self.m_yref)
                bin["binsz"].real(self.m_binsz)
                bin["nxpix"].integer(self.m_nxpix)
                bin["nypix"].integer(self.m_nypix)
                bin["enumbins"].integer(self.m_ebins)
                bin["emin"].real(emin.TeV())
                bin["emax"].real(emax.TeV())        
                bin["coordsys"].string(self.m_coordsys)
                bin["proj"].string(self.m_proj)            
                bin.run()
                
                # Header
                if self.logTerse():
                    self.log.header3("Creating exposure cube")
                
                # Create exposure cube
                expcube = ctools.ctexpcube(select.obs())
                expcube["incube"].filename("NONE")
                expcube["usepnt"].boolean(False)
                expcube["ebinalg"].string("LOG")
                expcube["xref"].real(self.m_xref)
                expcube["yref"].real(self.m_yref)
                expcube["binsz"].real(self.m_binsz)
                expcube["nxpix"].integer(self.m_nxpix)
                expcube["nypix"].integer(self.m_nypix)
                expcube["enumbins"].integer(self.m_ebins)
                expcube["emin"].real(emin.TeV())
                expcube["emax"].real(emax.TeV()) 
                expcube["coordsys"].string(self.m_coordsys)
                expcube["proj"].string(self.m_proj)               
                expcube.run()
                
                # Header
                if self.logTerse():
                    self.log.header3("Creating PSF cube")
                
                # Create psf cube
                psfcube = ctools.ctpsfcube(select.obs())
                psfcube["incube"].filename("NONE")
                psfcube["usepnt"].boolean(False)
                psfcube["ebinalg"].string("LOG")
                psfcube["xref"].real(self.m_xref)
                psfcube["yref"].real(self.m_yref)
                psfcube["binsz"].real(self.m_binsz)
                psfcube["nxpix"].integer(self.m_nxpix)
                psfcube["nypix"].integer(self.m_nypix)
                psfcube["enumbins"].integer(self.m_ebins)
                psfcube["emin"].real(emin.TeV())
                psfcube["emax"].real(emax.TeV())  
                psfcube["coordsys"].string(self.m_coordsys)
                psfcube["proj"].string(self.m_proj)               
                psfcube.run()
                
                # Header
                if self.logTerse():
                    self.log.header3("Creating background cube")
                
                # Create background cube
                bkgcube = ctools.ctbkgcube(select.obs())
                bkgcube["incube"].filename("NONE")
                bkgcube["usepnt"].boolean(False)
                bkgcube["ebinalg"].string("LOG")
                bkgcube["xref"].real(self.m_xref)
                bkgcube["yref"].real(self.m_yref)
                bkgcube["binsz"].real(self.m_binsz)
                bkgcube["nxpix"].integer(self.m_nxpix)
                bkgcube["nypix"].integer(self.m_nypix)
                bkgcube["enumbins"].integer(self.m_ebins)
                bkgcube["emin"].real(emin.TeV())
                bkgcube["emax"].real(emax.TeV()) 
                bkgcube["coordsys"].string(self.m_coordsys)
                bkgcube["proj"].string(self.m_proj)                
                bkgcube.run()
                
                # Set new binned observation
                obs = bin.obs()
                
                # Set precomputed binned response
                obs[0].response(expcube.expcube(), psfcube.psfcube(), bkgcube.bkgcube())

                # Get new models
                models = bkgcube.models()
                
                # Fix background models if required
                if self.m_fix_bkg:
                    for model in models:
                        if not model.classname() == "GModelSky":
                            for par in model:
                                par.fix()
                                
                # Set new models to binned observation           
                obs.models(models)
                
            # Header
            if self.logTerse():
                self.log.header3("Performing fit")
                             
            # Likelihood
            like = ctools.ctlike(obs)
            like.run()
            
            # Skip bin if no event was present
            if like.obs().logL() == 0.0:
                
                # Log information
                if self.logTerse():
                    self.log("No event in this bin. Bin is skipped\n")

                # Set all values to 0
                flux[i]        = 0.0
                flux_err[i]    = 0.0
                TSvalues[i]    = 0.0
                ulim_values[i] = 0.0
                continue
                         
            # Get results
            fitted_models = like.obs().models()
            source        = fitted_models[self.m_srcname]

            # Calculate Upper Limit            
            ulimit_value = -1.0
            if self.m_calc_ulimit:
                
                # Logging information
                if self.logTerse():
                    self.log.header3("Computing upper limit")
                  
                # Create upper limit object  
                ulimit = ctools.ctulimit(like.obs())
                ulimit["srcname"].string(self.m_srcname)
                ulimit["eref"].real(elogmean.TeV())
                
                # Try to run upper limit and catch exceptions
                try:
                    ulimit.run()
                    ulimit_value = ulimit.diff_ulimit()
                except:
                    if self.logTerse():
                        self.log("Upper limit calculation failed\n")
                    ulimit_value = -1.0
            
            # Get TS value
            TS = -1.0
            if self.m_calc_ts:
                TS = source.ts() 
              
            # Get differential flux    
            fitted_flux = source.spectral().eval(elogmean,gammalib.GTime())
            
            # Compute flux error
            parvalue  = source.spectral()[0].value()
            rel_error = source.spectral()[0].error()/parvalue        
            e_flux    = fitted_flux*rel_error
            
            # Set values for storage
            TSvalues[i] = TS
            
            # Convert fluxes to nuFnu
            flux[i]     = fitted_flux * elogmean2 * gammalib.MeV2erg
            flux_err[i] = e_flux      * elogmean2 * gammalib.MeV2erg
            if ulimit_value > 0.0:
                ulim_values[i] = ulimit_value * elogmean2 * gammalib.MeV2erg
         
            # Log information
            if self.logExplicit(): 
                self.log("Bin "+str(i)+" ["+str(emin.TeV())+"-"+str(emax.TeV())+"] TeV: ")
                self.log("Flux = "+str(flux[i]))
                self.log(" +- "+str(flux_err[i])+" [erg/cm2/s]")
                if self.m_calc_ts and TSvalues[i] > 0.0:
                    self.log(", TS = "+str(TS))
                if self.m_calc_ulimit and ulim_values[i] > 0.0:
                    self.log(", UL = "+str(ulim_values[i])+" [erg/cm2/s]")
                self.log("\n")

        # Append filles columns to fits table    
        table.append(energy)
        table.append(energy_low)
        table.append(energy_high)
        table.append(flux)
        table.append(flux_err)
        table.append(TSvalues)
        table.append(ulim_values)
        
        # Create the FITS file now
        self.fits = gammalib.GFits()
        self.fits.append(table)
            
        # Return
        return
Example #18
0
    def _fit_mass_point(self, i) :
        """
        Fit Model to DATA in the observation for a specific
        value of dark matter mass

        Return
        ------
        Result , dictionary with relevant fit results
        """

        #   Get value of mass (already in GeV)
        dmmass = self._masses[i]

        self._log_header2(gammalib.EXPLICIT, 'Mass point ' + str(i + 1))

        #   Set reference energy and energy range for calculations
        geref = gammalib.GEnergy(dmmass / 2., 'GeV')
        gemin = gammalib.GEnergy(self['emin'].real(), 'GeV')
        gemax = gammalib.GEnergy(dmmass, 'GeV')

        #   Create file with flux according to process
        #   Well, at this moment, just annihilation :P
        self._log_header1( gammalib.TERSE , 'Compute DM model' )

        if self['process'].string() == 'ANNA' :

            thisdmmodel = self._gen_model_anna(i)

        # elif self['process'].string() == 'DEC' :

        #     print( 'Not Implemented' )
        #     sys.exit()

        #   Then create GModel containers for source and bkg
        # thisbkgmodel = self._gen_bkgmodel()

        #   GModels source and append dm and bkg models
        # mymodels = gammalib.GModels()
        # mymodels.append(thisdmmodel)
        # mymodels.append(thisbkgmodel)

        #   Show mymodels in logfile, just to check that everything is Ok!
        self._log_string(gammalib.EXPLICIT , str(self.obs().models()))

        self._log_header1(gammalib.TERSE, 'Set or replace by Dark matter model')

        for model in self.obs().models() :

            if model.classname() != 'GCTAModelIrfBackground' :

                self.obs().models().remove(model.name())

        self.obs().models().append(thisdmmodel)
        obssim = self.obs().copy()

        #   Now, all the analysis is the same as in csspec script

        #   Get expected dmflux between emin and emax
        #   for the source of interest
        # srcname  = self['srcname'].string()
        # srcmodel = obssim.models()[srcname]
        # srcspec  = srcmodel.spectral()
        theoflux  = thisdmmodel.spectral().flux(gemin, gemax)
        # theoflux *= thisdmmodel.spectral()['Normalization'].value()
        sigmav    = math.pow(10., self['logsigmav'].real())

        #   Header
        self._log_header1(gammalib.TERSE, 'Fitting DM Model')

        #   So, at this moment interesting results to save are:
        #       - Min and Max Energy to compute integrated fluxes
        #       - Mass of dark matter candidate
        #       - Differential flux obtained in the fit
        #       - Error
        #       - TS
        #       - Upper-limit on the differential flux
        #       - Reference value of sigmav
        #       - UL computed of sigmav
        #       - Scale factor computed to obtain the UL on sigmav
        #   This may be change when including Spectral class
        #   for DM annihilation
        result = {'e_min'     : gemin.TeV(),
                  'e_max'     : gemax.TeV(),
                  'mass'      : dmmass,
                  'flux'      : 0.0,
                  'flux_err'  : 0.0,
                  'logL'      : 0.0,
                  'TS'        : 0.0,
                  'ulimit'    : 0.0,
                  'sigma_ref' : sigmav,
                  'sigma_lim' : 0.0 ,
                  'sc_factor' : 0.0}

        #   Header for ctlike instance :)
        self._log_header3(gammalib.EXPLICIT, 'Performing likelihood fit')

        #   Maximum likelihood fit via ctlike
        like             = ctools.ctlike(obssim)
        like['edisp']    = self['edisp'].boolean()
        like['nthreads'] = 1

        #   Chatter
        if self._logVerbose() and self._logDebug() :

            like['debug'] = True

        like.run()

        #   Extract fit results
        model    = like.obs().models()[self['srcname'].string()]
        spectrum = model.spectral()
        logL0    = like.obs().logL()

        result['logL'] = logL0

        #   Write models results
        self._log_string(gammalib.EXPLICIT, str(like.obs().models()))

        #   Continue only if logL0 is different from zero
        if logL0 != 0.0 :

            #   Extract TS value
            result['TS'] = model.ts()


            #   Calculation of upper-limit via ctulimit
            ulimit_value = -1.0

            if self['calc_ulim'].boolean() :

                #   Print to log
                self._log_header3(gammalib.EXPLICIT,
                                   'Computing Upper Limit')

                #   Instance for ctulimit
                ulimit             = ctools.ctulimit(like.obs())
                ulimit['srcname']  = self['srcname'].string()
                ulimit['eref']     = geref.TeV()
                ulimit['emin']     = gemin.TeV()
                ulimit['emax']     = gemax.TeV()

                #   Set chatter
                if self._logVerbose() and self._logDebug() :

                    ulimit['debug'] = True

                ulimit.run()
                ulimit_value = ulimit.diff_ulimit()
                #    Catching exceptions
                # try :

                #     ulimit.run()
                #     ulimit_value = ulimit.diff_ulimit()

                # except :

                #     self._log_string(gammalib.EXPLICIT, 'UL Calculation failed')
                #     ulimit_value = -1.0

                #   Compute quantities related to ulimit

                if ulimit_value > 0.0 :

                    flimit_value          = ulimit.flux_ulimit()
                    result[ 'ulimit' ]    = flimit_value
                    scfactor              = flimit_value / theoflux
                    result[ 'sc_factor' ] = scfactor
                    result[ 'sigma_lim' ] = scfactor * sigmav

                #   Get flux and error
                fitted_flux = spectrum.eval(geref)
                parvalue    = spectrum[0].value()

                if parvalue != 0.0 :

                    rel_error = spectrum[0].error() / parvalue
                    e_flux    = fitted_flux * rel_error

                else :

                    e_flux    = 0.0

                # If a cube, then compute corresponding weight
                if model.spatial().classname() == 'GModelSpatialDiffuseCube' :

                    dir          = gammalib.GSkyDir()
                    model.spatial().set_mc_cone( dir , 180 )
                    norm         = model.spatial().spectrum().eval( geref )
                    fitted_flux *= norm
                    e_flux      *= norm

                #   Convert to nuFnu
                eref2              = geref.MeV() * geref.MeV()
                result['flux']     = fitted_flux * eref2 * gammalib.MeV2erg
                result['flux_err'] = e_flux      * eref2 * gammalib.MeV2erg

                #   Logging
                value = '%e +/- %e' % (fitted_flux, e_flux)
                svmsg = ''

                if self[ 'calc_ulim' ].boolean() and result[ 'ulimit' ] > 0.0 :

                    value += ' [< %e]' % (result['ulimit'])
                    svmsg += ' [%e]' % (result['sc_factor'])

                value += ' 1/cm**2/s'

                if self['calc_ts'].boolean() and result['TS'] > 0.0:

                    value += ' (TS = %.3f)' % (result['TS'])

                self._log_value(gammalib.TERSE, 'Flux', value)

                if len( svmsg ) > 0 :

                    self._log_value(gammalib.TERSE, 'ScaleFactor', svmsg)

        #   If logL0 == 0, then failed :(
        #   but, this does not raise any error
        else :

            value = 'Likelihood is zero. Something is weird. Check model'
            self._log_value(gammalib.TERSE, 'Warning: ', value)

        #   Return
        return result