Commit b930a2584089305409164fa136c1c4f0dc1c1ca6

Authored by Jürgen Knödlseder
2 parents 91a3d3f5 d5049a1a

Merge branch 'hess' into devel

Conflicts:
	.gitignore
	ChangeLog
.gitignore
@@ -22,9 +22,13 @@ ltmain.sh @@ -22,9 +22,13 @@ ltmain.sh
22 m4 22 m4
23 missing 23 missing
24 .libs 24 .libs
  25 +.deps
25 stamp-h1 26 stamp-h1
  27 +depcomp
26 28
  29 +src/ctools-setup
27 pyext/build/ 30 pyext/build/
  31 +pyext/setup.py
28 pyext/ctools.py 32 pyext/ctools.py
29 pyext/ctools_wrap.cpp 33 pyext/ctools_wrap.cpp
30 src/ctbin/ctbin 34 src/ctbin/ctbin
@@ -34,3 +38,7 @@ src/ctobssim/ctobssim @@ -34,3 +38,7 @@ src/ctobssim/ctobssim
34 src/ctselect/ctselect 38 src/ctselect/ctselect
35 src/ctskymap/ctskymap 39 src/ctskymap/ctskymap
36 test/pfiles/ 40 test/pfiles/
  41 +test/*.fits
  42 +test/*.dat
  43 +test/*.xml
  44 +test/test_cscripts.sh
1 Juergen Knoedlseder (jurgen.knodlseder@irap.omp.eu) - overall design 1 Juergen Knoedlseder (jurgen.knodlseder@irap.omp.eu) - overall design
2 Jean-Baptiste Cayrou (cayrou@etud.insa-toulouse.fr) - openmp support 2 Jean-Baptiste Cayrou (cayrou@etud.insa-toulouse.fr) - openmp support
  3 +Christoph Deil (Christoph.Deil@mpi-hd.mpg.de) - HESS support
  4 +Mathieu De Naurois (denauroi@in2p3.fr) - HESS support
3 5
ChangeLog
  1 +2012-12-05 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
  2 +
  3 + * Version 0.6.0 released
  4 + ========================
  5 +
  6 + Add ctmodel tool
  7 + Adapt to GammaLib-00-07-00 interface
  8 +
1 2012-10-11 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu> 9 2012-10-11 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
2 10
3 * Bug fix version 0.5.2 released 11 * Bug fix version 0.5.2 released
configure.ac
@@ -32,7 +32,8 @@ @@ -32,7 +32,8 @@
32 AC_INIT([ctools], [0.6.0], [jurgen.knodlseder@irap.omp.eu], [ctools]) 32 AC_INIT([ctools], [0.6.0], [jurgen.knodlseder@irap.omp.eu], [ctools])
33 AC_CONFIG_SRCDIR([src/ctselect/ctselect.cpp]) 33 AC_CONFIG_SRCDIR([src/ctselect/ctselect.cpp])
34 AC_CONFIG_MACRO_DIR([m4]) 34 AC_CONFIG_MACRO_DIR([m4])
35 -AM_INIT_AUTOMAKE([gnu no-dependencies]) 35 +#AM_INIT_AUTOMAKE([gnu no-dependencies])
  36 +AM_INIT_AUTOMAKE([gnu])
36 AM_CONFIG_HEADER([config.h]) 37 AM_CONFIG_HEADER([config.h])
37 38
38 39
@@ -870,11 +871,12 @@ AC_SUBST(LIB_LINK_OPTION) @@ -870,11 +871,12 @@ AC_SUBST(LIB_LINK_OPTION)
870 ############################################################################# 871 #############################################################################
871 AC_CONFIG_FILES([Makefile 872 AC_CONFIG_FILES([Makefile
872 src/Makefile 873 src/Makefile
873 - src/ctselect/Makefile  
874 src/ctbin/Makefile 874 src/ctbin/Makefile
875 src/ctlike/Makefile 875 src/ctlike/Makefile
  876 + src/ctmodel/Makefile
876 src/ctobssim/Makefile 877 src/ctobssim/Makefile
877 src/ctskymap/Makefile 878 src/ctskymap/Makefile
  879 + src/ctselect/Makefile
878 src/ctools-setup 880 src/ctools-setup
879 test/Makefile 881 test/Makefile
880 test/test_cscripts.sh 882 test/test_cscripts.sh
pyext/ctmodel.i 0 → 100644
  1 +/***************************************************************************
  2 + * ctmodel - CTA counts model tool *
  3 + * ----------------------------------------------------------------------- *
  4 + * copyright (C) 2012 by Juergen Knoedlseder *
  5 + * ----------------------------------------------------------------------- *
  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 +/**
  22 + * @file ctmodel.i
  23 + * @brief CTA counts model tool definition
  24 + * @author Juergen Knoedlseder
  25 + */
  26 +%{
  27 +/* Put headers and other declarations here that are needed for compilation */
  28 +#include "ctmodel.hpp"
  29 +#include "GTools.hpp"
  30 +%}
  31 +
  32 +
  33 +/***********************************************************************//**
  34 + * @class ctmodel
  35 + *
  36 + * @brief CTA counts model tool interface defintion
  37 + ***************************************************************************/
  38 +class ctmodel : public GApplication {
  39 +
  40 +public:
  41 + // Constructors and destructors
  42 + ctmodel(void);
  43 + explicit ctmodel(GObservations obs);
  44 + ctmodel(int argc, char *argv[]);
  45 + ctmodel(const ctmodel& app);
  46 + virtual ~ctmodel(void);
  47 +
  48 + // Methods
  49 + void clear(void);
  50 + void execute(void);
  51 + void run(void);
  52 + void save(void);
  53 + GObservations& obs(void) { return m_obs; }
  54 + void get_parameters(void);
  55 + void setup_obs(void);
  56 + void model_map(GCTAObservation* obs, const GModels& models);
  57 +};
  58 +
  59 +
  60 +/***********************************************************************//**
  61 + * @brief CTA counts model tool Python extension
  62 + ***************************************************************************/
  63 +%extend ctmodel {
  64 + ctmodel copy() {
  65 + return (*self);
  66 + }
  67 +}
pyext/ctools.i
1 /*************************************************************************** 1 /***************************************************************************
2 * ctools - SWIG file * 2 * ctools - SWIG file *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2010-2011 by Jurgen Knodlseder * 4 + * copyright (C) 2010-2012 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -21,6 +21,11 @@ @@ -21,6 +21,11 @@
21 * Usage: * 21 * Usage: *
22 * swig -c++ -python -Wall ctools.i * 22 * swig -c++ -python -Wall ctools.i *
23 ***************************************************************************/ 23 ***************************************************************************/
  24 +/**
  25 + * @file ctools.i
  26 + * @brief ctools SWIG file
  27 + * @author Juergen Knoedlseder
  28 + */
24 %module ctools 29 %module ctools
25 %feature("autodoc", "1"); 30 %feature("autodoc", "1");
26 31
@@ -31,10 +36,12 @@ @@ -31,10 +36,12 @@
31 %import(module="gammalib.support") "GException.i"; 36 %import(module="gammalib.support") "GException.i";
32 37
33 /* __ Inform about base classes __________________________________________ */ 38 /* __ Inform about base classes __________________________________________ */
34 -%import(module="gammalib.app") "GApplication.i"; 39 +%import(module="gammalib.base") "GBase.i";
  40 +%import(module="gammalib.app") "GApplication.i";
35 41
36 -/* __ CTA tools __________________________________________________________ */  
37 -%include "ctobssim.i"  
38 -%include "ctselect.i" 42 +/* __ ctools _____________________________________________________________ */
39 %include "ctbin.i" 43 %include "ctbin.i"
  44 +%include "ctobssim.i"
40 %include "ctlike.i" 45 %include "ctlike.i"
  46 +%include "ctmodel.i"
  47 +%include "ctselect.i"
scripts/cta_root2caldb.py
@@ -2,11 +2,9 @@ @@ -2,11 +2,9 @@
2 # ========================================================================== 2 # ==========================================================================
3 # This script generates IRFs in the CALDB format of HEASARC using ROOT 2D 3 # This script generates IRFs in the CALDB format of HEASARC using ROOT 2D
4 # performance files. 4 # performance files.
5 -#  
6 -# Requirements:  
7 -# - pyroot  
8 -#  
9 -# Copyright (C) 2011 Jurgen Knodlseder 5 +# -------------------------------------------------------------------------
  6 +# Copyright (C) 2011-2012 Juergen Knoedlseder
  7 +# -------------------------------------------------------------------------
10 # 8 #
11 # This program is free software: you can redistribute it and/or modify 9 # This program is free software: you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by 10 # it under the terms of the GNU General Public License as published by
@@ -21,6 +19,10 @@ @@ -21,6 +19,10 @@
21 # You should have received a copy of the GNU General Public License 19 # You should have received a copy of the GNU General Public License
22 # along with this program. If not, see <http://www.gnu.org/licenses/>. 20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
23 # 21 #
  22 +# -------------------------------------------------------------------------
  23 +# Requirements:
  24 +# - gammalib
  25 +# - pyroot
24 # ========================================================================== 26 # ==========================================================================
25 from ROOT import TFile, TH1F, TH2F 27 from ROOT import TFile, TH1F, TH2F
26 from gammalib import * 28 from gammalib import *
@@ -37,18 +39,27 @@ import os @@ -37,18 +39,27 @@ import os
37 class caldb(): 39 class caldb():
38 """ 40 """
39 """ 41 """
40 - def __init__(self, conf, path=""): 42 + def __init__(self, inst, obsid, path=""):
41 """ 43 """
42 - Constructor. 44 + CALDB constructor. The constructor will create one CALDB entry for
  45 + an observation.
  46 +
  47 + Parameters:
  48 + inst - Instrument string.
  49 + obsid - Observation ID string.
  50 + Keywords:
  51 + path - CALDB Root path.
43 """ 52 """
44 # Store root path 53 # Store root path
45 self.path = path 54 self.path = path
46 55
47 # Initialise some members 56 # Initialise some members
48 self.cif = None 57 self.cif = None
  58 + self.irf = None
49 self.ea = None 59 self.ea = None
50 self.psf = None 60 self.psf = None
51 self.edisp = None 61 self.edisp = None
  62 + self.bgd = None
52 self.hdu_cif = None 63 self.hdu_cif = None
53 64
54 # Store UTC date of job execution 65 # Store UTC date of job execution
@@ -56,7 +67,8 @@ class caldb(): @@ -56,7 +67,8 @@ class caldb():
56 67
57 # Set CALDB information 68 # Set CALDB information
58 self.cal_tel = "CTA" 69 self.cal_tel = "CTA"
59 - self.cal_inst = conf.upper() 70 + self.cal_inst = inst.upper()
  71 + self.cal_obsid = obsid
60 self.cal_det = "NONE" 72 self.cal_det = "NONE"
61 self.cal_flt = "NONE" 73 self.cal_flt = "NONE"
62 self.cal_class = "BCF" 74 self.cal_class = "BCF"
@@ -84,6 +96,11 @@ class caldb(): @@ -84,6 +96,11 @@ class caldb():
84 self.edisp_doc = "???" 96 self.edisp_doc = "???"
85 self.edisp_bounds = [self.cal_version, self.cal_cut, self.cal_analysis] 97 self.edisp_bounds = [self.cal_version, self.cal_cut, self.cal_analysis]
86 self.edisp_desc = "CTA energy dispersion" 98 self.edisp_desc = "CTA energy dispersion"
  99 + #
  100 + self.bgd_name = "BGD"
  101 + self.bgd_doc = "???"
  102 + self.bgd_bounds = [self.cal_version, self.cal_cut, self.cal_analysis]
  103 + self.bgd_desc = "CTA background"
87 104
88 # Create directory structure 105 # Create directory structure
89 self.make_dirs() 106 self.make_dirs()
@@ -93,6 +110,7 @@ class caldb(): @@ -93,6 +110,7 @@ class caldb():
93 110
94 def __del__(self): 111 def __del__(self):
95 """ 112 """
  113 + Destructor. Close all FITS files.
96 """ 114 """
97 # Close calibration 115 # Close calibration
98 self.close() 116 self.close()
@@ -102,32 +120,50 @@ class caldb(): @@ -102,32 +120,50 @@ class caldb():
102 120
103 def make_dirs(self): 121 def make_dirs(self):
104 """ 122 """
  123 + Generate CALDB directory structure for one observation identifier.
  124 + The structure is given by
  125 +
  126 + data/<tel>/<inst>/bcf/<obsid>
  127 +
  128 + where <tel> is "cta" and <inst> is the instrument specified in the
  129 + CALDB constructor (the instrument may be used for different array
  130 + configurations).
  131 +
  132 + Parameters:
  133 + None
  134 + Keywords:
  135 + None
105 """ 136 """
106 # Set base path 137 # Set base path
107 self.base_dir = "data" 138 self.base_dir = "data"
108 self.base_dir += "/"+self.cal_tel.lower() 139 self.base_dir += "/"+self.cal_tel.lower()
109 self.base_dir += "/"+self.cal_inst.lower() 140 self.base_dir += "/"+self.cal_inst.lower()
110 141
111 -  
112 # Set directory names 142 # Set directory names
113 self.bcf_dir = self.base_dir+"/bcf" 143 self.bcf_dir = self.base_dir+"/bcf"
114 - self.ea_dir = self.bcf_dir+"/ea"  
115 - self.psf_dir = self.bcf_dir+"/psf"  
116 - self.edisp_dir = self.bcf_dir+"/edisp" 144 + self.obs_dir = self.bcf_dir+"/"+self.cal_obsid
  145 + self.ea_dir = self.obs_dir
  146 + self.psf_dir = self.obs_dir
  147 + self.edisp_dir = self.obs_dir
  148 + self.bgd_dir = self.obs_dir
117 149
118 - # Add path (if required) 150 + # Optionally prefix path
119 if len(self.path) > 0: 151 if len(self.path) > 0:
120 self.base_path = self.path+"/"+self.base_dir 152 self.base_path = self.path+"/"+self.base_dir
121 self.bcf_path = self.path+"/"+self.bcf_dir 153 self.bcf_path = self.path+"/"+self.bcf_dir
  154 + self.obs_path = self.path+"/"+self.obs_dir
122 self.ea_path = self.path+"/"+self.ea_dir 155 self.ea_path = self.path+"/"+self.ea_dir
123 self.psf_path = self.path+"/"+self.psf_dir 156 self.psf_path = self.path+"/"+self.psf_dir
124 self.edisp_path = self.path+"/"+self.edisp_dir 157 self.edisp_path = self.path+"/"+self.edisp_dir
  158 + self.bgd_path = self.path+"/"+self.bgd_dir
125 else: 159 else:
126 self.base_path = self.base_dir 160 self.base_path = self.base_dir
127 self.bcf_path = self.bcf_dir 161 self.bcf_path = self.bcf_dir
  162 + self.obs_path = self.obs_dir
128 self.ea_path = self.ea_dir 163 self.ea_path = self.ea_dir
129 self.psf_path = self.psf_dir 164 self.psf_path = self.psf_dir
130 self.edisp_path = self.edisp_dir 165 self.edisp_path = self.edisp_dir
  166 + self.bgd_path = self.bgd_dir
131 167
132 # Create directory structure 168 # Create directory structure
133 if not os.path.isdir(self.ea_path): 169 if not os.path.isdir(self.ea_path):
@@ -136,18 +172,36 @@ class caldb(): @@ -136,18 +172,36 @@ class caldb():
136 os.makedirs(self.psf_path) 172 os.makedirs(self.psf_path)
137 if not os.path.isdir(self.edisp_path): 173 if not os.path.isdir(self.edisp_path):
138 os.makedirs(self.edisp_path) 174 os.makedirs(self.edisp_path)
  175 + if not os.path.isdir(self.bgd_path):
  176 + os.makedirs(self.bgd_path)
139 177
140 # Return 178 # Return
141 return 179 return
142 180
143 - def open(self, name, clobber=True): 181 + def open(self, version, split=False, clobber=True):
144 """ 182 """
145 - Open existing or create new calibration. 183 + Open existing or create new calibration. The actual version will put
  184 + all calibrations in the same file, although each part of the response
  185 + function will have its own logical name. We can thus easily modify
  186 + the script to put each calibration information in a separate file.
  187 +
  188 + Parameters:
  189 + version - Filename version
  190 + Keywords:
  191 + split - Split IRF over several files?
  192 + clobber - Overwrite existing files?
146 """ 193 """
147 # Set calibrate file names 194 # Set calibrate file names
148 - self.ea_file = "ea_"+name+".fits"  
149 - self.psf_file = "psf_"+name+".fits"  
150 - self.edisp_file = "edisp_"+name+".fits" 195 + if split:
  196 + self.ea_file = "ea_"+version+".fits"
  197 + self.psf_file = "psf_"+version+".fits"
  198 + self.edisp_file = "edisp_"+version+".fits"
  199 + self.bgd_file = "bgd_"+version+".fits"
  200 + else:
  201 + self.ea_file = "irf_"+version+".fits"
  202 + self.psf_file = "irf_"+version+".fits"
  203 + self.edisp_file = "irf_"+version+".fits"
  204 + self.bgd_file = "irf_"+version+".fits"
151 205
152 # Open calibration database index 206 # Open calibration database index
153 self.cif = GFits(self.base_path+"/caldb.indx", True) 207 self.cif = GFits(self.base_path+"/caldb.indx", True)
@@ -159,17 +213,42 @@ class caldb(): @@ -159,17 +213,42 @@ class caldb():
159 self.create_cif() 213 self.create_cif()
160 self.hdu_cif = self.cif.table("CIF") 214 self.hdu_cif = self.cif.table("CIF")
161 215
162 - # Open calibration files  
163 - self.open_ea(self.ea_path+"/"+self.ea_file)  
164 - self.open_psf(self.psf_path+"/"+self.psf_file)  
165 - self.open_edisp(self.edisp_path+"/"+self.edisp_file) 216 + # Set filenames
  217 + ea_filename = self.ea_path+"/"+self.ea_file
  218 + psf_filename = self.psf_path+"/"+self.psf_file
  219 + edisp_filename = self.edisp_path+"/"+self.edisp_file
  220 + bgd_filename = self.bgd_path+"/"+self.bgd_file
  221 +
  222 + # Open files
  223 + if split:
  224 + self.ea = GFits(ea_filename, True)
  225 + self.psf = GFits(psf_filename, True)
  226 + self.edisp = GFits(edisp_filename, True)
  227 + self.bgd = GFits(bgd_filename, True)
  228 + else:
  229 + self.irf = GFits(ea_filename, True)
  230 + self.ea = self.irf
  231 + self.psf = self.irf
  232 + self.edisp = self.irf
  233 + self.bgd = self.irf
  234 +
  235 + # Open HDUs
  236 + self.open_ea()
  237 + self.open_psf()
  238 + self.open_edisp()
  239 + self.open_bgd()
166 240
167 # Return 241 # Return
168 return 242 return
169 243
170 def close(self): 244 def close(self):
171 """ 245 """
172 - Close calibration. 246 + Close calibration FITS files.
  247 +
  248 + Parameters:
  249 + None
  250 + Keywords:
  251 + None
173 """ 252 """
174 # Add information to CIF. We do this now as before we did not 253 # Add information to CIF. We do this now as before we did not
175 # necessarily have all the information at hand (in particular 254 # necessarily have all the information at hand (in particular
@@ -181,31 +260,57 @@ class caldb(): @@ -181,31 +260,57 @@ class caldb():
181 self.cif.save(True) 260 self.cif.save(True)
182 self.cif.close() 261 self.cif.close()
183 self.cif = None 262 self.cif = None
184 -  
185 - # Close effective area  
186 - if self.ea != None:  
187 - self.ea.save(True)  
188 - self.ea.close()  
189 - self.ea = None  
190 -  
191 - # Close point spread function  
192 - if self.psf != None:  
193 - self.psf.save(True)  
194 - self.psf.close()  
195 - self.psf = None  
196 -  
197 - # Close energy dispersion  
198 - if self.edisp != None:  
199 - self.edisp.save(True)  
200 - self.edisp.close() 263 +
  264 + # If IRF file exists then close it now. All file pointers will
  265 + # be set to None
  266 + if self.irf != None:
  267 + self.irf.save(True)
  268 + self.irf.close()
  269 + self.irf = None
  270 + self.ea = None
  271 + self.psf = None
201 self.edisp = None 272 self.edisp = None
  273 + self.bgd = None
  274 +
  275 + # ... otherwise we have split files, so we have to close them
  276 + # all
  277 + else:
  278 +
  279 + # Close effective area file
  280 + if self.ea != None:
  281 + self.ea.save(True)
  282 + self.ea.close()
  283 + self.ea = None
  284 +
  285 + # Close point spread function file
  286 + if self.psf != None:
  287 + self.psf.save(True)
  288 + self.psf.close()
  289 + self.psf = None
  290 +
  291 + # Close energy dispersion file
  292 + if self.edisp != None:
  293 + self.edisp.save(True)
  294 + self.edisp.close()
  295 + self.edisp = None
  296 +
  297 + # Close background file
  298 + if self.bgd != None:
  299 + self.bgd.save(True)
  300 + self.bgd.close()
  301 + self.bgd = None
202 302
203 # Return 303 # Return
204 return 304 return
205 305
206 def create_cif(self): 306 def create_cif(self):
207 """ 307 """
208 - Create CIF extension in FITS file. 308 + Create Calibration Index File (CIF) extension in CIF FITS file.
  309 +
  310 + Parameters:
  311 + None
  312 + Keywords:
  313 + None
209 """ 314 """
210 # Create binary table 315 # Create binary table
211 table = GFitsBinTable() 316 table = GFitsBinTable()
@@ -248,6 +353,11 @@ class caldb(): @@ -248,6 +353,11 @@ class caldb():
248 def add_cif_info(self): 353 def add_cif_info(self):
249 """ 354 """
250 Add information to CIF extension. 355 Add information to CIF extension.
  356 +
  357 + Parameters:
  358 + None
  359 + Keywords:
  360 + None
251 """ 361 """
252 # Append 3 rows to CIF extension 362 # Append 3 rows to CIF extension
253 self.hdu_cif.append_rows(3) 363 self.hdu_cif.append_rows(3)
@@ -310,20 +420,35 @@ class caldb(): @@ -310,20 +420,35 @@ class caldb():
310 self.hdu_cif["CAL_CBD"][row, n] = "NONE" 420 self.hdu_cif["CAL_CBD"][row, n] = "NONE"
311 else: 421 else:
312 self.hdu_cif["CAL_CBD"][row, n] = self.edisp_bounds[n] 422 self.hdu_cif["CAL_CBD"][row, n] = self.edisp_bounds[n]
  423 +
  424 + # Add background information
  425 + row = self.hdu_cif.nrows()-1
  426 + self.hdu_cif["CAL_DIR"][row] = self.bgd_dir
  427 + self.hdu_cif["CAL_FILE"][row] = self.bgd_file
  428 + self.hdu_cif["CAL_CNAM"][row] = self.bgd_name
  429 + self.hdu_cif["CAL_DESC"][row] = self.bgd_desc
  430 + self.hdu_cif["CAL_XNO"][row] = 1
  431 + for n in range(9):
  432 + if n >= len(self.bgd_bounds):
  433 + self.hdu_cif["CAL_CBD"][row, n] = "NONE"
  434 + else:
  435 + self.hdu_cif["CAL_CBD"][row, n] = self.bgd_bounds[n]
313 436
314 # Return 437 # Return
315 return 438 return
316 439
317 - def open_ea(self, filename): 440 + def open_ea(self):
318 """ 441 """
319 Open effective area extension. If no extension was found 442 Open effective area extension. If no extension was found
320 then create one. We do not yet set any data as we don't 443 then create one. We do not yet set any data as we don't
321 know the dimensions of the table yet. 444 know the dimensions of the table yet.
322 - """  
323 - # Open FITS file  
324 - self.ea = GFits(filename, True)  
325 445
326 - # Get extensions. If they do not exist then create them now 446 + Parameters:
  447 + None
  448 + Keywords:
  449 + None
  450 + """
  451 + # Get extension. If it does not exist then create it now.
327 try: 452 try:
328 self.hdu_ea = self.ea.table("EFFECTIVE AREA") 453 self.hdu_ea = self.ea.table("EFFECTIVE AREA")
329 except: 454 except:
@@ -346,16 +471,18 @@ class caldb(): @@ -346,16 +471,18 @@ class caldb():
346 # Return 471 # Return
347 return 472 return
348 473
349 - def open_psf(self, filename): 474 + def open_psf(self):
350 """ 475 """
351 Open point spread function extension. If no extension was 476 Open point spread function extension. If no extension was
352 found then create one. We do not yet set any data as we don't 477 found then create one. We do not yet set any data as we don't
353 know the dimensions of the table yet. 478 know the dimensions of the table yet.
354 - """  
355 - # Open FITS file  
356 - self.psf = GFits(filename, True)  
357 479
358 - # Get extensions. If they do not exist then create them now 480 + Parameters:
  481 + None
  482 + Keywords:
  483 + None
  484 + """
  485 + # Get extension. If it does not exist then create it now.
359 try: 486 try:
360 self.hdu_psf = self.psf.table("POINT SPREAD FUNCTION") 487 self.hdu_psf = self.psf.table("POINT SPREAD FUNCTION")
361 except: 488 except:
@@ -378,16 +505,18 @@ class caldb(): @@ -378,16 +505,18 @@ class caldb():
378 # Return 505 # Return
379 return 506 return
380 507
381 - def open_edisp(self, filename): 508 + def open_edisp(self):
382 """ 509 """
383 Open energy dispersion extension. If no extension was found 510 Open energy dispersion extension. If no extension was found
384 then create one. We do not yet set any data as we don't 511 then create one. We do not yet set any data as we don't
385 know the dimensions of the table yet. 512 know the dimensions of the table yet.
386 - """  
387 - # Open FITS file  
388 - self.edisp = GFits(filename, True)  
389 513
390 - # Get extensions. If they do not exist then create them now 514 + Parameters:
  515 + None
  516 + Keywords:
  517 + None
  518 + """
  519 + # Get extension. If it does not exist then create it now.
391 try: 520 try:
392 self.hdu_edisp = self.edisp.table("ENERGY DISPERSION") 521 self.hdu_edisp = self.edisp.table("ENERGY DISPERSION")
393 except: 522 except:
@@ -410,9 +539,50 @@ class caldb(): @@ -410,9 +539,50 @@ class caldb():
410 # Return 539 # Return
411 return 540 return
412 541
  542 + def open_bgd(self):
  543 + """
  544 + Open background extension. If no extension was found
  545 + then create one. We do not yet set any data as we don't
  546 + know the dimensions of the table yet.
  547 +
  548 + Parameters:
  549 + None
  550 + Keywords:
  551 + None
  552 + """
  553 + # Get extension. If it does not exist then create it now.
  554 + try:
  555 + self.hdu_bgd = self.bgd.table("BACKGROUND")
  556 + except:
  557 + # Create binary table
  558 + table = GFitsBinTable()
  559 +
  560 + # Set extension name
  561 + table.extname("BACKGROUND")
  562 +
  563 + # Set OGIP keywords
  564 + self.set_ogip_keywords(table, self.bgd_doc, \
  565 + ["RESPONSE", self.bgd_name])
  566 +
  567 + # Append table
  568 + self.bgd.append(table)
  569 +
  570 + # Get extension
  571 + self.hdu_bgd = self.bgd.table("BACKGROUND")
  572 +
  573 + # Return
  574 + return
  575 +
413 def set_ogip_keywords(self, hdu, hdudoc, hduclas): 576 def set_ogip_keywords(self, hdu, hdudoc, hduclas):
414 """ 577 """
415 Set standard OGIP keywords for extension. 578 Set standard OGIP keywords for extension.
  579 +
  580 + Parameters:
  581 + hdu - Header Data Unit.
  582 + hdudoc - Documentation reference string
  583 + hduclas - Array of HDUCLAS fields
  584 + Keywords:
  585 + None
416 """ 586 """
417 # Set keywords 587 # Set keywords
418 hdu.card("ORIGIN", "IRAP", "Name of organization making this file") 588 hdu.card("ORIGIN", "IRAP", "Name of organization making this file")
@@ -433,12 +603,17 @@ class caldb(): @@ -433,12 +603,17 @@ class caldb():
433 def make_2D(self, array, hdu, name, unit, scale=1.0): 603 def make_2D(self, array, hdu, name, unit, scale=1.0):
434 """ 604 """
435 Make 2D matrix as function of energy and offset angle from a 605 Make 2D matrix as function of energy and offset angle from a
436 - ROOT 2D histogram. 606 + ROOT 2D histogram. If the HDU has already the energy and
  607 + offset angle columns, this method will simply add another data
  608 + column.
  609 + If name==None, the method will not append any data column.
437 610
438 Parameters: 611 Parameters:
439 - array - ROOT 2D histgram. 612 + array - ROOT 2D histogram.
440 hdu - FITS HDU. 613 hdu - FITS HDU.
441 - Keyword: 614 + name - Data column name.
  615 + unit - Data unit.
  616 + Keywords:
442 scale - Scaling factor for histogram values. 617 scale - Scaling factor for histogram values.
443 """ 618 """
444 # Extract energy and offset angle vectors 619 # Extract energy and offset angle vectors
@@ -485,7 +660,7 @@ class caldb(): @@ -485,7 +660,7 @@ class caldb():
485 hdu["THETA_HI"][0,ioff] = o_hi 660 hdu["THETA_HI"][0,ioff] = o_hi
486 # 661 #
487 # "NAME" 662 # "NAME"
488 - if not hdu.hascolumn(name): 663 + if name != None and not hdu.hascolumn(name):
489 hdu.append_column(GFitsTableFloatCol(name, 1, neng*noffset)) 664 hdu.append_column(GFitsTableFloatCol(name, 1, neng*noffset))
490 hdu[name].unit(unit) 665 hdu[name].unit(unit)
491 hdu[name].dim([neng, noffset]) 666 hdu[name].dim([neng, noffset])
@@ -515,44 +690,217 @@ class caldb(): @@ -515,44 +690,217 @@ class caldb():
515 Parameters: 690 Parameters:
516 filename - ROOT 2D performance filename. 691 filename - ROOT 2D performance filename.
517 """ 692 """
518 - # Open performance file 693 + # Open ROOT performance file
519 file = TFile(filename) 694 file = TFile(filename)
520 695
521 - # Allocate ROOT 2D array  
522 - array = TH2F() 696 + # Create effective area
  697 + self.root2ea(file)
  698 +
  699 + # Create point spread function
  700 + self.root2psf(file)
  701 +
  702 + # Create energy dispersion
  703 + self.root2edisp(file)
  704 +
  705 + # Create background
  706 + self.root2bgd(file)
  707 +
  708 + # Return
  709 + return
523 710
524 - # Make 2D effective 80% area 711 + def root2ea(self, file):
  712 + """
  713 + Translate ROOT to CALDB effective area extension. The following ROOT
  714 + histograms are used:
  715 +
  716 + EffectiveAreaEtrue_offaxis -> EFFAREA
  717 + EffectiveArea_offaxis -> EFFAREA_RECO
  718 +
  719 + Parameters:
  720 + file - ROOT file.
  721 + Keywords:
  722 + None
  723 + """
  724 + # Continue only if effective area HDU has been opened
525 if self.hdu_ea != None: 725 if self.hdu_ea != None:
526 - file.GetObject("EffectiveArea80_offaxis", array)  
527 - bounds = self.make_2D(array, self.hdu_ea, "EFFAREA", "m2", scale=1.0/0.8) 726 +
  727 + # Allocate ROOT 2D arrays
  728 + etrue = TH2F()
  729 + ereco = TH2F()
  730 + file.GetObject("EffectiveAreaEtrue_offaxis", etrue)
  731 + file.GetObject("EffectiveArea_offaxis", ereco)
  732 + #print etrue.GetXaxis().GetBinLowEdge(1), etrue.GetXaxis().GetBinUpEdge(etrue.GetXaxis().GetNbins())
  733 + #print ereco.GetXaxis().GetBinLowEdge(1), ereco.GetXaxis().GetBinUpEdge(ereco.GetXaxis().GetNbins())
  734 +
  735 + # Rebin etrue histogram
  736 + etrue.RebinX(10)
  737 + neng = etrue.GetXaxis().GetNbins()
  738 + noffset = etrue.GetYaxis().GetNbins()
  739 + for ioff in range(noffset):
  740 + for ieng in range(neng):
  741 + value = etrue.GetBinContent(ieng+1,ioff+1) / 10.0
  742 + etrue.SetBinContent(ieng+1,ioff+1,value)
  743 +
  744 + # Write boundaries (use Ereco boundaries)
  745 + bounds = self.make_2D(ereco, self.hdu_ea, None, "m2")
528 for b in bounds: 746 for b in bounds:
529 self.ea_bounds.append(b) 747 self.ea_bounds.append(b)
530 self.set_cif_keywords(self.hdu_ea, self.ea_name, \ 748 self.set_cif_keywords(self.hdu_ea, self.ea_name, \
531 self.ea_bounds, self.ea_desc) 749 self.ea_bounds, self.ea_desc)
532 750
533 - # Make 2D 68% point spread function 751 + # EFFAREA
  752 + self.make_2D(etrue, self.hdu_ea, "EFFAREA", "m2")
  753 +
  754 + # EFFAREA_RECO
  755 + self.make_2D(ereco, self.hdu_ea, "EFFAREA_RECO", "m2")
  756 +
  757 + # Return
  758 + return
  759 +
  760 + def root2psf(self, file):
  761 + """
  762 + Translate ROOT to CALDB point spread function extension. The following
  763 + ROOT histograms are used:
  764 +
  765 + 1/(2*pi*SIGMA_1) -> SCALE
  766 + AngRes_offaxis -> SIGMA_1 (scaling: 1/0.8)
  767 + 0.0 -> AMPL_2
  768 + 0.0 -> SIGMA_2
  769 + 0.0 -> AMPL_3
  770 + 0.0 -> SIGMA_3
  771 +
  772 + Parameters:
  773 + file - ROOT file.
  774 + Keywords:
  775 + None
  776 + """
  777 + # Continue only if point spread function HDU has been opened
534 if self.hdu_psf != None: 778 if self.hdu_psf != None:
535 - file.GetObject("AngRes_offaxis", array)  
536 - bounds = self.make_2D(array, self.hdu_psf, "R68", "deg") 779 +
  780 + # Allocate ROOT 2D array
  781 + r68 = TH2F()
  782 +
  783 + # Read 68% containment histogram
  784 + file.GetObject("AngRes_offaxis", r68)
  785 + neng = r68.GetXaxis().GetNbins()
  786 + noffset = r68.GetYaxis().GetNbins()
  787 +
  788 + # Compute scale histogram
  789 + scale = r68.Clone()
  790 + for ioff in range(noffset):
  791 + for ieng in range(neng):
  792 + integral = 2.0 * math.pi * r68.GetBinContent(ieng+1,ioff+1)
  793 + if integral > 0.0:
  794 + value = 1.0 / integral
  795 + else:
  796 + value = 0.0
  797 + scale.SetBinContent(ieng+1,ioff+1,value)
  798 +
  799 + # Set zero histogram
  800 + zero = r68.Clone()
  801 + for ioff in range(noffset):
  802 + for ieng in range(neng):
  803 + zero.SetBinContent(ieng+1,ioff+1,0.0)
  804 +
  805 + # Set boundaries
  806 + bounds = self.make_2D(r68, self.hdu_psf, None, "deg")
537 for b in bounds: 807 for b in bounds:
538 self.psf_bounds.append(b) 808 self.psf_bounds.append(b)
539 self.set_cif_keywords(self.hdu_psf, self.psf_name, \ 809 self.set_cif_keywords(self.hdu_psf, self.psf_name, \
540 self.psf_bounds, self.psf_desc) 810 self.psf_bounds, self.psf_desc)
541 811
542 - # Make 2D 80% point spread function  
543 - if self.hdu_psf != None:  
544 - file.GetObject("AngRes80_offaxis", array)  
545 - self.make_2D(array, self.hdu_psf, "R80", "deg") 812 + # SCALE
  813 + self.make_2D(scale, self.hdu_psf, "SCALE", "")
  814 +
  815 + # SIGMA_1
  816 + self.make_2D(r68, self.hdu_psf, "SIGMA_1", "deg")
546 817
547 - # Make 2D energy resolution 818 + # AMPL_2
  819 + self.make_2D(zero, self.hdu_psf, "AMPL_2", "")
  820 +
  821 + # SIGMA_2
  822 + self.make_2D(zero, self.hdu_psf, "SIGMA_2", "deg")
  823 +
  824 + # AMPL_3
  825 + self.make_2D(zero, self.hdu_psf, "AMPL_3", "")
  826 +
  827 + # SIGMA_3
  828 + self.make_2D(zero, self.hdu_psf, "SIGMA_3", "deg")
  829 +
  830 + # Return
  831 + return
  832 +
  833 + def root2edisp(self, file):
  834 + """
  835 + Translate ROOT to CALDB energy dispersion extension. The following ROOT
  836 + histograms are used:
  837 +
  838 + ERes_offaxis -> ERES
  839 + Ebias_offaxis -> EBIAS
  840 +
  841 + Parameters:
  842 + file - ROOT file.
  843 + Keywords:
  844 + None
  845 + """
  846 + # Continue only if energy dispersion HDU has been opened
548 if self.hdu_edisp != None: 847 if self.hdu_edisp != None:
549 - file.GetObject("ERes", array)  
550 - bounds = self.make_2D(array, self.hdu_edisp, "ERES68", "") 848 +
  849 + # Allocate ROOT 2D array
  850 + eres = TH2F()
  851 + ebias = TH2F()
  852 + file.GetObject("ERes_offaxis", eres)
  853 + file.GetObject("Ebias_offaxis", ebias)
  854 +
  855 + # Set boundaries
  856 + bounds = self.make_2D(eres, self.hdu_edisp, None, "deg")
551 for b in bounds: 857 for b in bounds:
552 self.edisp_bounds.append(b) 858 self.edisp_bounds.append(b)
553 self.set_cif_keywords(self.hdu_edisp, self.edisp_name, \ 859 self.set_cif_keywords(self.hdu_edisp, self.edisp_name, \
554 self.edisp_bounds, self.edisp_desc) 860 self.edisp_bounds, self.edisp_desc)
555 - 861 +
  862 + # ERES
  863 + self.make_2D(eres, self.hdu_edisp, "ERES", "Ereco/Etrue")
  864 +
  865 + # EBIAS
  866 + self.make_2D(ebias, self.hdu_edisp, "EBIAS", "Ereco/Etrue")
  867 +
  868 + # Return
  869 + return
  870 +
  871 + def root2bgd(self, file):
  872 + """
  873 + Translate ROOT to CALDB background extension. The following ROOT
  874 + histograms are used:
  875 +
  876 + BGRatePerSqDeg_offaxis -> BGD
  877 + BGRatePerSqDeg_offaxis -> BGD_RECO
  878 +
  879 + Parameters:
  880 + file - ROOT file.
  881 + Keywords:
  882 + None
  883 + """
  884 + # Continue only if background HDU has been opened
  885 + if self.hdu_bgd != None:
  886 +
  887 + # Allocate ROOT 2D array
  888 + array = TH2F()
  889 + file.GetObject("BGRatePerSqDeg_offaxis", array)
  890 +
  891 + # Set boundaries
  892 + bounds = self.make_2D(array, self.hdu_bgd, None, "deg")
  893 + for b in bounds:
  894 + self.bgd_bounds.append(b)
  895 + self.set_cif_keywords(self.hdu_bgd, self.bgd_name, \
  896 + self.bgd_bounds, self.bgd_desc)
  897 +
  898 + # BGD
  899 + self.make_2D(array, self.hdu_bgd, "BGD", "")
  900 +
  901 + # BGD_RECO
  902 + self.make_2D(array, self.hdu_bgd, "BGD_RECO", "")
  903 +
556 # Return 904 # Return
557 return 905 return
558 906
@@ -589,22 +937,41 @@ class caldb(): @@ -589,22 +937,41 @@ class caldb():
589 #==========================# 937 #==========================#
590 if __name__ == '__main__': 938 if __name__ == '__main__':
591 """ 939 """
592 - This script translates a ROOT 2D performance file in a CALDB compliant  
593 - CTA response. 940 + This script translates a CTA ROOT 2D performance files in a CALDB compliant
  941 + CTA response. The script will create the response for 3 observations to
  942 + illustrate the run-wise file structure.
  943 +
  944 + The CTA ROOT 2D performance files contain the following histograms:
  945 + - DiffSens_offaxis (2D) - Differential sensitivity
  946 + - EffectiveArea_offaxis (2D) - Effective area (full containment?, reco energy?)
  947 + - EffectiveArea80_offaxis (2D) - Effective area for 80% source containment
  948 + - AngRes_offaxis (2D) - Angular resolution 68% containment
  949 + - AngRes80_offaxis (2D) - Angular resolution 80% containment
  950 + - BGRatePerSqDeg_offaxis (2D) - Background rate per square degree
  951 + - BGRate_offaxis (2D) - Background rate
  952 + - EffectiveAreaEtrue_offaxis (2D) - Effective area in true energy (finer bins)
  953 + - MigMatrix_offaxis (3D)
  954 + - EestOverEtrue_offaxis (3D)
  955 + - ERes_offaxis (2D) - Energy Resolution
  956 + - Ebias_offaxis (2D) - Energy bias
594 """ 957 """
595 # Set ROOT filename 958 # Set ROOT filename
596 - #path = "/Users/jurgen/Documents/Travail/Projects/CTA/WP-MC/root/IFAEOffaxis"  
597 - #irf = "SubarrayE_offaxis.root"  
598 - path = "/Users/jurgen/Documents/Travail/Projects/CTA/WP-MC/root/IFAEOffaxisPerformanceBEI_Nov2011"  
599 - irf = "SubarrayE_IFAE_50hours_20111121_offaxis.root" 959 + path = "/Users/jurgen/Documents/Travail/Projects/CTA/WP-MC/root/IFAEOffaxisPerformanceBEI_May2012"
  960 + irf = "SubarrayE_IFAE_50hours_20120510_offaxis.root"
600 filename = path+"/"+irf 961 filename = path+"/"+irf
601 962
602 - # Allocate caldb  
603 - db = caldb("E") 963 + # Set observation identifiers
  964 + obsids = ["000001", "000002", "000003"]
  965 +
  966 + # Generate CALDB entries, one for each observation (or run)
  967 + for obsid in obsids:
  968 +
  969 + # Allocate caldb
  970 + db = caldb("E", obsid)
604 971
605 - # Open calibration  
606 - db.open("test") 972 + # Open calibration
  973 + db.open("test")
607 974
608 - # Translate ROOT to CALDB information  
609 - db.root2caldb(filename) 975 + # Translate ROOT to CALDB information
  976 + db.root2caldb(filename)
610 977
611 \ No newline at end of file 978 \ No newline at end of file
scripts/obsutils.py
@@ -183,7 +183,7 @@ def cntmap(obs, proj=&quot;TAN&quot;, coord=&quot;GAL&quot;, xval=0.0, yval=0.0, \ @@ -183,7 +183,7 @@ def cntmap(obs, proj=&quot;TAN&quot;, coord=&quot;GAL&quot;, xval=0.0, yval=0.0, \
183 event = cast_GCTAEventAtom(event) 183 event = cast_GCTAEventAtom(event)
184 184
185 # Determine sky pixel 185 # Determine sky pixel
186 - skydir = event.dir().skydir() 186 + skydir = event.dir().dir()
187 pixel = map.dir2pix(skydir) 187 pixel = map.dir2pix(skydir)
188 188
189 # Set pixel 189 # Set pixel
@@ -237,7 +237,7 @@ def modmap(obs, eref=0.1, proj=&quot;TAN&quot;, coord=&quot;GAL&quot;, xval=0.0, yval=0.0, \ @@ -237,7 +237,7 @@ def modmap(obs, eref=0.1, proj=&quot;TAN&quot;, coord=&quot;GAL&quot;, xval=0.0, yval=0.0, \
237 237
238 # Get sky direction 238 # Get sky direction
239 skydir = map.pix2dir(pixel) 239 skydir = map.pix2dir(pixel)
240 - instdir.skydir(skydir) 240 + instdir.dir(skydir)
241 241
242 # Create event atom for map pixel 242 # Create event atom for map pixel
243 atom = GCTAEventAtom() 243 atom = GCTAEventAtom()
@@ -295,7 +295,7 @@ def set(pntdir, tstart=0.0, duration=1800.0, deadc=0.95, \ @@ -295,7 +295,7 @@ def set(pntdir, tstart=0.0, duration=1800.0, deadc=0.95, \
295 # Set ROI 295 # Set ROI
296 roi = GCTARoi() 296 roi = GCTARoi()
297 instdir = GCTAInstDir() 297 instdir = GCTAInstDir()
298 - instdir.skydir(pntdir) 298 + instdir.dir(pntdir)
299 roi.centre(instdir) 299 roi.centre(instdir)
300 roi.radius(rad) 300 roi.radius(rad)
301 301
src/Makefile.am
@@ -5,10 +5,11 @@ MACOSX_DEPLOYMENT_TARGET=@CONFIGURE_MACOSX_DEPLOYMENT_TARGET@ @@ -5,10 +5,11 @@ MACOSX_DEPLOYMENT_TARGET=@CONFIGURE_MACOSX_DEPLOYMENT_TARGET@
5 @EXPORT_MACOSX_DEPLOYMENT_TARGET@export MACOSX_DEPLOYMENT_TARGET 5 @EXPORT_MACOSX_DEPLOYMENT_TARGET@export MACOSX_DEPLOYMENT_TARGET
6 6
7 # Set sub directories 7 # Set sub directories
8 -SUBDIRS = ctselect \  
9 - ctbin \ 8 +SUBDIRS = ctbin \
10 ctlike \ 9 ctlike \
  10 + ctmodel \
11 ctobssim \ 11 ctobssim \
  12 + ctselect \
12 ctskymap 13 ctskymap
13 14
14 # Scripts to be distributed 15 # Scripts to be distributed
@@ -22,9 +23,10 @@ scripts = ctools-setup \ @@ -22,9 +23,10 @@ scripts = ctools-setup \
22 lib_LTLIBRARIES = libctools.la 23 lib_LTLIBRARIES = libctools.la
23 libctools_la_SOURCES = 24 libctools_la_SOURCES =
24 libctools_la_LIBADD = ctbin/libctbin.la \ 25 libctools_la_LIBADD = ctbin/libctbin.la \
25 - ctselect/libctselect.la \  
26 ctlike/libctlike.la \ 26 ctlike/libctlike.la \
  27 + ctmodel/libctmodel.la \
27 ctobssim/libctobssim.la \ 28 ctobssim/libctobssim.la \
  29 + ctselect/libctselect.la \
28 ctskymap/libctskymap.la 30 ctskymap/libctskymap.la
29 31
30 # Distribute scripts 32 # Distribute scripts
src/ctbin/ctbin.cpp
@@ -534,7 +534,7 @@ void ctbin::bin_events(GCTAObservation* obs) @@ -534,7 +534,7 @@ void ctbin::bin_events(GCTAObservation* obs)
534 534
535 // Determine sky pixel 535 // Determine sky pixel
536 GCTAInstDir* inst = (GCTAInstDir*)&(event->dir()); 536 GCTAInstDir* inst = (GCTAInstDir*)&(event->dir());
537 - GSkyDir dir = inst->skydir(); 537 + GSkyDir dir = inst->dir();
538 GSkyPixel pixel = map.dir2xy(dir); 538 GSkyPixel pixel = map.dir2xy(dir);
539 539
540 // Skip if pixel is out of range 540 // Skip if pixel is out of range
src/ctmodel/Makefile.am 0 → 100644
  1 +## Process this file with automake to produce Makefile.in
  2 +
  3 +# Program name
  4 +bin_PROGRAMS = ctmodel
  5 +
  6 +# Sources
  7 +sources = ctmodel.cpp
  8 +
  9 +# Libtool library
  10 +noinst_LTLIBRARIES = libctmodel.la
  11 +libctmodel_la_SOURCES = $(sources)
  12 +
  13 +# Program definition
  14 +ctmodel_SOURCES = main.cpp
  15 +ctmodel_LDFLAGS = $(LIB_LINK_OPTION) @LDFLAGS@
  16 +ctmodel_CPPFLAGS = @CPPFLAGS@
  17 +ctmodel_LDADD = libctmodel.la
  18 +
  19 +# Parameter files
  20 +pfilesdir = $(prefix)/syspfiles
  21 +pfiles_DATA = ctmodel.par
src/ctmodel/ctmodel.cpp 0 → 100644
  1 +/***************************************************************************
  2 + * ctmodel - CTA counts model tool *
  3 + * ----------------------------------------------------------------------- *
  4 + * copyright (C) 2012 by Juergen Knoedlseder *
  5 + * ----------------------------------------------------------------------- *
  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 +/**
  22 + * @file ctmodel.cpp
  23 + * @brief CTA counts model tool implementation
  24 + * @author Juergen Knoedlseder
  25 + */
  26 +
  27 +/* __ Includes ___________________________________________________________ */
  28 +#ifdef HAVE_CONFIG_H
  29 +#include <config.h>
  30 +#endif
  31 +#include <cstdio>
  32 +#include "ctmodel.hpp"
  33 +#include "GTools.hpp"
  34 +
  35 +/* __ Method name definitions ____________________________________________ */
  36 +#define G_SETUP_OBS "ctmodel::setup_obs()"
  37 +#define G_MODEL_MAP "ctmodel::model_map(GCTAObservation*)"
  38 +
  39 +/* __ Debug definitions __________________________________________________ */
  40 +
  41 +/* __ Coding definitions _________________________________________________ */
  42 +
  43 +
  44 +/*==========================================================================
  45 + = =
  46 + = Constructors/destructors =
  47 + = =
  48 + ==========================================================================*/
  49 +
  50 +/***********************************************************************//**
  51 + * @brief Void constructor
  52 + ***************************************************************************/
  53 +ctmodel::ctmodel(void) : GApplication(CTMODEL_NAME, CTMODEL_VERSION)
  54 +{
  55 + // Initialise members
  56 + init_members();
  57 +
  58 + // Write header into logger
  59 + log_header();
  60 +
  61 + // Return
  62 + return;
  63 +}
  64 +
  65 +
  66 +/***********************************************************************//**
  67 + * @brief Observations constructor
  68 + *
  69 + * This method creates an instance of the class by copying an existing
  70 + * observations container.
  71 + ***************************************************************************/
  72 +ctmodel::ctmodel(GObservations obs) : GApplication(CTMODEL_NAME, CTMODEL_VERSION)
  73 +{
  74 + // Initialise members
  75 + init_members();
  76 +
  77 + // Set observations
  78 + m_obs = obs;
  79 +
  80 + // Write header into logger
  81 + log_header();
  82 +
  83 + // Return
  84 + return;
  85 +}
  86 +
  87 +
  88 +
  89 +/***********************************************************************//**
  90 + * @brief Command line constructor
  91 + *
  92 + * @param[in] argc Number of arguments in command line.
  93 + * @param[in] argv Array of command line arguments.
  94 + ***************************************************************************/
  95 +ctmodel::ctmodel(int argc, char *argv[]) :
  96 + GApplication(CTMODEL_NAME, CTMODEL_VERSION, argc, argv)
  97 +{
  98 + // Initialise members
  99 + init_members();
  100 +
  101 + // Write header into logger
  102 + log_header();
  103 +
  104 + // Return
  105 + return;
  106 +}
  107 +
  108 +
  109 +/***********************************************************************//**
  110 + * @brief Copy constructor
  111 + *
  112 + * @param[in] app Application.
  113 + ***************************************************************************/
  114 +ctmodel::ctmodel(const ctmodel& app) : GApplication(app)
  115 +{
  116 + // Initialise members
  117 + init_members();
  118 +
  119 + // Copy members
  120 + copy_members(app);
  121 +
  122 + // Return
  123 + return;
  124 +}
  125 +
  126 +
  127 +/***********************************************************************//**
  128 + * @brief Destructor
  129 + ***************************************************************************/
  130 +ctmodel::~ctmodel(void)
  131 +{
  132 + // Free members
  133 + free_members();
  134 +
  135 + // Return
  136 + return;
  137 +}
  138 +
  139 +
  140 +/*==========================================================================
  141 + = =
  142 + = Operators =
  143 + = =
  144 + ==========================================================================*/
  145 +
  146 +/***********************************************************************//**
  147 + * @brief Assignment operator
  148 + *
  149 + * @param[in] app ctmodel application.
  150 + * @return Returns ctmodel application.
  151 + ***************************************************************************/
  152 +ctmodel& ctmodel::operator= (const ctmodel& app)
  153 +{
  154 + // Execute only if object is not identical
  155 + if (this != &app) {
  156 +
  157 + // Copy base class members
  158 + this->GApplication::operator=(app);
  159 +
  160 + // Free members
  161 + free_members();
  162 +
  163 + // Initialise members
  164 + init_members();
  165 +
  166 + // Copy members
  167 + copy_members(app);
  168 +
  169 + } // endif: object was not identical
  170 +
  171 + // Return this object
  172 + return *this;
  173 +}
  174 +
  175 +
  176 +/*==========================================================================
  177 + = =
  178 + = Public methods =
  179 + = =
  180 + ==========================================================================*/
  181 +
  182 +/***********************************************************************//**
  183 + * @brief Clear instance
  184 + ***************************************************************************/
  185 +void ctmodel::clear(void)
  186 +{
  187 + // Free members
  188 + free_members();
  189 + this->GApplication::free_members();
  190 +
  191 + // Initialise members
  192 + this->GApplication::init_members();
  193 + init_members();
  194 +
  195 + // Return
  196 + return;
  197 +}
  198 +
  199 +
  200 +/***********************************************************************//**
  201 + * @brief Execute application
  202 + *
  203 + * This is the main execution method of the ctmodel class. It is invoked
  204 + * when the executable is called from command line. The method generates
  205 + * the model maps and saves the results.
  206 + ***************************************************************************/
  207 +void ctmodel::execute(void)
  208 +{
  209 + // Signal that some parameters should be read ahead
  210 + m_read_ahead = true;
  211 +
  212 + // Create the model map(s)
  213 + run();
  214 +
  215 + // Save the model map(s) into FITS file
  216 + save();
  217 +
  218 + // Return
  219 + return;
  220 +}
  221 +
  222 +
  223 +/***********************************************************************//**
  224 + * @brief Generate the model map(s)
  225 + *
  226 + * This method reads the task parameters from the parfile, sets up the
  227 + * observation container, loops over all CTA observations in the container
  228 + * and generates a model map for each CTA observation.
  229 + ***************************************************************************/
  230 +void ctmodel::run(void)
  231 +{
  232 + // If we're in debug mode then all output is also dumped on the screen
  233 + if (logDebug()) {
  234 + log.cout(true);
  235 + }
  236 +
  237 + // Get task parameters
  238 + get_parameters();
  239 +
  240 + // Setup observation container
  241 + setup_obs();
  242 +
  243 + // Write parameters into logger
  244 + if (logTerse()) {
  245 + log_parameters();
  246 + log << std::endl;
  247 + }
  248 +
  249 + // Write observation(s) into logger
  250 + if (logTerse()) {
  251 + log << std::endl;
  252 + if (m_obs.size() > 1) {
  253 + log.header1("Observations");
  254 + }
  255 + else {
  256 + log.header1("Observation");
  257 + }
  258 + log << m_obs << std::endl;
  259 + }
  260 +
  261 + // Write header
  262 + if (logTerse()) {
  263 + log << std::endl;
  264 + if (m_obs.size() > 1) {
  265 + log.header1("Generate model maps");
  266 + }
  267 + else {
  268 + log.header1("Generate model map");
  269 + }
  270 + }
  271 +
  272 + // Initialise observation counter
  273 + int n_observations = 0;
  274 +
  275 + // Loop over all observations in the container
  276 + for (int i = 0; i < m_obs.size(); ++i) {
  277 +
  278 + // Initialise event input and output filenames
  279 + m_infiles.push_back("");
  280 +
  281 + // Get CTA observation
  282 + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(&m_obs[i]);
  283 +
  284 + // Continue only if observation is a CTA observation
  285 + if (obs != NULL) {
  286 +
  287 + // Write header for observation
  288 + if (logTerse()) {
  289 + if (obs->name().length() > 1) {
  290 + log.header3("Observation "+obs->name());
  291 + }
  292 + else {
  293 + log.header3("Observation");
  294 + }
  295 + }
  296 +
  297 + // Increment number of observations
  298 + n_observations++;
  299 +
  300 + // Save event file name (for possible saving)
  301 + m_infiles[i] = obs->eventfile();
  302 +
  303 + // Generate model map
  304 + model_map(obs, m_obs.models());
  305 +
  306 + } // endif: CTA observation found
  307 +
  308 + } // endfor: looped over observations
  309 +
  310 + // If more than a single observation has been handled then make sure
  311 + // that an XML file will be used for storage
  312 + if (n_observations > 1) {
  313 + m_use_xml = true;
  314 + }
  315 +
  316 + // Write observation(s) into logger
  317 + if (logTerse()) {
  318 + log << std::endl;
  319 + if (m_obs.size() > 1) {
  320 + log.header1("Observations after model map generation");
  321 + }
  322 + else {
  323 + log.header1("Observation after model map generation");
  324 + }
  325 + log << m_obs << std::endl;
  326 + }
  327 +
  328 + // Return
  329 + return;
  330 +}
  331 +
  332 +
  333 +/***********************************************************************//**
  334 + * @brief Save model map(s)
  335 + *
  336 + * This method saves the model map(s) into FITS file(s). There are two
  337 + * modes, depending on the m_use_xml flag.
  338 + *
  339 + * If m_use_xml is true, all model map(s) will be saved into FITS files,
  340 + * where the output filenames are constructued from the input filenames by
  341 + * prepending the m_prefix string to name. Any path information will be
  342 + * stripped form the input name, hence event files will be written into the
  343 + * local working directory (unless some path information is present
  344 + * in the prefix). In addition, an XML file will be created that gathers
  345 + * the filename information for the model map(s). If an XML file was present
  346 + * on input, all metadata information will be copied from this input file.
  347 + *
  348 + * If m_use_xml is false, the model map will be saved into a FITS file.
  349 + ***************************************************************************/
  350 +void ctmodel::save(void)
  351 +{
  352 + // Write header
  353 + if (logTerse()) {
  354 + log << std::endl;
  355 + if (m_obs.size() > 1) {
  356 + log.header1("Save observations");
  357 + }
  358 + else {
  359 + log.header1("Save observation");
  360 + }
  361 + }
  362 +
  363 + // Case A: Save model map(s) and XML metadata information
  364 + if (m_use_xml) {
  365 + save_xml();
  366 + }
  367 +
  368 + // Case B: Save model map as FITS file
  369 + else {
  370 + save_fits();
  371 + }
  372 +
  373 + // Return
  374 + return;
  375 +}
  376 +
  377 +
  378 +/***********************************************************************//**
  379 + * @brief Get application parameters
  380 + *
  381 + * Get all task parameters from parameter file or (if required) by querying
  382 + * the user. The parameters are read in the correct order.
  383 + ***************************************************************************/
  384 +void ctmodel::get_parameters(void)
  385 +{
  386 + // If we do not have any observations in the container then get all
  387 + // information to build (at least) one
  388 + if (m_obs.size() == 0) {
  389 +
  390 + // Read general parameters. Only read the output parameters if
  391 + // required, and also only read the model XML filename if no
  392 + // model is yet in the container.
  393 + m_infile = (*this)["infile"].filename();
  394 + if (m_read_ahead) {
  395 + m_outfile = (*this)["outfile"].filename();
  396 + m_prefix = (*this)["prefix"].string();
  397 + }
  398 + m_caldb = (*this)["caldb"].string();
  399 + m_irf = (*this)["irf"].string();
  400 + if (m_obs.models().size() == 0) {
  401 + m_srcmdl = (*this)["srcmdl"].filename();
  402 + }
  403 +
  404 + // If there is no input filename then read all parameters that
  405 + // are required to build a model map from scratch
  406 + if ((m_infile == "NONE") || (strip_whitespace(m_infile) == "")) {
  407 + m_ra = (*this)["ra"].real();
  408 + m_dec = (*this)["dec"].real();
  409 + m_deadc = (*this)["deadc"].real();
  410 + m_tmin = (*this)["tmin"].real();
  411 + m_tmax = (*this)["tmax"].real();
  412 + m_emin = (*this)["emin"].real();
  413 + m_emax = (*this)["emax"].real();
  414 + m_enumbins = (*this)["enumbins"].integer();
  415 + m_proj = (*this)["proj"].string();
  416 + m_coordsys = (*this)["coordsys"].string();
  417 + m_xref = (*this)["xref"].real();
  418 + m_yref = (*this)["yref"].real();
  419 + m_binsz = (*this)["binsz"].real();
  420 + m_nxpix = (*this)["nxpix"].integer();
  421 + m_nypix = (*this)["nypix"].integer();
  422 + }
  423 + }
  424 +
  425 + // ... otherwise, read only the parameters that are required for the
  426 + // model generation.
  427 + else {
  428 + if (m_read_ahead) {
  429 + m_outfile = (*this)["outfile"].filename();
  430 + m_prefix = (*this)["prefix"].string();
  431 + }
  432 + m_caldb = (*this)["caldb"].string();
  433 + m_irf = (*this)["irf"].string();
  434 + if (m_obs.models().size() == 0) {
  435 + m_srcmdl = (*this)["srcmdl"].filename();
  436 + }
  437 + }
  438 +
  439 + // Return
  440 + return;
  441 +}
  442 +
  443 +
  444 +/***********************************************************************//**
  445 + * @brief Setup observation container
  446 + *
  447 + * @exception GException::no_cube
  448 + * No event cube found in CTA observation.
  449 + *
  450 + * This method sets up the observation container for processing. There are
  451 + * two cases:
  452 + *
  453 + * If there are no observations in the actual observation container, the
  454 + * method will check in "infile" parameter. If this parameter is "NONE" or
  455 + * empty, the task parameters will be used to construct a model map.
  456 + * Otherwise, the method first tries to interpret the "infile" parameter as
  457 + * a counts map, and attemps loading of the file in an event cube. If this
  458 + * fails, the method tries to interpret the "infile" parameter as an
  459 + * observation definition XML file. If this also fails, an exception will
  460 + * be thrown.
  461 + *
  462 + * If observations exist already in the observation container, the method
  463 + * will simply keep them.
  464 + *
  465 + * Test if all CTA observations contain counts maps.
  466 + *
  467 + * Finally, if no models exist so far in the observation container, the
  468 + * models will be loaded from the model XML file.
  469 + ***************************************************************************/
  470 +void ctmodel::setup_obs(void)
  471 +{
  472 + // If there are no observations in the container then try to build some
  473 + if (m_obs.size() == 0) {
  474 +
  475 + // If no input filename has been specified, then create a model map
  476 + // from the task parameters
  477 + if ((m_infile == "NONE") || (strip_whitespace(m_infile) == "")) {
  478 +
  479 + // Set pointing direction
  480 + GCTAPointing pnt;
  481 + GSkyDir skydir;
  482 + skydir.radec_deg(m_ra, m_dec);
  483 + pnt.dir(skydir);
  484 +
  485 + // Setup energy range covered by model
  486 + GEnergy emin;
  487 + GEnergy emax;
  488 + GEbounds ebds;
  489 + emin.TeV(m_emin);
  490 + emax.TeV(m_emax);
  491 + ebds.setlog(emin, emax, m_enumbins);
  492 +
  493 + // Setup time interval covered by model
  494 + GGti gti;
  495 + GTime tmin;
  496 + GTime tmax;
  497 + tmin.met(m_tmin);
  498 + tmax.met(m_tmax);
  499 + gti.append(tmin, tmax);
  500 +
  501 + // Setup skymap
  502 + GSkymap map = GSkymap(m_proj, m_coordsys,
  503 + m_xref, m_yref, m_binsz, m_binsz,
  504 + m_nxpix, m_nypix, m_enumbins);
  505 +
  506 + // Create model cube from sky map
  507 + GCTAEventCube cube(map, ebds, gti);
  508 +
  509 + // Allocate CTA observation
  510 + GCTAObservation obs;
  511 +
  512 + // Set CTA observation attributes
  513 + obs.pointing(pnt);
  514 + obs.ontime(gti.ontime());
  515 + obs.livetime(gti.ontime()*m_deadc);
  516 + obs.deadc(m_deadc);
  517 +
  518 + // Set event cube in observation
  519 + obs.events(&cube);
  520 +
  521 + // Append CTA observation to container
  522 + m_obs.append(obs);
  523 +
  524 + // Signal that no XML file should be used for storage
  525 + m_use_xml = false;
  526 +
  527 + } // endif: created model map from task parameters
  528 +
  529 + // ... otherwise try to load information from the file
  530 + else {
  531 +
  532 + // First try to open the file as a counts map
  533 + try {
  534 +
  535 + // Allocate CTA observation
  536 + GCTAObservation obs;
  537 +
  538 + // Load counts map in CTA observation
  539 + obs.load_binned(m_infile);
  540 +
  541 + // Append CTA observation to container
  542 + m_obs.append(obs);
  543 +
  544 + // Signal that no XML file should be used for storage
  545 + m_use_xml = false;
  546 +
  547 + }
  548 +
  549 + // ... otherwise try to open as XML file
  550 + catch (GException::fits_open_error &e) {
  551 +
  552 + // Load observations from XML file. This will throw
  553 + // an exception if it fails.
  554 + m_obs.load(m_infile);
  555 +
  556 + // Signal that XML file should be used for storage
  557 + m_use_xml = true;
  558 +
  559 + }
  560 +
  561 + } // endelse: loaded information from input file
  562 +
  563 + } // endif: there was no observation in the container
  564 +
  565 + // If there are no models associated with the observations then
  566 + // load now the model definition from the XML file
  567 + if (m_obs.models().size() == 0) {
  568 + m_obs.models(GModels(m_srcmdl));
  569 + }
  570 +
  571 + // Check if all CTA observations contain an event cube and setup response
  572 + // for all observations
  573 + for (int i = 0; i < m_obs.size(); ++i) {
  574 +
  575 + // Is this observation a CTA observation?
  576 + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(&m_obs[i]);
  577 +
  578 + // Yes ...
  579 + if (obs != NULL) {
  580 +
  581 + // Throw an exception if this observation does not contain
  582 + // an event cube
  583 + if (dynamic_cast<const GCTAEventCube*>(obs->events()) == NULL) {
  584 + throw GException::no_cube(G_SETUP_OBS);
  585 + }
  586 +
  587 + // Set response
  588 + obs->response(m_irf, m_caldb);
  589 +
  590 + } // endif: observation was a CTA observation
  591 + } // endfor: looped over all observations
  592 +
  593 + // Return
  594 + return;
  595 +}
  596 +
  597 +
  598 +/***********************************************************************//**
  599 + * @brief Generate model map
  600 + *
  601 + * @param[in] obs CTA observation pointer.
  602 + * @param[in] models Model container.
  603 + *
  604 + * @exception GException::no_cube
  605 + * No event cube found in CTA observation.
  606 + ***************************************************************************/
  607 +void ctmodel::model_map(GCTAObservation* obs, const GModels& models)
  608 +{
  609 + // Continue only if observation pointer is valid
  610 + if (obs != NULL) {
  611 +
  612 + // Get event cube pointer
  613 + GCTAEventCube* cube =
  614 + const_cast<GCTAEventCube*>(dynamic_cast<const GCTAEventCube*>(obs->events()));
  615 +
  616 + // Throw an exception if the observation does not hold and event
  617 + // cube
  618 + if (cube == NULL) {
  619 + throw GException::no_cube(G_MODEL_MAP);
  620 + }
  621 +
  622 + // Initialise statistics
  623 + double sum = 0.0;
  624 +
  625 + // Loop over all events in counts map
  626 + for (int i = 0; i < cube->size(); ++i) {
  627 +
  628 + // Get event bin
  629 + GCTAEventBin* bin = (*cube)[i];
  630 +
  631 + // Compute model value for event bin
  632 + double model =
  633 + models.eval(*(const_cast<const GCTAEventBin*>(bin)), *obs) *
  634 + bin->size();
  635 +
  636 + // Store value
  637 + bin->counts(model);
  638 +
  639 + // Sum all events
  640 + sum += model;
  641 + }
  642 +
  643 + // Log results
  644 + if (logTerse()) {
  645 + log << parformat("Model events in cube");
  646 + log << sum << std::endl;
  647 + }
  648 +
  649 + } // endif: observation pointer was not valid
  650 +
  651 + // Return
  652 + return;
  653 +}
  654 +
  655 +
  656 +/*==========================================================================
  657 + = =
  658 + = Private methods =
  659 + = =
  660 + ==========================================================================*/
  661 +
  662 +/***********************************************************************//**
  663 + * @brief Initialise class members
  664 + ***************************************************************************/
  665 +void ctmodel::init_members(void)
  666 +{
  667 + // Initialise members
  668 + m_infile.clear();
  669 + m_outfile.clear();
  670 + m_prefix.clear();
  671 + m_caldb.clear();
  672 + m_irf.clear();
  673 + m_srcmdl.clear();
  674 + m_proj.clear();
  675 + m_coordsys.clear();
  676 + m_ra = 0.0;
  677 + m_dec = 0.0;
  678 + m_deadc = 1.0;
  679 + m_tmin = 0.0;
  680 + m_tmax = 0.0;
  681 + m_emin = 0.0;
  682 + m_emax = 0.0;
  683 + m_enumbins = 0;
  684 + m_xref = 0.0;
  685 + m_yref = 0.0;
  686 + m_binsz = 0.0;
  687 + m_nxpix = 0;
  688 + m_nypix = 0;
  689 +
  690 + // Initialise protected members
  691 + m_obs.clear();
  692 + m_infiles.clear();
  693 + m_use_xml = false;
  694 + m_read_ahead = false;
  695 +
  696 + // Set logger properties
  697 + log.date(true);
  698 +
  699 + // Return
  700 + return;
  701 +}
  702 +
  703 +
  704 +/***********************************************************************//**
  705 + * @brief Copy class members
  706 + *
  707 + * @param[in] app Application.
  708 + ***************************************************************************/
  709 +void ctmodel::copy_members(const ctmodel& app)
  710 +{
  711 + // Copy attributes
  712 + m_infile = app.m_infile;
  713 + m_outfile = app.m_outfile;
  714 + m_prefix = app.m_prefix;
  715 + m_caldb = app.m_caldb;
  716 + m_irf = app.m_irf;
  717 + m_srcmdl = app.m_srcmdl;
  718 + m_proj = app.m_proj;
  719 + m_coordsys = app.m_coordsys;
  720 + m_ra = app.m_ra;
  721 + m_dec = app.m_dec;
  722 + m_deadc = app.m_deadc;
  723 + m_tmin = app.m_tmin;
  724 + m_tmax = app.m_tmax;
  725 + m_emin = app.m_emin;
  726 + m_emax = app.m_emax;
  727 + m_enumbins = app.m_enumbins;
  728 + m_xref = app.m_xref;
  729 + m_yref = app.m_yref;
  730 + m_binsz = app.m_binsz;
  731 + m_nxpix = app.m_nxpix;
  732 + m_nypix = app.m_nypix;
  733 +
  734 + // Copy protected members
  735 + m_obs = app.m_obs;
  736 + m_infiles = app.m_infiles;
  737 + m_use_xml = app.m_use_xml;
  738 + m_read_ahead = app.m_read_ahead;
  739 +
  740 + // Return
  741 + return;
  742 +}
  743 +
  744 +
  745 +/***********************************************************************//**
  746 + * @brief Delete class members
  747 + ***************************************************************************/
  748 +void ctmodel::free_members(void)
  749 +{
  750 + // Write separator into logger
  751 + if (logTerse()) {
  752 + log << std::endl;
  753 + }
  754 +
  755 + // Return
  756 + return;
  757 +}
  758 +
  759 +
  760 +/***********************************************************************//**
  761 + * @brief Set output file name.
  762 + *
  763 + * @param[in] filename Input file name.
  764 + *
  765 + * This method converts an input filename into an output filename by
  766 + * prepending the prefix specified by m_prefix to the input filename. Any
  767 + * path will be stripped from the input filename.
  768 + ***************************************************************************/
  769 +std::string ctmodel::set_outfile_name(const std::string& filename) const
  770 +{
  771 + // Split input filename into path elements
  772 + std::vector<std::string> elements = split(filename, "/");
  773 +
  774 + // The last path element is the filename
  775 + std::string outname = m_prefix + elements[elements.size()-1];
  776 +
  777 + // Return output filename
  778 + return outname;
  779 +}
  780 +
  781 +
  782 +/***********************************************************************//**
  783 + * @brief Save model map in FITS format.
  784 + *
  785 + * Save the model map as a FITS file. The filename of the FITS file is
  786 + * specified by the m_outfile member.
  787 + ***************************************************************************/
  788 +void ctmodel::save_fits(void)
  789 +{
  790 + // Get output filename
  791 + m_outfile = (*this)["outfile"].filename();
  792 +
  793 + // Get CTA observation from observation container
  794 + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(&m_obs[0]);
  795 +
  796 + // Save model map
  797 + save_model_map(obs, m_outfile);
  798 +
  799 + // Return
  800 + return;
  801 +}
  802 +
  803 +
  804 +/***********************************************************************//**
  805 + * @brief Save model map(s) in XML format.
  806 + *
  807 + * Save the model map(s) into FITS files and write the file path information
  808 + * into a XML file. The filename of the XML file is specified by the
  809 + * m_outfile member, the filename(s) of the model map(s) are built by
  810 + * prepending the prefix given by the m_prefix member to the input model
  811 + * map(s) filenames. Any path present in the input filename will be stripped,
  812 + * i.e. the model map(s) will be written in the local working directory
  813 + * (unless a path is specified in the m_prefix member).
  814 + ***************************************************************************/
  815 +void ctmodel::save_xml(void)
  816 +{
  817 + // Get output filename and prefix
  818 + m_outfile = (*this)["outfile"].filename();
  819 + m_prefix = (*this)["prefix"].string();
  820 +
  821 + // Loop over all observation in the container
  822 + for (int i = 0; i < m_obs.size(); ++i) {
  823 +
  824 + // Get CTA observation
  825 + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(&m_obs[i]);
  826 +
  827 + // Handle only CTA observations
  828 + if (obs != NULL) {
  829 +
  830 + // Set event output file name
  831 + std::string outfile = set_outfile_name(m_infiles[i]);
  832 +
  833 + // Store output file name in observation
  834 + obs->eventfile(outfile);
  835 +
  836 + // Save event list
  837 + save_model_map(obs, outfile);
  838 +
  839 + } // endif: observation was a CTA observations
  840 +
  841 + } // endfor: looped over observations
  842 +
  843 + // Save observations in XML file
  844 + m_obs.save(m_outfile);
  845 +
  846 + // Return
  847 + return;
  848 +}
  849 +
  850 +
  851 +/***********************************************************************//**
  852 + * @brief Save a single model map into a FITS file
  853 + *
  854 + * @param[in] obs Pointer to CTA observation.
  855 + * @param[in] outfile Output file name.
  856 + *
  857 + * This method saves a single model map into a FITS file. The method does
  858 + * nothing if the observation pointer is not valid.
  859 + ***************************************************************************/
  860 +void ctmodel::save_model_map(const GCTAObservation* obs,
  861 + const std::string& outfile) const
  862 +{
  863 + // Save only if observation is valid
  864 + if (obs != NULL) {
  865 +
  866 + // Save observation into FITS file
  867 + obs->save(outfile, clobber());
  868 +
  869 + } // endif: observation was valid
  870 +
  871 + // Return
  872 + return;
  873 +}
src/ctmodel/ctmodel.hpp 0 → 100644
  1 +/***************************************************************************
  2 + * ctmodel - CTA counts model tool *
  3 + * ----------------------------------------------------------------------- *
  4 + * copyright (C) 2012 by Juergen Knoedlseder *
  5 + * ----------------------------------------------------------------------- *
  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 +/**
  22 + * @file ctmodel.hpp
  23 + * @brief CTA counts model tool definition
  24 + * @author Juergen Knoedlseder
  25 + */
  26 +
  27 +#ifndef CTMODEL_HPP
  28 +#define CTMODEL_HPP
  29 +
  30 +/* __ Includes ___________________________________________________________ */
  31 +#include "GammaLib.hpp"
  32 +#include "GCTALib.hpp"
  33 +
  34 +/* __Definitions _________________________________________________________ */
  35 +#define CTMODEL_NAME "ctmodel"
  36 +#define CTMODEL_VERSION "00-01-00"
  37 +
  38 +
  39 +/***********************************************************************//**
  40 + * @class ctmodel
  41 + *
  42 + * @brief CTA counts model tool interface defintion
  43 + *
  44 + * This class creates counts model map(s). The definition of the counts model
  45 + * can be taken from a predefined observation container, from the counts maps
  46 + * found in an observation definition XML file, from an individual counts
  47 + * map, or from the parameter definition.
  48 + *
  49 + * Results are stored in an observation container that can be written to disk
  50 + * in form of FITS files (model maps) and an updated observation definition
  51 + * XML file.
  52 + ***************************************************************************/
  53 +class ctmodel : public GApplication {
  54 +
  55 +public:
  56 + // Constructors and destructors
  57 + ctmodel(void);
  58 + explicit ctmodel(GObservations obs);
  59 + ctmodel(int argc, char *argv[]);
  60 + ctmodel(const ctmodel& app);
  61 + virtual ~ctmodel(void);
  62 +
  63 + // Operators
  64 + ctmodel& operator= (const ctmodel& app);
  65 +
  66 + // Methods
  67 + void clear(void);
  68 + void execute(void);
  69 + void run(void);
  70 + void save(void);
  71 + GObservations& obs(void) { return m_obs; }
  72 + void get_parameters(void);
  73 + void setup_obs(void);
  74 + void model_map(GCTAObservation* obs, const GModels& models);
  75 +
  76 +protected:
  77 + // Protected methods
  78 + void init_members(void);
  79 + void copy_members(const ctmodel& app);
  80 + void free_members(void);
  81 + std::string set_outfile_name(const std::string& filename) const;
  82 + void save_fits(void);
  83 + void save_xml(void);
  84 + void save_model_map(const GCTAObservation* obs,
  85 + const std::string& outfile) const;
  86 +
  87 + // User parameters
  88 + std::string m_infile; //!< Input counts map or XML file
  89 + std::string m_outfile; //!< Output model map or XML file
  90 + std::string m_prefix; //!< Prefix for multiple model maps
  91 + std::string m_caldb; //!< Calibration database
  92 + std::string m_irf; //!< Instrument response functions
  93 + std::string m_srcmdl; //!< Source model
  94 + double m_ra; //!< RA of pointing direction
  95 + double m_dec; //!< DEC of pointing direction
  96 + double m_deadc; //!< Deadtime correction factor
  97 + double m_tmin; //!< Start time
  98 + double m_tmax; //!< Stop time
  99 + double m_emin; //!< Lower energy
  100 + double m_emax; //!< Upper energy
  101 + int m_enumbins; //!< Number of energy bins
  102 + std::string m_proj; //!< WCS projection
  103 + std::string m_coordsys; //!< Coordinate system
  104 + double m_xref; //!< Longitude reference coordinate
  105 + double m_yref; //!< Latitude reference coordinate
  106 + double m_binsz; //!< Pixel size
  107 + int m_nxpix; //!< Number of pixels in longitude
  108 + int m_nypix; //!< Number of pixels in latitude
  109 +
  110 + // Protected members
  111 + GObservations m_obs; //!< Observation container
  112 + std::vector<std::string> m_infiles; //!< Input event filenames
  113 + bool m_use_xml; //!< Use XML file instead of FITS file
  114 + bool m_read_ahead; //!< Read ahead parameters
  115 +};
  116 +
  117 +#endif /* CTMODEL_HPP */
src/ctmodel/ctmodel.par 0 → 100644
  1 +#############################################################################
  2 +# #
  3 +# CTA Science Analysis Tools #
  4 +# #
  5 +# ------------------------------------------------------------------------- #
  6 +# #
  7 +# File: ctmodel.par #
  8 +# Version: 00-01-00 #
  9 +# #
  10 +# Author: Juergen Knoedlseder #
  11 +# Jurgen.Knodlseder@irap.omp.eu #
  12 +# IRAP #
  13 +# #
  14 +# Purpose: Parameter file for the ctmodel application #
  15 +# #
  16 +#############################################################################
  17 +#
  18 +# General parameters
  19 +#===================
  20 +infile, f, a, "NONE",,, "Input counts map or observation definition file"
  21 +outfile, f, a, "modmap.fits",,, "Output counts map or observation definition file"
  22 +prefix, s, h, "modmap_",,, "Prefix for counts maps in observation definition file"
  23 +caldb, s, a, "test/irf",,, "Calibration database"
  24 +irf, s, a, "kb_E_50h_v3",,, "Instrument response function"
  25 +srcmdl, f, a, "test/data/crab.xml",,, "Source model"
  26 +#
  27 +# Instrument parameters
  28 +#======================
  29 +ra, r, a, 83.63, 0,360, "RA of pointing (degrees)"
  30 +dec, r, a, 22.01, -90, 90, "Dec of pointing (degrees)"
  31 +deadc, r, h, 0.95, 0, 1, "Average deadtime correction factor"
  32 +#
  33 +# Time range parameters
  34 +#======================
  35 +tmin, r, a, 0.0, 0, , "Start time (MET in s)"
  36 +tmax, r, a, 1800.0, 0, , "End time (MET in s)"
  37 +#
  38 +# Energy binning parameters
  39 +#==========================
  40 +ebinalg, s, h, "LOG", FILE|LIN|LOG,,"Algorithm for defining energy bins"
  41 +emin, r, a, 0.1,,,"Start value for first energy bin in TeV"
  42 +emax, r, a, 100.0,,,"Stop value for last energy bin in TeV"
  43 +enumbins, i, a, 20,,,"Number of energy bins"
  44 +ebinfile, f, h, "NONE",,,"Name of the file containing the energy bin definition"
  45 +#
  46 +# Spatial binning parameters
  47 +#===========================
  48 +nxpix, i, a, 200,,, "Size of the X axis in pixels"
  49 +nypix, i, a, 200,,, "Size of the Y axis in pixels"
  50 +binsz, r, a, 0.02,,, "Image scale (in degrees/pixel)"
  51 +coordsys, s, a, "CEL", CEL|GAL,,"Coordinate system (CEL - celestial, GAL - galactic)"
  52 +xref, r, a, 83.63,,, "First coordinate of image center in degrees (RA or galactic l)"
  53 +yref, r, a, 22.01,,, "Second coordinate of image center in degrees (DEC or galactic b)"
  54 +axisrot, r, h, 0.0,,, "Rotation angle of image axis, in degrees"
  55 +proj, s, a, "CAR",,, "Projection method e.g. AIT|ARC|CAR|GLS|MER|NCP|SIN|STG|TAN"
  56 +#
  57 +# Standard parameters
  58 +#====================
  59 +chatter, i, h, 1,0,4, "Chattiness of output"
  60 +clobber, b, h, yes,,, "Overwrite existing output files with new output files?"
  61 +debug, b, h, no,,, "Debugging mode activated"
  62 +mode, s, h, "ql",,, "Mode of automatic parameters"
src/ctmodel/main.cpp 0 → 100644
  1 +/***************************************************************************
  2 + * ctmodel - CTA counts model tool *
  3 + * ----------------------------------------------------------------------- *
  4 + * copyright (C) 2012 by Juergen Knoedlseder *
  5 + * ----------------------------------------------------------------------- *
  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 +/**
  22 + * @file main.cpp
  23 + * @brief CTA counts model tool main code
  24 + * @author Juergen Knoedlseder
  25 + */
  26 +
  27 +/* __ Includes ___________________________________________________________ */
  28 +#ifdef HAVE_CONFIG_H
  29 +#include <config.h>
  30 +#endif
  31 +#include <cstdio>
  32 +#include "ctmodel.hpp"
  33 +
  34 +
  35 +/***********************************************************************//**
  36 + * @brief Main entry point of application
  37 + *
  38 + * @param[in] argc Number of command line arguments.
  39 + * @param[in] argv Command line arguments.
  40 + *
  41 + * This is the main entry point of the gtbin application. It allocates a
  42 + * ctmodel object and runs the application.
  43 + ***************************************************************************/
  44 +int main (int argc, char *argv[])
  45 +{
  46 + // Initialise return code
  47 + int rc = 1;
  48 +
  49 + // Create instance of application
  50 + ctmodel application(argc, argv);
  51 +
  52 + // Run application
  53 + try {
  54 + // Execute application
  55 + application.execute();
  56 +
  57 + // Signal success
  58 + rc = 0;
  59 + }
  60 + catch (std::exception &e) {
  61 +
  62 + // Extract error message
  63 + std::string message = e.what();
  64 + std::string signal = "*** ERROR encounterted in the execution of"
  65 + " ctmodel. Run aborted ...";
  66 +
  67 + // Write error in logger
  68 + application.log << signal << std::endl;
  69 + application.log << message << std::endl;
  70 +
  71 + // Write error on standard output
  72 + std::cout << signal << std::endl;
  73 + std::cout << message << std::endl;
  74 +
  75 + } // endcatch: catched any application error
  76 +
  77 + // Return
  78 + return rc;
  79 +}
src/ctobssim/ctobssim.cpp
@@ -621,7 +621,7 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels&amp; models, @@ -621,7 +621,7 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels&amp; models,
621 GCTAEventList* events = static_cast<GCTAEventList*>(const_cast<GEvents*>(obs->events())); 621 GCTAEventList* events = static_cast<GCTAEventList*>(const_cast<GEvents*>(obs->events()));
622 622
623 // Extract ROI 623 // Extract ROI
624 - GSkyDir dir = events->roi().centre().skydir(); 624 + GSkyDir dir = events->roi().centre().dir();
625 double rad = events->roi().radius(); 625 double rad = events->roi().radius();
626 626
627 // Dump simulation cone information 627 // Dump simulation cone information
src/ctools-setup.in
@@ -29,7 +29,7 @@ fi @@ -29,7 +29,7 @@ fi
29 prefix="@prefix@" 29 prefix="@prefix@"
30 exec_prefix="@exec_prefix@" 30 exec_prefix="@exec_prefix@"
31 ctools_bin="@bindir@" 31 ctools_bin="@bindir@"
32 -ctools_lib="@libdir@@TEST_ENV_DIR@" 32 +ctools_lib="@libdir@"
33 uname_system=`uname` 33 uname_system=`uname`
34 python_dir="@pythondir@" 34 python_dir="@pythondir@"
35 python_exec_dir="@pyexecdir@" 35 python_exec_dir="@pyexecdir@"
src/ctskymap/ctskymap.cpp
@@ -492,7 +492,7 @@ void ctskymap::map_events(GCTAObservation* obs) @@ -492,7 +492,7 @@ void ctskymap::map_events(GCTAObservation* obs)
492 492
493 // Determine sky pixel 493 // Determine sky pixel
494 GCTAInstDir* inst = (GCTAInstDir*)&(event->dir()); 494 GCTAInstDir* inst = (GCTAInstDir*)&(event->dir());
495 - GSkyDir dir = inst->skydir(); 495 + GSkyDir dir = inst->dir();
496 GSkyPixel pixel = m_skymap.dir2xy(dir); 496 GSkyPixel pixel = m_skymap.dir2xy(dir);
497 497
498 // Skip if pixel is out of range 498 // Skip if pixel is out of range
test/test_ctools.sh
@@ -34,11 +34,12 @@ $ECHO &quot;***************&quot; @@ -34,11 +34,12 @@ $ECHO &quot;***************&quot;
34 # 34 #
35 # Define executables 35 # Define executables
36 # ================== 36 # ==================
37 -ctobssim=../src/ctobssim/ctobssim  
38 -ctskymap=../src/ctskymap/ctskymap  
39 ctbin=../src/ctbin/ctbin 37 ctbin=../src/ctbin/ctbin
40 -ctselect=../src/ctselect/ctselect  
41 ctlike=../src/ctlike/ctlike 38 ctlike=../src/ctlike/ctlike
  39 +ctmodel=../src/ctmodel/ctmodel
  40 +ctobssim=../src/ctobssim/ctobssim
  41 +ctselect=../src/ctselect/ctselect
  42 +ctskymap=../src/ctskymap/ctskymap
42 43
43 44
44 # 45 #
@@ -136,6 +137,57 @@ $ECHO &quot; ok&quot; @@ -136,6 +137,57 @@ $ECHO &quot; ok&quot;
136 137
137 138
138 # 139 #
  140 +# Test ctmodel
  141 +# ============
  142 +$ECHO -n "Test ctmodel: "
  143 +#
  144 +# Run 1
  145 +$ctmodel infile="cntmap.fits" \
  146 + outfile="modmap1.fits" \
  147 + caldb="irf" \
  148 + irf="kb_E_50h_v3" \
  149 + srcmdl="data/crab.xml"
  150 +$ECHO -n "."
  151 +if [ -s "modmap1.fits" ]
  152 +then
  153 + $ECHO -n "."
  154 +else
  155 + $ECHO " modmap1.fits file is not valid"
  156 + exit 1
  157 +fi
  158 +#
  159 +# Run 2
  160 +$ctmodel infile="NONE" \
  161 + outfile="modmap2.fits" \
  162 + caldb="irf" \
  163 + irf="kb_E_50h_v3" \
  164 + srcmdl="data/crab.xml" \
  165 + ra=83.63 \
  166 + dec=22.01 \
  167 + tmin=0.0 \
  168 + tmax=1800.0 \
  169 + emin=0.1 \
  170 + emax=100.0 \
  171 + enumbins=20 \
  172 + nxpix=200 \
  173 + nypix=200 \
  174 + binsz=0.02 \
  175 + coordsys="CEL" \
  176 + xref=83.63 \
  177 + yref=22.01 \
  178 + proj="CAR"
  179 +$ECHO -n "."
  180 +if [ -s "modmap2.fits" ]
  181 +then
  182 + $ECHO -n "."
  183 +else
  184 + $ECHO " modmap2.fits file is not valid"
  185 + exit 1
  186 +fi
  187 +$ECHO " ok"
  188 +
  189 +
  190 +#
139 # Test ctselect 191 # Test ctselect
140 # ============= 192 # =============
141 $ECHO -n "Test ctselect: " 193 $ECHO -n "Test ctselect: "