diff --git a/ChangeLog b/ChangeLog index 67d9a53..c637531 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,12 +6,13 @@ Support energy dispersion in ctobssim, ctlike and ctmodel -2014-02-10 Juergen Knoedlseder +2014-02-20 Juergen Knoedlseder * Bug fix Version 0.7.2 released ================================ Add logL and event statistics to cspull output file + Properly close temporary file in ctselect (#1149) 2014-02-05 Juergen Knoedlseder diff --git a/NEWS b/NEWS index a300548..ce93dfa 100644 --- a/NEWS +++ b/NEWS @@ -2,7 +2,7 @@ New Features and Important Changes in ctools 00-08-00 Author(s) : Juergen Knoedlseder -10 February 2014 +20 February 2014 1. Introduction @@ -31,7 +31,8 @@ dispersion can be switched on or off using the hidden edisp parameter. 5. ctselect - CTA event selection --------------------------------- -None +The temporary file is now properly close to avoid file opening errors +when iterating over ctselect (#1149). 6. ctbin - CTA event binning diff --git a/caldb/Makefile.am b/caldb/Makefile.am index 0dd7d27..4d26926 100644 --- a/caldb/Makefile.am +++ b/caldb/Makefile.am @@ -1,10 +1,12 @@ ## Process this file with automake to produce Makefile.in # Calibration files to distribute -irfs = cta_dummy_irf.dat +caldb_indx = caldb.indx +caldb_irf = cta_dummy_irf.dat -caldbdir = $(datadir)/caldb/data/cta/dummy -caldb_DATA = $(irfs) - -# Extra files to be distributed in the tar file -EXTRA_DIST = $(irfs) +# Distribute calibration database files +EXTRA_DIST = $(caldb_indx) $(caldb_irf) +caldbindxdir = $(datadir)/caldb/data/cta/dummy +caldbindx_DATA = $(caldb_indx) +caldbirfdir = $(datadir)/caldb/data/cta/dummy/bcf +caldbirf_DATA = $(caldb_irf) diff --git a/caldb/caldb.indx b/caldb/caldb.indx new file mode 100644 index 0000000..5aa32fc --- /dev/null +++ b/caldb/caldb.indx @@ -0,0 +1 @@ +SIMPLE = T / file does conform to FITS standard BITPIX = 8 / number of bits per data pixel NAXIS = 0 / number of data axes EXTEND = T / FITS dataset may contain extensions COMMENT FITS (Flexible Image Transport System) format is defined in 'AstronomyCOMMENT and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H COMMENT FITS (Flexible Image Transport System) format is defined in 'AstronomyCOMMENT and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H END XTENSION= 'BINTABLE' / binary table extension BITPIX = 8 / 8-bit bytes NAXIS = 2 / 2-dimensional binary table NAXIS1 = 945 / width of table in bytes NAXIS2 = 4 / number of rows in table PCOUNT = 0 / size of special data area GCOUNT = 1 / one data group (required keyword) TFIELDS = 18 / number of fields in each row TTYPE1 = 'TELESCOP' / label for field 1 TFORM1 = '10A ' / data format of field: ASCII Character TTYPE2 = 'INSTRUME' / label for field 2 TFORM2 = '10A ' / data format of field: ASCII Character TTYPE3 = 'DETNAM ' / label for field 3 TFORM3 = '20A ' / data format of field: ASCII Character TTYPE4 = 'FILTER ' / label for field 4 TFORM4 = '10A ' / data format of field: ASCII Character TTYPE5 = 'CAL_DEV ' / label for field 5 TFORM5 = '20A ' / data format of field: ASCII Character TTYPE6 = 'CAL_DIR ' / label for field 6 TFORM6 = '70A ' / data format of field: ASCII Character TTYPE7 = 'CAL_FILE' / label for field 7 TFORM7 = '40A ' / data format of field: ASCII Character TTYPE8 = 'CAL_CLAS' / label for field 8 TFORM8 = '3A ' / data format of field: ASCII Character TTYPE9 = 'CAL_DTYP' / label for field 9 TFORM9 = '4A ' / data format of field: ASCII Character TTYPE10 = 'CAL_CNAM' / label for field 10 TFORM10 = '20A ' / data format of field: ASCII Character TTYPE11 = 'CAL_CBD ' / label for field 11 TFORM11 = '630A70 ' / data format of field: ASCII Character TTYPE12 = 'CAL_XNO ' / label for field 12 TFORM12 = '1I ' / data format of field: 2-byte INTEGER TTYPE13 = 'CAL_VSD ' / label for field 13 TFORM13 = '10A ' / data format of field: ASCII Character TTYPE14 = 'CAL_VST ' / label for field 14 TFORM14 = '8A ' / data format of field: ASCII Character TTYPE15 = 'REF_TIME' / label for field 15 TFORM15 = '1D ' / data format of field: 8-byte DOUBLE TTYPE16 = 'CAL_QUAL' / label for field 16 TFORM16 = '1I ' / data format of field: 2-byte INTEGER TTYPE17 = 'CAL_DATE' / label for field 17 TFORM17 = '8A ' / data format of field: ASCII Character TTYPE18 = 'CAL_DESC' / label for field 18 TFORM18 = '70A ' / data format of field: ASCII Character EXTNAME = 'CIF ' / name of this extension CIFVERSN= '1992a ' / Version of CIF format HISTORY File modified by user 'jurgen' with fv on 2014-02-20T15:10:40 END CTA DUMMY NONE NONE ONLINE data/cta/dummy/bcf cta_dummy_irf.dat BCFDATAEFF_AREA NAME(cta_dummy_irf) VERSION(Prod1) CLASS(BEST) ANALYSIS(MPIK) NONE NONE NONE NONE NONE 2014-01-0100:00:00@é+14/01/01CTA effective area CTA DUMMY NONE NONE ONLINE data/cta/dummy/bcf cta_dummy_irf.dat BCFDATARPSF NAME(cta_dummy_irf) VERSION(Prod1) CLASS(BEST) ANALYSIS(MPIK) NONE NONE NONE NONE NONE 2014-01-0100:00:00@é+14/01/01CTA point spread function CTA DUMMY NONE NONE ONLINE data/cta/dummy/bcf cta_dummy_irf.dat BCFDATAEDISP NAME(cta_dummy_irf) VERSION(Prod1) CLASS(BEST) ANALYSIS(MPIK) NONE NONE NONE NONE NONE 2014-01-0100:00:00@é+14/01/01CTA energy dispersion CTA DUMMY NONE NONE ONLINE data/cta/dummy/bcf cta_dummy_irf.dat BCFDATABGD NAME(cta_dummy_irf) VERSION(Prod1) CLASS(BEST) ANALYSIS(MPIK) NONE NONE NONE NONE NONE 2014-01-0100:00:00@é+14/01/01CTA background \ No newline at end of file diff --git a/doc/source/_templates/index.html b/doc/source/_templates/index.html index ff701d0..2597495 100644 --- a/doc/source/_templates/index.html +++ b/doc/source/_templates/index.html @@ -34,7 +34,8 @@ CTA format), Fermi/LAT and COMPTEL data. {%endtrans%}

  • {%trans%}Installation{%endtrans%}
  • -
  • {%trans%}Quickstart{%endtrans%}
  • +
  • {%trans%}Quickstart{%endtrans%}
  • +
  • {%trans%}CTA response functions{%endtrans%}
  • {%trans%}User Manual{%endtrans%}
  • {%trans%}ctools reference{%endtrans%}
  • {%trans%}Source code documentation (Doxygen){%endtrans%}
  • diff --git a/doc/source/conf.py b/doc/source/conf.py index c7c62bd..0aa0c60 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -51,7 +51,7 @@ copyright = u'2014, ctools developers' version = '0.7' # The full version, including alpha/beta/rc tags. -release = '0.7.1' +release = '0.7.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -165,7 +165,7 @@ html_show_copyright = False #html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'GammaLibdoc' +htmlhelp_basename = 'ctoolsdoc' # -- Options for LaTeX output -------------------------------------------------- diff --git a/doc/source/user_manual/cntmap-fits.jpg b/doc/source/user_manual/getting_started/cntmap-fits.jpg index f9c73aa..f9c73aa 100644 --- a/doc/source/user_manual/cntmap-fits.jpg +++ b/doc/source/user_manual/getting_started/cntmap-fits.jpg diff --git a/doc/source/user_manual/cntmap-map.jpg b/doc/source/user_manual/getting_started/cntmap-map.jpg index b22de89..b22de89 100644 --- a/doc/source/user_manual/cntmap-map.jpg +++ b/doc/source/user_manual/getting_started/cntmap-map.jpg diff --git a/doc/source/user_manual/dskeys.jpg b/doc/source/user_manual/getting_started/dskeys.jpg index 0185466..0185466 100644 --- a/doc/source/user_manual/dskeys.jpg +++ b/doc/source/user_manual/getting_started/dskeys.jpg diff --git a/doc/source/user_manual/getting_started/faq.rst b/doc/source/user_manual/getting_started/faq.rst new file mode 100644 index 0000000..d6444b9 --- /dev/null +++ b/doc/source/user_manual/getting_started/faq.rst @@ -0,0 +1,4 @@ +Frequently asked questions +-------------------------- + +To be written ... diff --git a/doc/source/user_manual/getting_started/index.rst b/doc/source/user_manual/getting_started/index.rst new file mode 100644 index 0000000..d5ddba6 --- /dev/null +++ b/doc/source/user_manual/getting_started/index.rst @@ -0,0 +1,12 @@ +Getting started +=============== + +.. toctree:: + :maxdepth: 2 + + quickstart + response + models + python + faq + diff --git a/doc/source/user_manual/getting_started/irfs.jpg b/doc/source/user_manual/getting_started/irfs.jpg new file mode 100644 index 0000000..c60bb63 --- /dev/null +++ b/doc/source/user_manual/getting_started/irfs.jpg diff --git a/doc/source/user_manual/getting_started/models.rst b/doc/source/user_manual/getting_started/models.rst new file mode 100644 index 0000000..d9fa054 --- /dev/null +++ b/doc/source/user_manual/getting_started/models.rst @@ -0,0 +1,5 @@ +Models available in ctools +-------------------------- + +To be written ... (you may read +http://gammalib.sourceforge.net/user_manual/modules/model.html#spectral-models for the time being). diff --git a/doc/source/user_manual/getting_started/python.rst b/doc/source/user_manual/getting_started/python.rst new file mode 100644 index 0000000..2c75456 --- /dev/null +++ b/doc/source/user_manual/getting_started/python.rst @@ -0,0 +1,4 @@ +Using ctools from Python +------------------------ + +To be written ... diff --git a/doc/source/user_manual/quickstart.rst b/doc/source/user_manual/getting_started/quickstart.rst index 875416e..13b5a5f 100644 --- a/doc/source/user_manual/quickstart.rst +++ b/doc/source/user_manual/getting_started/quickstart.rst @@ -1,6 +1,3 @@ -Getting started -=============== - A quick ctools tutorial ----------------------- @@ -641,22 +638,3 @@ the same events for both analyses. 2014-01-09T21:47:54: +==============+ 2014-01-09T21:47:54: 2014-01-09T21:47:54: Application "ctlike" terminated after 6 wall clock seconds, consuming 0.163384 seconds of CPU time. - - -Models available in ctools --------------------------- - -To be written ... (you may read -http://gammalib.sourceforge.net/user_manual/modules/model.html#spectral-models for the time being). - - -Using ctools from Python ------------------------- - -To be written ... - - -Frequently asked questions --------------------------- - -To be written ... diff --git a/doc/source/user_manual/getting_started/response.rst b/doc/source/user_manual/getting_started/response.rst new file mode 100644 index 0000000..e65d5c6 --- /dev/null +++ b/doc/source/user_manual/getting_started/response.rst @@ -0,0 +1,395 @@ +CTA Instrument Response Functions +--------------------------------- + +.. note :: + + Instrument response functions are formally not part of ctools as they + should be provided by the instrument teams. The GammaLib framework on + which ctools are built comes with a set of basic response functions, but + for getting the latest instrument response functions you should contact + the relevant instrument teams. CTA consortium members should + `download + `_ + the latest calibration database containing Prod1 and Prod2 instrument + response functions from the consortium Sharepoint site (requires + password). + + +What are instrument response functions? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The instrument response functions provide a mathematical description that +links the measured quantities :math:`\vec{d}` of an event to the physical +quantities :math:`\vec{p}` of the incident photon. The following figure +illustrates this relationship: + +.. figure:: irfs.jpg + :width: 70% + +:math:`I(\vec{p})` is the gamma-ray intensity arriving at Earth as a +function of photon properties :math:`\vec{p}` +(which usually are true photon energy, true photon incident direction, +and true photon arrival time), +while :math:`e(\vec{d})` is the expected event rate as function of event +properties :math:`\vec{d}` (which usually are the measured photon energy, +measured or reconstructued photon incident direction, and measured photon +arrival time). The expected event rate is obtained by integrating the +product of +the instrumental response function :math:`R(\vec{d}|\vec{p},\vec{a}`) +and the emitted intensity :math:`I(\vec{p})` over the photon properties +:math:`\vec{p}`. +The argument :math:`\vec{a}` in the response function comprises any +auxiliary parameter on which the response function may depend on (e.g. +pointing direction, triggered telescopes, optical efficiencies, +atmospheric conditions, etc.). All these quantities and hence the +instrument response function may depend on time. + + +Data formats +~~~~~~~~~~~~ + +So far the data format of the CTA instrument response functions has not +yet been settled, and information about instrument response functions is +provided in various ways. Three types of data formats are supported: + +- :ref:`sec_cta_rsp_perftable` + +- :ref:`sec_cta_rsp_xspec` + +- :ref:`sec_cta_rsp_rsptable` + +All formats provide the instrument response as function of true (and +sometimes also measured) photon energy, typically from about 20 GeV to +about 125 TeV. +Performance tables provide the instrument response for on-axis sources. +ARF, RMF and PSF files provide the instrument response for a specific +source position (and region) within the field of view. +Response tables provide the instrument response as function of position in +the field of view. Response tables are thus the most universal form of +instrument response functions available, and we recommend using this form +for any analysis. + +.. note :: + + Instrument response functions are so far only provided for a fixed + zenith angle of 20 deg. Therefore, no zenith or azimuth angle dependence has + been implemented so far. + + +Installing the CTA calibration database +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +After `downloading +`_ +the latest calibration database (only possible for CTA consortium members), +the database is installed using + +.. code-block:: bash + + $ [sudo] tar -C $CALDB -zxvf cta-caldb-20140220.tar.gz + +or + +.. code-block:: bash + + $ [sudo] tar -C $CALDB -xvf cta-caldb-20140220.tar + +depending on whether the database has been retrieved as a gzipped file or +not. Depending on your access rights to the ``$CALDB`` directory, +installation of the calibration database may require root privileges +(type ``sudo`` in this case, otherwise omit this part of the command). + +The calibration database must be installed into the directory to which you +``CALDB`` environment variable points. By default, ctools sets this +enviroment variable to + +.. code-block:: bash + + $CTOOLS/share/caldb + +but it may be that due to some other analysis software on your system the +``CALDB`` environment variable points to another directory. If in doubt, type + +.. code-block:: bash + + echo $CALDB + +to find out to which directory your ``CALDB`` environment variable points. +You may always overwrite this setting using + +.. code-block:: bash + + export CALDB=/my/preferred/caldb/directory + +which you can add to your ``.bashrc`` file to set the directory +permanently. +ctools will use the ``CALDB`` environment variable to find out where the +calibration database is located. If needed, this mechanism can be +circumvented (see :ref:`sec_cta_rsp_abspath`). + + +Specifying the CTA Instrument Response Functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The specification of the CTA Instrument Response Functions depends on the +way how ctools are used. Common to all methods is that the IRFs are +defined by a response name and a calibration database name. + +There are different means to specify the CTA Instrument Response Functions +when using ctools, and the following section describe the + + +Specifying the response function as input parameters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +ctools that require instrument response functions have two parameters +to specify the calibration database name and the response function name. +The following example shows a ``ctobssim`` run using the ``dummy`` +calibration database and the ``cta_dummy_irf`` response function: + +.. code-block:: bash + + $ ctobssim + Model [$CTOOLS/share/models/crab.xml] + Calibration database [dummy] + Instrument response function [cta_dummy_irf] + RA of pointing (degrees) (0-360) [83.63] + Dec of pointing (degrees) (-90-90) [22.01] + Radius of FOV (degrees) (0-180) [5.0] + Start time (MET in s) (0) [0.0] + End time (MET in s) (0) [1800.0] + Lower energy limit (TeV) (0) [0.1] + Upper energy limit (TeV) (0) [100.0] + Output event data file or observation definition file [events.fits] + +Running the other tools is equivalent. + + +Specifying the response function in an observation definition file +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the above example, only a single global response function can be +used for all CTA observations. If you need to specify response functions +per observation you can add the information directly in the XML observation +definition file: + +.. code-block:: xml + + + + + + + + +The ``Calibration`` parameter specifies the calibration database and +response name. You can then pass this file directly to, e.g., ``ctlike``: + +.. code-block:: bash + + $ ctlike + Event list, counts map or observation definition file [events.fits] obs_rsp.xml + Source model [$CTOOLS/share/models/crab.xml] + Source model output file [crab_results.xml] + +Note that ``ctlike`` does not ask for the calibration database and +response name as it found the relevant information in the XML file. + +.. _sec_cta_rsp_abspath: + + +Specifying individual instrument response files +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you need even more control over individual response files, you can +specify them individually in the XML observation file as follows: + +.. code-block:: xml + + + + + + + + + + + + +From within a Python script +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following example illustrates how to set the calibration database +and response name from within Python: + +.. code-block:: python + + import gammalib + obs = gammalib.GCTAObservation() + caldb = gammalib.GCaldb("cta", "dummy") + irf = "cta_dummy_irf" + obs.response(irf, caldb) + +The calibration database is set by creating a ``GCaldb`` object. The +constructor takes as argument the mission (always ``cta``) and the +database name, in our case ``dummy``. The response function is then set +by passing the response name (here ``cta_dummy_irf``) and the calibration +database object to the ``response`` method. + +Alternatively, you can specify a specific response file by using + +.. code-block:: python + + import gammalib + obs = gammalib.GCTAObservation() + caldb = gammalib.GCaldb("$CALDB/data/cta/dummy/bcf") + irf = "cta_dummy_irf.dat" + obs.response(irf, caldb) + +Here, the directory in which the calibration file resides is specified +as argument to the ``GCaldb`` constructor, and the filename is passed +as response function name to the ``response`` method. + + +What response functions are available? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To see what response functions are available on your system, type + +.. code-block:: bash + + $ cscaldb + +This creates the file ``cscaldb.log`` in your current working directory +that contains information about the available response functions. The +format of the file is: + +.. code-block:: bash + + 2014-02-20T17:15:21: +==============+ + 2014-02-20T17:15:21: | Mission: cta | + 2014-02-20T17:15:21: +==============+ + 2014-02-20T17:15:21: === Calibration: aar === + 2014-02-20T17:15:21: DESY20140105_50h + 2014-02-20T17:15:21: DESY20140105_50h_0deg + 2014-02-20T17:15:21: DESY20140105_50h_180deg + 2014-02-20T17:15:21: + 2014-02-20T17:15:21: === Calibration: aar500 === + 2014-02-20T17:15:21: DESY20140105_50h + 2014-02-20T17:15:21: DESY20140105_50h_0deg + 2014-02-20T17:15:21: DESY20140105_50h_180deg + +The name after ``Calibration`` is what we called earlier the calibration +database, and the names that are following each +``=== Calibration: xxx ===`` header are the response file names. + +To get the same information also onto the console, type + +.. code-block:: bash + + $ cscaldb debug=yes + + +Data format details +~~~~~~~~~~~~~~~~~~~ + +.. _sec_cta_rsp_perftable: + +Performance tables +^^^^^^^^^^^^^^^^^^ + +In the early days, the instrument performances derived from Monte-Carlo +simulations have been summarised in what we call here Performance +Tables, which are ASCII files that contain as function of energy the +on-axis performance parameters of CTA, such as effective area, point spread +function containment radius, energy resolution, background count rate and +differential sensitivity. + +Below an example of a CTA performance table:: + + log(E) Area r68 r80 ERes. BG Rate Diff Sens + -1.7 261.6 0.3621 0.4908 0.5134 0.0189924 6.88237e-11 + -1.5 5458.2 0.2712 0.3685 0.4129 0.1009715 1.72717e-11 + -1.3 15590.0 0.1662 0.2103 0.2721 0.0575623 6.16963e-12 + -1.1 26554.1 0.1253 0.1567 0.2611 0.0213008 2.89932e-12 + -0.9 52100.5 0.1048 0.1305 0.1987 0.0088729 1.39764e-12 + -0.7 66132.1 0.0827 0.1024 0.1698 0.0010976 6.03531e-13 + -0.5 108656.8 0.0703 0.0867 0.1506 0.0004843 3.98147e-13 + -0.3 129833.0 0.0585 0.0722 0.1338 0.0001575 3.23090e-13 + -0.1 284604.3 0.0531 0.0656 0.1008 0.0001367 2.20178e-13 + 0.1 263175.3 0.0410 0.0506 0.0831 0.0000210 1.87452e-13 + 0.3 778048.6 0.0470 0.0591 0.0842 0.0000692 1.53976e-13 + 0.5 929818.8 0.0391 0.0492 0.0650 0.0000146 1.18947e-13 + 0.7 1078450.0 0.0335 0.0415 0.0541 0.0000116 1.51927e-13 + 0.9 1448579.1 0.0317 0.0397 0.0516 0.0000047 1.42439e-13 + 1.1 1899905.0 0.0290 0.0372 0.0501 0.0000081 1.96670e-13 + 1.3 2476403.8 0.0285 0.0367 0.0538 0.0000059 2.20695e-13 + 1.5 2832570.6 0.0284 0.0372 0.0636 0.0000073 3.22523e-13 + 1.7 3534065.3 0.0290 0.0386 0.0731 0.0000135 4.84153e-13 + 1.9 3250103.4 0.0238 0.0308 0.0729 0.0000044 6.26265e-13 + 2.1 3916071.6 0.0260 0.0354 0.0908 0.0000023 7.69921e-13 + --------------------------------------------- + 1) log(E) = log10(E/TeV) - bin centre + 2) Eff Area - in square metres after background cut (no theta cut) + 3) Ang. Res - 68% containment radius of gamma-ray PSF post cuts - in degrees + 4) Ang. Res - 80% containment radius of gamma-ray PSF post cuts - in degrees + 5) Fractional Energy Resolution (rms) + 6) BG Rate - inside point-source selection region - post call cuts - in Hz + 7) Diff Sens - differential sensitivity for this bin expressed as E^2 dN/dE + - in erg cm^-2 s^-1 - for a 50 hours exposure - 5 sigma significance including + systematics and statistics and at least 10 photons. + + +.. _sec_cta_rsp_xspec: + +ARF, RMF and PSF files +^^^^^^^^^^^^^^^^^^^^^^ + +Instrument response information for the first CTA Data Challenge (1DC) has been +provided in a format that was heavily inspired by the +`RMF and ARF file formats +`_ +that have been introduced by +`HEASARC `_ +for spectral analysis of X-ray data. + +The Redistribution Matrix File (RMF) describes how an incoming photon with +a given true energy is redistributed in measured energy. In other words, it +describes the energy dispersion of the instrument. The RMF is organised as +a two-dimensional matrix, with the first axis being in true energies while +the second axis represents the measured energies. + +The Ancillary Response File (ARF) describes the sensitivity of the +instrument to photons of a given true energy. The ARF gives the effective +area of the detector system after applying an event selection cut +(theta cut). For computing the ARF, some knowledge of the Point Spread +Function (PSF) is needed, so that the fraction of photons that falls into +the event selection region for a given source can be properly estimated. +Once this is done, no further PSF information is needed for the analysis. + +ctools however relies on the full modelling of the instrument, including +the Point Spread Function, and hence, PSF information has also been +provided for 1DC. Two data formats have been used for this: a first that +is based on a simple one-dimensional vector, providing the width of a +2-dimensional Gaussian as function of energy; and a second that is based +on a three-component 2D Gaussian as function of energy and offset angle +in the camera system. While the former was implement by a simply FITS +table with two columns, the latter was implemented by +:ref:`sec_cta_rsp_rsptable`. + + +.. _sec_cta_rsp_rsptable: + +Response tables +^^^^^^^^^^^^^^^ + +The CTA response table class ``GCTAResponseTable`` provides a generic +handle for multi-dimensional response information. It is based on the +response format used for storing response information for the +*Fermi*/LAT telescope. In this format, all information is stored in +a single row of a FITS binary table. Each element of the row contains +a vector column, that describes the axes of the multi-dimensional response +cube and the response information. Note that this class may in the future +be promoted to the GammaLib core, as a similar class has been implemented +in the *Fermi*/LAT interface. diff --git a/doc/source/user_manual/index.rst b/doc/source/user_manual/index.rst index 079b194..0c5a40d 100644 --- a/doc/source/user_manual/index.rst +++ b/doc/source/user_manual/index.rst @@ -7,7 +7,7 @@ User Manual introduction getting - quickstart + getting_started/index enhancing reference expert diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 810837b..c23790b 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -4,12 +4,12 @@ binscripts = cta_kb_bkgrates.py cta_root2irf.py cta_make_nodes.py # Scripts to be distributed in pythondir -pythonscripts = cspull.py cssens.py cstsdist.py \ +pythonscripts = cspull.py cssens.py cstsdist.py cscaldb.py \ obsutils.py \ lsmodel.py # Scripts for which symbolic links will be created in bindir -linkscripts = cspull cssens cstsdist \ +linkscripts = cspull cssens cstsdist cscaldb \ lsmodel # Distribute scripts diff --git a/scripts/cscaldb.py b/scripts/cscaldb.py new file mode 100755 index 0000000..dadc680 --- /dev/null +++ b/scripts/cscaldb.py @@ -0,0 +1,209 @@ +#! /usr/bin/env python +# ========================================================================== +# This script dumps all available calibrations into the console. +# +# Copyright (C) 2014 Juergen Knoedlseder +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# ========================================================================== +import gammalib +import sys +import glob +import os + + +# ============ # +# cspull class # +# ============ # +class cscaldb(gammalib.GApplication): + """ + This class implements the pull distribution generation script. It derives + from the GammaLib::GApplication class which provides support for parameter + files, command line arguments, and logging. In that way the Python + script behaves just as a regular ctool. + """ + def __init__(self, *argv): + """ + Constructor. + """ + # Set name + self.name = "cscaldb" + self.version = "0.1.0" + + # Make sure that parfile exists + file = self.parfile() + + # Initialise application + if len(argv) == 0: + gammalib.GApplication.__init__(self, self.name, self.version) + elif len(argv) ==1: + gammalib.GApplication.__init__(self, self.name, self.version, *argv) + else: + raise TypeError("Invalid number of arguments given.") + + # Set logger properties + self.log_header() + self.log.date(True) + + # Return + return + + def __del__(self): + """ + Destructor. + """ + # Return + return + + def parfile(self): + """ + Check if parfile exists. If parfile does not exist then create a + default parfile. This kluge avoids shipping the cscript with a parfile. + """ + # Set parfile name + parfile = self.name+".par" + + try: + pars = gammalib.GApplicationPars(parfile) + except: + # Signal if parfile was not found + sys.stdout.write("Parfile "+parfile+" not found. Create default parfile.\n") + + # Create default parfile + pars = gammalib.GApplicationPars() + pars.append_standard() + pars.save(parfile) + + # Return + return + + def get_parameters(self): + """ + Get parameters from parfile. + """ + # Return + return + + def execute(self): + """ + Execute the script. + """ + # Run the script + self.run() + + # Return + return + + 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") + + # Get the calibration database path + caldb = gammalib.GCaldb() + + # Gather missions + missions = [] + paths = glob.glob(caldb.rootdir()+"/data/*") + paths.sort() + for path in paths: + head, tail = os.path.split(path) + missions.append(tail) + + # Loop over missions + for mission in missions: + + # Skip all non-CTA instruments + if mission != "cta": + continue + + # Write mission into logger + if self.logTerse(): + self.log("\n") + self.log.header1("Mission: "+mission) + + # Gather instruments + instruments = [] + paths = glob.glob(caldb.rootdir()+"/data/"+mission+"/*") + paths.sort() + for path in paths: + head, tail = os.path.split(path) + instruments.append(tail) + + # Loop over instruments + for instrument in instruments: + + # Write mission into logger + if self.logTerse(): + self.log.header3("Calibration: "+instrument) + + # Open calibration index file + cifname = caldb.rootdir()+"/data/"+mission+"/"+instrument+"/caldb.indx" + fits = gammalib.GFits(cifname) + cif = fits["CIF"] + cals = cif["CAL_CBD"] + + # Extract response names + names = [] + nrows = cals.length() + ncols = cals.number() + for row in range(nrows): + for col in range(ncols): + cal = cals.string(row, col) + istart = cal.find("NAME(") + if istart != -1: + istop = cal.find(")") + name = cal[5:istop] + if names.count(name) == 0: + names.append(name) + names.sort() + + # Print response name + if self.logTerse(): + for name in names: + self.log(name+"\n") + self.log("\n") + + # Return + return + + +# ======================== # +# Main routine entry point # +# ======================== # +if __name__ == '__main__': + """ + Dumps calibration database into log file. + """ + # Create instance of application + app = cscaldb(sys.argv) + + # Open logfile + app.logFileOpen() + + # Execute application + app.execute() + \ No newline at end of file diff --git a/scripts/cssens.py b/scripts/cssens.py index 242bee8..0bb8858 100755 --- a/scripts/cssens.py +++ b/scripts/cssens.py @@ -57,7 +57,7 @@ class cssens(GApplication): """ # Set name self.name = "cssens" - self.version = "0.3.0" + self.version = "0.4.0" # Make sure that parfile exists file = self.parfile() @@ -106,11 +106,11 @@ class cssens(GApplication): # Create default parfile pars = GApplicationPars() pars.append(GApplicationPar("outfile","f","h","sensitivity.dat","","","Output file name")) - pars.append(GApplicationPar("caldb","s","a","$GAMMALIB/share/caldb/cta","","","Calibration database")) + pars.append(GApplicationPar("caldb","s","a","$CTOOLS/share/caldb/data/cta/dummy","","","Calibration database")) pars.append(GApplicationPar("irf","s","a","cta_dummy_irf","","","Instrument response function")) pars.append(GApplicationPar("type","s","a","point","","","Source model type (point/gauss/shell/disk)")) pars.append(GApplicationPar("offset","r","a","0.0","0.0","","Source offset angle (deg)")) - pars.append(GApplicationPar("bkg","s","a","$GAMMALIB/share/models/bkg_dummy.txt","","","Background model file function (none=power law for E)")) + pars.append(GApplicationPar("bkg","s","a","$CTOOLS/share/models/bkg_dummy.txt","","","Background model file function (none=power law for E)")) pars.append(GApplicationPar("duration","r","a","180000.0","","","Effective exposure time (s)")) pars.append(GApplicationPar("rad","r","a","5.0","","","Radius of ROI (deg)")) pars.append(GApplicationPar("enumbins","i","h","0","","","Number of energy bins (0=unbinned)")) @@ -333,7 +333,7 @@ class cssens(GApplication): location.lb_deg(l, b) # Set source spectrum - spectrum = GModelSpectralPlaw(flux*5.7e-16, index, GEnergy(0.3, "TeV") + spectrum = GModelSpectralPlaw(flux*5.7e-16, index, GEnergy(0.3, "TeV")) if fitidx: spectrum["Index"].free() else: diff --git a/scripts/cta_kb_root2caldb.py b/scripts/cta_kb_root2caldb.py new file mode 100755 index 0000000..37c8244 --- /dev/null +++ b/scripts/cta_kb_root2caldb.py @@ -0,0 +1,545 @@ +#! /usr/bin/env python +# ========================================================================== +# This script generates CALDB compliant performance tables from MC ROOT +# files. +# +# Note that the effective area given in the ASCII file is the full effective +# area (i.e. the area before applying any theta cut). This is required by +# GammaLib as the maximum likelihood analysis does not imply any theta cut. +# +# Copyright (C) 2014 Juergen Knoedlseder +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# ========================================================================== +from ROOT import TFile, TH1F, TH2F +from datetime import datetime +import gammalib +import math +import sys +import glob +import os + + +# =========== # +# CalDB class # +# =========== # +class caldb(): + """ + """ + def __init__(self, inst, path=""): + """ + CALDB constructor. The constructor will create one CALDB entry for + an observation. + + Parameters: + inst - Instrument string. + Keywords: + path - CALDB Root path. + """ + # Store root path + self.path = path + + # Initialise some members + self.cif = None + self.irf = None + self.ea = None + self.psf = None + self.edisp = None + self.bgd = None + self.hdu_cif = None + + # Store UTC date of job execution + self.utc = datetime.utcnow().isoformat()[:19] + + # Set CALDB information + self.cal_tel = "CTA" + self.cal_inst = inst.upper() + self.cal_det = "NONE" + self.cal_flt = "NONE" + self.cal_class = "BCF" + self.cal_type = "DATA" + self.cal_qual = 0 # 0=good, 1=bad, 2=dubious, ... + self.cal_date = "14/01/01" + self.val_date = "2014-01-01" + self.val_time = "00:00:00" + self.ref_time = 51544.0 + self.cal_name = "NAME()" + self.cal_version = "VERSION(Prod1)" + self.cal_cut = "CLASS(BEST)" + self.cal_analysis = "ANALYSIS(MPIK)" + # + self.ea_name = "EFF_AREA" + self.ea_doc = "???" + self.ea_bounds = [self.cal_name, self.cal_version, self.cal_cut, self.cal_analysis] + self.ea_desc = "CTA effective area" + # + self.psf_name = "RPSF" + self.psf_doc = "???" + self.psf_bounds = [self.cal_name, self.cal_version, self.cal_cut, self.cal_analysis] + self.psf_desc = "CTA point spread function" + # + self.edisp_name = "EDISP" + self.edisp_doc = "???" + self.edisp_bounds = [self.cal_name, self.cal_version, self.cal_cut, self.cal_analysis] + self.edisp_desc = "CTA energy dispersion" + # + self.bgd_name = "BGD" + self.bgd_doc = "???" + self.bgd_bounds = [self.cal_name, self.cal_version, self.cal_cut, self.cal_analysis] + self.bgd_desc = "CTA background" + + # Create directory structure + self.make_dirs() + + # Return + return + + def __del__(self): + """ + Destructor. Close all FITS files. + """ + # Close calibration + self.close() + + # Return + return + + def make_dirs(self): + """ + Generate CALDB directory structure for one observation identifier. + The structure is given by + + data///bcf/ + + where is "cta" and is the instrument specified in the + CALDB constructor (the instrument may be used for different array + configurations). + + Parameters: + None + Keywords: + None + """ + # Set base path + self.base_dir = "data" + self.base_dir += "/"+self.cal_tel.lower() + self.base_dir += "/"+self.cal_inst.lower() + + # Set directory names + self.bcf_dir = self.base_dir+"/bcf" + + # Optionally prefix path + if len(self.path) > 0: + self.base_path = self.path+"/"+self.base_dir + self.bcf_path = self.path+"/"+self.bcf_dir + else: + self.base_path = self.base_dir + self.bcf_path = self.bcf_dir + + # Create directory structure + if not os.path.isdir(self.bcf_path): + os.makedirs(self.bcf_path) + + # Return + return + + def add(self, rspname, split=False, clobber=True): + """ + Add new calibration. The actual version will put + all calibrations in the same file, although each part of the response + function will have its own logical name. We can thus easily modify + the script to put each calibration information in a separate file. + + Parameters: + rspname - Response name + Keywords: + split - Split IRF over several files? + clobber - Overwrite existing files? + """ + # Set calibrate file names + if split: + self.ea_file = "ea_"+rspname+".dat" + self.psf_file = "psf_"+rspname+".dat" + self.edisp_file = "edisp_"+rspname+".dat" + self.bgd_file = "bgd_"+rspname+".dat" + else: + self.ea_file = "irf_"+rspname+".dat" + self.psf_file = "irf_"+rspname+".dat" + self.edisp_file = "irf_"+rspname+".dat" + self.bgd_file = "irf_"+rspname+".dat" + + # Open calibration database index + if self.cif == None: + self.cif = gammalib.GFits(self.base_path+"/caldb.indx", True) + + # If file has no CIF extension than create it now + try: + self.hdu_cif = self.cif.table("CIF") + except: + self.create_cif() + self.hdu_cif = self.cif.table("CIF") + + # Set response name + self.cal_name = "NAME("+rspname+")" + + # Return + return + + def close(self): + """ + Close calibration FITS files. + + Parameters: + None + Keywords: + None + """ + # Add information to CIF. We do this now as before we did not + # necessarily have all the information at hand (in particular + # about the boundaries) + #self.add_cif_info() + + # Close CIF + if self.cif != None: + self.cif.save(True) + self.cif.close() + self.cif = None + + # Free + self.cif = None + + # Return + return + + def create_cif(self): + """ + Create Calibration Index File (CIF) extension in CIF FITS file. + + Parameters: + None + Keywords: + None + """ + # Create binary table + table = gammalib.GFitsBinTable() + + # Set boundary + + # Attach columns. Reference: CAL/GEN/92-008 + table.append(gammalib.GFitsTableStringCol("TELESCOP", 0, 10)) + table.append(gammalib.GFitsTableStringCol("INSTRUME", 0, 10)) + table.append(gammalib.GFitsTableStringCol("DETNAM", 0, 20)) + table.append(gammalib.GFitsTableStringCol("FILTER", 0, 10)) + table.append(gammalib.GFitsTableStringCol("CAL_DEV", 0, 20)) + table.append(gammalib.GFitsTableStringCol("CAL_DIR", 0, 70)) + table.append(gammalib.GFitsTableStringCol("CAL_FILE", 0, 40)) + table.append(gammalib.GFitsTableStringCol("CAL_CLAS", 0, 3)) + table.append(gammalib.GFitsTableStringCol("CAL_DTYP", 0, 4)) + table.append(gammalib.GFitsTableStringCol("CAL_CNAM", 0, 20)) + table.append(gammalib.GFitsTableStringCol("CAL_CBD", 0, 70, 9)) + table.append(gammalib.GFitsTableShortCol("CAL_XNO", 0)) + table.append(gammalib.GFitsTableStringCol("CAL_VSD", 0, 10)) + table.append(gammalib.GFitsTableStringCol("CAL_VST", 0, 8)) + table.append(gammalib.GFitsTableDoubleCol("REF_TIME", 0)) + table.append(gammalib.GFitsTableShortCol("CAL_QUAL", 0)) + table.append(gammalib.GFitsTableStringCol("CAL_DATE", 0, 8)) + table.append(gammalib.GFitsTableStringCol("CAL_DESC", 0, 70)) + + # Set keywords. Reference: CAL/GEN/92-008 + table.extname("CIF") + table.card("CIFVERSN", "1992a", "Version of CIF format") + + # Attach table to FITS file. Note that at this moment the + # FITS table gets connected to the FITS file. Yet since + # nothing was yet written to the FITS file, we cannot read + # anything from it. + self.cif.append(table) + + # Return + return + + def add_cif_info(self): + """ + Add information to CIF extension. + + Parameters: + None + Keywords: + None + """ + # Set boundaries + self.ea_bounds = [self.cal_name, self.cal_version, self.cal_cut, self.cal_analysis] + self.psf_bounds = [self.cal_name, self.cal_version, self.cal_cut, self.cal_analysis] + self.edisp_bounds = [self.cal_name, self.cal_version, self.cal_cut, self.cal_analysis] + self.bgd_bounds = [self.cal_name, self.cal_version, self.cal_cut, self.cal_analysis] + + # Append 4 rows to CIF extension + self.hdu_cif.append_rows(4) + + # Add generic information for these 4 rows + for i in range(4): + + # Set row number + row = i+self.hdu_cif.nrows()-4 + + # Set element + self.hdu_cif["TELESCOP"][row] = self.cal_tel + self.hdu_cif["INSTRUME"][row] = self.cal_inst + self.hdu_cif["DETNAM"][row] = self.cal_det + self.hdu_cif["FILTER"][row] = self.cal_flt + self.hdu_cif["CAL_DEV"][row] = "ONLINE" + self.hdu_cif["CAL_CLAS"][row] = self.cal_class + self.hdu_cif["CAL_DTYP"][row] = self.cal_type + self.hdu_cif["CAL_VSD"][row] = self.val_date + self.hdu_cif["CAL_VST"][row] = self.val_time + self.hdu_cif["REF_TIME"][row] = self.ref_time + self.hdu_cif["CAL_QUAL"][row] = self.cal_qual + self.hdu_cif["CAL_DATE"][row] = self.cal_date + + # Add effective area information + row = self.hdu_cif.nrows()-4 + self.hdu_cif["CAL_DIR"][row] = self.bcf_dir + self.hdu_cif["CAL_FILE"][row] = self.ea_file + self.hdu_cif["CAL_CNAM"][row] = self.ea_name + self.hdu_cif["CAL_DESC"][row] = self.ea_desc + self.hdu_cif["CAL_XNO"][row] = 1 + for n in range(9): + if n >= len(self.ea_bounds): + self.hdu_cif["CAL_CBD"][row, n] = "NONE" + else: + self.hdu_cif["CAL_CBD"][row, n] = self.ea_bounds[n] + + # Add point spread function information + row = self.hdu_cif.nrows()-3 + self.hdu_cif["CAL_DIR"][row] = self.bcf_dir + self.hdu_cif["CAL_FILE"][row] = self.psf_file + self.hdu_cif["CAL_CNAM"][row] = self.psf_name + self.hdu_cif["CAL_DESC"][row] = self.psf_desc + self.hdu_cif["CAL_XNO"][row] = 1 + for n in range(9): + if n >= len(self.psf_bounds): + self.hdu_cif["CAL_CBD"][row, n] = "NONE" + else: + self.hdu_cif["CAL_CBD"][row, n] = self.psf_bounds[n] + + # Add energy dispersion information + row = self.hdu_cif.nrows()-2 + self.hdu_cif["CAL_DIR"][row] = self.bcf_dir + self.hdu_cif["CAL_FILE"][row] = self.edisp_file + self.hdu_cif["CAL_CNAM"][row] = self.edisp_name + self.hdu_cif["CAL_DESC"][row] = self.edisp_desc + self.hdu_cif["CAL_XNO"][row] = 1 + for n in range(9): + if n >= len(self.edisp_bounds): + self.hdu_cif["CAL_CBD"][row, n] = "NONE" + else: + self.hdu_cif["CAL_CBD"][row, n] = self.edisp_bounds[n] + + # Add background information + row = self.hdu_cif.nrows()-1 + self.hdu_cif["CAL_DIR"][row] = self.bcf_dir + self.hdu_cif["CAL_FILE"][row] = self.bgd_file + self.hdu_cif["CAL_CNAM"][row] = self.bgd_name + self.hdu_cif["CAL_DESC"][row] = self.bgd_desc + self.hdu_cif["CAL_XNO"][row] = 1 + for n in range(9): + if n >= len(self.bgd_bounds): + self.hdu_cif["CAL_CBD"][row, n] = "NONE" + else: + self.hdu_cif["CAL_CBD"][row, n] = self.bgd_bounds[n] + + # Return + return + + def root2caldb(self, filename): + """ + Generate files. + + Parameters: + filename - Performance file name + """ + # Open ROOT performance file + rootfile = TFile(filename) + + # Set filenames + ea_filename = self.bcf_path+"/"+self.ea_file + psf_filename = self.bcf_path+"/"+self.psf_file + edisp_filename = self.bcf_path+"/"+self.edisp_file + bgd_filename = self.bcf_path+"/"+self.bgd_file + + # Open ASCII performance tables + if self.ea_file == self.psf_file and \ + self.ea_file == self.edisp_file and \ + self.ea_file == self.bgd_file : + split = False + fprf = open(ea_filename, "w") + files = [fprf] + else: + split = True + fea = open(ea_filename, "w") + fpsf = open(psf_filename, "w") + fedisp = open(edisp_filename, "w") + fbgd = open(bgd_filename, "w") + files = [fea, fpsf, fedisp, fbgd] + + # Write header + for file in files: + file.write("log(E) Area r68 r80 ERes. BG Rate Diff Sens\n") + + # Get histograms. Konrad's root files do not have an EffectiveArea80 + # histogram, but his effective area is for 80% containment radius + # anyways, so we simply read this histogram into aeff80. + sens = TH1F() + bgrate = TH1F() + bgratesqdeg = TH1F() + aeff = TH1F() + aeff80 = TH1F() + angres = TH1F() + angres80 = TH1F() + eres = TH1F() + rootfile.GetObject("DiffSens", sens) + rootfile.GetObject("BGRate", bgrate) + rootfile.GetObject("BGRatePerSqDeg", bgratesqdeg) + rootfile.GetObject("EffectiveArea", aeff) + try: + rootfile.GetObject("EffectiveArea80", aeff80) + except: + rootfile.GetObject("EffectiveArea", aeff80) + rootfile.GetObject("AngRes", angres) + rootfile.GetObject("AngRes80", angres80) + rootfile.GetObject("ERes", eres) + + # Setup vectors + energies = bgrate.GetXaxis() + nbins_eng = energies.GetNbins() + for i in range(nbins_eng): + + # Get logE and background rate per squared degree + logE = energies.GetBinCenter(i+1) + bgd = bgrate.GetBinContent(i+1,1) + bgdsq = bgratesqdeg.GetBinContent(i+1,1) + area = aeff.GetBinContent(i+1,1) + area80 = aeff80.GetBinContent(i+1,1) + r68 = angres.GetBinContent(i+1,1) + r80 = angres80.GetBinContent(i+1,1) + dE = eres.GetBinContent(i+1,1) + diffs = sens.GetBinContent(i+1,1) + + # Skip any NaNs + if math.isnan(area80): + continue + + # Compute energy (in MeV) + energy = math.pow(10.0, logE)*1.0e6 + emin = math.pow(10.0, logE-0.1)*1.0e6 + emax = math.pow(10.0, logE+0.1)*1.0e6 + ewidth = emax-emin + + # Convert into background rate per steradian and MeV + bkg_rate = bgdsq / (0.01745329*0.01745329) / ewidth + + # Compute control background rate (this only works for KB files + # as they are for 80% containment radius). But we don't use this + # anyways, it's just for control on display ... + omega = 2.0 * math.pi * (1.0 - math.cos(math.radians(r80))) + if omega > 0.0: + bkg_rate2 = bgd / omega / ewidth + else: + bkg_rate2 = 0.0 + + # Compute full effective area by dividing area80/0.80 + area = area80/0.80 + + # Write results in file + line = "%.1f %.1f %.4f %.4f %.4f %.5e %.5e" % \ + (logE, area, r68, r80, dE, bgd, diffs) + for file in files: + file.write(line+"\n") + #fbkg.write(str(energy)+" "+str(bkg_rate)+"\n") + + # Write trailer + for file in files: + file.write("---------------------------------------------\n") + file.write("Notes\n") + file.write(" 1) log(E) = log10(E/TeV) - bin centre\n") + file.write(" 2) Eff Area - in square metres after background cut (no theta cut)\n") + file.write(" 3) Ang. Res - 68% containment radius of gamma-ray PSF post cuts - in degrees\n") + file.write(" 4) Ang. Res - 80% containment radius of gamma-ray PSF post cuts - in degrees\n") + file.write(" 5) Fractional Energy Resolution (rms)\n") + file.write(" 6) BG Rate - inside point-source selection region - post call cuts - in Hz\n") + file.write(" 7) Diff Sens - differential sensitivity for this bin expressed as E^2 dN/dE\n") + file.write(" - in erg cm^-2 s^-1 - for a 50 hours exposure - 5 sigma significance including\n") + file.write(" systematics and statistics and at least 10 photons.\n") + + # Close files + for file in files: + file.close() + + # Close ROOT performance file + rootfile.Close() + + # Add information to CIF. We do this now as before we did not + # necessarily have all the information at hand (in particular + # about the boundaries) + self.add_cif_info() + + # Return + return + + +#==========================# +# Main routine entry point # +#==========================# +if __name__ == '__main__': + """ + """ + # Get ROOT filename from command line argument + if (len(sys.argv) > 1): + filename = sys.argv[1] + else: + db = "/Users/jurgen/Documents/Travail/Projects/CTA/WP-MC/root/Kb_all_20deg_root" + #db = "/Users/jurgen/Documents/Travail/Projects/CTA/WP-MC/root/Kb_all_50deg_root" + + # Get list of all performance files + files = glob.glob(db+"/*.root") + files.sort() + + # Allocate caldb + irf = caldb("kb") + + # Loop over all files + for file in files: + + # Get filename + head, tail = os.path.split(file) + + # Build name + name = tail.strip(".root") + if name.find("kb_") != -1: + name = name.replace("_20deg", "") + elif name.find("IFAE_") != -1: + name = name.replace("Subarray", "") + name = name.replace("IFAE_", "") + name = "IFAE_"+name + i = name.find("hours") + if i != -1: + name = name[0:i+1] + print(tail) + + # Open calibration file + irf.add(name) + + # Translate ROOT to CALDB information + irf.root2caldb(file) diff --git a/scripts/cta_root2caldb.py b/scripts/cta_root2caldb.py index 8618101..e406369 100755 --- a/scripts/cta_root2caldb.py +++ b/scripts/cta_root2caldb.py @@ -1319,9 +1319,9 @@ def set_prod1_ifae(): #=========================# # Set Prod2 DESY database # #=========================# -def set_prod2_desy(): +def set_prod2_desy_ignore(): """ - Set Prod2 DESY database. + Set Prod2 DESY database (ignore these files). """ # Set database attributes path_aar = "/project-data/cta/performance/prod2/Performance_DESY_20140131_Aar" @@ -1366,6 +1366,56 @@ def set_prod2_desy(): return db +#=========================# +# Set Prod2 DESY database # +#=========================# +def set_prod2_desy(): + """ + Set Prod2 DESY database. + """ + # Set database attributes + path_aar = "/project-data/cta/performance/prod2/Performance_DESY_20140131_Aar" + path_ten = "/project-data/cta/performance/prod2/Performance_DESY_20140131_Tenerife_50h" + rebin = False + psftype = "Gauss" + scale = 1.0 + + # Set database content + db = [{'inst': "aar", 'id': "DESY20140105_50h", + 'path': path_aar, 'rebin': rebin, 'psftype': psftype, 'scale': scale, + 'file': "DESY.d20140105.Erec1.V3.ID0NIM2.prod2-Aar-NS.S.2a.180000s.root"}, + {'inst': "aar", 'id': "DESY20140105_50h_0deg", + 'path': path_aar, 'rebin': rebin, 'psftype': psftype, 'scale': scale, + 'file': "DESY.d20140105.Erec1.V3.ID0_0degNIM2.prod2-Aar-NS.S.2a.180000s.root"}, + {'inst': "aar", 'id': "DESY20140105_50h_180deg", + 'path': path_aar, 'rebin': rebin, 'psftype': psftype, 'scale': scale, + 'file': "DESY.d20140105.Erec1.V3.ID0_180degNIM2.prod2-Aar-NS.S.2a.180000s.root"}, + + {'inst': "aar500", 'id': "DESY20140105_50h", + 'path': path_aar, 'rebin': rebin, 'psftype': psftype, 'scale': scale, + 'file': "DESY.d20140105.Erec1.V3.ID0NIM2.prod2-Aar-500m-NS.S.2a.180000s.root"}, + {'inst': "aar500", 'id': "DESY20140105_50h_0deg", + 'path': path_aar, 'rebin': rebin, 'psftype': psftype, 'scale': scale, + 'file': "DESY.d20140105.Erec1.V3.ID0_0degNIM2.prod2-Aar-NS.S.2a.180000s.root"}, + {'inst': "aar500", 'id': "DESY20140105_50h_180deg", + 'path': path_aar, 'rebin': rebin, 'psftype': psftype, 'scale': scale, + 'file': "DESY.d20140105.Erec1.V3.ID0_180degNIM2.prod2-Aar-NS.S.2a.180000s.root"}, + + {'inst': "tenerife", 'id': "DESY20140105_50h", + 'path': path_ten, 'rebin': rebin, 'psftype': psftype, 'scale': scale, + 'file': "DESY.d20140105.Erec1.V3.ID0NIM2.prod2-Tenerife-NS.N.2NN.180000s.root"}, + {'inst': "tenerife", 'id': "DESY20140105_50h_0deg", + 'path': path_ten, 'rebin': rebin, 'psftype': psftype, 'scale': scale, + 'file': "DESY.d20140105.Erec1.V3.ID0_0degNIM2.prod2-Tenerife-NS.N.2NN.180000s.root"}, + {'inst': "tenerife", 'id': "DESY20140105_50h_180deg", + 'path': path_ten, 'rebin': rebin, 'psftype': psftype, 'scale': scale, + 'file': "DESY.d20140105.Erec1.V3.ID0_180degNIM2.prod2-Tenerife-NS.N.2NN.180000s.root"} + ] + + # Return database + return db + + #==========================# # Main routine entry point # #==========================# @@ -1381,7 +1431,7 @@ if __name__ == '__main__': - EffectiveArea80_offaxis (2D) - Effective area for 80% source containment - AngRes_offaxis (2D) - Angular resolution 68% containment - AngRes80_offaxis (2D) - Angular resolution 80% containment - - BGRatePerSqDeg_offaxis (2D) - Background rate per square degree + - BGRatePerSqDeg_offaxis (2D) - Background rate per square degree [counts/s/deg2] - BGRate_offaxis (2D) - Background rate - EffectiveAreaEtrue_offaxis (2D) - Effective area in true energy (finer bins) - MigMatrix_offaxis (3D) diff --git a/scripts/cta_root2irf.py b/scripts/cta_root2irf.py index c12f7b4..466750e 100755 --- a/scripts/cta_root2irf.py +++ b/scripts/cta_root2irf.py @@ -38,58 +38,58 @@ import os # Compute Eq. (17) of Li & Ma (1983) # # ================================== # def sigma_lima(Non, Noff, alpha=0.2): - """ - Compute Eq. (17) of Li & Ma (1983). - - Parameters: - Non - Number of on counts - Noff - Number of off counts - Keywords: - alpha - Ratio of on-to-off exposure - """ - # Compute sensitivity - alpha1 = alpha + 1.0 - sum = Non + Noff - arg1 = Non / sum - arg2 = Noff / sum - term1 = Non * math.log((alpha1/alpha)*arg1) - term2 = Noff * math.log(alpha1*arg2) - sigma = math.sqrt(2.0 * (term1 + term2)) - - # Return sensitivity - return sigma + """ + Compute Eq. (17) of Li & Ma (1983). + + Parameters: + Non - Number of on counts + Noff - Number of off counts + Keywords: + alpha - Ratio of on-to-off exposure + """ + # Compute sensitivity + alpha1 = alpha + 1.0 + sum = Non + Noff + arg1 = Non / sum + arg2 = Noff / sum + term1 = Non * math.log((alpha1/alpha)*arg1) + term2 = Noff * math.log(alpha1*arg2) + sigma = math.sqrt(2.0 * (term1 + term2)) + + # Return sensitivity + return sigma # ======================================== # # Solve Eq. (17) of Li & Ma (1983) for Non # # ======================================== # def Non_lima(sigma, Noff, alpha=0.2): - """ - Solve Eq. (17) of Li & Ma (1983) for Non - - Parameters: - sigma - Required significance - Noff - Number of off counts - Keywords: - alpha - Ratio of on-to-off exposure - """ - # Set initial guess for Non - S = 25.0 - Non = S + alpha*Noff - - # Compute initial sigma estimate - s = sigma_lima(Non, Noff, alpha=alpha) - delta = s - sigma - - # Iterate - while abs(delta) > 1.0e-6: - S *= sigma/s - Non = S + alpha*Noff - s = sigma_lima(Non, Noff, alpha=alpha) - delta = s - sigma - - # Return - return Non + """ + Solve Eq. (17) of Li & Ma (1983) for Non + + Parameters: + sigma - Required significance + Noff - Number of off counts + Keywords: + alpha - Ratio of on-to-off exposure + """ + # Set initial guess for Non + S = 25.0 + Non = S + alpha*Noff + + # Compute initial sigma estimate + s = sigma_lima(Non, Noff, alpha=alpha) + delta = s - sigma + + # Iterate + while abs(delta) > 1.0e-6: + S *= sigma/s + Non = S + alpha*Noff + s = sigma_lima(Non, Noff, alpha=alpha) + delta = s - sigma + + # Return + return Non # =============================================== # @@ -97,195 +97,195 @@ def Non_lima(sigma, Noff, alpha=0.2): # =============================================== # def get_aeff(bgrate, emin, emax, \ duration=180000.0, alpha=0.2, sigma=5.0, norm=2.79e-7, index=-2.57): - """ - Computes effective area assuming a Crab spectrum. This does not - include any hadron cut efficiencies, and thus is not very useful in a first - place ... - - Parameters: - bgrate - Background rate (TeV) - emin - Minimum energy (TeV) - emax - Maximum energy (TeV) - Keywords: - duration - Observing time in seconds (default: 50h) - alpha - Non/Noff ratio (default: 0.2) - sigma - Significance (default: 5.0) - norm - Crab spectrum normalization at 1 TeV (default: 2.79e-7) - index - Crab spectral index (default: -2.57) - """ - # Compute number of source events - B = bgrate*duration - Noff = B/alpha - Non = Non_lima(sigma, Noff) - S = (Non - B) - - # Compute Crab flux in specified energy band - inx = index+1.0 - cu = norm/inx * (math.pow(emax, inx) - math.pow(emin, inx)) - - # Compute effective area - area = S / duration / cu - - # Return effective area - return area + """ + Computes effective area assuming a Crab spectrum. This does not + include any hadron cut efficiencies, and thus is not very useful in a first + place ... + + Parameters: + bgrate - Background rate (TeV) + emin - Minimum energy (TeV) + emax - Maximum energy (TeV) + Keywords: + duration - Observing time in seconds (default: 50h) + alpha - Non/Noff ratio (default: 0.2) + sigma - Significance (default: 5.0) + norm - Crab spectrum normalization at 1 TeV (default: 2.79e-7) + index - Crab spectral index (default: -2.57) + """ + # Compute number of source events + B = bgrate*duration + Noff = B/alpha + Non = Non_lima(sigma, Noff) + S = (Non - B) + + # Compute Crab flux in specified energy band + inx = index+1.0 + cu = norm/inx * (math.pow(emax, inx) - math.pow(emin, inx)) + + # Compute effective area + area = S / duration / cu + + # Return effective area + return area # ============== # # Generate files # # ============== # def make_files(filename, prfname, bkgname): - """ - Generate files. - - Parameters: - filename - Performance file name - prfname - Performance file name - bkgname - File function filename - """ - # Open performance file and file function - file = TFile(filename) - fprf = open(prfname, "w") - fbkg = open(bkgname, "w") - - # Write header - fprf.write("log(E) Area r68 r80 ERes. BG Rate Diff Sens\n") - #sys.stdout.write("log(E) Area Area80 r68 r80 ERes. BG Rate Diff Sens BGRateSqDeg BGInt (BGIntControl)\n") + """ + Generate files. + + Parameters: + filename - Performance file name + prfname - Performance file name + bkgname - File function filename + """ + # Open performance file and file function + file = TFile(filename) + fprf = open(prfname, "w") + fbkg = open(bkgname, "w") + + # Write header + fprf.write("log(E) Area r68 r80 ERes. BG Rate Diff Sens\n") + #sys.stdout.write("log(E) Area Area80 r68 r80 ERes. BG Rate Diff Sens BGRateSqDeg BGInt (BGIntControl)\n") - # Get histograms. Konrad's root files do not have an EffectiveArea80 - # histogram, but his effective area is for 80% containment radius - # anyways, so we simply read this histogram into aeff80. - sens = TH1F() - bgrate = TH1F() - bgratesqdeg = TH1F() - aeff = TH1F() - aeff80 = TH1F() - angres = TH1F() - angres80 = TH1F() - eres = TH1F() - file.GetObject("DiffSens", sens) - file.GetObject("BGRate", bgrate) - file.GetObject("BGRatePerSqDeg", bgratesqdeg) - file.GetObject("EffectiveArea", aeff) - try: - file.GetObject("EffectiveArea80", aeff80) - except: - file.GetObject("EffectiveArea", aeff80) - file.GetObject("AngRes", angres) - file.GetObject("AngRes80", angres80) - file.GetObject("ERes", eres) - - # Setup vectors - energies = bgrate.GetXaxis() - nbins_eng = energies.GetNbins() - for i in range(nbins_eng): - - # Get logE and background rate per squared degree - logE = energies.GetBinCenter(i+1) - bgd = bgrate.GetBinContent(i+1,1) - bgdsq = bgratesqdeg.GetBinContent(i+1,1) - area = aeff.GetBinContent(i+1,1) - area80 = aeff80.GetBinContent(i+1,1) - r68 = angres.GetBinContent(i+1,1) - r80 = angres80.GetBinContent(i+1,1) - dE = eres.GetBinContent(i+1,1) - diffs = sens.GetBinContent(i+1,1) - - # Skip any NaNs - if math.isnan(area80): - continue + # Get histograms. Konrad's root files do not have an EffectiveArea80 + # histogram, but his effective area is for 80% containment radius + # anyways, so we simply read this histogram into aeff80. + sens = TH1F() + bgrate = TH1F() + bgratesqdeg = TH1F() + aeff = TH1F() + aeff80 = TH1F() + angres = TH1F() + angres80 = TH1F() + eres = TH1F() + file.GetObject("DiffSens", sens) + file.GetObject("BGRate", bgrate) + file.GetObject("BGRatePerSqDeg", bgratesqdeg) + file.GetObject("EffectiveArea", aeff) + try: + file.GetObject("EffectiveArea80", aeff80) + except: + file.GetObject("EffectiveArea", aeff80) + file.GetObject("AngRes", angres) + file.GetObject("AngRes80", angres80) + file.GetObject("ERes", eres) + + # Setup vectors + energies = bgrate.GetXaxis() + nbins_eng = energies.GetNbins() + for i in range(nbins_eng): + + # Get logE and background rate per squared degree + logE = energies.GetBinCenter(i+1) + bgd = bgrate.GetBinContent(i+1,1) + bgdsq = bgratesqdeg.GetBinContent(i+1,1) + area = aeff.GetBinContent(i+1,1) + area80 = aeff80.GetBinContent(i+1,1) + r68 = angres.GetBinContent(i+1,1) + r80 = angres80.GetBinContent(i+1,1) + dE = eres.GetBinContent(i+1,1) + diffs = sens.GetBinContent(i+1,1) + + # Skip any NaNs + if math.isnan(area80): + continue - # Compute energy (in MeV) - energy = math.pow(10.0, logE)*1.0e6 - emin = math.pow(10.0, logE-0.1)*1.0e6 - emax = math.pow(10.0, logE+0.1)*1.0e6 - ewidth = emax-emin - - # Convert into background rate per steradian and MeV - bkg_rate = bgdsq / (0.01745329*0.01745329) / ewidth - - # Compute control background rate (this only works for KB files - # as they are for 80% containment radius). But we don't use this - # anyways, it's just for control on display ... - omega = 2.0 * math.pi * (1.0 - math.cos(math.radians(r80))) - if omega > 0.0: - bkg_rate2 = bgd / omega / ewidth - else: - bkg_rate2 = 0.0 - - # Compute full effective area by dividing area80/0.80 - area = area80/0.80 + # Compute energy (in MeV) + energy = math.pow(10.0, logE)*1.0e6 + emin = math.pow(10.0, logE-0.1)*1.0e6 + emax = math.pow(10.0, logE+0.1)*1.0e6 + ewidth = emax-emin + + # Convert into background rate per steradian and MeV + bkg_rate = bgdsq / (0.01745329*0.01745329) / ewidth + + # Compute control background rate (this only works for KB files + # as they are for 80% containment radius). But we don't use this + # anyways, it's just for control on display ... + omega = 2.0 * math.pi * (1.0 - math.cos(math.radians(r80))) + if omega > 0.0: + bkg_rate2 = bgd / omega / ewidth + else: + bkg_rate2 = 0.0 + + # Compute full effective area by dividing area80/0.80 + area = area80/0.80 - # Write results in file - line = "%.1f %.1f %.4f %.4f %.4f %.5e %.5e" % \ - (logE, area, r68, r80, dE, bgd, diffs) - fprf.write(line+"\n") - fbkg.write(str(energy)+" "+str(bkg_rate)+"\n") + # Write results in file + line = "%.1f %.1f %.4f %.4f %.4f %.5e %.5e" % \ + (logE, area, r68, r80, dE, bgd, diffs) + fprf.write(line+"\n") + fbkg.write(str(energy)+" "+str(bkg_rate)+"\n") - # Show performance file - #print "%.1f %.1f %.1f %.4f %.4f %.4f %.7f %.5e %.5e %.5e (%.5e)" % \ - # (logE, area, area80, r68, r80, dE, bgd, diffs, bgdsq, bkg_rate, bkg_rate2) + # Show performance file + #print "%.1f %.1f %.1f %.4f %.4f %.4f %.7f %.5e %.5e %.5e (%.5e)" % \ + # (logE, area, area80, r68, r80, dE, bgd, diffs, bgdsq, bkg_rate, bkg_rate2) - # Write trailer - fprf.write("---------------------------------------------\n") - fprf.write("Notes\n") - fprf.write(" 1) log(E) = log10(E/TeV) - bin centre\n") - fprf.write(" 2) Eff Area - in square metres after background cut (no theta cut)\n") - fprf.write(" 3) Ang. Res - 68% containment radius of gamma-ray PSF post cuts - in degrees\n") - fprf.write(" 4) Ang. Res - 80% containment radius of gamma-ray PSF post cuts - in degrees\n") - fprf.write(" 5) Fractional Energy Resolution (rms)\n") - fprf.write(" 6) BG Rate - inside point-source selection region - post call cuts - in Hz\n") - fprf.write(" 7) Diff Sens - differential sensitivity for this bin expressed as E^2 dN/dE\n") - fprf.write(" - in erg cm^-2 s^-1 - for a 50 hours exposure - 5 sigma significance including\n") - fprf.write(" systematics and statistics and at least 10 photons.\n") + # Write trailer + fprf.write("---------------------------------------------\n") + fprf.write("Notes\n") + fprf.write(" 1) log(E) = log10(E/TeV) - bin centre\n") + fprf.write(" 2) Eff Area - in square metres after background cut (no theta cut)\n") + fprf.write(" 3) Ang. Res - 68% containment radius of gamma-ray PSF post cuts - in degrees\n") + fprf.write(" 4) Ang. Res - 80% containment radius of gamma-ray PSF post cuts - in degrees\n") + fprf.write(" 5) Fractional Energy Resolution (rms)\n") + fprf.write(" 6) BG Rate - inside point-source selection region - post call cuts - in Hz\n") + fprf.write(" 7) Diff Sens - differential sensitivity for this bin expressed as E^2 dN/dE\n") + fprf.write(" - in erg cm^-2 s^-1 - for a 50 hours exposure - 5 sigma significance including\n") + fprf.write(" systematics and statistics and at least 10 photons.\n") - # Close files - fprf.close() - fbkg.close() + # Close files + fprf.close() + fbkg.close() - # Return - return + # Return + return #==========================# # Main routine entry point # #==========================# if __name__ == '__main__': - """ - """ - # Get ROOT filename from command line argument - if (len(sys.argv) > 1): - filename = sys.argv[1] - else: - #caldb = "/Users/jurgen/Documents/Travail/Projects/CTA/WP-MC/root/IFAEPerformanceBCE_Nov2010" - #caldb = "/Users/jurgen/Documents/Travail/Projects/CTA/WP-MC/root/Kb_subarrays_root" - caldb = "/Users/jurgen/Documents/Travail/Projects/CTA/WP-MC/root/Kb_all_50deg_root" + """ + """ + # Get ROOT filename from command line argument + if (len(sys.argv) > 1): + filename = sys.argv[1] + else: + #caldb = "/Users/jurgen/Documents/Travail/Projects/CTA/WP-MC/root/IFAEPerformanceBCE_Nov2010" + #caldb = "/Users/jurgen/Documents/Travail/Projects/CTA/WP-MC/root/Kb_subarrays_root" + caldb = "/Users/jurgen/Documents/Travail/Projects/CTA/WP-MC/root/Kb_all_50deg_root" - # Get list of all performance files - files = glob.glob(caldb+"/*.root") - files.sort() - - # Loop over all files - for file in files: - - # Get filename - head, tail = os.path.split(file) - - # Build name - name = tail.strip(".root") - if name.find("kb_") != -1: - name = name.replace("_20deg", "") - elif name.find("IFAE_") != -1: - name = name.replace("Subarray", "") - name = name.replace("IFAE_", "") - name = "IFAE_"+name - i = name.find("hours") - if i != -1: - name = name[0:i+1] - - # Build output filenames - prfname = name + ".dat" - bkgname = "bkg_"+name+".txt" - #print prfname, bkgname + # Get list of all performance files + files = glob.glob(caldb+"/*.root") + files.sort() + + # Loop over all files + for file in files: + + # Get filename + head, tail = os.path.split(file) + + # Build name + name = tail.strip(".root") + if name.find("kb_") != -1: + name = name.replace("_20deg", "") + elif name.find("IFAE_") != -1: + name = name.replace("Subarray", "") + name = name.replace("IFAE_", "") + name = "IFAE_"+name + i = name.find("hours") + if i != -1: + name = name[0:i+1] + + # Build output filenames + prfname = name + ".dat" + bkgname = "bkg_"+name+".txt" + #print prfname, bkgname - # Create files - make_files(file, prfname, bkgname) + # Create files + make_files(file, prfname, bkgname) diff --git a/src/ctlike/ctlike.cpp b/src/ctlike/ctlike.cpp index d003648..f9e3dff 100644 --- a/src/ctlike/ctlike.cpp +++ b/src/ctlike/ctlike.cpp @@ -356,15 +356,18 @@ void ctlike::get_parameters(void) // Get event file name std::string filename = (*this)["infile"].filename(); - // Try first to open as unbinned FITS file + // Try first to open as FITS file try { // Determine whether FITS file has EVENTS extension + /* GFits fits(filename); bool is_unbinned = fits.contains("EVENTS"); fits.close(); + */ // If FITS file has an events header then load as unbinned + /* if (is_unbinned) { obs.load_unbinned(filename); } @@ -373,8 +376,12 @@ void ctlike::get_parameters(void) else { obs.load_binned(filename); } + */ - // Get task parameters for event file loading + // Load data + obs.load(filename); + + // Get other task parameters m_stat = gammalib::toupper((*this)["stat"].string()); m_caldb = (*this)["caldb"].string(); m_irf = (*this)["irf"].string(); @@ -408,7 +415,45 @@ void ctlike::get_parameters(void) // Load observations from XML file m_obs.load(filename); - } + // Check if all observations have response information. If + // not, get the calibration database parameters and set + // the response properly + bool asked_for_response = false; + for (int i = 0; i < m_obs.size(); ++i) { + + // Get CTA observation + GCTAObservation* obs = dynamic_cast(m_obs[i]); + + // Continue only if observation is a CTA observation + if (obs != NULL) { + + // If there is no effective area information then + // set response from task parameters + if (obs->response().aeff() == NULL) { + + // Get calibration parameters + if (!asked_for_response) { + m_caldb = (*this)["caldb"].string(); + m_irf = (*this)["irf"].string(); + asked_for_response = true; + } + + // Set response + GCaldb caldb; + if (gammalib::dir_exists(m_caldb)) { + caldb.rootdir(m_caldb); + } + else { + caldb.open("cta", m_caldb); + } + obs->response(m_irf, caldb); + + } // endif: there was no response + } // endif: observation was a CTA observation + + } // endfor: looped over observations + + } // endcatch: file was an XML file } // endif: there was no observation in the container diff --git a/src/ctlike/ctlike.par b/src/ctlike/ctlike.par index 85d939b..cdaf144 100644 --- a/src/ctlike/ctlike.par +++ b/src/ctlike/ctlike.par @@ -17,14 +17,13 @@ # # General parameters #=================== -infile, f, a, "events.fits",,,"Event list, counts map or observation definition file" +infile, f, a, "events.fits",,, "Event list, counts map or observation definition file" stat, s, h, "POISSON",,, "Optimization statistics" refit, b, h, no,,, "Do refitting?" -edisp, b, h, no,,, "Apply energy dispersion?" -caldb, s, a, "$CTOOLS/share/caldb/data/cta/dummy",,, "Calibration database" +caldb, s, a, "dummy",,, "Calibration database" irf, s, a, "cta_dummy_irf",,, "Instrument response function" srcmdl, f, a, "$CTOOLS/share/models/crab.xml",,, "Source model" -outmdl, f, a, "crab_results.xml",,, "Source model output file" +outmdl, f, a, "crab_results.xml",,, "Source model output file" # # Standard parameters #==================== diff --git a/src/ctobssim/ctobssim.par b/src/ctobssim/ctobssim.par index c246ccf..19e9e49 100644 --- a/src/ctobssim/ctobssim.par +++ b/src/ctobssim/ctobssim.par @@ -18,12 +18,12 @@ # File information #================= infile, f, a, "$CTOOLS/share/models/crab.xml",,, "Model" -outfile,f, a, "events.fits",,, "Output event data file or observation definition file" -prefix, s, h, "sim_events_",,, "Prefix for event lists in observation definition file" +outfile,f, a, "events.fits",,, "Output event data file or observation definition file" +prefix, s, h, "sim_events_",,, "Prefix for event lists in observation definition file" # # Observation parameters #======================= -caldb, s, a, "$CTOOLS/share/caldb/data/cta/dummy",,, "Calibration database" +caldb, s, a, "dummy",,, "Calibration database" irf, s, a, "cta_dummy_irf",,, "Instrument response function" # # Simulation parameters @@ -31,7 +31,7 @@ irf, s, a, "cta_dummy_irf",,, "Instrument response function" seed, i, h, 1, , , "Random number generator seed" ra, r, a, 83.63, 0,360, "RA of pointing (degrees)" dec, r, a, 22.01, -90, 90, "Dec of pointing (degrees)" -rad, r, a, 10.0, 0,180, "Radius of FOV (degrees)" +rad, r, a, 5.0, 0,180, "Radius of FOV (degrees)" tmin, r, a, 0.0, 0, , "Start time (MET in s)" tmax, r, a, 1800.0, 0, , "End time (MET in s)" emin, r, a, 0.1, 0, , "Lower energy limit (TeV)"