Commit 2de25f8ed3c99a7b3c746f2cad8757efa05a263b
Merge branch '1439-adapt-ctools-to-consistently-handle-observation-types' into integration
Conflicts: scripts/csresmap.py
Showing
4 changed files
with
191 additions
and
69 deletions
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& app) | @@ -397,6 +423,7 @@ void ctmodel::copy_members(const ctmodel& 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 |