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 42 self.version = "1.0.0"
43 43  
44 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 52 # Initialise some members
50 53 if len(argv) > 0 and isinstance(argv[0],gammalib.GObservations):
... ... @@ -101,6 +104,10 @@ class csresmap(ctools.cscript):
101 104 # Create default parfile
102 105 pars = gammalib.GApplicationPars()
103 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 111 pars.append(gammalib.GApplicationPar("inmodel","f","a","$CTOOLS/share/models/crab.xml","","","Source model"))
105 112 pars.append(gammalib.GApplicationPar("outmap","f","a","resmap.fits","","","Output residual map"))
106 113 pars.append(gammalib.GApplicationPar("caldb","s","a","prod2","","","Calibration database"))
... ... @@ -117,7 +124,7 @@ class csresmap(ctools.cscript):
117 124 pars.append(gammalib.GApplicationPar("nxpix","i","a","200","","","Size of the X axis in pixels"))
118 125 pars.append(gammalib.GApplicationPar("nypix","i","a","200","","","Size of the Y axis in pixels"))
119 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 128 pars.append_standard()
122 129 pars.append(gammalib.GApplicationPar("logfile","f","h","csresmap.log","","","Log filename"))
123 130 pars.save(parfile)
... ... @@ -129,32 +136,64 @@ class csresmap(ctools.cscript):
129 136 """
130 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 195 self.m_algorithm = self["algorithm"].string()
157   -
  196 +
158 197 # Set some fixed parameters
159 198 self.m_log = False # Logging in client tools
160 199 self.m_chatter = self["chatter"].integer()
... ... @@ -210,53 +249,76 @@ class csresmap(ctools.cscript):
210 249 self.log(str(self.obs))
211 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 315 # Store counts map as residual map. Note that we need a
237 316 # special construct here to avoid memory leaks. This seems
238 317 # to be a SWIG feature as SWIG creates a new object when
239 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 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 322 modelmap.stack_maps()
261 323  
262 324 # Continue calculations depending on given algorithm
... ...
src/ctmodel/ctmodel.cpp
... ... @@ -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 292 // Fill the cube
274 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 301 // Dispose events to free memory if event file exists on disk
277 302 if (obs->eventfile().length() > 0 &&
278 303 gammalib::file_exists(obs->eventfile())) {
... ... @@ -374,6 +399,7 @@ void ctmodel::init_members(void)
374 399 m_gti.clear();
375 400 m_has_cube = false;
376 401 m_append_cube = false;
  402 + m_binned = false;
377 403  
378 404 // Return
379 405 return;
... ... @@ -397,6 +423,7 @@ void ctmodel::copy_members(const ctmodel&amp; app)
397 423 m_gti = app.m_gti;
398 424 m_has_cube = app.m_has_cube;
399 425 m_append_cube = app.m_append_cube;
  426 + m_binned = app.m_binned;
400 427  
401 428 // Return
402 429 return;
... ... @@ -430,6 +457,36 @@ void ctmodel::get_parameters(void)
430 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 490 // Read model definition file if required
434 491 if (m_obs.models().size() == 0) {
435 492  
... ... @@ -583,3 +640,4 @@ void ctmodel::fill_cube(const GCTAObservation* obs)
583 640 // Return
584 641 return;
585 642 }
  643 +
... ...
src/ctmodel/ctmodel.hpp
... ... @@ -92,6 +92,7 @@ protected:
92 92 GGti m_gti; //!< Model cube GTIs
93 93 bool m_has_cube; //!< Signal if cube has been set or loaded
94 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 182 xref=83.63 \
183 183 yref=22.01 \
184 184 proj="CAR" \
185   - binsz=0.05 > csresmap.log
  185 + binsz=0.05 \
  186 + algorithm="SUBDIV" > csresmap.log
186 187 $ECHO -n "."
187 188 if [ -s "resmap.fits" ]
188 189 then
... ...