Commit e9f7fb0a06651f39aa8a93501e6990b896c07971
1 parent
1c4c3571
Updated model trimming and parallelization in ctmodel (#2189)
Updated the model trimming so that the models that are outside an observation are offloaded to another model container and then re-appended after the evaluation. Parallelization scheduling set to "static" with a chunk size of 1. This will slightly help with the issue in which multiple observations in a row do not contribute to the model cube and thus dividing the observations into "n-observations/n-cores" is not ideal.
Showing
2 changed files
with
71 additions
and
61 deletions
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) { | |
| 245 | + | |
| 246 | + // Get CTA observation | |
| 247 | + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]); | |
| 271 | 248 | |
| 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(); | |
| 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,7 +826,7 @@ 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 = trim_models(m_obs.models(), roi); | |
| 829 | + GModels ex_models = trim_models(models, roi); | |
| 823 | 830 | |
| 824 | 831 | // Get pointer to event cube pixels |
| 825 | 832 | double* pixels = const_cast<double*>(m_cube.counts().pixels()); |
| ... | ... | @@ -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 | { |
| ... | ... | @@ -918,27 +928,24 @@ void ctmodel::fill_cube(const GCTAObservation* obs) |
| 918 | 928 | * point sources (which have radius=0) are appropriately included if they |
| 919 | 929 | * fall near the edge of the observation. |
| 920 | 930 | ***************************************************************************/ |
| 921 | -GModels ctmodel::trim_models(const GModels& all_models, const GCTARoi& roi) | |
| 931 | +GModels ctmodel::trim_models(GModels& all_models, const GCTARoi& roi) | |
| 922 | 932 | { |
| 933 | + // Create the model object to be returned | |
| 934 | + GModels excluded_models; | |
| 935 | + | |
| 923 | 936 | // Do nothing if roi is not valid. This will be the case for binned data |
| 924 | 937 | // sets as they have the default roi radius of 0. In this case we would |
| 925 | 938 | // remove ALL models, which is obviously incorrect. So we keep all models |
| 926 | 939 | // when filling based on a counts cube. |
| 927 | 940 | if (!roi.is_valid()) { |
| 928 | - return all_models; | |
| 941 | + return excluded_models; | |
| 929 | 942 | } |
| 930 | 943 | |
| 931 | 944 | // Remove all models that dont overlap with the region of interest. Note |
| 932 | 945 | // that an extra factor is used since point sources have regions of |
| 933 | 946 | // radius 0, which is a problem when they fall just barely outside the |
| 934 | 947 | // ROI. This ensures point sources are appropriately included. |
| 935 | - GSkyRegionCircle obsreg( | |
| 936 | - roi.centre().dir().ra_deg(), | |
| 937 | - roi.centre().dir().dec_deg(), | |
| 938 | - roi.radius()+0.5); // Note the buffer | |
| 939 | - | |
| 940 | - // Create the model object to be returned | |
| 941 | - GModels contained_models; | |
| 948 | + GSkyRegionCircle obsreg(roi.centre().dir(), roi.radius()+0.5); | |
| 942 | 949 | |
| 943 | 950 | // Loop over the models in the passed container |
| 944 | 951 | for (int mod=0; mod<all_models.size(); mod++) { |
| ... | ... | @@ -947,18 +954,21 @@ GModels ctmodel::trim_models(const GModels& all_models, const GCTARoi& roi) |
| 947 | 954 | |
| 948 | 955 | if (model == NULL) { |
| 949 | 956 | // Model is most likely a background model and should be kept |
| 950 | - contained_models.append(*all_models.at(mod)->clone()); | |
| 951 | - | |
| 952 | - } else if (model->spatial()->region()->overlaps(obsreg)) { | |
| 953 | - // Model represents a source, that overlaps the observation | |
| 954 | - // and should be kept. | |
| 955 | - contained_models.append(*model); | |
| 956 | - | |
| 957 | - // Delete model since it isnt needed anymore | |
| 958 | - delete model; | |
| 957 | + continue; | |
| 958 | + } | |
| 959 | + // Otherwise, exclude the model if it isn't a diffuse cube and it | |
| 960 | + // doesn't overlap with the observation. | |
| 961 | + else if (!(model->spatial()->code() == GMODEL_SPATIAL_DIFFUSE) && | |
| 962 | + (!model->spatial()->region()->overlaps(obsreg))) { | |
| 963 | + // Model represents a source, that doesn't overlap the observation | |
| 964 | + // and should be removed for now. | |
| 965 | + excluded_models.append(*model); | |
| 966 | + all_models.remove(mod); | |
| 967 | + mod--; // decrement to prevent skipping models | |
| 959 | 968 | } |
| 960 | 969 | |
| 970 | + delete model; | |
| 961 | 971 | } |
| 962 | 972 | |
| 963 | - return contained_models; | |
| 973 | + return excluded_models; | |
| 964 | 974 | } | ... | ... |
src/ctmodel/ctmodel.hpp
| ... | ... | @@ -80,9 +80,9 @@ protected: |
| 80 | 80 | void get_parameters(void); |
| 81 | 81 | void get_obs(void); |
| 82 | 82 | void extract_cube_properties(void); |
| 83 | - void fill_cube(const GCTAObservation* obs); | |
| 83 | + void fill_cube(const GCTAObservation* obs, GModels& models); | |
| 84 | 84 | bool has_cube(void) const; |
| 85 | - GModels trim_models(const GModels& all_models, const GCTARoi& roi); | |
| 85 | + GModels trim_models(GModels& all_models, const GCTARoi& roi); | |
| 86 | 86 | |
| 87 | 87 | // User parameters |
| 88 | 88 | GFilename m_outcube; //!< Output model cube | ... | ... |