Commit a2954be5a38c12152d65aec5c1d0202fab1bdafe

Authored by Jürgen Knödlseder
2 parents 6f3d5e5a 561d0ed4

Merge branch '1335-write-csresmap' into integration

Conflicts:
	scripts/csresmap.py
ChangeLog
1   -2014-10-10 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
  1 +2014-10-15 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
2 2  
3 3 * Version 0.8.0 released
4 4 ========================
5 5  
6 6 Clean-up public interface
7   - Adapt to GammaLib 0.9.0 interface
8   - Introduce ctool base class
9   - ctbin now always merges event lists into a single counts cube
10   - ctmodel now always creates a single model cube
  7 + Adapt to GammaLib 0.9.0 interface
11 8 Add ctexpcube tool (generates exposure cube)
12 9 Add ctpsfcube tool (generates PSF cube)
13 10 Add ctbkgcube tool (generates background cube)
14 11 Add ctcubemask tool (masks event bins in event cube)
15 12 Add cttsmap tool (generates TS map)
  13 + Add csresmap script (generates residual map)
  14 + Introduce ctool base class
  15 + ctbin now always merges event lists into a single counts cube
  16 + ctmodel now always creates a single model cube
16 17 Support energy dispersion in ctobssim, ctlike and ctmodel
17 18 Correct ctobssim for thread safety
18 19 Correctly apply time references in ctselect
... ...
... ... @@ -2,7 +2,7 @@ New Features and Important Changes in ctools 00-08-00
2 2  
3 3 Author(s) : Juergen Knoedlseder
4 4  
5   -10 October 2014
  5 +15 October 2014
6 6  
7 7  
8 8 1. Introduction
... ... @@ -192,6 +192,9 @@ The following functions have been added to obsutils:
192 192 * spectrum() generates spectral points by fitting a source model in
193 193 specified energy bins.
194 194  
  195 +Add the csresmap script that uses ctbin and ctmodel to generate a
  196 +residual counts cube for a given model.
  197 +
195 198  
196 199 18. caldb
197 200 ---------
... ...
pyext/ctmodel.i
... ... @@ -49,6 +49,7 @@ public:
49 49 void save(void);
50 50 const GObservations& obs(void) const;
51 51 const GCTAEventCube& cube(void) const;
  52 + void cube(const GCTAEventCube& cube);
52 53 };
53 54  
54 55  
... ...
scripts/csresmap.py
1 1 #! /usr/bin/env python
2 2 # ==========================================================================
3   -# This script generates a residual map.
  3 +# Residual map generation script.
4 4 #
5 5 # Copyright (C) 2014 Michael Mayer
6 6 #
... ... @@ -18,18 +18,17 @@
18 18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 19 #
20 20 # ==========================================================================
21   -from ctools import *
22   -from gammalib import *
  21 +import ctools
  22 +import gammalib
23 23 import sys
24   -import csv
25   -import math
26 24 import tempfile
  25 +import os
27 26  
28 27  
29 28 # ============== #
30 29 # cstsdist class #
31 30 # ============== #
32   -class csresmap(GApplication):
  31 +class csresmap(gammalib.GApplication):
33 32 """
34 33 This class implements the creation of a residual map. It derives
35 34 from the GammaLib::GApplication class which provides support for parameter
... ... @@ -45,14 +44,17 @@ class csresmap(GApplication):
45 44 self.version = "0.1.0"
46 45  
47 46 # Initialise some members
48   - self.obs = None
49   - self.algorithm = "SUB"
  47 + self.obs = None
  48 + self.algorithm = "SUB"
  49 + self.resmap = None
50 50  
51 51 # Initialise some members
52   - if isinstance(argv[0],GObservations):
  52 + if isinstance(argv[0],gammalib.GObservations):
53 53 self.obs = argv[0]
  54 + argv = argv[1:]
54 55 else:
55   - self.obs = GObservations()
  56 + self.obs = gammalib.GObservations()
  57 + self.obs.clear()
56 58 self.outfile = ""
57 59  
58 60 # Make sure that parfile exists
... ... @@ -60,9 +62,9 @@ class csresmap(GApplication):
60 62  
61 63 # Initialise application
62 64 if len(argv) == 0:
63   - GApplication.__init__(self, self.name, self.version)
  65 + gammalib.GApplication.__init__(self, self.name, self.version)
64 66 elif len(argv) ==1:
65   - GApplication.__init__(self, self.name, self.version, argv[1:])
  67 + gammalib.GApplication.__init__(self, self.name, self.version, *argv)
66 68 else:
67 69 raise TypeError("Invalid number of arguments given.")
68 70  
... ... @@ -93,32 +95,32 @@ class csresmap(GApplication):
93 95 parfile = self.name+".par"
94 96  
95 97 try:
96   - pars = GApplicationPars(parfile)
  98 + pars = gammalib.GApplicationPars(parfile)
97 99 except:
98 100 # Signal if parfile was not found
99 101 sys.stdout.write("Parfile "+parfile+" not found. Create default parfile.\n")
100 102  
101 103 # Create default parfile
102   - pars = GApplicationPars()
103   - pars.append(GApplicationPar("infile","f","h","obs.xml","","","Observation definition"))
104   - pars.append(GApplicationPar("srcmdl","f","h","crab.xml","","","model file name"))
105   - pars.append(GApplicationPar("outfile","f","h","resmap.fits","","","Output file name"))
106   - pars.append(GApplicationPar("binfile","f","h","binned.fits","","","Output binned file name"))
107   - pars.append(GApplicationPar("modfile","f","h","model.fits","","","Output model file name"))
108   - pars.append(GApplicationPar("caldb","s","a","$GAMMALIB/share/caldb/cta","","","Calibration database"))
109   - pars.append(GApplicationPar("irf","s","a","cta_dummy_irf","","","Instrument response function"))
110   - pars.append(GApplicationPar("emin","r","h","0.1","0.0","","Lower energy limit (TeV)"))
111   - pars.append(GApplicationPar("emax","r","h","100.0","0.0","","Upper energy limit (TeV)"))
112   - pars.append(GApplicationPar("enumbins","i","h","20","","","Number of energy bins"))
113   - pars.append(GApplicationPar("ebinalg","s","h","LOG","LIN|LOG|FILE","","Binning algorithm"))
114   - pars.append(GApplicationPar("coordsys","s","a","CEL","CEL|GAL","","Coordinate System"))
115   - pars.append(GApplicationPar("proj","s","a","TAN","AIT|AZP|CAR|MER|STG|TAN","","Projection method e.g. AIT|AZP|CAR|MER|STG|TAN"))
116   - pars.append(GApplicationPar("xref","r","a","83.6331","","","First coordinate of image center in degrees (RA or galactic l)"))
117   - pars.append(GApplicationPar("yref","r","a","22.01","","","Second coordinate of image center in degrees (DEC or galactic b)"))
118   - pars.append(GApplicationPar("nxpix","i","h","200","","","Size of the X axis in pixels"))
119   - pars.append(GApplicationPar("nypix","i","h","200","","","Size of the Y axis in pixels"))
120   - pars.append(GApplicationPar("binsz","r","h","0.05","","","Pixel size (deg/pixel)"))
121   - pars.append(GApplicationPar("algorithm","s","h","SUBDIV","SUB|SUBDIV|SUBDIVSQRT","","Residualmap algorithm"))
  104 + pars = gammalib.GApplicationPars()
  105 + pars.append(gammalib.GApplicationPar("infile","f","a","obs.xml","","","Observation definition"))
  106 + pars.append(gammalib.GApplicationPar("srcmdl","f","a","crab.xml","","","model file name"))
  107 + pars.append(gammalib.GApplicationPar("outfile","f","a","resmap.fits","","","Output file name"))
  108 + pars.append(gammalib.GApplicationPar("binfile","f","h","binned.fits","","","Output binned file name"))
  109 + pars.append(gammalib.GApplicationPar("modfile","f","h","model.fits","","","Output model file name"))
  110 + pars.append(gammalib.GApplicationPar("caldb","s","a","$GAMMALIB/share/caldb/cta","","","Calibration database"))
  111 + pars.append(gammalib.GApplicationPar("irf","s","a","cta_dummy_irf","","","Instrument response function"))
  112 + pars.append(gammalib.GApplicationPar("emin","r","h","0.1","0.0","","Lower energy limit (TeV)"))
  113 + pars.append(gammalib.GApplicationPar("emax","r","h","100.0","0.0","","Upper energy limit (TeV)"))
  114 + pars.append(gammalib.GApplicationPar("enumbins","i","h","20","","","Number of energy bins"))
  115 + pars.append(gammalib.GApplicationPar("ebinalg","s","h","LOG","LIN|LOG|FILE","","Binning algorithm"))
  116 + pars.append(gammalib.GApplicationPar("coordsys","s","a","CEL","CEL|GAL","","Coordinate System"))
  117 + pars.append(gammalib.GApplicationPar("proj","s","a","TAN","AIT|AZP|CAR|MER|STG|TAN","","Projection method e.g. AIT|AZP|CAR|MER|STG|TAN"))
  118 + pars.append(gammalib.GApplicationPar("xref","r","a","83.6331","","","First coordinate of image center in degrees (RA or galactic l)"))
  119 + pars.append(gammalib.GApplicationPar("yref","r","a","22.01","","","Second coordinate of image center in degrees (DEC or galactic b)"))
  120 + pars.append(gammalib.GApplicationPar("nxpix","i","h","200","","","Size of the X axis in pixels"))
  121 + pars.append(gammalib.GApplicationPar("nypix","i","h","200","","","Size of the Y axis in pixels"))
  122 + pars.append(gammalib.GApplicationPar("binsz","r","h","0.05","","","Pixel size (deg/pixel)"))
  123 + pars.append(gammalib.GApplicationPar("algorithm","s","h","SUBDIV","SUB|SUBDIV|SUBDIVSQRT","","Residualmap algorithm"))
122 124 pars.append_standard()
123 125 pars.save(parfile)
124 126  
... ... @@ -133,9 +135,27 @@ class csresmap(GApplication):
133 135  
134 136 # Set observation if not done before
135 137 if self.obs.size() == 0:
136   - self.obs = GObservations(self["infile"].filename)
137   - self.m_irf = self["irf"].string()
138   - self.m_caldb = self["caldb"].string()
  138 +
  139 + obsfile = self["infile"].filename()
  140 + try:
  141 +
  142 + self.obs = gammalib.GObservations(obsfile)
  143 + except:
  144 + self.obs.clear()
  145 + observation = gammalib.GCTAObservation()
  146 + observation.load(obsfile)
  147 +
  148 + self.m_irf = self["irf"].string()
  149 + self.m_caldb = self["caldb"].string()
  150 +
  151 + caldb = gammalib.GCaldb()
  152 + if os.path.isdir(self.m_caldb):
  153 + caldb.rootdir(self.m_caldb)
  154 + else:
  155 + caldb.open("cta",self. m_caldb)
  156 +
  157 + observation.response(self.m_irf, caldb);
  158 + self.obs.append(observation)
139 159  
140 160 # Check for models in the container
141 161 # read models from file if there were none
... ... @@ -185,6 +205,9 @@ class csresmap(GApplication):
185 205 """
186 206 # Run the script
187 207 self.run()
  208 +
  209 + # Save residual map
  210 + self.resmap.save(self.m_outfile, self.m_clobber)
188 211  
189 212 # Return
190 213 return
... ... @@ -218,7 +241,8 @@ class csresmap(GApplication):
218 241 self.log.header1("Generate binned map")
219 242  
220 243 # Create countsmap
221   - bin = ctbin(self.obs)
  244 + bin = ctools.ctbin(self.obs)
  245 + bin["debug"].boolean(True)
222 246 bin["nxpix"].integer(self.m_nxpix)
223 247 bin["nypix"].integer(self.m_nypix)
224 248 bin["proj"].string(self.m_proj)
... ... @@ -231,75 +255,59 @@ class csresmap(GApplication):
231 255 bin["emax"].real(self.m_emax)
232 256 bin["binsz"].real(self.m_binsz)
233 257 bin["clobber"].boolean(self.m_clobber)
234   - if not self.m_binfile == "NONE":
235   - bin["outfile"].filename(self.m_binfile)
236   - else:
237   - os,filename = tempfile.mkstemp()
238   - bin["outfile"].filename(filename)
239   - bin.execute()
  258 + bin.run()
  259 +
  260 + # Store counts map as residual map. Note that we need a
  261 + # special construct here to avoid memory leaks. This seems
  262 + # to be a SWIG feature as SWIG creates a new object when
  263 + # calling bin.cube()
  264 + #residualmap = bin.cube().map()
  265 + counts_cube = bin.cube()
  266 + self.resmap = counts_cube.map().copy()
  267 + self.resmap.stack_maps()
240 268  
241 269 # Write header
242 270 if self.logTerse():
243 271 self.log("\n")
244 272 self.log.header1("Generate model map")
245 273  
246   - # create model map
247   - model = ctmodel(self.obs)
248   - model["infile"].filename(bin["outfile"].filename())
  274 + # Create model map
  275 + model = ctools.ctmodel(self.obs)
  276 + model["debug"].boolean(True)
  277 + model.cube(bin.cube())
249 278 model["clobber"].boolean(self.m_clobber)
250   - if not self.m_modfile == "NONE":
251   - model["outfile"].filename(self.m_modfile)
252   - else:
253   - os,filename = tempfile.mkstemp()
254   - model["outfile"].filename(filename)
255   - model.execute()
  279 + model.run()
256 280  
257 281 # Get model map into GSkymap object
258   - modelmap = GSkymap(model["outfile"].filename())
  282 + modelmap = model.cube().map()
259 283 modelmap.stack_maps()
260   -
261   - # Initialise resiudalmap from countmap
262   - residualmap = GSkymap(bin["outfile"].filename())
263   - residualmap.stack_maps()
264 284  
265   -
266   -
267   -
268   - # continue calculations depending on given algorithm
  285 + # Continue calculations depending on given algorithm
269 286 if self.m_algorithm == "SUB":
270 287  
271 288 # Subtract maps
272   - residualmap -= modelmap
  289 + self.resmap -= modelmap
273 290  
274 291 elif self.m_algorithm == "SUBDIV":
275 292  
276 293 # Subtract and divide by model map
277   - residualmap -= modelmap
278   - residualmap /= modelmap
  294 + self.resmap -= modelmap
  295 + self.resmap /= modelmap
279 296  
280 297 elif self.m_algorithm == "SUBDIVSQRT":
281 298  
282 299 # subtract and divide by sqrt of model map
283   - residualmap -= modelmap
284   - residualmap /= modelmap.sqrt()
  300 + self.resmap -= modelmap
  301 + self.resmap /= modelmap.sqrt()
285 302  
286 303 else:
287 304  
288   - # Rais error if algorithm is unkown
  305 + # Raise error if algorithm is unkown
289 306 raise TypeError("Algorithm \""+self.m_algorithm+"\" not known")
290 307  
291   - # Save files
292   - residualmap.save(self.m_outfile,self.m_clobber)
293   -
294   - # Remove binned and model files in case they shouldnt be saved
295   - if self.m_binfile == "NONE":
296   - os.remove(bin["outfile"].filename())
297   - if self.m_modfile == "NONE":
298   - os.remove(model["outfile"].filename())
299   -
300 308 # Return
301 309 return
302   -
  310 +
303 311  
304 312 # ======================== #
305 313 # Main routine entry point #
... ...
src/ctmodel/ctmodel.cpp
... ... @@ -246,8 +246,10 @@ void ctmodel::run(void)
246 246 log.header1("Generate model cube");
247 247 }
248 248  
249   - // Initialise counts cube
250   - init_cube();
  249 + // Initialise counts cube if cube has not yet been set
  250 + if (!has_cube()) {
  251 + init_cube();
  252 + }
251 253  
252 254 // Loop over all observations in the container
253 255 for (int i = 0; i < m_obs.size(); ++i) {
... ... @@ -320,6 +322,31 @@ void ctmodel::save(void)
320 322 }
321 323  
322 324  
  325 +/***********************************************************************//**
  326 + * @brief Set model cube
  327 + *
  328 + * @param[in] cube Model cube.
  329 + *
  330 + * Set model cube and set all cube bins to zero.
  331 + ***************************************************************************/
  332 +void ctmodel::cube(const GCTAEventCube& cube)
  333 +{
  334 + // Set cube
  335 + m_cube = cube;
  336 +
  337 + // Set all cube bins to zero
  338 + for (int i = 0; i < m_cube.size(); ++i) {
  339 + m_cube[i]->counts(0.0);
  340 + }
  341 +
  342 + // Signal that cube has been set
  343 + m_has_cube = true;
  344 +
  345 + // Return
  346 + return;
  347 +}
  348 +
  349 +
323 350 /*==========================================================================
324 351 = =
325 352 = Private methods =
... ... @@ -362,6 +389,7 @@ void ctmodel::init_members(void)
362 389 m_cube.clear();
363 390 m_ebounds.clear();
364 391 m_gti.clear();
  392 + m_has_cube = false;
365 393  
366 394 // Return
367 395 return;
... ... @@ -406,6 +434,7 @@ void ctmodel::copy_members(const ctmodel&amp; app)
406 434 m_cube = app.m_cube;
407 435 m_ebounds = app.m_ebounds;
408 436 m_gti = app.m_gti;
  437 + m_has_cube = app.m_has_cube;
409 438  
410 439 // Return
411 440 return;
... ... @@ -431,7 +460,9 @@ void ctmodel::free_members(void)
431 460 void ctmodel::get_parameters(void)
432 461 {
433 462 // Read input and optionally output cube filenames
434   - m_infile = (*this)["infile"].filename();
  463 + if (!has_cube()) {
  464 + m_infile = (*this)["infile"].filename();
  465 + }
435 466 if (read_ahead()) {
436 467 m_outfile = (*this)["outfile"].filename();
437 468 }
... ... @@ -482,7 +513,8 @@ void ctmodel::get_parameters(void)
482 513  
483 514 // If no cube file has been specified then read all parameters that
484 515 // are necessary to create the cube from scratch (see method init_cube)
485   - if ((m_infile == "NONE") || (gammalib::strip_whitespace(m_infile) == "")) {
  516 + if ((!has_cube()) &&
  517 + ((m_infile == "NONE") || (gammalib::strip_whitespace(m_infile) == ""))) {
486 518 m_ebinalg = (*this)["ebinalg"].string();
487 519 if (m_ebinalg == "FILE") {
488 520 m_ebinfile = (*this)["ebinfile"].filename();
... ... @@ -670,6 +702,9 @@ void ctmodel::init_cube(void)
670 702  
671 703 }
672 704  
  705 + // Signal that cube has been set
  706 + m_has_cube = true;
  707 +
673 708 // Return
674 709 return;
675 710 }
... ... @@ -738,7 +773,7 @@ void ctmodel::fill_cube(const GCTAObservation* obs)
738 773 if (logTerse()) {
739 774 log << gammalib::parformat("Model events in cube");
740 775 log << sum << std::endl;
741   - log << gammalib::parformat("Cube bins outside energy range");
  776 + log << gammalib::parformat("Bins outside energy range");
742 777 log << num_outside_ebds << std::endl;
743 778 }
744 779  
... ...
src/ctmodel/ctmodel.hpp
... ... @@ -70,6 +70,7 @@ public:
70 70 void save(void);
71 71 const GObservations& obs(void) const;
72 72 const GCTAEventCube& cube(void) const;
  73 + void cube(const GCTAEventCube& cube);
73 74  
74 75 protected:
75 76 // Protected methods
... ... @@ -80,6 +81,7 @@ protected:
80 81 void setup_obs(void);
81 82 void init_cube(void);
82 83 void fill_cube(const GCTAObservation* obs);
  84 + bool has_cube(void) const;
83 85  
84 86 // User parameters
85 87 std::string m_infile; //!< Input counts cube
... ... @@ -112,13 +114,14 @@ protected:
112 114 GCTAEventCube m_cube; //!< Model cube
113 115 GEbounds m_ebounds; //!< Energy boundaries
114 116 GGti m_gti; //!< Model cube GTIs
  117 + bool m_has_cube; //!< Signal if cube has been set or loaded
115 118 };
116 119  
117 120  
118 121 /***********************************************************************//**
119 122 * @brief Return observation container
120 123 *
121   - * @return Reference to observation container
  124 + * @return Reference to observation container.
122 125 ***************************************************************************/
123 126 inline
124 127 const GObservations& ctmodel::obs(void) const
... ... @@ -130,7 +133,7 @@ const GObservations&amp; ctmodel::obs(void) const
130 133 /***********************************************************************//**
131 134 * @brief Return model cube
132 135 *
133   - * @return Reference to model cube
  136 + * @return Reference to model cube.
134 137 ***************************************************************************/
135 138 inline
136 139 const GCTAEventCube& ctmodel::cube(void) const
... ... @@ -138,4 +141,16 @@ const GCTAEventCube&amp; ctmodel::cube(void) const
138 141 return m_cube;
139 142 }
140 143  
  144 +
  145 +/***********************************************************************//**
  146 + * @brief Signal if cube has been set or loaded
  147 + *
  148 + * @return True if cube has been set or loaded.
  149 + ***************************************************************************/
  150 +inline
  151 +bool ctmodel::has_cube(void) const
  152 +{
  153 + return m_has_cube;
  154 +}
  155 +
141 156 #endif /* CTMODEL_HPP */
... ...
test/test_cscripts.sh.in
... ... @@ -131,3 +131,32 @@ else
131 131 exit 1
132 132 fi
133 133 $ECHO " ok"
  134 +
  135 +#
  136 +# Test csresmap
  137 +# =============
  138 +$ECHO @ECHO_N@ "Test csresmap: "
  139 +chmod +x @abs_top_srcdir@/scripts/csresmap.py
  140 +@abs_top_srcdir@/scripts/csresmap.py \
  141 + infile="data/crab_events.fits" \
  142 + outfile="resmap.fits" \
  143 + srcmdl="data/crab.xml" \
  144 + caldb="irf" \
  145 + irf="cta_dummy_irf" \
  146 + nxpix=50 \
  147 + nypix=50 \
  148 + binsz=0.02 \
  149 + coordsys="CEL" \
  150 + xref=83.63 \
  151 + yref=22.01 \
  152 + proj="CAR" \
  153 + binsz=0.05 > csresmap.log
  154 +$ECHO @ECHO_N@ "."
  155 +if [ -s "resmap.fits" ]
  156 +then
  157 + $ECHO @ECHO_N@ "."
  158 +else
  159 + $ECHO " resmap.fits file is not valid"
  160 + exit 1
  161 +fi
  162 +$ECHO " ok"
... ...