Commit 0823df67dde6bf48490a7050f6b21b2194bba422

Authored by Jürgen Knödlseder
2 parents 624999d9 36b7c210

Merge branch 'integration' into devel

ChangeLog
1   -2017-07-27
  1 +2017-07-28
2 2  
3 3 * Version 1.4.0 released
4 4 ========================
5 5  
6 6 Fix ctmodel bug for stacked analysis with diffuse maps or cubes (#2171)
7 7 Install ctools header files (#2145)
  8 + Parallelize event binning in ctbin using OpenMP (#1970)
8 9  
9 10  
10 11 2017-07-07
... ...
1 1 New Features and Important Changes in ctools 1.4.0
2 2  
3   -27 July 2017
  3 +28 July 2017
4 4  
5 5  
6 6 Introduction
... ... @@ -37,7 +37,9 @@ None
37 37  
38 38 ctbin - CTA event binning
39 39 -------------------------
40   -None
  40 +The loop over the observations was parallelized using OpenMP for faster
  41 +execution. In addition, the sky directions were cached for faster computation
  42 +of the weights (#1970).
41 43  
42 44  
43 45 ctlike - Maximum likelihood fitting
... ...
doc/source/admin/release_history/1.4.rst
... ... @@ -25,6 +25,8 @@ Improvements
25 25 Fix ctmodel bug for stacked analysis with diffuse maps or cubes
26 26 * [`2145 <https://cta-redmine.irap.omp.eu/issues/2145>`_] -
27 27 Install C++ header files
  28 +* [`1970 <https://cta-redmine.irap.omp.eu/issues/1970>`_] -
  29 + Parallelize :ref:`ctbin` using OpenMP
28 30  
29 31  
30 32 New features
... ...
src/ctbin/ctbin.cpp
... ... @@ -233,11 +233,32 @@ void ctbin::run(void)
233 233 log_observations(NORMAL, m_obs, "Input observation");
234 234  
235 235 // Write header into logger
  236 + log_header1(TERSE, gammalib::number("Find unbinned observation",
  237 + m_obs.size()));
  238 +
  239 + // Find all unbinned CTA observations in m_obs
  240 + std::vector<GCTAObservation*> obs_list(0);
  241 + for (GCTAObservation* obs = first_unbinned_observation(); obs != NULL;
  242 + obs = next_unbinned_observation()) {
  243 +
  244 + // Push observation into list
  245 + obs_list.push_back(obs);
  246 +
  247 + // Write message
  248 + std::string msg = " Including unbinned "+obs->instrument()+
  249 + " observation";
  250 + log_string(NORMAL, msg);
  251 + }
  252 +
  253 + // Write header into logger
236 254 log_header1(TERSE, gammalib::number("Bin observation", m_obs.size()));
237 255  
238 256 // Loop over all unbinned CTA observations in the container
239   - for (GCTAObservation* obs = first_unbinned_observation(); obs != NULL;
240   - obs = next_unbinned_observation()) {
  257 + #pragma omp parallel for
  258 + for (int i = 0; i < obs_list.size(); ++i) {
  259 +
  260 + // Get pointer to observation
  261 + GCTAObservation* obs = obs_list[i];
241 262  
242 263 // Fill the cube
243 264 fill_cube(obs);
... ... @@ -361,6 +382,9 @@ void ctbin::init_members(void)
361 382 m_ontime = 0.0;
362 383 m_livetime = 0.0;
363 384  
  385 + // Initialise cache members
  386 + m_dirs.clear();
  387 +
364 388 // Set CTA reference time
365 389 m_gti.reference(m_cta_ref);
366 390  
... ... @@ -383,13 +407,16 @@ void ctbin::copy_members(const ctbin&amp; app)
383 407 m_chatter = app.m_chatter;
384 408  
385 409 // Copy protected members
386   - m_counts = app.m_counts;
387   - m_weights = app.m_weights;
388   - m_ebounds = app.m_ebounds;
389   - m_gti = app.m_gti;
390   - m_cube = app.m_cube;
391   - m_ontime = app.m_ontime;
392   - m_livetime = app.m_livetime;
  410 + m_counts = app.m_counts;
  411 + m_weights = app.m_weights;
  412 + m_ebounds = app.m_ebounds;
  413 + m_gti = app.m_gti;
  414 + m_cube = app.m_cube;
  415 + m_ontime = app.m_ontime;
  416 + m_livetime = app.m_livetime;
  417 +
  418 + // Copy cache members
  419 + m_dirs = app.m_dirs;
393 420  
394 421 // Return
395 422 return;
... ... @@ -443,6 +470,13 @@ void ctbin::get_parameters(void)
443 470 m_outcube = (*this)["outcube"].filename();
444 471 }
445 472  
  473 + // Cache sky directions in m_counts
  474 + m_dirs.resize(m_counts.npix());
  475 + for (int pix = 0; pix < m_counts.npix(); ++pix) {
  476 + m_dirs[pix] = m_counts.inx2dir(pix);
  477 + m_dirs[pix].radec(m_dirs[pix].ra(), m_dirs[pix].dec());
  478 + }
  479 +
446 480 // Write parameters into logger
447 481 log_parameters(TERSE);
448 482  
... ... @@ -503,8 +537,8 @@ void ctbin::fill_cube(GCTAObservation* obs)
503 537 const GCTAEventAtom* event = (*events)[i];
504 538  
505 539 // Determine event sky direction
506   - GCTAInstDir* inst = (GCTAInstDir*)&(event->dir());
507   - GSkyDir dir = inst->dir();
  540 + GCTAInstDir* inst = (GCTAInstDir*)&(event->dir());
  541 + GSkyDir dir = inst->dir();
508 542  
509 543 // Skip event if it is outside the RoI
510 544 if (roi.centre().dir().dist_deg(dir) > roi.radius()) {
... ... @@ -542,25 +576,36 @@ void ctbin::fill_cube(GCTAObservation* obs)
542 576 }
543 577  
544 578 // Fill event in skymap
  579 + #pragma omp critical(ctbin_fill_cube)
545 580 m_counts(pixel, iebin) += 1.0;
  581 +
  582 + // Increment number of maps
546 583 num_in_map++;
547 584  
548 585 } // endfor: looped over all events
549 586  
550   - // Append GTIs
551   - m_gti.extend(events->gti());
  587 + // Update time information
  588 + #pragma omp critical(ctbin_fill_cube)
  589 + {
  590 + // Append GTIs
  591 + m_gti.extend(events->gti());
552 592  
553   - // Update ontime and livetime
554   - m_ontime += obs->ontime();
555   - m_livetime += obs->livetime();
  593 + // Update ontime and livetime
  594 + m_ontime += obs->ontime();
  595 + m_livetime += obs->livetime();
  596 + }
556 597  
557 598 // Log filling results
558   - log_value(NORMAL, "Events in list", obs->events()->size());
559   - log_value(NORMAL, "Events in cube", num_in_map);
560   - log_value(NORMAL, "Events outside RoI", num_outside_roi);
561   - log_value(NORMAL, "Events with invalid WCS", num_invalid_wcs);
562   - log_value(NORMAL, "Events outside cube area", num_outside_map);
563   - log_value(NORMAL, "Events outside energy bins", num_outside_ebds);
  599 + #pragma omp critical(ctbin_fill_cube)
  600 + {
  601 + log_header3(TERSE, get_obs_header(obs));
  602 + log_value(NORMAL, "Events in list", obs->events()->size());
  603 + log_value(NORMAL, "Events in cube", num_in_map);
  604 + log_value(NORMAL, "Events outside RoI", num_outside_roi);
  605 + log_value(NORMAL, "Events with invalid WCS", num_invalid_wcs);
  606 + log_value(NORMAL, "Events outside cube area", num_outside_map);
  607 + log_value(NORMAL, "Events outside energy bins", num_outside_ebds);
  608 + }
564 609  
565 610 // Return
566 611 return;
... ... @@ -609,11 +654,8 @@ void ctbin::set_weights(GCTAObservation* obs)
609 654 // Loop over all pixels in counts cube
610 655 for (int pixel = 0; pixel < m_counts.npix(); ++pixel) {
611 656  
612   - // Get pixel sky direction
613   - GSkyDir dir = m_counts.inx2dir(pixel);
614   -
615 657 // Skip pixel if it is outside the RoI
616   - if (roi.centre().dir().dist_deg(dir) > roi.radius()) {
  658 + if (roi.centre().dir().dist_deg(m_dirs[pixel]) > roi.radius()) {
617 659 continue;
618 660 }
619 661  
... ... @@ -624,7 +666,9 @@ void ctbin::set_weights(GCTAObservation* obs)
624 666 if (!usage[iebin]) {
625 667 continue;
626 668 }
  669 +
627 670 // Signal that bin was filled
  671 + #pragma omp critical(ctbin_set_weights)
628 672 m_weights(pixel, iebin) = 1.0;
629 673  
630 674 } // endfor: looped over energy layers of counts cube
... ...
src/ctbin/ctbin.hpp
1 1 /***************************************************************************
2 2 * ctbin - Event binning tool *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2010-2016 by Juergen Knoedlseder *
  4 + * copyright (C) 2010-2017 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -102,6 +102,9 @@ protected:
102 102 GCTAEventCube m_cube; //!< Events cube (for cube() method)
103 103 double m_ontime; //!< Total ontime
104 104 double m_livetime; //!< Total livetime
  105 +
  106 + // Cache members
  107 + std::vector<GSkyDir> m_dirs; //!< Cached GSkyDir for each pixel in m_counts
105 108 };
106 109  
107 110  
... ...