Commit ff7d5576b246bb517db3361d0109d9ff965c6b11

Authored by Jürgen Knödlseder
1 parent 629d633b

Optimized and parallelized ctmodel (#2147)

Optimized computation intensive parts of ctmodel to reduce computation time.
Implemented openmp parallelization of ctmodel to reduce computation time.
Updated information logging (#2147)

Updated writing information to log file in order to prevent messy log file messages. This doesnt appear to impact the computation time.
Integrate code without modification of GammaLib (#2147)
Implement efficient model computation (#2147)
Update change log (#2147)
ChangeLog
... ... @@ -6,11 +6,16 @@
6 6 Install ctools header files (#2145)
7 7  
8 8  
9   -2017-06-23
  9 +2017-07-07
10 10  
11 11 * Bug fix version 1.3.1 released
12 12 ================================
13 13  
  14 + Reduce computation time of ctmodel and parallelize using OpenMP (#2147)
  15 + Fix csresmap significance computation error (#2136)
  16 + Use MigMatrixNoTheta2cut_offaxis and AngularPSF2DEtrue_offaxis histograms to
  17 + compute PSF and energy dispersion IRFs (#2135)
  18 + Add self.logFileOpen() to cstsmapsplit.execute() method (#2127)
14 19 Properly forward working log file pointer in ctobssim::set_mc_id_names() (#2123)
15 20 Correct computation of standard deviations in cssrcdetect
16 21 csobsselect accepts an observation container upon construction
... ...
doc/source/admin/release_history/1.3.1.rst 0 → 100644
  1 +.. _1.3.1:
  2 +
  3 +ctools 1.3.1 release
  4 +====================
  5 +
  6 +Overview
  7 +--------
  8 +
  9 +ctools 1.3.1 is a bug fix for ctools release 1.3.
  10 +
  11 +The following bugs have been fixed:
  12 +
  13 +* [`2136 <https://cta-redmine.irap.omp.eu/issues/2136>`_] -
  14 + Fix csresmap significance computation error
  15 +* [`2135 <https://cta-redmine.irap.omp.eu/issues/2135>`_] -
  16 + Use ``MigMatrixNoTheta2cut_offaxis`` and ``AngularPSF2DEtrue_offaxis``
  17 + histograms to compute PSF and energy dispersion IRFs
  18 +* [`2127 <https://cta-redmine.irap.omp.eu/issues/2127>`_] -
  19 + Add ``self.logFileOpen()`` to ``cstsmapsplit.execute()`` method
  20 +* [`2123 <https://cta-redmine.irap.omp.eu/issues/2123>`_] -
  21 + Properly forward working log file pointer in ``ctobssim::set_mc_id_names()``
  22 +* Correct computation of standard deviations in :ref:`cssrcdetect`
  23 +* :ref:`csobsselect` accepts an observation container upon construction
  24 +
  25 +The following improvements have been made:
  26 +
  27 +* [`2147 <https://cta-redmine.irap.omp.eu/issues/2147>`_] -
  28 + Reduce computation time of ctmodel and parallelize using OpenMP
... ...
doc/source/admin/release_history/index.rst
... ... @@ -19,8 +19,9 @@ Bug fix releases:
19 19 .. toctree::
20 20 :maxdepth: 1
21 21  
22   - ctools 1.0.1 <1.0.1>
  22 + ctools 1.3.1 <1.3.1>
23 23 ctools 1.2.1 <1.2.1>
  24 + ctools 1.0.1 <1.0.1>
24 25  
25 26 For older ctools versions see
26 27 `here <https://cta-redmine.irap.omp.eu/projects/ctools/wiki/Release_notes>`_.
... ...
src/ctmodel/ctmodel.cpp
1 1 /***************************************************************************
2 2 * ctmodel - Model cube generation tool *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2012-2016 by Juergen Knoedlseder *
  4 + * copyright (C) 2012-2017 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -218,6 +218,9 @@ void ctmodel::run(void)
218 218 // Get task parameters
219 219 get_parameters();
220 220  
  221 + // Extract cube properties
  222 + extract_cube_properties();
  223 +
221 224 // Set energy dispersion flags of all CTA observations and save old
222 225 // values in save_edisp vector
223 226 std::vector<bool> save_edisp = set_edisp(m_obs, m_apply_edisp);
... ... @@ -232,43 +235,44 @@ void ctmodel::run(void)
232 235 log_header1(TERSE, "Generate model cube");
233 236  
234 237 // Loop over all observations in the container
  238 + #pragma omp parallel for
235 239 for (int i = 0; i < m_obs.size(); ++i) {
236   -
237   - // Write header for the current observation
238   - log_header3(TERSE, get_obs_header(m_obs[i]));
239   -
  240 +
240 241 // Get CTA observation
241 242 GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]);
242 243  
243 244 // Skip observation if it's not CTA
244 245 if (obs == NULL) {
  246 + log_header3(TERSE, get_obs_header(m_obs[i]));
245 247 std::string msg = " Skipping "+m_obs[i]->instrument()+
246 248 " observation";
247 249 log_string(NORMAL, msg);
248   - continue;
249 250 }
250 251  
251   - // Fill cube and leave loop if we are binned mode (meaning we
  252 + // Fill cube and leave loop if we are binned mode (meaning we
252 253 // only have one binned observation)
253   - if (m_binned) {
  254 + else if (m_binned) {
254 255 fill_cube(obs);
255   - break;
  256 + i = m_obs.size();
256 257 }
257 258  
258 259 // Skip observation if we have a binned observation
259   - if (obs->eventtype() == "CountsCube") {
  260 + else if (obs->eventtype() == "CountsCube") {
  261 + log_header3(TERSE, get_obs_header(m_obs[i]));
260 262 std::string msg = " Skipping binned "+m_obs[i]->instrument()+
261 263 " observation";
262 264 log_string(NORMAL, msg);
263   - continue;
264 265 }
265 266  
266   - // Fill the cube
267   - fill_cube(obs);
268   -
269   - // Dispose events to free memory if event file exists on disk
270   - if (obs->eventfile().length() > 0 && obs->eventfile().exists()) {
271   - obs->dispose_events();
  267 + // Otherwise, everything seems to be fine, so fill the cube from obs
  268 + else {
  269 + // Fill the cube
  270 + fill_cube(obs);
  271 +
  272 + // Dispose events to free memory if event file exists on disk
  273 + if (obs->eventfile().length() > 0 && obs->eventfile().exists()) {
  274 + obs->dispose_events();
  275 + }
272 276 }
273 277  
274 278 } // endfor: looped over observations
... ... @@ -396,6 +400,12 @@ void ctmodel::init_members(void)
396 400 m_has_cube = false;
397 401 m_append_cube = false;
398 402 m_binned = false;
  403 + m_dir.clear();
  404 + m_solidangle.clear();
  405 + m_energy.clear();
  406 + m_ewidth.clear();
  407 + m_time.clear();
  408 + m_ontime = 0.0;
399 409  
400 410 // Return
401 411 return;
... ... @@ -421,6 +431,12 @@ void ctmodel::copy_members(const ctmodel&amp; app)
421 431 m_has_cube = app.m_has_cube;
422 432 m_append_cube = app.m_append_cube;
423 433 m_binned = app.m_binned;
  434 + m_dir = app.m_dir;
  435 + m_solidangle = app.m_solidangle;
  436 + m_energy = app.m_energy;
  437 + m_ewidth = app.m_ewidth;
  438 + m_time = app.m_time;
  439 + m_ontime = app.m_ontime;
424 440  
425 441 // Return
426 442 return;
... ... @@ -478,7 +494,6 @@ void ctmodel::get_parameters(void)
478 494 // Set cube from binned observation
479 495 GCTAEventCube* evtcube = dynamic_cast<GCTAEventCube*>
480 496 (const_cast<GEvents*>(obs->events()));
481   -
482 497 cube(*evtcube);
483 498  
484 499 // Signal that cube has been set
... ... @@ -714,6 +729,60 @@ void ctmodel::get_obs(void)
714 729  
715 730  
716 731 /***********************************************************************//**
  732 + * @brief Extract cube properties in data members
  733 + ***************************************************************************/
  734 +void ctmodel::extract_cube_properties(void)
  735 +{
  736 + // Clear cube properties
  737 + m_dir.clear();
  738 + m_solidangle.clear();
  739 + m_energy.clear();
  740 + m_ewidth.clear();
  741 +
  742 + // Get number of spatial pixels and energy layers in counts cube
  743 + int npix = m_cube.npix();
  744 + int nebins = m_cube.ebins();
  745 +
  746 + // Reserve capacity in vectors
  747 + m_dir.reserve(npix);
  748 + m_solidangle.reserve(npix);
  749 + m_energy.reserve(nebins);
  750 + m_ewidth.reserve(nebins);
  751 +
  752 + // Loop over all the spatial bins and extract spatial cube properties
  753 + for (int i = 0; i < npix; ++i) {
  754 +
  755 + // Get cube bin
  756 + GCTAEventBin* bin = m_cube[i];
  757 +
  758 + // Extract sky direction and solid angle
  759 + m_dir.push_back(bin->dir());
  760 + m_solidangle.push_back(bin->solidangle());
  761 +
  762 + } // endfor: looped over spatial bins
  763 +
  764 + // Loop over all the spectral bins and extract spectral cube properties
  765 + for (int iebin = 0, ibin = 0; iebin < nebins; ++iebin, ibin += npix) {
  766 +
  767 + // Get cube bin
  768 + GCTAEventBin* bin = m_cube[ibin];
  769 +
  770 + // Extract energy and energy width
  771 + m_energy.push_back(bin->energy());
  772 + m_ewidth.push_back(bin->ewidth());
  773 +
  774 + } // endfor: looped over spectral bins
  775 +
  776 + // Set time and ontime
  777 + m_time = m_cube[0]->time();
  778 + m_ontime = m_cube[0]->ontime();
  779 +
  780 + // Return
  781 + return;
  782 +}
  783 +
  784 +
  785 +/***********************************************************************//**
717 786 * @brief Fill model into model cube
718 787 *
719 788 * @param[in] obs CTA observation.
... ... @@ -725,6 +794,10 @@ void ctmodel::get_obs(void)
725 794 ***************************************************************************/
726 795 void ctmodel::fill_cube(const GCTAObservation* obs)
727 796 {
  797 + // Get number of spatial and spectral bins in counts cube
  798 + int npix = m_cube.npix();
  799 + int nebins = m_cube.ebins();
  800 +
728 801 // Get references to GTI and energy boundaries for the event list
729 802 const GGti& gti = obs->events()->gti();
730 803 const GEbounds& obs_ebounds = obs->ebounds();
... ... @@ -748,64 +821,88 @@ void ctmodel::fill_cube(const GCTAObservation* obs)
748 821 int num_outside_ebds = 0;
749 822 int num_outside_roi = 0;
750 823  
751   - // Setup cube GTIs for this observation
752   - m_cube.gti(obs->events()->gti());
  824 + // Extract copy of models from observation container
  825 + GModels models(m_obs.models());
753 826  
754   - // Loop over all cube bins
755   - for (int i = 0; i < m_cube.size(); ++i) {
  827 + // Get pointer to event cube pixels
  828 + double* pixels = const_cast<double*>(m_cube.counts().pixels());
756 829  
757   - // Get cube bin
758   - GCTAEventBin* bin = m_cube[i];
  830 + // Initialise event bin
  831 + GCTAEventBin bin;
759 832  
760   - // Determine counts cube energy bin
761   - int iebin = cube_ebounds.index(bin->energy());
  833 + // Set event bin attributes that are constant for a counts cube
  834 + bin.time(m_time);
  835 + bin.ontime(m_ontime);
  836 + bin.weight(1.0);
762 837  
763   - // Skip bin if the corresponding counts cube energy bin is not fully
764   - // contained in the event list energy range. This avoids having
765   - // partially filled bins.
766   - if (!usage[iebin]) {
767   - num_outside_ebds++;
768   - continue;
769   - }
  838 + // Loop over all the spatial bins
  839 + for (int i = 0; i < npix; ++i) {
770 840  
771 841 // If RoI is valid then skip bin if it is outside the RoI of the
772 842 // observation
773   - if (roi.is_valid() && !roi.contains(*bin)) {
774   - num_outside_roi++;
  843 + if (roi.is_valid() && !roi.contains(m_dir[i])) {
  844 + num_outside_roi += nebins;
775 845 continue;
776 846 }
777 847  
778   - // Get actual bin value
779   - double value = bin->counts();
780   -
781   - // Compute model value for cube bin
782   - double model = m_obs.models().eval(*bin, *obs) * bin->size();
  848 + // Set instrument direction and solid angle of bin
  849 + bin.dir(m_dir[i]);
  850 + bin.solidangle(m_solidangle[i]);
  851 +
  852 + // Loop over all of the energy bins of the cube
  853 + for (int iebin = 0, ibin = i; iebin < nebins; ++iebin, ibin += npix) {
783 854  
784   - // Add model to actual value
785   - value += model;
786   - sum += model;
  855 + // Skip bin if the corresponding counts cube energy bin is not fully
  856 + // contained in the event list energy range. This avoids having
  857 + // partially filled bins.
  858 + if (!usage[iebin]) {
  859 + num_outside_ebds++;
  860 + continue;
  861 + }
787 862  
788   - // Store value
789   - bin->counts(value);
  863 + // Set energy and energy width of bin
  864 + bin.energy(m_energy[iebin]);
  865 + bin.ewidth(m_ewidth[iebin]);
790 866  
791   - } // endfor: looped over all cube bins
  867 + // Compute model value for cube bin
  868 + double model = models.eval(bin, *obs) * bin.size();
792 869  
793   - // Append GTIs of observation to list of GTIs
794   - m_gti.extend(gti);
  870 + // Sum model
  871 + sum += model;
  872 +
  873 + // Store value
  874 + #pragma omp critical(ctmodel_fill_cube)
  875 + pixels[ibin] += model;
  876 +
  877 + } // endfor: looped over all spatial bins
  878 +
  879 + } // endfor: looped over all cube bins
795 880  
796 881 // Update GTIs
797   - m_cube.gti(m_gti);
  882 + #pragma omp critical(ctmodel_fill_cube)
  883 + {
  884 + // Append GTIs of observation to list of GTIs
  885 + m_gti.extend(gti);
  886 +
  887 + // Update GTIs
  888 + m_cube.gti(m_gti);
  889 + }
798 890  
799 891 // Log filling results
800   - log_value(NORMAL, "Model events in cube", sum);
801   - log_value(NORMAL, "Bins outside energy range", num_outside_ebds);
802   - log_value(NORMAL, "Bins outside RoI", num_outside_roi);
  892 + #pragma omp critical(ctmodel_fill_cube)
  893 + {
  894 + log_header3(TERSE, get_obs_header(obs));
  895 + log_value(NORMAL, "Model events in cube", sum);
  896 + log_value(NORMAL, "Bins outside energy range", num_outside_ebds);
  897 + log_value(NORMAL, "Bins outside RoI", num_outside_roi);
  898 + }
803 899  
804 900 // Write model cube into header
805   - log_header2(EXPLICIT, "Model cube");
806   - log_string(EXPLICIT, m_cube.print(m_chatter));
  901 + if (m_chatter >= EXPLICIT) {
  902 + log_header2(EXPLICIT, "Model cube");
  903 + log_string(EXPLICIT, m_cube.print(m_chatter));
  904 + }
807 905  
808 906 // Return
809 907 return;
810 908 }
811   -
... ...
src/ctmodel/ctmodel.hpp
1 1 /***************************************************************************
2 2 * ctmodel - Model cube generation tool *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2012-2016 by Juergen Knoedlseder *
  4 + * copyright (C) 2012-2017 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -79,6 +79,7 @@ protected:
79 79 void free_members(void);
80 80 void get_parameters(void);
81 81 void get_obs(void);
  82 + void extract_cube_properties(void);
82 83 void fill_cube(const GCTAObservation* obs);
83 84 bool has_cube(void) const;
84 85  
... ... @@ -89,11 +90,17 @@ protected:
89 90 GChatter m_chatter; //!< Chattiness
90 91  
91 92 // Protected members
92   - GCTAEventCube m_cube; //!< Model cube
93   - GGti m_gti; //!< Model cube GTIs
94   - bool m_has_cube; //!< Signal if cube has been set or loaded
95   - bool m_append_cube; //!< Signal that cube should be appended
96   - bool m_binned; //!< Signals that we are in binned mode
  93 + GCTAEventCube m_cube; //!< Model cube
  94 + GGti m_gti; //!< Model cube GTIs
  95 + bool m_has_cube; //!< Signal if cube exists
  96 + bool m_append_cube; //!< Signal to append cube
  97 + bool m_binned; //!< Signal binned mode
  98 + std::vector<GCTAInstDir> m_dir; //!< Cube directions
  99 + std::vector<double> m_solidangle; //!< Cube solid angles
  100 + std::vector<GEnergy> m_energy; //!< Cube energies
  101 + std::vector<GEnergy> m_ewidth; //!< Cube energy widths
  102 + GTime m_time; //!< Cube time
  103 + double m_ontime; //!< Cube ontime
97 104 };
98 105  
99 106  
... ...