Commit f25aeb73625d6d907da46a75ada6823c19f96513
1 parent
cf3f1ec9
Enable ctbin to produce counts cubes for a joint binned analysis (#2714)
Showing
8 changed files
with
448 additions
and
313 deletions
ChangeLog
| 1 | -2018-11-03 | |
| 1 | +2018-11-07 | |
| 2 | 2 | |
| 3 | 3 | * Version 1.6.0 released |
| 4 | 4 | ======================== |
| 5 | 5 | |
| 6 | + Enable ctbin to produce counts cubes for a joint binned analysis (#2714) | |
| 6 | 7 | Add code generator (#2709) |
| 7 | 8 | Add csbkgmodel script (#2694) |
| 8 | 9 | Compute DETX and DETY in ctmodel if they are not available (#2694) | ... | ... |
NEWS
| ... | ... | @@ -55,6 +55,14 @@ of the filename is now done by the GApplicationPar class. |
| 55 | 55 | |
| 56 | 56 | ctbin - CTA event binning |
| 57 | 57 | ------------------------- |
| 58 | +Added the option to produce an individual counts cube for each event list in | |
| 59 | +the input observation definition XML file. The option is enabled by setting | |
| 60 | +the new hidden parameter "stack" to "no". The cube() method now has an optional | |
| 61 | +index argument, providing access to the i'th counts cube that was produced. | |
| 62 | +The cubes() method specifies the number of counts cubes that were produced. | |
| 63 | +If no counts cube was produced, the cube() method now throws an exception | |
| 64 | +(#2714). | |
| 65 | + | |
| 58 | 66 | ctbin now accouts for varying energy thresholds when computing the weight |
| 59 | 67 | array (#2685). |
| 60 | 68 | ... | ... |
doc/source/admin/release_history/1.6.rst
| ... | ... | @@ -41,6 +41,8 @@ Bug fixes |
| 41 | 41 | Improvements |
| 42 | 42 | ------------ |
| 43 | 43 | |
| 44 | +* [`2714 <https://cta-redmine.irap.omp.eu/issues/2714>`_] - | |
| 45 | + Enable :ref:`ctbin` to produce counts cubes for a joint binned analysis | |
| 44 | 46 | * [`2685 <https://cta-redmine.irap.omp.eu/issues/2685>`_] - |
| 45 | 47 | Add ``ctbkgcube::cntcube()`` method |
| 46 | 48 | Account for varying energy thresholds in :ref:`ctbin` weight computation | ... | ... |
pyext/ctbin.i
| 1 | 1 | /*************************************************************************** |
| 2 | 2 | * ctbin - Event binning tool * |
| 3 | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2010-2016 by Juergen Knoedlseder * | |
| 4 | + * copyright (C) 2010-2018 by Juergen Knoedlseder * | |
| 5 | 5 | * ----------------------------------------------------------------------- * |
| 6 | 6 | * * |
| 7 | 7 | * This program is free software: you can redistribute it and/or modify * |
| ... | ... | @@ -46,10 +46,10 @@ public: |
| 46 | 46 | // Methods |
| 47 | 47 | void clear(void); |
| 48 | 48 | void run(void); |
| 49 | + int cubes(void) const; | |
| 50 | + const GCTAEventCube& cube(const int& index = 0) const; | |
| 49 | 51 | void save(void); |
| 50 | 52 | void publish(const std::string& name = ""); |
| 51 | - const GCTAEventCube& cube(void) const; | |
| 52 | - const GCTAEventCube& cube(const size_t& index) const; | |
| 53 | 53 | }; |
| 54 | 54 | |
| 55 | 55 | ... | ... |
src/ctbin/ctbin.cpp
| ... | ... | @@ -38,6 +38,7 @@ |
| 38 | 38 | #endif |
| 39 | 39 | |
| 40 | 40 | /* __ Method name definitions ____________________________________________ */ |
| 41 | +#define G_CUBE "ctbin::cube(int&)" | |
| 41 | 42 | #define G_GET_PARAMETERS "ctbin::get_parameters()" |
| 42 | 43 | #define G_FILL_CUBE "ctbin::fill_cube(GCTAObservation*)" |
| 43 | 44 | #define G_SET_WEIGHTS "ctbin::set_weights(GCTAObservation*)" |
| ... | ... | @@ -234,6 +235,9 @@ void ctbin::run(void) |
| 234 | 235 | // Get task parameters |
| 235 | 236 | get_parameters(); |
| 236 | 237 | |
| 238 | + // Initialise sky direction cache for stacking | |
| 239 | + init_sky_dir_cache(); | |
| 240 | + | |
| 237 | 241 | // Write input observation container into logger |
| 238 | 242 | log_observations(NORMAL, m_obs, "Input observation"); |
| 239 | 243 | |
| ... | ... | @@ -255,33 +259,33 @@ void ctbin::run(void) |
| 255 | 259 | log_string(NORMAL, msg); |
| 256 | 260 | } |
| 257 | 261 | |
| 258 | - // Initialise cubes and ids if unstacked | |
| 259 | - if (!m_stack) { | |
| 260 | - m_cubes = std::vector<GCTAEventCube>(obs_list.size()); | |
| 261 | - m_ids = std::vector<std::string>(obs_list.size()); | |
| 262 | + // Set number of relevant observations | |
| 263 | + int nobs = obs_list.size(); | |
| 264 | + | |
| 265 | + // Initialise arrays | |
| 266 | + if (nobs > 0) { | |
| 267 | + m_counts = std::vector<GSkyMap>(nobs); | |
| 268 | + m_weights = std::vector<GSkyMap>(nobs); | |
| 269 | + m_cubes = std::vector<GCTAEventCube>(nobs); | |
| 270 | + m_ids = std::vector<std::string>(nobs); | |
| 271 | + } | |
| 272 | + else { | |
| 273 | + m_counts.clear(); | |
| 274 | + m_weights.clear(); | |
| 275 | + m_cubes.clear(); | |
| 276 | + m_ids.clear(); | |
| 262 | 277 | } |
| 263 | 278 | |
| 264 | 279 | // Write header into logger |
| 265 | - log_header1(TERSE, gammalib::number("Bin observation", m_obs.size())); | |
| 280 | + log_header1(TERSE, gammalib::number("Bin observation", nobs)); | |
| 266 | 281 | |
| 267 | 282 | // Loop over all unbinned CTA observations in the container |
| 268 | 283 | #pragma omp parallel for |
| 269 | - for (int i = 0; i < obs_list.size(); ++i) { | |
| 284 | + for (int i = 0; i < nobs; ++i) { | |
| 270 | 285 | |
| 271 | 286 | // Get pointer to observation |
| 272 | 287 | GCTAObservation* obs = obs_list[i]; |
| 273 | 288 | |
| 274 | - // Make sure that the observation holds a CTA event list. If this | |
| 275 | - // is not the case then throw an exception. | |
| 276 | - const GCTAEventList* events = dynamic_cast<const GCTAEventList*> | |
| 277 | - (obs->events()); | |
| 278 | - if (events == NULL) { | |
| 279 | - std::string msg = "CTA Observation does not contain an event " | |
| 280 | - "list. An event list is needed to fill the " | |
| 281 | - "counts cube."; | |
| 282 | - throw GException::invalid_value(G_FILL_CUBE, msg); | |
| 283 | - } | |
| 284 | - | |
| 285 | 289 | // Fill the cube |
| 286 | 290 | GSkyMap counts = fill_cube(obs); |
| 287 | 291 | |
| ... | ... | @@ -291,88 +295,118 @@ void ctbin::run(void) |
| 291 | 295 | // Dispose events to free memory |
| 292 | 296 | obs->dispose_events(); |
| 293 | 297 | |
| 298 | + // Post process cubes | |
| 294 | 299 | #pragma omp critical(ctbin_fill_cube) |
| 295 | - if (m_stack) { | |
| 296 | - | |
| 297 | - | |
| 298 | - m_counts += counts; | |
| 299 | - | |
| 300 | - for (int iebin = 0; iebin < m_ebounds.size(); ++iebin) { | |
| 301 | - for (int pixel = 0; pixel < m_counts.npix(); ++pixel) { | |
| 302 | - if (weights(pixel, iebin) == 1.0) { | |
| 303 | - m_weights(pixel, iebin) = 1.0; | |
| 304 | - } | |
| 305 | - } | |
| 306 | - } | |
| 307 | - | |
| 308 | - | |
| 309 | - // If GTI is empty then set its time reference from the observation. | |
| 310 | - // From then on we keep that time reference | |
| 300 | + { | |
| 301 | + // If stacking of cubes is requested then add up counts cube | |
| 302 | + // and set weights in the first slot of the m_counts and | |
| 303 | + // m_weights arrays | |
| 304 | + if (m_stack) { | |
| 305 | + if (i == 0) { | |
| 306 | + m_counts[0] = counts; | |
| 307 | + m_weights[0] = weights; | |
| 308 | + } | |
| 309 | + else { | |
| 310 | + for (int iebin = 0; iebin < m_ebounds.size(); ++iebin) { | |
| 311 | + for (int pixel = 0; pixel < counts.npix(); ++pixel) { | |
| 312 | + m_counts[0](pixel, iebin) += counts(pixel, iebin); | |
| 313 | + if (weights(pixel, iebin) == 1.0) { | |
| 314 | + m_weights[0](pixel, iebin) = 1.0; | |
| 315 | + } | |
| 316 | + } | |
| 317 | + } | |
| 318 | + } | |
| 319 | + } | |
| 320 | + | |
| 321 | + // ... otherwise store counts, weights and observation ID | |
| 322 | + else { | |
| 323 | + m_counts[i] = counts; | |
| 324 | + m_weights[i] = weights; | |
| 325 | + m_ids[i] = obs->id(); | |
| 326 | + } | |
| 327 | + | |
| 328 | + } // end: omp critical section | |
| 329 | + | |
| 330 | + } // endfor: looped over observations | |
| 331 | + | |
| 332 | + // Combine GTIs of all observations and compute total ontime and livetime | |
| 333 | + for (int i = 0; i < nobs; ++i) { | |
| 334 | + | |
| 335 | + // Get pointer to observation | |
| 336 | + GCTAObservation* obs = obs_list[i]; | |
| 337 | + | |
| 338 | + // Get Good Time Intervals for observation | |
| 339 | + GGti gti = obs->gti(); | |
| 340 | + | |
| 341 | + // If resulting GTI is not filled then copy over the reference from | |
| 342 | + // the observation and use it for the resulting GTI | |
| 311 | 343 | if (m_gti.is_empty()) { |
| 312 | - m_gti.reference(events->gti().reference()); | |
| 344 | + m_gti.reference(gti.reference()); | |
| 313 | 345 | } |
| 314 | - | |
| 346 | + | |
| 315 | 347 | // Append GTIs |
| 316 | - m_gti.extend(events->gti()); | |
| 317 | - | |
| 348 | + m_gti.extend(gti); | |
| 349 | + | |
| 318 | 350 | // Update ontime and livetime |
| 319 | 351 | m_ontime += obs->ontime(); |
| 320 | 352 | m_livetime += obs->livetime(); |
| 321 | - | |
| 322 | - } else { // don't stack cubes | |
| 323 | 353 | |
| 324 | - // Construct a cube from this observation | |
| 325 | - GCTAEventCube cube(counts, weights, m_ebounds, events->gti()); | |
| 326 | - m_cubes[i] = cube; | |
| 327 | - obs->events(cube); | |
| 354 | + } // endfor: looped over all observations | |
| 355 | + | |
| 356 | + // Post process data for a stacked cube | |
| 357 | + if (m_stack && nobs > 0) { | |
| 358 | + | |
| 359 | + // Compute livetime fraction per energy bin so that varying energy | |
| 360 | + // thresholds are correctly taken into account in the weighting | |
| 361 | + // array. Computational speed is not optimum, we have to see later | |
| 362 | + // whether this is an issue. | |
| 363 | + for (int iebin = 0; iebin < m_ebounds.size(); ++iebin) { | |
| 364 | + double livetime_ebin = 0.0; | |
| 365 | + for (int i = 0; i < obs_list.size(); ++i) { | |
| 366 | + std::vector<bool> usage = | |
| 367 | + cube_layer_usage(m_ebounds, obs_list[i]->ebounds()); | |
| 368 | + if (usage[iebin]) { | |
| 369 | + livetime_ebin += obs_list[i]->livetime(); | |
| 370 | + } | |
| 371 | + } | |
| 372 | + if (m_livetime > 0.0) { | |
| 373 | + double fraction = livetime_ebin / m_livetime; | |
| 374 | + for (int pixel = 0; pixel < m_counts[0].npix(); ++pixel) { | |
| 375 | + if (m_weights[0](pixel, iebin) > 0.0) { | |
| 376 | + m_weights[0](pixel, iebin) *= fraction; | |
| 377 | + } | |
| 378 | + } | |
| 379 | + } | |
| 380 | + } | |
| 328 | 381 | |
| 329 | - // Store id of the observation | |
| 330 | - m_ids[i] = obs->id(); | |
| 331 | - | |
| 332 | - } | |
| 382 | + // Set a single cube in the observation container | |
| 383 | + obs_cube_stacked(); | |
| 333 | 384 | |
| 385 | + } // endif: stacked cube post processing | |
| 334 | 386 | |
| 335 | - } // endfor: looped over observations | |
| 387 | + // Post process data for non-stacked cubes | |
| 388 | + else { | |
| 336 | 389 | |
| 337 | - if (m_stack) { | |
| 338 | - // Compute total livetime in all observations | |
| 339 | - double livetime = 0.0; | |
| 340 | - for (int i = 0; i < obs_list.size(); ++i) { | |
| 341 | - livetime += obs_list[i]->livetime(); | |
| 342 | - } | |
| 343 | - | |
| 344 | - // Compute livetime fraction per energy bin so that varying energy | |
| 345 | - // thresholds are correctly taken into account in the weighting | |
| 346 | - // array. Computational speed is not optimum, we have to see later | |
| 347 | - // whether this is an issue. | |
| 348 | - for (int iebin = 0; iebin < m_ebounds.size(); ++iebin) { | |
| 349 | - double livetime_ebin = 0.0; | |
| 350 | - for (int i = 0; i < obs_list.size(); ++i) { | |
| 351 | - const GCTAEventList* events = dynamic_cast<const GCTAEventList*> | |
| 352 | - (obs_list[i]->events()); | |
| 353 | - std::vector<bool> usage = cube_layer_usage(m_ebounds, | |
| 354 | - events->ebounds()); | |
| 355 | - if (usage[iebin]) { | |
| 356 | - livetime_ebin += obs_list[i]->livetime(); | |
| 357 | - } | |
| 358 | - } | |
| 359 | - if (livetime > 0.0) { | |
| 360 | - double fraction = livetime_ebin / livetime; | |
| 361 | - for (int pixel = 0; pixel < m_counts.npix(); ++pixel) { | |
| 362 | - if (m_weights(pixel, iebin) > 0.0) { | |
| 363 | - m_weights(pixel, iebin) *= fraction; | |
| 364 | - } | |
| 365 | - } | |
| 366 | - } | |
| 367 | - } | |
| 390 | + // Loop over all relevant observations | |
| 391 | + for (int i = 0; i < nobs; ++i) { | |
| 368 | 392 | |
| 369 | - // Build event cube (needs to come before obs_cube() since this method | |
| 370 | - // relies on correct setting of m_cube) | |
| 371 | - m_cube = GCTAEventCube(m_counts, m_weights, m_ebounds, m_gti); | |
| 393 | + // Get pointer to observation | |
| 394 | + GCTAObservation* obs = obs_list[i]; | |
| 372 | 395 | |
| 373 | - // Set a single cube in the observation container | |
| 374 | - obs_cube(); | |
| 375 | - } | |
| 396 | + // Build counts cube | |
| 397 | + m_cubes[i] = GCTAEventCube(m_counts[i], m_weights[i], m_ebounds, | |
| 398 | + obs->gti()); | |
| 399 | + | |
| 400 | + // Attach event cube in the correct slot of the observation | |
| 401 | + // container | |
| 402 | + obs->events(m_cubes[i]); | |
| 403 | + | |
| 404 | + // Store ID of the observation for saving of XML file | |
| 405 | + m_ids[i] = obs->id(); | |
| 406 | + | |
| 407 | + } // endfor: looped over relevant observations | |
| 408 | + | |
| 409 | + } // endelse: non-stacked cube post processing | |
| 376 | 410 | |
| 377 | 411 | // Write resulting observation container into logger |
| 378 | 412 | log_observations(NORMAL, m_obs, "Binned observation"); |
| ... | ... | @@ -388,72 +422,108 @@ void ctbin::run(void) |
| 388 | 422 | |
| 389 | 423 | |
| 390 | 424 | /***********************************************************************//** |
| 425 | + * @brief Return event cube at index | |
| 426 | + * | |
| 427 | + * @param[in] index Cube index (0,...,cubes()-1). | |
| 428 | + * @return Reference to event cube. | |
| 429 | + * | |
| 430 | + * @exception GException::out_of_range | |
| 431 | + * Event cube index out of range. | |
| 432 | + * | |
| 433 | + * Returns a reference to the event cube at the given index. | |
| 434 | + ***************************************************************************/ | |
| 435 | +const GCTAEventCube& ctbin::cube(const int& index) const | |
| 436 | +{ | |
| 437 | + // Compile option: raise an exception if index is out of range | |
| 438 | + if (index < 0 || index >= cubes()) { | |
| 439 | + throw GException::out_of_range(G_CUBE, "Cube index", index, cubes()); | |
| 440 | + } | |
| 441 | + | |
| 442 | + // Return cube | |
| 443 | + return m_cubes[index]; | |
| 444 | +} | |
| 445 | + | |
| 446 | + | |
| 447 | +/***********************************************************************//** | |
| 391 | 448 | * @brief Save counts cube |
| 392 | 449 | * |
| 393 | - * Saves the counts cube into a FITS file. | |
| 450 | + * Saves the counts cube. If the counts cube was stacked single FITS file | |
| 451 | + * will be written. Otherwise each generated counts cube will be written | |
| 452 | + * into a FITS file, and an observation definition XML file will be written | |
| 453 | + * out that contains an observation for each counts cube. | |
| 394 | 454 | ***************************************************************************/ |
| 395 | 455 | void ctbin::save(void) |
| 396 | 456 | { |
| 397 | 457 | // Write header |
| 398 | 458 | log_header1(TERSE, "Save counts cube"); |
| 399 | 459 | |
| 400 | - if (!m_stack) { | |
| 401 | - | |
| 402 | - // Loop over all observations | |
| 403 | - for (size_t i = 0; i < m_obs.size(); ++i) { | |
| 404 | - | |
| 405 | - // Loop over all ids of observations that were binned | |
| 406 | - for (size_t j = 0; j < m_ids.size(); ++j) { | |
| 407 | - | |
| 408 | - // Check if ids are equal | |
| 409 | - if (m_ids[j] == m_obs[i]->id()) { | |
| 410 | - | |
| 411 | - // Construct filename | |
| 412 | - std::string filename(m_ids[j]); | |
| 413 | - filename.insert(0, m_prefix); | |
| 414 | - filename.append(".fits"); | |
| 415 | - | |
| 416 | - // Set filename for counts cube | |
| 417 | - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]); | |
| 418 | - obs->eventfile(filename); | |
| 419 | - | |
| 420 | - // Save countscube | |
| 421 | - obs->save(filename, clobber()); | |
| 422 | - } | |
| 423 | - } | |
| 424 | - } | |
| 425 | - if ((*this)["outcube"].is_valid()) { | |
| 426 | - // Get counts cube filename | |
| 427 | - m_outcube = (*this)["outcube"].filename(); | |
| 428 | - m_obs.save(m_outcube); | |
| 429 | - } | |
| 430 | - | |
| 431 | - } else { // else: stack | |
| 432 | - | |
| 433 | - // Save only if filename is valid and if there is at least one | |
| 434 | - // observation | |
| 435 | - if ((*this)["outcube"].is_valid() && m_obs.size() > 0) { | |
| 436 | - | |
| 437 | - // Get counts cube filename | |
| 438 | - m_outcube = (*this)["outcube"].filename(); | |
| 439 | - | |
| 440 | - // Get CTA observation from observation container | |
| 441 | - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[0]); | |
| 442 | - | |
| 443 | - // Save only if observation is valid | |
| 444 | - if (obs != NULL) { | |
| 445 | - | |
| 446 | - // Log counts cube file name | |
| 447 | - log_value(NORMAL, "Counts cube file", m_outcube.url()); | |
| 448 | - | |
| 449 | - // Save cube | |
| 450 | - obs->save(m_outcube, clobber()); | |
| 451 | - | |
| 452 | - } // endif: observation was valid | |
| 453 | - | |
| 454 | - } // endif: outcube file was valid | |
| 455 | - | |
| 456 | - } // endelse: stack | |
| 460 | + // If counts cube was stacked then save first observation | |
| 461 | + if (m_stack) { | |
| 462 | + | |
| 463 | + // Save only if filename is valid and if there is at least one | |
| 464 | + // observation | |
| 465 | + if ((*this)["outcube"].is_valid() && m_obs.size() > 0) { | |
| 466 | + | |
| 467 | + // Get counts cube filename | |
| 468 | + m_outcube = (*this)["outcube"].filename(); | |
| 469 | + | |
| 470 | + // Get CTA observation from observation container | |
| 471 | + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[0]); | |
| 472 | + | |
| 473 | + // Save only if observation is valid | |
| 474 | + if (obs != NULL) { | |
| 475 | + | |
| 476 | + // Log counts cube file name | |
| 477 | + log_value(NORMAL, "Counts cube file", m_outcube.url()); | |
| 478 | + | |
| 479 | + // Save cube | |
| 480 | + obs->save(m_outcube, clobber()); | |
| 481 | + | |
| 482 | + } // endif: observation was valid | |
| 483 | + | |
| 484 | + } // endif: outcube file was valid | |
| 485 | + | |
| 486 | + } // endif: counts cube was stacked | |
| 487 | + | |
| 488 | + // ... otherwise write out all relevant counts cubes and the observation | |
| 489 | + // definition XML file | |
| 490 | + else { | |
| 491 | + | |
| 492 | + // Loop over all observations | |
| 493 | + for (int i = 0; i < m_obs.size(); ++i) { | |
| 494 | + | |
| 495 | + // Loop over all ids of observations that were binned | |
| 496 | + for (int j = 0; j < m_ids.size(); ++j) { | |
| 497 | + | |
| 498 | + // Skip if ID differes | |
| 499 | + if (m_ids[j] != m_obs[i]->id()) { | |
| 500 | + continue; | |
| 501 | + } | |
| 502 | + | |
| 503 | + // Construct filename | |
| 504 | + std::string filename(m_ids[j]); | |
| 505 | + filename.insert(0, m_prefix); | |
| 506 | + filename.append(".fits"); | |
| 507 | + | |
| 508 | + // Set filename for counts cube | |
| 509 | + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]); | |
| 510 | + obs->eventfile(filename); | |
| 511 | + | |
| 512 | + // Save countscube | |
| 513 | + obs->save(filename, clobber()); | |
| 514 | + | |
| 515 | + } // endfor: looped over all IDs | |
| 516 | + | |
| 517 | + } // endfor: looped over all observations | |
| 518 | + | |
| 519 | + // Write XML file | |
| 520 | + if ((*this)["outcube"].is_valid()) { | |
| 521 | + m_outcube = (*this)["outcube"].filename(); | |
| 522 | + m_obs.save(m_outcube); | |
| 523 | + } | |
| 524 | + | |
| 525 | + } // endelse: counts cube were not stacked | |
| 526 | + | |
| 457 | 527 | // Return |
| 458 | 528 | return; |
| 459 | 529 | } |
| ... | ... | @@ -478,8 +548,10 @@ void ctbin::publish(const std::string& name) |
| 478 | 548 | // Write counts cube name into logger |
| 479 | 549 | log_value(NORMAL, "Counts cube name", user_name); |
| 480 | 550 | |
| 481 | - // Publish counts cube | |
| 482 | - m_counts.publish(user_name); | |
| 551 | + // Publish first counts cube if it exists | |
| 552 | + if (cubes() > 0) { | |
| 553 | + m_counts[0].publish(user_name); | |
| 554 | + } | |
| 483 | 555 | |
| 484 | 556 | // Return |
| 485 | 557 | return; |
| ... | ... | @@ -505,15 +577,14 @@ void ctbin::init_members(void) |
| 505 | 577 | m_chatter = static_cast<GChatter>(2); |
| 506 | 578 | |
| 507 | 579 | // Initialise protected members |
| 580 | + m_cubes.clear(); | |
| 508 | 581 | m_counts.clear(); |
| 509 | 582 | m_weights.clear(); |
| 583 | + m_ids.clear(); | |
| 510 | 584 | m_ebounds.clear(); |
| 511 | 585 | m_gti.clear(); |
| 512 | - m_cube.clear(); | |
| 513 | 586 | m_ontime = 0.0; |
| 514 | 587 | m_livetime = 0.0; |
| 515 | - m_cubes.clear(); | |
| 516 | - m_ids.clear(); | |
| 517 | 588 | |
| 518 | 589 | // Initialise cache members |
| 519 | 590 | m_dirs.clear(); |
| ... | ... | @@ -538,15 +609,14 @@ void ctbin::copy_members(const ctbin& app) |
| 538 | 609 | m_chatter = app.m_chatter; |
| 539 | 610 | |
| 540 | 611 | // Copy protected members |
| 612 | + m_cubes = app.m_cubes; | |
| 541 | 613 | m_counts = app.m_counts; |
| 542 | 614 | m_weights = app.m_weights; |
| 615 | + m_ids = app.m_ids; | |
| 543 | 616 | m_ebounds = app.m_ebounds; |
| 544 | 617 | m_gti = app.m_gti; |
| 545 | - m_cube = app.m_cube; | |
| 546 | 618 | m_ontime = app.m_ontime; |
| 547 | 619 | m_livetime = app.m_livetime; |
| 548 | - m_cubes = app.m_cubes; | |
| 549 | - m_ids = app.m_ids; | |
| 550 | 620 | |
| 551 | 621 | // Copy cache members |
| 552 | 622 | m_dirs = app.m_dirs; |
| ... | ... | @@ -581,14 +651,8 @@ void ctbin::get_parameters(void) |
| 581 | 651 | // information and do not accept counts cubes. |
| 582 | 652 | setup_observations(m_obs, false, true, false); |
| 583 | 653 | |
| 584 | - // Create an event cube based on task parameters | |
| 585 | - GCTAEventCube cube = create_cube(m_obs); | |
| 586 | - | |
| 587 | - // Get the skymap from the cube and initialise all counts cube bins and | |
| 588 | - // weights to zero | |
| 589 | - m_counts = cube.counts(); | |
| 590 | - m_counts = 0.0; | |
| 591 | - m_weights = m_counts; | |
| 654 | + // Create an event cube to query task parameters | |
| 655 | + GCTAEventCube cube = this->ctool::create_cube(m_obs); | |
| 592 | 656 | |
| 593 | 657 | // Get energy boundaries |
| 594 | 658 | m_ebounds = cube.ebounds(); |
| ... | ... | @@ -608,13 +672,6 @@ void ctbin::get_parameters(void) |
| 608 | 672 | (*this)["outcube"].query(); |
| 609 | 673 | } |
| 610 | 674 | |
| 611 | - // Cache sky directions in m_counts | |
| 612 | - m_dirs.resize(m_counts.npix()); | |
| 613 | - for (int pix = 0; pix < m_counts.npix(); ++pix) { | |
| 614 | - m_dirs[pix] = m_counts.inx2dir(pix); | |
| 615 | - m_dirs[pix].radec(m_dirs[pix].ra(), m_dirs[pix].dec()); | |
| 616 | - } | |
| 617 | - | |
| 618 | 675 | // Set number of OpenMP threads |
| 619 | 676 | #ifdef _OPENMP |
| 620 | 677 | int nthreads = (*this)["nthreads"].integer(); |
| ... | ... | @@ -632,6 +689,95 @@ void ctbin::get_parameters(void) |
| 632 | 689 | |
| 633 | 690 | |
| 634 | 691 | /***********************************************************************//** |
| 692 | + * @brief Initialise sky direction cache for cube stack | |
| 693 | + * | |
| 694 | + * Initialises a cache that holds the sky directions of each counts cube | |
| 695 | + * pixel for a stacked analysis. This will speed up the computations later. | |
| 696 | + * | |
| 697 | + * If no stacking is requested, the method does nothing. | |
| 698 | + ***************************************************************************/ | |
| 699 | +void ctbin::init_sky_dir_cache(void) | |
| 700 | +{ | |
| 701 | + // Continue only is stacking is requested | |
| 702 | + if (m_stack) { | |
| 703 | + | |
| 704 | + // Create a sky map from task parameters | |
| 705 | + GSkyMap map = this->ctool::create_map(m_obs); | |
| 706 | + | |
| 707 | + // Initialise sky direction | |
| 708 | + m_dirs.resize(map.npix()); | |
| 709 | + | |
| 710 | + // Compute sky direction for each pixel | |
| 711 | + for (int pixel = 0; pixel < map.npix(); ++pixel) { | |
| 712 | + m_dirs[pixel] = map.inx2dir(pixel); | |
| 713 | + } | |
| 714 | + | |
| 715 | + } // endif: stacking was requested | |
| 716 | + | |
| 717 | + // Return | |
| 718 | + return; | |
| 719 | +} | |
| 720 | + | |
| 721 | + | |
| 722 | +/***********************************************************************//** | |
| 723 | + * @brief Create counts cube sky map for current observation | |
| 724 | + * | |
| 725 | + * @param[in] obs CTA observation. | |
| 726 | + * | |
| 727 | + * Creates a counts cube sky map for current observations. | |
| 728 | + ***************************************************************************/ | |
| 729 | +GSkyMap ctbin::create_cube(const GCTAObservation* obs) | |
| 730 | +{ | |
| 731 | + // Read coordinate system and projection | |
| 732 | + std::string coordsys = (*this)["coordsys"].string(); | |
| 733 | + std::string proj = (*this)["proj"].string(); | |
| 734 | + | |
| 735 | + // Read sky map reference | |
| 736 | + double xref = 0.0; | |
| 737 | + double yref = 0.0; | |
| 738 | + bool usepnt = (*this)["usepnt"].boolean(); | |
| 739 | + if (!usepnt) { | |
| 740 | + xref = (*this)["xref"].real(); | |
| 741 | + yref = (*this)["yref"].real(); | |
| 742 | + } | |
| 743 | + | |
| 744 | + // Read sky map pixel size and number of bins | |
| 745 | + double binsz = (*this)["binsz"].real(); | |
| 746 | + int nxpix = (*this)["nxpix"].integer(); | |
| 747 | + int nypix = (*this)["nypix"].integer(); | |
| 748 | + | |
| 749 | + // Read energy boundaries | |
| 750 | + GEbounds ebounds = create_ebounds(); | |
| 751 | + | |
| 752 | + // If requested, get pointing from observations | |
| 753 | + if (usepnt) { | |
| 754 | + | |
| 755 | + // Get pointing direction for observation | |
| 756 | + GSkyDir pnt = obs->pointing().dir(); | |
| 757 | + | |
| 758 | + // Set xref/yref based on the coordinate system | |
| 759 | + if (gammalib::toupper(coordsys) == "GAL") { | |
| 760 | + xref = pnt.l_deg(); | |
| 761 | + yref = pnt.b_deg(); | |
| 762 | + } | |
| 763 | + else { | |
| 764 | + xref = pnt.ra_deg(); | |
| 765 | + yref = pnt.dec_deg(); | |
| 766 | + } | |
| 767 | + | |
| 768 | + } // endif: got pointing from observation | |
| 769 | + | |
| 770 | + // Initialise counts cube | |
| 771 | + GSkyMap cube = GSkyMap(proj, coordsys, xref, yref, -binsz, binsz, | |
| 772 | + nxpix, nypix, ebounds.size()); | |
| 773 | + | |
| 774 | + | |
| 775 | + // Return cube | |
| 776 | + return cube; | |
| 777 | +} | |
| 778 | + | |
| 779 | + | |
| 780 | +/***********************************************************************//** | |
| 635 | 781 | * @brief Fill events into counts cube |
| 636 | 782 | * |
| 637 | 783 | * @param[in] obs CTA observation. |
| ... | ... | @@ -641,10 +787,10 @@ void ctbin::get_parameters(void) |
| 641 | 787 | * |
| 642 | 788 | * Fills the events from an event list into the counts cube. |
| 643 | 789 | ***************************************************************************/ |
| 644 | -GSkyMap ctbin::fill_cube(GCTAObservation* obs) | |
| 790 | +GSkyMap ctbin::fill_cube(const GCTAObservation* obs) | |
| 645 | 791 | { |
| 646 | - // Make sure that the observation holds a CTA event list. If this | |
| 647 | - // is not the case then throw an exception. | |
| 792 | + // Make sure that the observation holds a CTA event list. If this is | |
| 793 | + // not the case then throw an exception. | |
| 648 | 794 | const GCTAEventList* events = dynamic_cast<const GCTAEventList*> |
| 649 | 795 | (obs->events()); |
| 650 | 796 | if (events == NULL) { |
| ... | ... | @@ -655,7 +801,7 @@ GSkyMap ctbin::fill_cube(GCTAObservation* obs) |
| 655 | 801 | } |
| 656 | 802 | |
| 657 | 803 | // Get the RoI |
| 658 | - const GCTARoi& roi = events->roi(); | |
| 804 | + const GCTARoi& roi = obs->roi(); | |
| 659 | 805 | |
| 660 | 806 | // Check for RoI sanity |
| 661 | 807 | if (!roi.is_valid()) { |
| ... | ... | @@ -667,7 +813,7 @@ GSkyMap ctbin::fill_cube(GCTAObservation* obs) |
| 667 | 813 | } |
| 668 | 814 | |
| 669 | 815 | // Get counts cube usage flags |
| 670 | - std::vector<bool> usage = cube_layer_usage(m_ebounds, events->ebounds()); | |
| 816 | + std::vector<bool> usage = cube_layer_usage(m_ebounds, obs->ebounds()); | |
| 671 | 817 | |
| 672 | 818 | // Initialise binning statistics |
| 673 | 819 | int num_outside_roi = 0; |
| ... | ... | @@ -676,9 +822,12 @@ GSkyMap ctbin::fill_cube(GCTAObservation* obs) |
| 676 | 822 | int num_outside_ebds = 0; |
| 677 | 823 | int num_in_map = 0; |
| 678 | 824 | |
| 679 | - // Initialise new empty counts map | |
| 680 | - GSkyMap counts(m_counts); | |
| 681 | - counts *= 0.; | |
| 825 | + // Create counts cube | |
| 826 | + GSkyMap counts = create_cube(obs); | |
| 827 | + | |
| 828 | + // Extract counts cube boundaries | |
| 829 | + double pixel_x_max = counts.nx() - 0.5; | |
| 830 | + double pixel_y_max = counts.ny() - 0.5; | |
| 682 | 831 | |
| 683 | 832 | // Fill counts sky map |
| 684 | 833 | for (int i = 0; i < events->size(); ++i) { |
| ... | ... | @@ -699,7 +848,7 @@ GSkyMap ctbin::fill_cube(GCTAObservation* obs) |
| 699 | 848 | // Determine sky pixel |
| 700 | 849 | GSkyPixel pixel; |
| 701 | 850 | try { |
| 702 | - pixel = m_counts.dir2pix(dir); | |
| 851 | + pixel = counts.dir2pix(dir); | |
| 703 | 852 | } |
| 704 | 853 | catch (std::exception &e) { |
| 705 | 854 | num_invalid_wcs++; |
| ... | ... | @@ -708,8 +857,8 @@ GSkyMap ctbin::fill_cube(GCTAObservation* obs) |
| 708 | 857 | |
| 709 | 858 | // Skip event if corresponding counts cube pixel is outside the |
| 710 | 859 | // counts cube map range |
| 711 | - if (pixel.x() < -0.5 || pixel.x() > (m_counts.nx()-0.5) || | |
| 712 | - pixel.y() < -0.5 || pixel.y() > (m_counts.ny()-0.5)) { | |
| 860 | + if (pixel.x() < -0.5 || pixel.x() > pixel_x_max || | |
| 861 | + pixel.y() < -0.5 || pixel.y() > pixel_y_max) { | |
| 713 | 862 | num_outside_map++; |
| 714 | 863 | continue; |
| 715 | 864 | } |
| ... | ... | @@ -726,7 +875,6 @@ GSkyMap ctbin::fill_cube(GCTAObservation* obs) |
| 726 | 875 | } |
| 727 | 876 | |
| 728 | 877 | // Fill event in skymap |
| 729 | - //#pragma omp critical(ctbin_fill_cube) | |
| 730 | 878 | counts(pixel, iebin) += 1.0; |
| 731 | 879 | |
| 732 | 880 | // Increment number of maps |
| ... | ... | @@ -734,23 +882,6 @@ GSkyMap ctbin::fill_cube(GCTAObservation* obs) |
| 734 | 882 | |
| 735 | 883 | } // endfor: looped over all events |
| 736 | 884 | |
| 737 | - // Update time information | |
| 738 | - /*#pragma omp critical(ctbin_fill_cube) | |
| 739 | - { | |
| 740 | - // If GTI is empty then set its time reference from the observation. | |
| 741 | - // From then on we keep that time reference | |
| 742 | - if (m_gti.is_empty()) { | |
| 743 | - m_gti.reference(events->gti().reference()); | |
| 744 | - } | |
| 745 | - | |
| 746 | - // Append GTIs | |
| 747 | - m_gti.extend(events->gti()); | |
| 748 | - | |
| 749 | - // Update ontime and livetime | |
| 750 | - m_ontime += obs->ontime(); | |
| 751 | - m_livetime += obs->livetime(); | |
| 752 | - }*/ | |
| 753 | - | |
| 754 | 885 | // Log filling results |
| 755 | 886 | #pragma omp critical(ctbin_fill_cube) |
| 756 | 887 | { |
| ... | ... | @@ -779,21 +910,10 @@ GSkyMap ctbin::fill_cube(GCTAObservation* obs) |
| 779 | 910 | * Sets the counts cube weights for all bins that are considered for the |
| 780 | 911 | * specific observation to unity. |
| 781 | 912 | ***************************************************************************/ |
| 782 | -GSkyMap ctbin::set_weights(GCTAObservation* obs) | |
| 913 | +GSkyMap ctbin::set_weights(const GCTAObservation* obs) | |
| 783 | 914 | { |
| 784 | - // Make sure that the observation holds a CTA event list. If this | |
| 785 | - // is not the case then throw an exception. | |
| 786 | - const GCTAEventList* events = dynamic_cast<const GCTAEventList*> | |
| 787 | - (obs->events()); | |
| 788 | - if (events == NULL) { | |
| 789 | - std::string msg = "CTA Observation does not contain an event " | |
| 790 | - "list. An event list is needed to fill the " | |
| 791 | - "counts cube."; | |
| 792 | - throw GException::invalid_value(G_SET_WEIGHTS, msg); | |
| 793 | - } | |
| 794 | - | |
| 795 | 915 | // Get the RoI |
| 796 | - const GCTARoi& roi = events->roi(); | |
| 916 | + const GCTARoi& roi = obs->roi(); | |
| 797 | 917 | |
| 798 | 918 | // Check for RoI sanity |
| 799 | 919 | if (!roi.is_valid()) { |
| ... | ... | @@ -804,19 +924,32 @@ GSkyMap ctbin::set_weights(GCTAObservation* obs) |
| 804 | 924 | throw GException::invalid_value(G_SET_WEIGHTS, msg); |
| 805 | 925 | } |
| 806 | 926 | |
| 927 | + // Get the RoI centre and radius in radians | |
| 928 | + GSkyDir roi_centre = roi.centre().dir(); | |
| 929 | + double roi_radius = roi.radius() * gammalib::deg2rad; | |
| 930 | + | |
| 807 | 931 | // Get counts cube usage flags |
| 808 | - std::vector<bool> usage = cube_layer_usage(m_ebounds, events->ebounds()); | |
| 932 | + std::vector<bool> usage = cube_layer_usage(m_ebounds, obs->ebounds()); | |
| 933 | + | |
| 934 | + // Create weights cube | |
| 935 | + GSkyMap weights = create_cube(obs); | |
| 809 | 936 | |
| 810 | - // Initialise new empty weights map | |
| 811 | - GSkyMap weights(m_weights); | |
| 812 | - weights *= 0.; | |
| 937 | + // Set sky direction cache availability flag | |
| 938 | + bool cache = (m_stack && m_dirs.size() == weights.npix()); | |
| 813 | 939 | |
| 814 | 940 | // Loop over all pixels in counts cube |
| 815 | - for (int pixel = 0; pixel < m_counts.npix(); ++pixel) { | |
| 941 | + for (int pixel = 0; pixel < weights.npix(); ++pixel) { | |
| 816 | 942 | |
| 817 | 943 | // Skip pixel if it is outside the RoI |
| 818 | - if (roi.centre().dir().dist_deg(m_dirs[pixel]) > roi.radius()) { | |
| 819 | - continue; | |
| 944 | + if (cache) { | |
| 945 | + if (m_dirs[pixel].dist(roi_centre) > roi_radius) { | |
| 946 | + continue; | |
| 947 | + } | |
| 948 | + } | |
| 949 | + else { | |
| 950 | + if (roi_centre.dist(weights.inx2dir(pixel)) > roi_radius) { | |
| 951 | + continue; | |
| 952 | + } | |
| 820 | 953 | } |
| 821 | 954 | |
| 822 | 955 | // Loop over all energy layers of counts cube |
| ... | ... | @@ -828,7 +961,6 @@ GSkyMap ctbin::set_weights(GCTAObservation* obs) |
| 828 | 961 | } |
| 829 | 962 | |
| 830 | 963 | // Signal that bin was filled |
| 831 | - //#pragma omp critical(ctbin_set_weights) | |
| 832 | 964 | weights(pixel, iebin) = 1.0; |
| 833 | 965 | |
| 834 | 966 | } // endfor: looped over energy layers of counts cube |
| ... | ... | @@ -851,8 +983,11 @@ GSkyMap ctbin::set_weights(GCTAObservation* obs) |
| 851 | 983 | * information in case that a single CTA observation is provided to support |
| 852 | 984 | * binned analysis. |
| 853 | 985 | ***************************************************************************/ |
| 854 | -void ctbin::obs_cube(void) | |
| 986 | +void ctbin::obs_cube_stacked(void) | |
| 855 | 987 | { |
| 988 | + // Set event cube in first slot | |
| 989 | + m_cubes[0] = GCTAEventCube(m_counts[0], m_weights[0], m_ebounds, m_gti); | |
| 990 | + | |
| 856 | 991 | // If we have only a single CTA observation in the container, then |
| 857 | 992 | // keep that observation and just attach the event cube to it. Reset |
| 858 | 993 | // the filename, otherwise we still will have the old event filename |
| ... | ... | @@ -865,9 +1000,9 @@ void ctbin::obs_cube(void) |
| 865 | 1000 | |
| 866 | 1001 | // Change the event type if we had an unbinned observation |
| 867 | 1002 | if (obs->eventtype() == "EventList") { |
| 868 | - | |
| 1003 | + | |
| 869 | 1004 | // Assign cube to the observation |
| 870 | - obs->events(this->cube()); | |
| 1005 | + obs->events(m_cubes[0]); | |
| 871 | 1006 | |
| 872 | 1007 | } |
| 873 | 1008 | |
| ... | ... | @@ -877,7 +1012,8 @@ void ctbin::obs_cube(void) |
| 877 | 1012 | else { |
| 878 | 1013 | |
| 879 | 1014 | // Create empty counts cube |
| 880 | - GCTAEventCube cube(m_counts, m_weights, m_ebounds, obs->gti()); | |
| 1015 | + GCTAEventCube cube(m_counts[0], m_weights[0], m_ebounds, | |
| 1016 | + obs->gti()); | |
| 881 | 1017 | |
| 882 | 1018 | // Assign empty cube to observation |
| 883 | 1019 | obs->events(cube); |
| ... | ... | @@ -899,49 +1035,49 @@ void ctbin::obs_cube(void) |
| 899 | 1035 | // Allocate observation container |
| 900 | 1036 | GObservations container; |
| 901 | 1037 | |
| 902 | - // Allocate CTA observation. | |
| 903 | - GCTAObservation obs; | |
| 904 | - | |
| 905 | - // Attach event cube to CTA observation | |
| 906 | - obs.events(this->cube()); | |
| 907 | - | |
| 908 | - // Compute average pointing direction for all CTA event lists | |
| 909 | - double ra = 0.0; | |
| 910 | - double dec = 0.0; | |
| 911 | - double number = 0.0; | |
| 912 | - for (int i = 0; i < m_obs.size(); ++i) { | |
| 913 | - GCTAObservation* cta = dynamic_cast<GCTAObservation*>(m_obs[i]); | |
| 914 | - if ((cta != NULL) && (cta->eventtype() == "EventList")) { | |
| 915 | - ra += cta->pointing().dir().ra(); | |
| 916 | - dec += cta->pointing().dir().dec(); | |
| 917 | - number += 1.0; | |
| 918 | - } | |
| 919 | - } | |
| 920 | - if (number > 0.0) { | |
| 921 | - ra /= number; | |
| 922 | - dec /= number; | |
| 923 | - } | |
| 924 | - GSkyDir dir; | |
| 925 | - dir.radec(ra, dec); | |
| 926 | - GCTAPointing pointing(dir); | |
| 927 | - | |
| 928 | - // Compute deadtime correction | |
| 929 | - double deadc = (m_ontime > 0.0) ? m_livetime / m_ontime : 0.0; | |
| 930 | - | |
| 931 | - // Set CTA observation attributes | |
| 932 | - obs.pointing(pointing); | |
| 933 | - obs.ra_obj(dir.ra_deg()); //!< Dummy | |
| 934 | - obs.dec_obj(dir.dec_deg()); //!< Dummy | |
| 935 | - obs.ontime(m_ontime); | |
| 936 | - obs.livetime(m_livetime); | |
| 937 | - obs.deadc(deadc); | |
| 938 | - | |
| 939 | - // Append CTA observation | |
| 940 | - container.append(obs); | |
| 1038 | + // Allocate CTA observation. | |
| 1039 | + GCTAObservation obs; | |
| 1040 | + | |
| 1041 | + // Attach event cube to CTA observation | |
| 1042 | + obs.events(m_cubes[0]); | |
| 1043 | + | |
| 1044 | + // Compute average pointing direction for all CTA event lists | |
| 1045 | + double ra = 0.0; | |
| 1046 | + double dec = 0.0; | |
| 1047 | + double number = 0.0; | |
| 1048 | + for (int i = 0; i < m_obs.size(); ++i) { | |
| 1049 | + GCTAObservation* cta = dynamic_cast<GCTAObservation*>(m_obs[i]); | |
| 1050 | + if ((cta != NULL) && (cta->eventtype() == "EventList")) { | |
| 1051 | + ra += cta->pointing().dir().ra(); | |
| 1052 | + dec += cta->pointing().dir().dec(); | |
| 1053 | + number += 1.0; | |
| 1054 | + } | |
| 1055 | + } | |
| 1056 | + if (number > 0.0) { | |
| 1057 | + ra /= number; | |
| 1058 | + dec /= number; | |
| 1059 | + } | |
| 1060 | + GSkyDir dir; | |
| 1061 | + dir.radec(ra, dec); | |
| 1062 | + GCTAPointing pointing(dir); | |
| 1063 | + | |
| 1064 | + // Compute deadtime correction | |
| 1065 | + double deadc = (m_ontime > 0.0) ? m_livetime / m_ontime : 0.0; | |
| 1066 | + | |
| 1067 | + // Set CTA observation attributes | |
| 1068 | + obs.pointing(pointing); | |
| 1069 | + obs.ra_obj(dir.ra_deg()); //!< Dummy | |
| 1070 | + obs.dec_obj(dir.dec_deg()); //!< Dummy | |
| 1071 | + obs.ontime(m_ontime); | |
| 1072 | + obs.livetime(m_livetime); | |
| 1073 | + obs.deadc(deadc); | |
| 941 | 1074 | |
| 942 | 1075 | // Set models in observation container |
| 943 | 1076 | container.models(m_obs.models()); |
| 944 | 1077 | |
| 1078 | + // Append CTA observation | |
| 1079 | + container.append(obs); | |
| 1080 | + | |
| 945 | 1081 | // Copy over all remaining non-CTA observations |
| 946 | 1082 | for (int i = 0; i < m_obs.size(); ++i) { |
| 947 | 1083 | GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]); | ... | ... |
src/ctbin/ctbin.hpp
| 1 | 1 | /*************************************************************************** |
| 2 | 2 | * ctbin - Event binning tool * |
| 3 | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2010-2017 by Juergen Knoedlseder * | |
| 4 | + * copyright (C) 2010-2018 by Juergen Knoedlseder * | |
| 5 | 5 | * ----------------------------------------------------------------------- * |
| 6 | 6 | * * |
| 7 | 7 | * This program is free software: you can redistribute it and/or modify * |
| ... | ... | @@ -81,10 +81,10 @@ public: |
| 81 | 81 | // Methods |
| 82 | 82 | void clear(void); |
| 83 | 83 | void run(void); |
| 84 | + int cubes(void) const; | |
| 85 | + const GCTAEventCube& cube(const int& index = 0) const; | |
| 84 | 86 | void save(void); |
| 85 | 87 | void publish(const std::string& name = ""); |
| 86 | - const GCTAEventCube& cube(void) const; | |
| 87 | - const GCTAEventCube& cube(const size_t& index) const; | |
| 88 | 88 | |
| 89 | 89 | protected: |
| 90 | 90 | // Protected methods |
| ... | ... | @@ -92,60 +92,46 @@ protected: |
| 92 | 92 | void copy_members(const ctbin& app); |
| 93 | 93 | void free_members(void); |
| 94 | 94 | void get_parameters(void); |
| 95 | - GSkyMap fill_cube(GCTAObservation* obs); | |
| 96 | - GSkyMap set_weights(GCTAObservation* obs); | |
| 97 | - void obs_cube(void); | |
| 95 | + void init_sky_dir_cache(void); | |
| 96 | + GSkyMap create_cube(const GCTAObservation* obs); | |
| 97 | + GSkyMap fill_cube(const GCTAObservation* obs); | |
| 98 | + GSkyMap set_weights(const GCTAObservation* obs); | |
| 99 | + void obs_cube_stacked(void); | |
| 98 | 100 | |
| 99 | 101 | // User parameters |
| 100 | - GFilename m_outcube; //!< Output counts map file name | |
| 101 | - bool m_usepnt; //!< Use pointing instead of xref/yref parameters | |
| 102 | - bool m_stack; //!< Output one stacked cube or multiple cubes | |
| 103 | - std::string m_prefix; //!< Prefix for output path of multiple cubes | |
| 104 | - bool m_publish; //!< Publish counts cube? | |
| 105 | - GChatter m_chatter; //!< Chattiness | |
| 102 | + GFilename m_outcube; //!< Output counts map file name | |
| 103 | + bool m_usepnt; //!< Use pointing instead of xref/yref parameters | |
| 104 | + bool m_stack; //!< Output one stacked cube or multiple cubes | |
| 105 | + std::string m_prefix; //!< Prefix for output path of multiple cubes | |
| 106 | + bool m_publish; //!< Publish counts cube? | |
| 107 | + GChatter m_chatter; //!< Chattiness | |
| 106 | 108 | |
| 107 | 109 | // Protected members |
| 108 | - GSkyMap m_counts; //!< Event cube counts | |
| 109 | - GSkyMap m_weights; //!< Event cube weights | |
| 110 | - GEbounds m_ebounds; //!< Energy boundaries | |
| 111 | - GGti m_gti; //!< Good time intervals | |
| 112 | - GCTAEventCube m_cube; //!< Events cube (for cube() method) | |
| 113 | - double m_ontime; //!< Total ontime | |
| 114 | - double m_livetime; //!< Total livetime | |
| 115 | - std::vector<GCTAEventCube> m_cubes; //!< Event cubes (for cube() method) | |
| 116 | - std::vector<std::string> m_ids; //!< Observation ids | |
| 110 | + std::vector<GCTAEventCube> m_cubes; //!< Event cubes | |
| 111 | + std::vector<GSkyMap> m_counts; //!< List of event cube counts | |
| 112 | + std::vector<GSkyMap> m_weights; //!< List of event cube weights | |
| 113 | + std::vector<std::string> m_ids; //!< List of observation ids | |
| 114 | + GEbounds m_ebounds; //!< Energy boundaries | |
| 115 | + GGti m_gti; //!< Stacked Good time intervals | |
| 116 | + double m_ontime; //!< Total ontime | |
| 117 | + double m_livetime; //!< Total livetime | |
| 117 | 118 | |
| 118 | 119 | // Cache members |
| 119 | - std::vector<GSkyDir> m_dirs; //!< Cached GSkyDir for each pixel in m_counts | |
| 120 | + std::vector<GSkyDir> m_dirs; //!< Cached GSkyDir for all pixels | |
| 120 | 121 | }; |
| 121 | 122 | |
| 122 | 123 | |
| 123 | 124 | /***********************************************************************//** |
| 124 | - * @brief Return event cube | |
| 125 | + * @brief Return number of event cubes | |
| 125 | 126 | * |
| 126 | - * @return Reference to event cube | |
| 127 | + * @return Number of event cubes. | |
| 127 | 128 | * |
| 128 | - * Returns a reference to the event cube. | |
| 129 | + * Returns number of event cubes. | |
| 129 | 130 | ***************************************************************************/ |
| 130 | 131 | inline |
| 131 | -const GCTAEventCube& ctbin::cube(void) const | |
| 132 | +int ctbin::cubes(void) const | |
| 132 | 133 | { |
| 133 | - return m_cube; | |
| 134 | -} | |
| 135 | - | |
| 136 | - | |
| 137 | -/***********************************************************************//** | |
| 138 | - * @brief Return event cube at index | |
| 139 | - * | |
| 140 | - * @param[in] index Index of cube | |
| 141 | - * @return Reference to event cube | |
| 142 | - * | |
| 143 | - * Returns a reference to the event cube at the given index. | |
| 144 | - ***************************************************************************/ | |
| 145 | -inline | |
| 146 | -const GCTAEventCube& ctbin::cube(const size_t& index) const | |
| 147 | -{ | |
| 148 | - return m_cubes[index]; | |
| 134 | + return m_cubes.size(); | |
| 149 | 135 | } |
| 150 | 136 | |
| 151 | 137 | #endif /* CTBIN_HPP */ | ... | ... |
src/ctbin/ctbin.par
| ... | ... | @@ -18,7 +18,7 @@ |
| 18 | 18 | #=================== |
| 19 | 19 | inobs, f, a, events.fits,,, "Input event list or observation definition XML file" |
| 20 | 20 | outcube, f, a, cntcube.fits,,, "Output counts cube file" |
| 21 | -stack, b, h, yes,,, "Stack events to one cube?" | |
| 21 | +stack, b, h, yes,,, "Stack events into one cube?" | |
| 22 | 22 | prefix, s, h, binned_,,, "Prefix for counts cubes in observation definition XML file" |
| 23 | 23 | |
| 24 | 24 | # | ... | ... |
test/test_ctbin.py
| ... | ... | @@ -165,7 +165,7 @@ class Test(test): |
| 165 | 165 | # cube |
| 166 | 166 | self.test_value(binning.obs().size(), 0, |
| 167 | 167 | 'Check that empty ctbin has an empty observation container') |
| 168 | - self.test_value(binning.cube().size(), 0, | |
| 168 | + self.test_value(binning.cubes(), 0, | |
| 169 | 169 | 'Check that empty ctbin has an empty counts cube') |
| 170 | 170 | |
| 171 | 171 | # Check that saving does not nothing |
| ... | ... | @@ -220,11 +220,13 @@ class Test(test): |
| 220 | 220 | cpy_bin.logFileOpen() |
| 221 | 221 | cpy_bin.run() |
| 222 | 222 | |
| 223 | - # Check content of observation container and counts cube. Now an empty | |
| 224 | - # event cube is expected since on input the observation is binned, and | |
| 225 | - # any binned observation will be skipped. | |
| 226 | - self._check_observation(cpy_bin, 0) | |
| 227 | - self._check_cube(cpy_bin.cube(), 0) | |
| 223 | + # Check content of observation container and number of counts cubes. | |
| 224 | + # There should be a single binned observation in the observation | |
| 225 | + # container, which is the one that was produced in the run before. | |
| 226 | + # Since ctbin finds no unbinned observation in the container, the | |
| 227 | + # number of cubes should be zero. | |
| 228 | + self._check_observation(cpy_bin, 245) | |
| 229 | + self.test_value(cpy_bin.cubes(), 0, 'Check that there are no counts cubes') | |
| 228 | 230 | |
| 229 | 231 | # Save counts cube |
| 230 | 232 | binning.save() |
| ... | ... | @@ -240,7 +242,7 @@ class Test(test): |
| 240 | 242 | # counts cube |
| 241 | 243 | self.test_value(binning.obs().size(), 0, |
| 242 | 244 | 'Check that empty ctbin has an empty observation container') |
| 243 | - self.test_value(binning.cube().size(), 0, | |
| 245 | + self.test_value(binning.cubes(), 0, | |
| 244 | 246 | 'Check that empty ctbin has an empty counts cube') |
| 245 | 247 | |
| 246 | 248 | # Prepare observation container for stacking of events into a | ... | ... |