Commit 2de25f8ed3c99a7b3c746f2cad8757efa05a263b

Authored by Jürgen Knödlseder
2 parents e0d12cc9 f476909b

Merge branch '1439-adapt-ctools-to-consistently-handle-observation-types' into integration

Conflicts:
	scripts/csresmap.py
scripts/csresmap.py
@@ -42,9 +42,12 @@ class csresmap(ctools.cscript): @@ -42,9 +42,12 @@ class csresmap(ctools.cscript):
42 self.version = "1.0.0" 42 self.version = "1.0.0"
43 43
44 # Initialise some members 44 # Initialise some members
45 - self.obs = None  
46 - self.algorithm = "SUB"  
47 - self.resmap = None 45 + self.obs = None
  46 + self.algorithm = "SUB"
  47 + self.resmap = None
  48 + self.m_modcube = "None"
  49 + self.m_use_maps = False
  50 + self.m_skip_binning = False
48 51
49 # Initialise some members 52 # Initialise some members
50 if len(argv) > 0 and isinstance(argv[0],gammalib.GObservations): 53 if len(argv) > 0 and isinstance(argv[0],gammalib.GObservations):
@@ -101,6 +104,10 @@ class csresmap(ctools.cscript): @@ -101,6 +104,10 @@ class csresmap(ctools.cscript):
101 # Create default parfile 104 # Create default parfile
102 pars = gammalib.GApplicationPars() 105 pars = gammalib.GApplicationPars()
103 pars.append(gammalib.GApplicationPar("inobs","f","a","events.fits","","","Event list, counts cube, or observation definition file")) 106 pars.append(gammalib.GApplicationPar("inobs","f","a","events.fits","","","Event list, counts cube, or observation definition file"))
  107 + pars.append(gammalib.GApplicationPar("modcube","f","a","NONE","","","Model cube file (generated with ctmodel)"))
  108 + pars.append(gammalib.GApplicationPar("expcube","f","a","NONE","","","Exposure cube file (only needed for stacked analysis)"))
  109 + pars.append(gammalib.GApplicationPar("psfcube","f","a","NONE","","","PSF cube file (only needed for stacked analysis)"))
  110 + pars.append(gammalib.GApplicationPar("bkgcube","s","a","NONE","","","Background cube file (only needed for stacked analysis)"))
104 pars.append(gammalib.GApplicationPar("inmodel","f","a","$CTOOLS/share/models/crab.xml","","","Source model")) 111 pars.append(gammalib.GApplicationPar("inmodel","f","a","$CTOOLS/share/models/crab.xml","","","Source model"))
105 pars.append(gammalib.GApplicationPar("outmap","f","a","resmap.fits","","","Output residual map")) 112 pars.append(gammalib.GApplicationPar("outmap","f","a","resmap.fits","","","Output residual map"))
106 pars.append(gammalib.GApplicationPar("caldb","s","a","prod2","","","Calibration database")) 113 pars.append(gammalib.GApplicationPar("caldb","s","a","prod2","","","Calibration database"))
@@ -117,7 +124,7 @@ class csresmap(ctools.cscript): @@ -117,7 +124,7 @@ class csresmap(ctools.cscript):
117 pars.append(gammalib.GApplicationPar("nxpix","i","a","200","","","Size of the X axis in pixels")) 124 pars.append(gammalib.GApplicationPar("nxpix","i","a","200","","","Size of the X axis in pixels"))
118 pars.append(gammalib.GApplicationPar("nypix","i","a","200","","","Size of the Y axis in pixels")) 125 pars.append(gammalib.GApplicationPar("nypix","i","a","200","","","Size of the Y axis in pixels"))
119 pars.append(gammalib.GApplicationPar("binsz","r","a","0.02","","","Pixel size (deg/pixel)")) 126 pars.append(gammalib.GApplicationPar("binsz","r","a","0.02","","","Pixel size (deg/pixel)"))
120 - pars.append(gammalib.GApplicationPar("algorithm","s","h","SUBDIV","SUB|SUBDIV|SUBDIVSQRT","","Residual map computation algorithm")) 127 + pars.append(gammalib.GApplicationPar("algorithm","s","a","SUBDIV","SUB|SUBDIV|SUBDIVSQRT","","Residual map computation algorithm"))
121 pars.append_standard() 128 pars.append_standard()
122 pars.append(gammalib.GApplicationPar("logfile","f","h","csresmap.log","","","Log filename")) 129 pars.append(gammalib.GApplicationPar("logfile","f","h","csresmap.log","","","Log filename"))
123 pars.save(parfile) 130 pars.save(parfile)
@@ -129,32 +136,64 @@ class csresmap(ctools.cscript): @@ -129,32 +136,64 @@ class csresmap(ctools.cscript):
129 """ 136 """
130 Get parameters from parfile and setup the observation. 137 Get parameters from parfile and setup the observation.
131 """ 138 """
132 - # Get parameters  
133 -  
134 - # Set observation if not done before  
135 - if self.obs.size() == 0:  
136 - self.require_inobs("csresmap.get_parameters()")  
137 - self.obs = self.get_observations() 139 + # Initialise some flags
  140 + self.m_use_maps = False
  141 + self.m_skip_binning = False
138 142
139 - # Set models if we have none  
140 - if self.obs.models().size() == 0:  
141 - self.obs.models(self["inmodel"].filename()) 143 + # First check if the inobs parameter is a counts cube
  144 + if self["inobs"].filename() != "NONE":
  145 + if gammalib.is_fits(self["inobs"].filename()):
  146 + cta = gammalib.GCTAObservation()
  147 + cta.load(self["inobs"].filename())
  148 + if self.obs[0].eventtype() == "CountsCube":
  149 + self.m_skip_binning = True
142 150
143 - # Read other parameters  
144 - self.m_outfile = self["outmap"].filename()  
145 - self.m_xref = self["xref"].real()  
146 - self.m_yref = self["yref"].real()  
147 - self.m_emin = self["emin"].real()  
148 - self.m_emax = self["emax"].real()  
149 - self.m_enumbins = self["enumbins"].integer()  
150 - self.m_ebinalg = self["ebinalg"].string()  
151 - self.m_coordsys = self["coordsys"].string()  
152 - self.m_proj = self["proj"].string()  
153 - self.m_nxpix = self["nxpix"].integer()  
154 - self.m_nypix = self["nypix"].integer()  
155 - self.m_binsz = self["binsz"].real() 151 + # If we have a counts cube, then ask whether we also have a model
  152 + if self.m_skip_binning:
  153 + self.m_modcube = self["modcube"].filename()
  154 + if self.m_modcube != "NONE":
  155 + self.m_use_maps = True
  156 +
  157 + # If not two maps are given, proceed to set up observation
  158 + if not self.m_use_maps:
  159 +
  160 + # Set observation if not done before
  161 + if self.obs.size() == 0:
  162 + self.require_inobs("csresmap.get_parameters()")
  163 + self.obs = self.get_observations()
  164 +
  165 + # Check if we have exactly one binned CTA observation
  166 + if self.obs.size() == 1:
  167 +
  168 + if self.obs[0].classname() == "GCTAObservation":
  169 + if self.obs[0].eventtype() == "CountsCube":
  170 + # Skip ctbin step later on
  171 + self.m_skip_binning = True
  172 +
  173 +
  174 + # Set models if we have none
  175 + if self.obs.models().size() == 0:
  176 + self.obs.models(self["inmodel"].filename())
  177 +
  178 + # Skip query for spatial parameters if a binning is provided in the observation
  179 + if not self.m_skip_binning:
  180 + # Read other parameters
  181 + self.m_xref = self["xref"].real()
  182 + self.m_yref = self["yref"].real()
  183 + self.m_emin = self["emin"].real()
  184 + self.m_emax = self["emax"].real()
  185 + self.m_enumbins = self["enumbins"].integer()
  186 + self.m_ebinalg = self["ebinalg"].string()
  187 + self.m_coordsys = self["coordsys"].string()
  188 + self.m_proj = self["proj"].string()
  189 + self.m_nxpix = self["nxpix"].integer()
  190 + self.m_nypix = self["nypix"].integer()
  191 + self.m_binsz = self["binsz"].real()
  192 +
  193 + # Read necessary parameters
  194 + self.m_outfile = self["outmap"].filename()
156 self.m_algorithm = self["algorithm"].string() 195 self.m_algorithm = self["algorithm"].string()
157 - 196 +
158 # Set some fixed parameters 197 # Set some fixed parameters
159 self.m_log = False # Logging in client tools 198 self.m_log = False # Logging in client tools
160 self.m_chatter = self["chatter"].integer() 199 self.m_chatter = self["chatter"].integer()
@@ -210,53 +249,76 @@ class csresmap(ctools.cscript): @@ -210,53 +249,76 @@ class csresmap(ctools.cscript):
210 self.log(str(self.obs)) 249 self.log(str(self.obs))
211 self.log("\n") 250 self.log("\n")
212 251
213 - # Write header  
214 - if self.logTerse():  
215 - self.log("\n")  
216 - self.log.header1("Generate binned map (ctbin)")  
217 -  
218 - # Create countsmap  
219 - bin = ctools.ctbin(self.obs)  
220 - bin["nxpix"] = self.m_nxpix  
221 - bin["nypix"] = self.m_nypix  
222 - bin["proj"] = self.m_proj  
223 - bin["coordsys"] = self.m_coordsys  
224 - bin["xref"] = self.m_xref  
225 - bin["yref"] = self.m_yref  
226 - bin["enumbins"] = self.m_enumbins  
227 - bin["ebinalg"] = self.m_ebinalg  
228 - bin["emin"] = self.m_emin  
229 - bin["emax"] = self.m_emax  
230 - bin["binsz"] = self.m_binsz  
231 - bin["chatter"] = self.m_chatter  
232 - bin["clobber"] = self.m_clobber  
233 - bin["debug"] = self.m_debug  
234 - bin.run() 252 + countmap = gammalib.GSkymap()
  253 + modelmap = gammalib.GSkymap()
  254 +
  255 + # Use input file directly if given
  256 + if self.m_use_maps:
  257 + countmap = gammalib.GSkymap(self.m_cntcube)
  258 + modelmap = gammalib.GSkymap(self.m_modcube)
  259 +
  260 + else:
  261 +
  262 + cta_counts_cube = gammalib.GCTAEventCube()
  263 +
  264 + if self.m_skip_binning:
  265 + cta_counts_cube = gammalib.GCTAEventCube(self.obs[0].events().clone())
235 266
  267 + else:
  268 +
  269 + # Write header
  270 + if self.logTerse():
  271 + self.log("\n")
  272 + self.log.header1("Generate binned map (ctbin)")
  273 +
  274 + # Create countsmap
  275 + bin = ctools.ctbin(self.obs)
  276 + bin["nxpix"].integer(self.m_nxpix)
  277 + bin["nypix"].integer(self.m_nypix)
  278 + bin["proj"].string(self.m_proj)
  279 + bin["coordsys"].string(self.m_coordsys)
  280 + bin["xref"].real(self.m_xref)
  281 + bin["yref"].real(self.m_yref)
  282 + bin["enumbins"].integer(self.m_enumbins)
  283 + bin["ebinalg"].string(self.m_ebinalg)
  284 + bin["emin"].real(self.m_emin)
  285 + bin["emax"].real(self.m_emax)
  286 + bin["binsz"].real(self.m_binsz)
  287 + bin["chatter"].integer(self.m_chatter)
  288 + bin["clobber"].boolean(self.m_clobber)
  289 + bin["debug"].boolean(self.m_debug)
  290 + bin.run()
  291 +
  292 + # Retrieve counts cube
  293 + cta_counts_cube = bin.cube()
  294 +
  295 + # Assign GCTAEventCube to skymap
  296 + countmap = cta_counts_cube.map()
  297 +
  298 + # Write header
  299 + if self.logTerse():
  300 + self.log("\n")
  301 + self.log.header1("Generate model map (ctmodel)")
  302 +
  303 + # Create model map
  304 + model = ctools.ctmodel(self.obs)
  305 + model.cube(cta_counts_cube)
  306 + model["chatter"].integer(self.m_chatter)
  307 + model["clobber"].boolean(self.m_clobber)
  308 + model["debug"].boolean(self.m_debug)
  309 + model.run()
  310 +
  311 + # Get model map into GSkymap object
  312 + modelmap = model.cube().map().copy()
  313 +
  314 +
236 # Store counts map as residual map. Note that we need a 315 # Store counts map as residual map. Note that we need a
237 # special construct here to avoid memory leaks. This seems 316 # special construct here to avoid memory leaks. This seems
238 # to be a SWIG feature as SWIG creates a new object when 317 # to be a SWIG feature as SWIG creates a new object when
239 # calling bin.cube() 318 # calling bin.cube()
240 - #residualmap = bin.cube().map()  
241 - counts_cube = bin.cube()  
242 - self.resmap = counts_cube.map().copy() 319 + #residualmap = bin.cube().map()
  320 + self.resmap = countmap.copy()
243 self.resmap.stack_maps() 321 self.resmap.stack_maps()
244 -  
245 - # Write header  
246 - if self.logTerse():  
247 - self.log("\n")  
248 - self.log.header1("Generate model map (ctmodel)")  
249 -  
250 - # Create model map  
251 - model = ctools.ctmodel(self.obs)  
252 - model.cube(bin.cube())  
253 - model["chatter"] = self.m_chatter  
254 - model["clobber"] = self.m_clobber  
255 - model["debug"] = self.m_debug  
256 - model.run()  
257 -  
258 - # Get model map into GSkymap object  
259 - modelmap = model.cube().map()  
260 modelmap.stack_maps() 322 modelmap.stack_maps()
261 323
262 # Continue calculations depending on given algorithm 324 # Continue calculations depending on given algorithm
src/ctmodel/ctmodel.cpp
@@ -270,9 +270,34 @@ void ctmodel::run(void) @@ -270,9 +270,34 @@ void ctmodel::run(void)
270 } 270 }
271 } 271 }
272 272
  273 + // Fill cube and leave loop if we are binned mode (meaning we only have
  274 + // one binned observation)
  275 + if (m_binned && m_obs.size() == 1) {
  276 + fill_cube(obs);
  277 + break;
  278 + }
  279 +
  280 + // Skip observation if we don't have an unbinned observation
  281 + if (obs->eventtype() != "EventList") {
  282 +
  283 + // Log that we skip the this observation
  284 + if (logTerse()) {
  285 + log << "Warning: Skipping binned observation \""+obs->name()+"\"";
  286 + log << std::endl;
  287 + }
  288 + continue;
  289 + }
  290 +
  291 +
273 // Fill the cube 292 // Fill the cube
274 fill_cube(obs); 293 fill_cube(obs);
275 294
  295 + // Leave loop if we are binned mode (meaning we only have
  296 + // one binned observation
  297 + if (m_binned && m_obs.size() == 1) {
  298 + break;
  299 + }
  300 +
276 // Dispose events to free memory if event file exists on disk 301 // Dispose events to free memory if event file exists on disk
277 if (obs->eventfile().length() > 0 && 302 if (obs->eventfile().length() > 0 &&
278 gammalib::file_exists(obs->eventfile())) { 303 gammalib::file_exists(obs->eventfile())) {
@@ -374,6 +399,7 @@ void ctmodel::init_members(void) @@ -374,6 +399,7 @@ void ctmodel::init_members(void)
374 m_gti.clear(); 399 m_gti.clear();
375 m_has_cube = false; 400 m_has_cube = false;
376 m_append_cube = false; 401 m_append_cube = false;
  402 + m_binned = false;
377 403
378 // Return 404 // Return
379 return; 405 return;
@@ -397,6 +423,7 @@ void ctmodel::copy_members(const ctmodel&amp; app) @@ -397,6 +423,7 @@ void ctmodel::copy_members(const ctmodel&amp; app)
397 m_gti = app.m_gti; 423 m_gti = app.m_gti;
398 m_has_cube = app.m_has_cube; 424 m_has_cube = app.m_has_cube;
399 m_append_cube = app.m_append_cube; 425 m_append_cube = app.m_append_cube;
  426 + m_binned = app.m_binned;
400 427
401 // Return 428 // Return
402 return; 429 return;
@@ -430,6 +457,36 @@ void ctmodel::get_parameters(void) @@ -430,6 +457,36 @@ void ctmodel::get_parameters(void)
430 m_obs = get_observations(); 457 m_obs = get_observations();
431 } 458 }
432 459
  460 + // Check if we got excactly one binned CTA observation
  461 + if (m_obs.size() == 1) {
  462 +
  463 + // Get CTA observation
  464 + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[0]);
  465 +
  466 + // Continue only if observation is a CTA observation
  467 + if (obs != NULL) {
  468 +
  469 + // Check for binned observation
  470 + if (obs->eventtype() == "CountsCube") {
  471 +
  472 + // Set cube from binned observation
  473 + GCTAEventCube* evtcube = dynamic_cast<GCTAEventCube*>(const_cast<GEvents*>(obs->events()));
  474 +
  475 + cube(*evtcube);
  476 +
  477 + // Signal that cube has been set
  478 + m_has_cube = true;
  479 +
  480 + // Signal that we are in binned mode
  481 + m_binned = true;
  482 +
  483 + } // endif: observation was binned
  484 +
  485 + } // endif: observation was CTA
  486 +
  487 + } // endif: had exactly one observation
  488 +
  489 +
433 // Read model definition file if required 490 // Read model definition file if required
434 if (m_obs.models().size() == 0) { 491 if (m_obs.models().size() == 0) {
435 492
@@ -583,3 +640,4 @@ void ctmodel::fill_cube(const GCTAObservation* obs) @@ -583,3 +640,4 @@ void ctmodel::fill_cube(const GCTAObservation* obs)
583 // Return 640 // Return
584 return; 641 return;
585 } 642 }
  643 +
src/ctmodel/ctmodel.hpp
@@ -92,6 +92,7 @@ protected: @@ -92,6 +92,7 @@ protected:
92 GGti m_gti; //!< Model cube GTIs 92 GGti m_gti; //!< Model cube GTIs
93 bool m_has_cube; //!< Signal if cube has been set or loaded 93 bool m_has_cube; //!< Signal if cube has been set or loaded
94 bool m_append_cube; //!< Signal that cube should be appended 94 bool m_append_cube; //!< Signal that cube should be appended
  95 + bool m_binned; //!< Signals that we are in binned mode
95 }; 96 };
96 97
97 98
test/test_cscripts.sh.in
@@ -182,7 +182,8 @@ chmod +x @abs_top_srcdir@/scripts/csresmap.py @@ -182,7 +182,8 @@ chmod +x @abs_top_srcdir@/scripts/csresmap.py
182 xref=83.63 \ 182 xref=83.63 \
183 yref=22.01 \ 183 yref=22.01 \
184 proj="CAR" \ 184 proj="CAR" \
185 - binsz=0.05 > csresmap.log 185 + binsz=0.05 \
  186 + algorithm="SUBDIV" > csresmap.log
186 $ECHO -n "." 187 $ECHO -n "."
187 if [ -s "resmap.fits" ] 188 if [ -s "resmap.fits" ]
188 then 189 then