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,11 +6,16 @@
6 Install ctools header files (#2145) 6 Install ctools header files (#2145)
7 7
8 8
9 -2017-06-23 9 +2017-07-07
10 10
11 * Bug fix version 1.3.1 released 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 Properly forward working log file pointer in ctobssim::set_mc_id_names() (#2123) 19 Properly forward working log file pointer in ctobssim::set_mc_id_names() (#2123)
15 Correct computation of standard deviations in cssrcdetect 20 Correct computation of standard deviations in cssrcdetect
16 csobsselect accepts an observation container upon construction 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,8 +19,9 @@ Bug fix releases:
19 .. toctree:: 19 .. toctree::
20 :maxdepth: 1 20 :maxdepth: 1
21 21
22 - ctools 1.0.1 <1.0.1> 22 + ctools 1.3.1 <1.3.1>
23 ctools 1.2.1 <1.2.1> 23 ctools 1.2.1 <1.2.1>
  24 + ctools 1.0.1 <1.0.1>
24 25
25 For older ctools versions see 26 For older ctools versions see
26 `here <https://cta-redmine.irap.omp.eu/projects/ctools/wiki/Release_notes>`_. 27 `here <https://cta-redmine.irap.omp.eu/projects/ctools/wiki/Release_notes>`_.
src/ctmodel/ctmodel.cpp
1 /*************************************************************************** 1 /***************************************************************************
2 * ctmodel - Model cube generation tool * 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 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -218,6 +218,9 @@ void ctmodel::run(void) @@ -218,6 +218,9 @@ void ctmodel::run(void)
218 // Get task parameters 218 // Get task parameters
219 get_parameters(); 219 get_parameters();
220 220
  221 + // Extract cube properties
  222 + extract_cube_properties();
  223 +
221 // Set energy dispersion flags of all CTA observations and save old 224 // Set energy dispersion flags of all CTA observations and save old
222 // values in save_edisp vector 225 // values in save_edisp vector
223 std::vector<bool> save_edisp = set_edisp(m_obs, m_apply_edisp); 226 std::vector<bool> save_edisp = set_edisp(m_obs, m_apply_edisp);
@@ -232,43 +235,44 @@ void ctmodel::run(void) @@ -232,43 +235,44 @@ void ctmodel::run(void)
232 log_header1(TERSE, "Generate model cube"); 235 log_header1(TERSE, "Generate model cube");
233 236
234 // Loop over all observations in the container 237 // Loop over all observations in the container
  238 + #pragma omp parallel for
235 for (int i = 0; i < m_obs.size(); ++i) { 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 // Get CTA observation 241 // Get CTA observation
241 GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]); 242 GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]);
242 243
243 // Skip observation if it's not CTA 244 // Skip observation if it's not CTA
244 if (obs == NULL) { 245 if (obs == NULL) {
  246 + log_header3(TERSE, get_obs_header(m_obs[i]));
245 std::string msg = " Skipping "+m_obs[i]->instrument()+ 247 std::string msg = " Skipping "+m_obs[i]->instrument()+
246 " observation"; 248 " observation";
247 log_string(NORMAL, msg); 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 // only have one binned observation) 253 // only have one binned observation)
253 - if (m_binned) { 254 + else if (m_binned) {
254 fill_cube(obs); 255 fill_cube(obs);
255 - break; 256 + i = m_obs.size();
256 } 257 }
257 258
258 // Skip observation if we have a binned observation 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 std::string msg = " Skipping binned "+m_obs[i]->instrument()+ 262 std::string msg = " Skipping binned "+m_obs[i]->instrument()+
261 " observation"; 263 " observation";
262 log_string(NORMAL, msg); 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 } // endfor: looped over observations 278 } // endfor: looped over observations
@@ -396,6 +400,12 @@ void ctmodel::init_members(void) @@ -396,6 +400,12 @@ void ctmodel::init_members(void)
396 m_has_cube = false; 400 m_has_cube = false;
397 m_append_cube = false; 401 m_append_cube = false;
398 m_binned = false; 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 // Return 410 // Return
401 return; 411 return;
@@ -421,6 +431,12 @@ void ctmodel::copy_members(const ctmodel&amp; app) @@ -421,6 +431,12 @@ void ctmodel::copy_members(const ctmodel&amp; app)
421 m_has_cube = app.m_has_cube; 431 m_has_cube = app.m_has_cube;
422 m_append_cube = app.m_append_cube; 432 m_append_cube = app.m_append_cube;
423 m_binned = app.m_binned; 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 // Return 441 // Return
426 return; 442 return;
@@ -478,7 +494,6 @@ void ctmodel::get_parameters(void) @@ -478,7 +494,6 @@ void ctmodel::get_parameters(void)
478 // Set cube from binned observation 494 // Set cube from binned observation
479 GCTAEventCube* evtcube = dynamic_cast<GCTAEventCube*> 495 GCTAEventCube* evtcube = dynamic_cast<GCTAEventCube*>
480 (const_cast<GEvents*>(obs->events())); 496 (const_cast<GEvents*>(obs->events()));
481 -  
482 cube(*evtcube); 497 cube(*evtcube);
483 498
484 // Signal that cube has been set 499 // Signal that cube has been set
@@ -714,6 +729,60 @@ void ctmodel::get_obs(void) @@ -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 * @brief Fill model into model cube 786 * @brief Fill model into model cube
718 * 787 *
719 * @param[in] obs CTA observation. 788 * @param[in] obs CTA observation.
@@ -725,6 +794,10 @@ void ctmodel::get_obs(void) @@ -725,6 +794,10 @@ void ctmodel::get_obs(void)
725 ***************************************************************************/ 794 ***************************************************************************/
726 void ctmodel::fill_cube(const GCTAObservation* obs) 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 // Get references to GTI and energy boundaries for the event list 801 // Get references to GTI and energy boundaries for the event list
729 const GGti& gti = obs->events()->gti(); 802 const GGti& gti = obs->events()->gti();
730 const GEbounds& obs_ebounds = obs->ebounds(); 803 const GEbounds& obs_ebounds = obs->ebounds();
@@ -748,64 +821,88 @@ void ctmodel::fill_cube(const GCTAObservation* obs) @@ -748,64 +821,88 @@ void ctmodel::fill_cube(const GCTAObservation* obs)
748 int num_outside_ebds = 0; 821 int num_outside_ebds = 0;
749 int num_outside_roi = 0; 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 // If RoI is valid then skip bin if it is outside the RoI of the 841 // If RoI is valid then skip bin if it is outside the RoI of the
772 // observation 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 continue; 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 // Update GTIs 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 // Log filling results 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 // Write model cube into header 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 // Return 906 // Return
809 return; 907 return;
810 } 908 }
811 -  
src/ctmodel/ctmodel.hpp
1 /*************************************************************************** 1 /***************************************************************************
2 * ctmodel - Model cube generation tool * 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 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -79,6 +79,7 @@ protected: @@ -79,6 +79,7 @@ protected:
79 void free_members(void); 79 void free_members(void);
80 void get_parameters(void); 80 void get_parameters(void);
81 void get_obs(void); 81 void get_obs(void);
  82 + void extract_cube_properties(void);
82 void fill_cube(const GCTAObservation* obs); 83 void fill_cube(const GCTAObservation* obs);
83 bool has_cube(void) const; 84 bool has_cube(void) const;
84 85
@@ -89,11 +90,17 @@ protected: @@ -89,11 +90,17 @@ protected:
89 GChatter m_chatter; //!< Chattiness 90 GChatter m_chatter; //!< Chattiness
90 91
91 // Protected members 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