Commit fe07c6cf980df683b23fdc051114e523f45588f5

Authored by Jürgen Knödlseder
1 parent be2350c0

Add show_lightcurve example script

1 1 New Features and Important Changes in ctools 1.2.0
2 2  
3   -1 December 2016
  3 +26 January 2017
4 4  
5 5  
6 6 Introduction
... ... @@ -195,6 +195,9 @@ in particular the "PhotonFlux" and "EnergyFlux" names (#1832).
195 195  
196 196 The class now derives from ctlikelihood (#1828).
197 197  
  198 +The tool now makes sure that the intensity parameter of the source of interest
  199 +is free in the model optimisation that preceeds the upper limit computation.
  200 +
198 201  
199 202 cterror - Likelihood profile error computation
200 203 ----------------------------------------------
... ... @@ -232,11 +235,14 @@ definition XML file (#1881).
232 235  
233 236 Add cssrcdetect script to detect sources in a sky map (#1617).
234 237  
  238 +Improve the upper limit computation in the cslightcrv script. Now all source
  239 +parameters, except the source intensity, are set to the initial values given
  240 +in the model definition file for upper limit computation.
235 241  
236 242  
237 243 Examples
238 244 --------
239   -None
  245 +Add show_lightcurve script to display a light curve.
240 246  
241 247  
242 248 caldb
... ...
cscripts/Makefile.am
... ... @@ -166,6 +166,7 @@ testdata = $(top_srcdir)/test/data/crab.xml \
166 166 $(top_srcdir)/test/data/sensitivity_integral.dat \
167 167 $(top_srcdir)/test/data/skymap.fits \
168 168 $(top_srcdir)/test/data/spectrum.fits \
  169 + $(top_srcdir)/test/data/lightcurve.fits \
169 170 $(top_srcdir)/test/data/ts.dat \
170 171 $(top_srcdir)/test/data/models_spatial.xml \
171 172 $(top_srcdir)/test/data/models_spectral.xml \
... ...
cscripts/cslightcrv.py
... ... @@ -2,7 +2,7 @@
2 2 # ==========================================================================
3 3 # Generates a lightcurve.
4 4 #
5   -# Copyright (C) 2014-2016 Michael Mayer
  5 +# Copyright (C) 2014-2017 Michael Mayer
6 6 #
7 7 # This program is free software: you can redistribute it and/or modify
8 8 # it under the terms of the GNU General Public License as published by
... ... @@ -69,7 +69,7 @@ class cslightcrv(ctools.cscript):
69 69 """
70 70 # Set name
71 71 self._name = 'cslightcrv'
72   - self._version = '1.2.0'
  72 + self._version = '1.3.0'
73 73  
74 74 # Initialise some members
75 75 self._srcname = ''
... ... @@ -335,18 +335,26 @@ class cslightcrv(ctools.cscript):
335 335 table.append(ts)
336 336  
337 337 # Append upper limit column "UpperLimit"
338   - ulimit = gammalib.GFitsTableDoubleCol('UpperLimit', nrows)
339   - ulimit.unit('ph/cm2/s')
  338 + ul_diff = gammalib.GFitsTableDoubleCol('DiffUpperLimit', nrows)
  339 + ul_flux = gammalib.GFitsTableDoubleCol('FluxUpperLimit', nrows)
  340 + ul_eflux = gammalib.GFitsTableDoubleCol('EFluxUpperLimit', nrows)
  341 + ul_diff.unit('ph/cm2/s/MeV')
  342 + ul_flux.unit('ph/cm2/s')
  343 + ul_eflux.unit('erg/cm2/s')
340 344 for i, result in enumerate(results):
341   - ulimit[i] = result['ulimit']
342   - table.append(ulimit)
  345 + ul_diff[i] = result['ul_diff']
  346 + ul_flux[i] = result['ul_flux']
  347 + ul_eflux[i] = result['ul_eflux']
  348 + table.append(ul_diff)
  349 + table.append(ul_flux)
  350 + table.append(ul_eflux)
343 351  
344 352 # Return table
345 353 return table
346 354  
347 355 def _compute_ulimit(self, obs):
348 356 """
349   - Computes upper flux limit
  357 + Computes upper limit
350 358  
351 359 Parameters
352 360 ----------
... ... @@ -355,35 +363,57 @@ class cslightcrv(ctools.cscript):
355 363  
356 364 Returns
357 365 -------
358   - ulimit : float
359   - Upper flux limit (-1.0 of not computed)
  366 + ul_diff, ul_flux, ul_eflux : tuple of float
  367 + Upper limits, -1.0 of not computed
360 368 """
361 369 # Initialise upper flux limit
362   - ulimit_value = -1.0
363   -
  370 + ul_diff = -1.0
  371 + ul_flux = -1.0
  372 + ul_eflux = -1.0
  373 +
364 374 # Perform computation only if requested
365 375 if self['calc_ulim'].boolean():
366 376  
367 377 # Write header in logger
368 378 if self._logExplicit():
369   - self._log.header3('Computing upper flux limit')
370   -
371   - # Create upper limit object
372   - ulimit = ctools.ctulimit(obs)
373   - ulimit['srcname'] = self._srcname
374   - ulimit['eref'] = 1.0
375   -
376   - # Try to run upper limit and catch any exceptions
  379 + self._log.header3('Computing upper limit')
  380 +
  381 + # Create copy of observations
  382 + cpy_obs = obs.copy()
  383 +
  384 + # Fix parameters of source of interest in copy of observations.
  385 + # This assures that the original spectral parameters and position
  386 + # are used in the upper limit search. The ctulimit tool makes sure
  387 + # that the flux parameter is freed when needed.
  388 + source = cpy_obs.models()[self._srcname]
  389 + for par in source:
  390 + if par.is_free():
  391 + par.fix()
  392 +
  393 + # Create instance of upper limit tool
  394 + ulimit = ctools.ctulimit(cpy_obs)
  395 + ulimit['srcname'] = self._srcname
  396 + ulimit['eref'] = 1.0
  397 + ulimit['emin'] = self['emin'].real()
  398 + ulimit['emax'] = self['emax'].real()
  399 + ulimit['sigma_min'] = 0.0
  400 + ulimit['sigma_max'] = 3.0
  401 +
  402 + # Try to run upper limit tool and catch any exceptions
377 403 try:
378 404 ulimit.run()
379   - ulimit_value = ulimit.flux_ulimit()
  405 + ul_diff = ulimit.diff_ulimit()
  406 + ul_flux = ulimit.flux_ulimit()
  407 + ul_eflux = ulimit.eflux_ulimit()
380 408 except:
381 409 if self._logTerse():
382   - self._log('Upper limit flux calculation failed.\n')
383   - ulimit_value = -1.0
  410 + self._log('Upper limit calculation failed.\n')
  411 + ul_diff = -1.0
  412 + ul_flux = -1.0
  413 + ul_eflux = -1.0
384 414  
385   - # Return upper limit
386   - return ulimit_value
  415 + # Return upper limit tuple
  416 + return ul_diff, ul_flux, ul_eflux
387 417  
388 418 def _bin_observation(self, obs):
389 419 """
... ... @@ -517,7 +547,9 @@ class cslightcrv(ctools.cscript):
517 547 result = {'mjd': tmean.mjd(),
518 548 'e_mjd': twidth / gammalib.sec_in_day,
519 549 'ts': 0.0,
520   - 'ulimit': 0.0,
  550 + 'ul_diff': 0.0,
  551 + 'ul_flux': 0.0,
  552 + 'ul_eflux': 0.0,
521 553 'pars': pars,
522 554 'values': {}}
523 555  
... ... @@ -581,9 +613,12 @@ class cslightcrv(ctools.cscript):
581 613 result['values']['e_'+par] = source.spectral()[par].error()
582 614  
583 615 # Calculate upper limit (-1 if not computed)
584   - ulimit_value = self._compute_ulimit(like.obs())
585   - if ulimit_value > 0.0:
586   - result['ulimit'] = ulimit_value
  616 + #ul_diff, ul_flux, ul_eflux = self._compute_ulimit(like.obs())
  617 + ul_diff, ul_flux, ul_eflux = self._compute_ulimit(obs)
  618 + if ul_diff > 0.0:
  619 + result['ul_diff'] = ul_diff
  620 + result['ul_flux'] = ul_flux
  621 + result['ul_eflux'] = ul_eflux
587 622  
588 623 # Extract Test Statistic value
589 624 if self['calc_ts'].boolean():
... ... @@ -601,9 +636,13 @@ class cslightcrv(ctools.cscript):
601 636 unit = source.spectral()[par].unit()
602 637 self._log_value(gammalib.NORMAL, par,
603 638 str(value)+' +/- '+str(error)+' '+unit)
604   - if result['ulimit'] > 0.0:
  639 + if ul_diff > 0.0:
  640 + self._log_value(gammalib.NORMAL, 'Upper flux limit',
  641 + str(result['ul_diff'])+' ph/cm2/s/MeV')
  642 + self._log_value(gammalib.NORMAL, 'Upper flux limit',
  643 + str(result['ul_flux'])+' ph/cm2/s')
605 644 self._log_value(gammalib.NORMAL, 'Upper flux limit',
606   - str(result['ulimit'])+' ph/cm2/s')
  645 + str(result['ul_eflux'])+' erg/cm2/s')
607 646 if self['calc_ts'].boolean():
608 647 self._log_value(gammalib.NORMAL, 'Test Statistic', result['ts'])
609 648  
... ...
examples/Makefile.am
... ... @@ -39,6 +39,7 @@ scripts = README.md \
39 39 show_response.py \
40 40 show_sensitivity.py \
41 41 show_spectrum.py \
  42 + show_lightcurve.py \
42 43 show_ts_distribution.py \
43 44 show_obs.py
44 45  
... ...
examples/README.md
... ... @@ -70,5 +70,8 @@ the ctools.
70 70 `show_spectrum.py`
71 71 > Displays spectrum generated by the csspec script.
72 72  
  73 +`show_lightcurve.py`
  74 +> Displays lightcurve generated by the cslightcrv script.
  75 +
73 76 `show_ts_distribution.py`
74 77 > Displays Test Statistic histograms generated using the cstsdist script.
... ...
examples/show_lightcurve.py 0 → 100755
  1 +#! /usr/bin/env python
  2 +# ==========================================================================
  3 +# Display lightcurve generated by cslightcrv
  4 +#
  5 +# Copyright (C) 2017 Juergen Knoedlseder
  6 +#
  7 +# This program is free software: you can redistribute it and/or modify
  8 +# it under the terms of the GNU General Public License as published by
  9 +# the Free Software Foundation, either version 3 of the License, or
  10 +# (at your option) any later version.
  11 +#
  12 +# This program is distributed in the hope that it will be useful,
  13 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 +# GNU General Public License for more details.
  16 +#
  17 +# You should have received a copy of the GNU General Public License
  18 +# along with this program. If not, see <http://www.gnu.org/licenses/>.
  19 +#
  20 +# ==========================================================================
  21 +import sys
  22 +import gammalib
  23 +import cscripts
  24 +try:
  25 + import matplotlib.pyplot as plt
  26 + plt.figure()
  27 + plt.close()
  28 +except (ImportError, RuntimeError):
  29 + print('This script needs the "matplotlib" module')
  30 + sys.exit()
  31 +
  32 +
  33 +# =============== #
  34 +# Plot lightcurve #
  35 +# =============== #
  36 +def plot_lightcurve(filename, plotfile):
  37 + """
  38 + Plot lightcurve
  39 +
  40 + Parameters
  41 + ----------
  42 + filename : str
  43 + Name of lightcurve FITS file
  44 + plotfile : str
  45 + Plot file name
  46 + """
  47 + # Read spectrum file
  48 + fits = gammalib.GFits(filename)
  49 + table = fits.table(1)
  50 + c_mjd = table['MJD']
  51 + c_emjd = table['e_MJD']
  52 + c_flux = table['EnergyFlux']
  53 + c_eflux = table['e_EnergyFlux']
  54 + c_ts = table['TS']
  55 + c_upper = table['EFluxUpperLimit']
  56 +
  57 + # Initialise arrays to be filled
  58 + mjd = []
  59 + e_mjd = []
  60 + flux = []
  61 + e_flux = []
  62 + ul_mjd = []
  63 + ul_e_mjd = []
  64 + ul_flux = []
  65 + ul_e_flux = []
  66 +
  67 + # Loop over rows of the file
  68 + nrows = table.nrows()
  69 + for row in range(nrows):
  70 +
  71 + # Get Test Statistic, flux and flux error
  72 + ts = c_ts.real(row)
  73 + flx = c_flux.real(row)
  74 + e_flx = c_eflux.real(row)
  75 +
  76 + # If Test Statistic is larger than 9 and twice the flux error is
  77 + # smaller than the flux, then append flux point ...
  78 + if ts > 9.0 and 2.0*e_flx < flx:
  79 + mjd.append(c_mjd.real(row))
  80 + e_mjd.append(c_emjd.real(row))
  81 + flux.append(c_flux.real(row))
  82 + e_flux.append(c_eflux.real(row))
  83 +
  84 + # ... otherwise append upper limit
  85 + else:
  86 + ul_mjd.append(c_mjd.real(row))
  87 + ul_e_mjd.append(c_emjd.real(row))
  88 + ul_flux.append(c_upper.real(row))
  89 + ul_e_flux.append(0.5*c_upper.real(row))
  90 +
  91 + # Plot the spectrum
  92 + plt.figure()
  93 + plt.semilogy()
  94 + plt.grid()
  95 + plt.errorbar(mjd, flux, yerr=e_flux, xerr=[e_mjd, e_mjd],
  96 + fmt='ro')
  97 + plt.errorbar(ul_mjd, ul_flux, xerr=[ul_e_mjd, ul_e_mjd],
  98 + yerr=ul_e_flux, uplims=True, fmt='ro')
  99 + plt.xlabel('MJD (days)')
  100 + plt.ylabel(r'E $\times$ dN/dE (erg cm$^{-2}$ s$^{-1}$)')
  101 +
  102 + # Show figure
  103 + if len(plotfile) > 0:
  104 + plt.savefig(plotfile)
  105 + else:
  106 + plt.show()
  107 +
  108 + # Return
  109 + return
  110 +
  111 +
  112 +# =============== #
  113 +# Show lightcurve #
  114 +# =============== #
  115 +def show_lightcurve():
  116 + """
  117 + Show lightcurve
  118 + """
  119 + # Set usage string
  120 + usage = 'show_lightcurve.py [-p plotfile] [file]'
  121 +
  122 + # Set default options
  123 + options = [{'option': '-p', 'value': ''}]
  124 +
  125 + # Get arguments and options from command line arguments
  126 + args, options = cscripts.ioutils.get_args_options(options, usage)
  127 +
  128 + # Extract script parameters from options
  129 + plotfile = options[0]['value']
  130 +
  131 + # Plot lightcurve
  132 + plot_lightcurve(args[0], plotfile)
  133 +
  134 + # Return
  135 + return
  136 +
  137 +
  138 +# ======================== #
  139 +# Main routine entry point #
  140 +# ======================== #
  141 +if __name__ == '__main__':
  142 +
  143 + # Show lightcurve
  144 + show_lightcurve()
... ...
examples/show_spectrum.py
... ... @@ -35,7 +35,7 @@ except (ImportError, RuntimeError):
35 35 # ============= #
36 36 def plot_spectrum(filename, plotfile):
37 37 """
38   - Plot sensitivity data
  38 + Plot spectrum
39 39  
40 40 Parameters
41 41 ----------
... ...
test/data/lightcurve.fits 0 → 100644
No preview for this file type
test/test_cslightcrv.py
... ... @@ -2,7 +2,7 @@
2 2 # ==========================================================================
3 3 # This scripts performs unit tests for the cslightcrv script.
4 4 #
5   -# Copyright (C) 2016 Juergen Knoedlseder
  5 +# Copyright (C) 2016-2017 Juergen Knoedlseder
6 6 #
7 7 # This program is free software: you can redistribute it and/or modify
8 8 # it under the terms of the GNU General Public License as published by
... ... @@ -239,7 +239,8 @@ class Test(test):
239 239 """
240 240 # Expected column names
241 241 cols = ['MJD', 'e_MJD', 'Prefactor', 'e_Prefactor',
242   - 'Index', 'e_Index', 'TS', 'UpperLimit']
  242 + 'Index', 'e_Index', 'TS', 'DiffUpperLimit',
  243 + 'FluxUpperLimit', 'EFluxUpperLimit']
243 244  
244 245 # Open FITS file
245 246 fits = gammalib.GFits(filename)
... ...
test/test_examples.py.in
... ... @@ -2,7 +2,7 @@
2 2 # ==========================================================================
3 3 # Performs unit tests for the ctools example scripts
4 4 #
5   -# Copyright (C) 2016 Juergen Knoedlseder
  5 +# Copyright (C) 2016-2017 Juergen Knoedlseder
6 6 #
7 7 # This program is free software: you can redistribute it and/or modify
8 8 # it under the terms of the GNU General Public License as published by
... ... @@ -128,6 +128,8 @@ class Test(gammalib.GPythonTestSuite):
128 128 'Test show_sensitivity.py')
129 129 self.append(self.test_show_spectrum,
130 130 'Test show_spectrum.py')
  131 + self.append(self.test_show_lightcurve,
  132 + 'Test show_lightcurve.py')
131 133 self.append(self.test_show_ts_distribution,
132 134 'Test ts_distribution.py')
133 135 self.append(self.test_show_obs,
... ... @@ -401,6 +403,20 @@ class Test(gammalib.GPythonTestSuite):
401 403 # Return
402 404 return
403 405  
  406 + # Test show_lightcurve
  407 + def test_show_lightcurve(self):
  408 + """
  409 + Test show_lightcurve
  410 + """
  411 + # Set arguments
  412 + args = '-p example_show_lightcurve.eps %s/lightcurve.fits' % self._datadir
  413 +
  414 + # Execute script
  415 + self._execute_python('show_lightcurve', args=args)
  416 +
  417 + # Return
  418 + return
  419 +
404 420 # Test show_ts_distribution
405 421 def test_show_ts_distribution(self):
406 422 """
... ...