Commit c5d45282c745d5ba5901a0a04aae3c68b2fb43b4

Authored by Jürgen Knödlseder
2 parents eaa252c2 fe0597f6

Merge branch '2189-ctmodel_trim_models' into integration

# Conflicts:
#	ChangeLog
#	NEWS
#	doc/source/admin/release_history/1.5.rst
ChangeLog
1   -2017-10-10
  1 +2017-10-11
2 2  
3 3 * Version 1.5.0 released
4 4 ========================
5 5  
6   - Use t-type parameters for all "tmin" and "tmax" parameters (#1864)
7 6 Add keywords to sky maps produced by ctskymap (#2194)
  7 + Enhance efficiency of computations in ctmodel (#2189)
  8 + Use t-type parameters for all "tmin" and "tmax" parameters (#1864)
8 9  
9 10  
10 11 2017-07-28
... ...
1 1 New Features and Important Changes in ctools 1.5.0
2 2  
3   -10 October 2017
  3 +11 October 2017
4 4  
5 5  
6 6 Introduction
... ... @@ -63,6 +63,11 @@ ctmodel - CTA counts cube modelling
63 63 Use t-type parameters for "tmin" and "tmax" to all specifying times in various
64 64 formats (#1864).
65 65  
  66 +The tool now also checks which models actually overlap with the RoI of a given
  67 +observation and then only use these models to compute the model cube. The
  68 +parallelization of the tool has also been optimised so that diffuse models are
  69 +not loaded over and over again (#2189).
  70 +
66 71  
67 72 ctexpcube - CTA exposure cube generation
68 73 ----------------------------------------
... ...
doc/source/admin/release_history/1.5.rst
... ... @@ -24,6 +24,8 @@ Improvements
24 24  
25 25 * [`2194 <https://cta-redmine.irap.omp.eu/issues/2194>`_] -
26 26 Add keywords to sky maps produced by :ref:`ctskymap`
  27 +* [`2189 <https://cta-redmine.irap.omp.eu/issues/2189>`_] -
  28 + Enhance efficiency of computations in :ref:`ctmodel`
27 29  
28 30  
29 31 New features
... ...
src/ctmodel/ctmodel.cpp
... ... @@ -235,48 +235,55 @@ void ctmodel::run(void)
235 235 log_header1(TERSE, "Generate model cube");
236 236  
237 237 // Loop over all observations in the container
238   - #pragma omp parallel for
239   - for (int i = 0; i < m_obs.size(); ++i) {
  238 + #pragma omp parallel
  239 + {
  240 + // Create a models object for this core
  241 + GModels models(m_obs.models());
240 242  
241   - // Get CTA observation
242   - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]);
243   -
244   - // Skip observation if it's not CTA
245   - if (obs == NULL) {
246   - log_header3(TERSE, get_obs_header(m_obs[i]));
247   - std::string msg = " Skipping "+m_obs[i]->instrument()+
248   - " observation";
249   - log_string(NORMAL, msg);
250   - }
251   -
252   - // Fill cube and leave loop if we are binned mode (meaning we
253   - // only have one binned observation)
254   - else if (m_binned) {
255   - fill_cube(obs);
256   - i = m_obs.size();
257   - }
258   -
259   - // Skip observation if we have a binned observation
260   - else if (obs->eventtype() == "CountsCube") {
261   - log_header3(TERSE, get_obs_header(m_obs[i]));
262   - std::string msg = " Skipping binned "+m_obs[i]->instrument()+
263   - " observation";
264   - log_string(NORMAL, msg);
265   - }
266   -
267   - // Otherwise, everything seems to be fine, so fill the cube from obs
268   - else {
269   - // Fill the cube
270   - fill_cube(obs);
  243 + #pragma omp for schedule(static,1)
  244 + for (int i = 0; i < m_obs.size(); ++i) {
271 245  
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();
  246 + // Get CTA observation
  247 + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]);
  248 +
  249 + // Skip observation if it's not CTA
  250 + if (obs == NULL) {
  251 + log_header3(TERSE, get_obs_header(m_obs[i]));
  252 + std::string msg = " Skipping "+m_obs[i]->instrument()+
  253 + " observation";
  254 + log_string(NORMAL, msg);
275 255 }
276   - }
277   -
278   - } // endfor: looped over observations
  256 +
  257 + // Fill cube and leave loop if we are binned mode (meaning we
  258 + // only have one binned observation)
  259 + else if (m_binned) {
  260 + fill_cube(obs, models);
  261 + i = m_obs.size();
  262 + }
  263 +
  264 + // Skip observation if we have a binned observation
  265 + else if (obs->eventtype() == "CountsCube") {
  266 + log_header3(TERSE, get_obs_header(m_obs[i]));
  267 + std::string msg = " Skipping binned "+m_obs[i]->instrument()+
  268 + " observation";
  269 + log_string(NORMAL, msg);
  270 + }
  271 +
  272 + // Otherwise, everything seems to be fine, so fill the cube from obs
  273 + else {
  274 + // Fill the cube
  275 + fill_cube(obs, models);
  276 +
  277 + // Dispose events to free memory if event file exists on disk
  278 + if (obs->eventfile().length() > 0 && obs->eventfile().exists()) {
  279 + obs->dispose_events();
  280 + }
  281 + }
  282 +
  283 + } // endfor: looped over observations
279 284  
  285 + } // end openmp parallel section
  286 +
280 287 // Write model cube into header
281 288 log_header1(NORMAL, "Model cube");
282 289 log_string(NORMAL, m_cube.print());
... ... @@ -789,7 +796,7 @@ void ctmodel::extract_cube_properties(void)
789 796 * GTI of the model cube so that cube GTI is a list of the GTIs of all
790 797 * observations that were used to generate the model cube.
791 798 ***************************************************************************/
792   -void ctmodel::fill_cube(const GCTAObservation* obs)
  799 +void ctmodel::fill_cube(const GCTAObservation* obs, GModels& models)
793 800 {
794 801 // Get number of spatial and spectral bins in counts cube
795 802 int npix = m_cube.npix();
... ... @@ -819,8 +826,8 @@ void ctmodel::fill_cube(const GCTAObservation* obs)
819 826 int num_outside_roi = 0;
820 827  
821 828 // Extract copy of models from observation container
822   - GModels models(m_obs.models());
823   -
  829 + GModels ex_models = trim_models(models, roi);
  830 +
824 831 // Get pointer to event cube pixels
825 832 double* pixels = const_cast<double*>(m_cube.counts().pixels());
826 833  
... ... @@ -877,6 +884,9 @@ void ctmodel::fill_cube(const GCTAObservation* obs)
877 884  
878 885 } // endfor: looped over all cube bins
879 886  
  887 + // Re-append the models to the main model
  888 + models.extend(ex_models);
  889 +
880 890 // Update GTIs
881 891 #pragma omp critical(ctmodel_fill_cube)
882 892 {
... ... @@ -905,3 +915,66 @@ void ctmodel::fill_cube(const GCTAObservation* obs)
905 915 // Return
906 916 return;
907 917 }
  918 +
  919 +
  920 +/***********************************************************************//**
  921 + * @brief Find the models falling inside a defined region of interest.
  922 + *
  923 + * @param[in,out] all_models Model container to be trimmed.
  924 + * @param[in] roi Observation region of interest.
  925 + * @return New model container containing only models inside RoI.
  926 + *
  927 + * Note that a buffer is added to the observation region to ensure that
  928 + * point sources (which have radius=0) are appropriately included if they
  929 + * fall near the edge of the observation.
  930 + ***************************************************************************/
  931 +GModels ctmodel::trim_models(GModels& all_models, const GCTARoi& roi)
  932 +{
  933 + // Create the model container containing only models in RoI
  934 + GModels excluded_models;
  935 +
  936 + // Do nothing if roi is not valid. This will be the case for binned data
  937 + // sets as they have the default roi radius of 0. In this case we would
  938 + // remove ALL models, which is obviously incorrect. So we keep all models
  939 + // when filling based on a counts cube.
  940 + if (!roi.is_valid()) {
  941 + return excluded_models;
  942 + }
  943 +
  944 + // Remove all models that dont overlap with the region of interest. Note
  945 + // that an extra factor is used since point sources have regions of
  946 + // radius 0, which is a problem when they fall just barely outside the
  947 + // RoI. This ensures point sources are appropriately included.
  948 + GSkyRegionCircle obsreg(roi.centre().dir(), roi.radius()+0.5);
  949 +
  950 + // Loop over the models in the passed container
  951 + for (int i = 0; i < all_models.size(); ++i) {
  952 +
  953 + // Cast the model to a GModelSky object
  954 + GModelSky* model = dynamic_cast<GModelSky*>(all_models[i]);
  955 +
  956 + // If model is not a GModelSky model than skip
  957 + if (model == NULL) {
  958 + continue;
  959 + }
  960 +
  961 + // Otherwise, exclude the model if it isn't a diffuse cube and it
  962 + // doesn't overlap with the observation.
  963 + if (!(model->spatial()->code() == GMODEL_SPATIAL_DIFFUSE) &&
  964 + (!model->spatial()->region()->overlaps(obsreg))) {
  965 +
  966 + // Append model to the excluded models
  967 + excluded_models.append(*model);
  968 +
  969 + // Remove model
  970 + all_models.remove(i);
  971 +
  972 + // Decrement to prevent skipping models
  973 + i--;
  974 + }
  975 +
  976 + } // endfor: looped over all models
  977 +
  978 + // Return excluded models
  979 + return excluded_models;
  980 +}
... ...
src/ctmodel/ctmodel.hpp
... ... @@ -74,14 +74,15 @@ public:
74 74  
75 75 protected:
76 76 // Protected methods
77   - void init_members(void);
78   - void copy_members(const ctmodel& app);
79   - void free_members(void);
80   - void get_parameters(void);
81   - void get_obs(void);
82   - void extract_cube_properties(void);
83   - void fill_cube(const GCTAObservation* obs);
84   - bool has_cube(void) const;
  77 + void init_members(void);
  78 + void copy_members(const ctmodel& app);
  79 + void free_members(void);
  80 + void get_parameters(void);
  81 + void get_obs(void);
  82 + void extract_cube_properties(void);
  83 + void fill_cube(const GCTAObservation* obs, GModels& models);
  84 + bool has_cube(void) const;
  85 + GModels trim_models(GModels& all_models, const GCTARoi& roi);
85 86  
86 87 // User parameters
87 88 GFilename m_outcube; //!< Output model cube
... ...