Commit 82c53c6fa15eba93ee1967bab649afa6d901f71e
1 parent
ca8209d4
Add and use GModel::has_eval_indices() and GModel::eval_indices() methods (#745)
The methods GModel::has_eval_indices() and GModel::eval_indices() allow for a more efficient parameter handling in GObservation::model() that is specifically relevant for a model with many parameters, such as the SPI data space models. These methods allow the GModel::eval() method to signal which of the parameters were actually updated, so that the gradients for only these parameters will be considered in GObservation::model(), while all other gradients will be ignored.
Showing
4 changed files
with
170 additions
and
91 deletions
include/GModel.hpp
| 1 | /*************************************************************************** | 1 | /*************************************************************************** |
| 2 | * GModel.hpp - Abstract virtual model base class * | 2 | * GModel.hpp - Abstract virtual model base class * |
| 3 | * ----------------------------------------------------------------------- * | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2009-2019 by Juergen Knoedlseder * | 4 | + * copyright (C) 2009-2020 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 * |
| @@ -126,29 +126,31 @@ public: | @@ -126,29 +126,31 @@ public: | ||
| 126 | virtual std::string print(const GChatter& chatter = NORMAL) const = 0; | 126 | virtual std::string print(const GChatter& chatter = NORMAL) const = 0; |
| 127 | 127 | ||
| 128 | // Implemented methods | 128 | // Implemented methods |
| 129 | - int size(void) const; | ||
| 130 | - int scales(void) const; | ||
| 131 | - GModelPar& at(const int& index); | ||
| 132 | - const GModelPar& at(const int& index) const; | ||
| 133 | - bool has_par(const std::string& name) const; | ||
| 134 | - bool has_scales(void) const; | ||
| 135 | - const std::string& name(void) const; | ||
| 136 | - void name(const std::string& name); | ||
| 137 | - const double& ts(void) const; | ||
| 138 | - void ts(const double& ts); | ||
| 139 | - const bool& tscalc(void) const; | ||
| 140 | - void tscalc(const bool& tscalc); | ||
| 141 | - const bool& has_ts(void) const; | ||
| 142 | - std::string instruments(void) const; | ||
| 143 | - void instruments(const std::string& instruments); | ||
| 144 | - GModelPar& scale(const int& index); | ||
| 145 | - const GModelPar& scale(const int& index) const; | ||
| 146 | - GModelPar scale(const std::string& instrument) const; | ||
| 147 | - void scale(const GModelPar& par); | ||
| 148 | - std::string ids(void) const; | ||
| 149 | - void ids(const std::string& ids); | ||
| 150 | - bool is_valid(const std::string& instruments, | ||
| 151 | - const std::string& ids) const; | 129 | + int size(void) const; |
| 130 | + int scales(void) const; | ||
| 131 | + GModelPar& at(const int& index); | ||
| 132 | + const GModelPar& at(const int& index) const; | ||
| 133 | + bool has_par(const std::string& name) const; | ||
| 134 | + bool has_scales(void) const; | ||
| 135 | + const std::string& name(void) const; | ||
| 136 | + void name(const std::string& name); | ||
| 137 | + const double& ts(void) const; | ||
| 138 | + void ts(const double& ts); | ||
| 139 | + const bool& tscalc(void) const; | ||
| 140 | + void tscalc(const bool& tscalc); | ||
| 141 | + const bool& has_ts(void) const; | ||
| 142 | + std::string instruments(void) const; | ||
| 143 | + void instruments(const std::string& instruments); | ||
| 144 | + GModelPar& scale(const int& index); | ||
| 145 | + const GModelPar& scale(const int& index) const; | ||
| 146 | + GModelPar scale(const std::string& instrument) const; | ||
| 147 | + void scale(const GModelPar& par); | ||
| 148 | + std::string ids(void) const; | ||
| 149 | + void ids(const std::string& ids); | ||
| 150 | + bool is_valid(const std::string& instruments, | ||
| 151 | + const std::string& ids) const; | ||
| 152 | + const bool& has_eval_indices(void) const; | ||
| 153 | + const std::vector<int>& eval_indices(void) const; | ||
| 152 | 154 | ||
| 153 | protected: | 155 | protected: |
| 154 | // Protected methods | 156 | // Protected methods |
| @@ -171,6 +173,12 @@ protected: | @@ -171,6 +173,12 @@ protected: | ||
| 171 | bool m_has_tscalc; //!< Signals if tscalc attribute is available | 173 | bool m_has_tscalc; //!< Signals if tscalc attribute is available |
| 172 | bool m_tscalc; //!< Signals if TS should be computed | 174 | bool m_tscalc; //!< Signals if TS should be computed |
| 173 | double m_ts; //!< Test Statistic of the model | 175 | double m_ts; //!< Test Statistic of the model |
| 176 | + | ||
| 177 | + // Protected members for efficient gradient access | ||
| 178 | + mutable bool m_has_eval_inx; //!< Signal that parameter indices | ||
| 179 | + //!< updated by eval() method exist | ||
| 180 | + mutable std::vector<int> m_eval_inx; //!< List of parameter indices updated | ||
| 181 | + //!< by eval() method | ||
| 174 | }; | 182 | }; |
| 175 | 183 | ||
| 176 | 184 | ||
| @@ -352,4 +360,28 @@ const bool& GModel::has_ts(void) const | @@ -352,4 +360,28 @@ const bool& GModel::has_ts(void) const | ||
| 352 | return m_has_ts; | 360 | return m_has_ts; |
| 353 | } | 361 | } |
| 354 | 362 | ||
| 363 | + | ||
| 364 | +/***********************************************************************//** | ||
| 365 | + * @brief Signals that parameter indices updated by eval() method were set | ||
| 366 | + * | ||
| 367 | + * @return True if parameter indices updated by eval() method were set. | ||
| 368 | + ***************************************************************************/ | ||
| 369 | +inline | ||
| 370 | +const bool& GModel::has_eval_indices(void) const | ||
| 371 | +{ | ||
| 372 | + return m_has_eval_inx; | ||
| 373 | +} | ||
| 374 | + | ||
| 375 | + | ||
| 376 | +/***********************************************************************//** | ||
| 377 | + * @brief Return vector of parameter indices updated by eval() method | ||
| 378 | + * | ||
| 379 | + * @return Vector of parameter indices updated by eval() method. | ||
| 380 | + ***************************************************************************/ | ||
| 381 | +inline | ||
| 382 | +const std::vector<int>& GModel::eval_indices(void) const | ||
| 383 | +{ | ||
| 384 | + return m_eval_inx; | ||
| 385 | +} | ||
| 386 | + | ||
| 355 | #endif /* GMODEL_HPP */ | 387 | #endif /* GMODEL_HPP */ |
pyext/GModel.i
| 1 | /*************************************************************************** | 1 | /*************************************************************************** |
| 2 | * GModel.i - Abstract virtual model base class * | 2 | * GModel.i - Abstract virtual model base class * |
| 3 | * ----------------------------------------------------------------------- * | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2009-2019 by Juergen Knoedlseder * | 4 | + * copyright (C) 2009-2020 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 * |
| @@ -59,26 +59,28 @@ public: | @@ -59,26 +59,28 @@ public: | ||
| 59 | virtual void write(GXmlElement& xml) const = 0; | 59 | virtual void write(GXmlElement& xml) const = 0; |
| 60 | 60 | ||
| 61 | // Implemented methods | 61 | // Implemented methods |
| 62 | - int size(void) const; | ||
| 63 | - int scales(void) const; | ||
| 64 | - bool has_par(const std::string& name) const; | ||
| 65 | - bool has_scales(void) const; | ||
| 66 | - const std::string& name(void) const; | ||
| 67 | - void name(const std::string& name); | ||
| 68 | - const double& ts(void) const; | ||
| 69 | - void ts(const double& ts); | ||
| 70 | - const bool& tscalc(void) const; | ||
| 71 | - void tscalc(const bool& tscalc); | ||
| 72 | - const bool& has_ts(void) const; | ||
| 73 | - std::string instruments(void) const; | ||
| 74 | - void instruments(const std::string& instruments); | ||
| 75 | - GModelPar& scale(const int& index); | ||
| 76 | - GModelPar scale(const std::string& instrument) const; | ||
| 77 | - void scale(const GModelPar& par); | ||
| 78 | - std::string ids(void) const; | ||
| 79 | - void ids(const std::string& ids); | ||
| 80 | - bool is_valid(const std::string& instruments, | ||
| 81 | - const std::string& ids) const; | 62 | + int size(void) const; |
| 63 | + int scales(void) const; | ||
| 64 | + bool has_par(const std::string& name) const; | ||
| 65 | + bool has_scales(void) const; | ||
| 66 | + const std::string& name(void) const; | ||
| 67 | + void name(const std::string& name); | ||
| 68 | + const double& ts(void) const; | ||
| 69 | + void ts(const double& ts); | ||
| 70 | + const bool& tscalc(void) const; | ||
| 71 | + void tscalc(const bool& tscalc); | ||
| 72 | + const bool& has_ts(void) const; | ||
| 73 | + std::string instruments(void) const; | ||
| 74 | + void instruments(const std::string& instruments); | ||
| 75 | + GModelPar& scale(const int& index); | ||
| 76 | + GModelPar scale(const std::string& instrument) const; | ||
| 77 | + void scale(const GModelPar& par); | ||
| 78 | + std::string ids(void) const; | ||
| 79 | + void ids(const std::string& ids); | ||
| 80 | + bool is_valid(const std::string& instruments, | ||
| 81 | + const std::string& ids) const; | ||
| 82 | + const bool& has_eval_indices(void) const; | ||
| 83 | + const std::vector<int>& eval_indices(void) const; | ||
| 82 | }; | 84 | }; |
| 83 | 85 | ||
| 84 | 86 |
src/model/GModel.cpp
| 1 | /*************************************************************************** | 1 | /*************************************************************************** |
| 2 | * GModel.cpp - Abstract virtual model base class * | 2 | * GModel.cpp - Abstract virtual model base class * |
| 3 | * ----------------------------------------------------------------------- * | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2009-2019 by Juergen Knoedlseder * | 4 | + * copyright (C) 2009-2020 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 * |
| @@ -617,11 +617,13 @@ void GModel::init_members(void) | @@ -617,11 +617,13 @@ void GModel::init_members(void) | ||
| 617 | m_scales.clear(); | 617 | m_scales.clear(); |
| 618 | m_ids.clear(); | 618 | m_ids.clear(); |
| 619 | m_pars.clear(); | 619 | m_pars.clear(); |
| 620 | - m_ts = 0.0; | ||
| 621 | - m_has_ts = false; | ||
| 622 | - m_has_tscalc = false; | ||
| 623 | - m_tscalc = false; | ||
| 624 | - | 620 | + m_ts = 0.0; |
| 621 | + m_has_ts = false; | ||
| 622 | + m_has_tscalc = false; | ||
| 623 | + m_tscalc = false; | ||
| 624 | + m_has_eval_inx = false; | ||
| 625 | + m_eval_inx.clear(); | ||
| 626 | + | ||
| 625 | // Return | 627 | // Return |
| 626 | return; | 628 | return; |
| 627 | } | 629 | } |
| @@ -635,15 +637,17 @@ void GModel::init_members(void) | @@ -635,15 +637,17 @@ void GModel::init_members(void) | ||
| 635 | void GModel::copy_members(const GModel& model) | 637 | void GModel::copy_members(const GModel& model) |
| 636 | { | 638 | { |
| 637 | // Copy members | 639 | // Copy members |
| 638 | - m_name = model.m_name; | ||
| 639 | - m_instruments = model.m_instruments; | ||
| 640 | - m_scales = model.m_scales; | ||
| 641 | - m_ids = model.m_ids; | ||
| 642 | - m_pars = model.m_pars; | ||
| 643 | - m_ts = model.m_ts; | ||
| 644 | - m_has_ts = model.m_has_ts; | ||
| 645 | - m_has_tscalc = model.m_has_tscalc; | ||
| 646 | - m_tscalc = model.m_tscalc; | 640 | + m_name = model.m_name; |
| 641 | + m_instruments = model.m_instruments; | ||
| 642 | + m_scales = model.m_scales; | ||
| 643 | + m_ids = model.m_ids; | ||
| 644 | + m_pars = model.m_pars; | ||
| 645 | + m_ts = model.m_ts; | ||
| 646 | + m_has_ts = model.m_has_ts; | ||
| 647 | + m_has_tscalc = model.m_has_tscalc; | ||
| 648 | + m_tscalc = model.m_tscalc; | ||
| 649 | + m_has_eval_inx = model.m_has_eval_inx; | ||
| 650 | + m_eval_inx = model.m_eval_inx; | ||
| 647 | 651 | ||
| 648 | // Return | 652 | // Return |
| 649 | return; | 653 | return; |
src/obs/GObservation.cpp
| 1 | /*************************************************************************** | 1 | /*************************************************************************** |
| 2 | * GObservation.cpp - Abstract observation base class * | 2 | * GObservation.cpp - Abstract observation base class * |
| 3 | * ----------------------------------------------------------------------- * | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2008-2019 by Juergen Knoedlseder * | 4 | + * copyright (C) 2008-2020 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 * |
| @@ -302,39 +302,80 @@ double GObservation::model(const GModels& models, | @@ -302,39 +302,80 @@ double GObservation::model(const GModels& models, | ||
| 302 | // over the energy dispersion. Here it's simpler to just use | 302 | // over the energy dispersion. Here it's simpler to just use |
| 303 | // numerical gradients. | 303 | // numerical gradients. |
| 304 | if (gradient != NULL) { | 304 | if (gradient != NULL) { |
| 305 | - for (int ipar = 0; ipar < mptr->size(); ++ipar) { | ||
| 306 | - | ||
| 307 | - // Get reference to model parameter | ||
| 308 | - const GModelPar& par = (*mptr)[ipar]; | ||
| 309 | - | ||
| 310 | - // Make sure that we have a slot for the gradient | ||
| 311 | - #if defined(G_RANGE_CHECK) | ||
| 312 | - if (igrad >= grad_size) { | ||
| 313 | - std::string msg = "Vector has not enough elements " | ||
| 314 | - "to store the model parameter " | ||
| 315 | - "gradients. "+ | ||
| 316 | - gammalib::str(models.npars())+ | ||
| 317 | - " elements requested while vector " | ||
| 318 | - "only contains "+ | ||
| 319 | - gammalib::str(gradient->size())+ | ||
| 320 | - " elements."; | ||
| 321 | - throw GException::invalid_value(G_MODEL, msg); | ||
| 322 | - } | ||
| 323 | - #endif | ||
| 324 | - | ||
| 325 | - if (par.is_free()) { | ||
| 326 | - if (par.has_grad() && !response()->use_edisp()) { | ||
| 327 | - (*gradient)[igrad+ipar] = par.factor_gradient(); | 305 | + |
| 306 | + // Make sure that we have a slot for the gradient | ||
| 307 | + #if defined(G_RANGE_CHECK) | ||
| 308 | + if (igrad+mptr->size() > grad_size) { | ||
| 309 | + std::string msg = "Vector has not enough elements to " | ||
| 310 | + "store the model parameter gradients. "+ | ||
| 311 | + gammalib::str(models.npars())+" elements " | ||
| 312 | + "requested while vector only contains "+ | ||
| 313 | + gammalib::str(gradient->size())+" elements."; | ||
| 314 | + throw GException::invalid_value(G_MODEL, msg); | ||
| 315 | + } | ||
| 316 | + #endif | ||
| 317 | + | ||
| 318 | + // If model provides the parameter indices that were | ||
| 319 | + // updated by the eval() method then use them as this is | ||
| 320 | + // less time consuming than looping over all indices | ||
| 321 | + if (mptr->has_eval_indices()) { | ||
| 322 | + | ||
| 323 | + // Get number of relevant parameters | ||
| 324 | + int npars = mptr->eval_indices().size(); | ||
| 325 | + | ||
| 326 | + // Loop over all relevant parameters | ||
| 327 | + for (int index = 0; index < npars; ++index) { | ||
| 328 | + | ||
| 329 | + // Retrieve parameter index | ||
| 330 | + int ipar = mptr->eval_indices()[index]; | ||
| 331 | + | ||
| 332 | + // Get reference to model parameter | ||
| 333 | + const GModelPar& par = (*mptr)[ipar]; | ||
| 334 | + | ||
| 335 | + // Set gradient | ||
| 336 | + if (par.is_free()) { | ||
| 337 | + if (par.has_grad() && !response()->use_edisp()) { | ||
| 338 | + (*gradient)[igrad+ipar] = par.factor_gradient(); | ||
| 339 | + } | ||
| 340 | + else { | ||
| 341 | + (*gradient)[igrad+ipar] = model_grad(*mptr, par, event); | ||
| 342 | + } | ||
| 328 | } | 343 | } |
| 329 | else { | 344 | else { |
| 330 | - (*gradient)[igrad+ipar] = model_grad(*mptr, par, event); | 345 | + (*gradient)[igrad+ipar] = 0.0; |
| 331 | } | 346 | } |
| 332 | - } | ||
| 333 | - else { | ||
| 334 | - (*gradient)[igrad+ipar] = 0.0; | ||
| 335 | - } | ||
| 336 | - } | ||
| 337 | - } | 347 | + |
| 348 | + } // endfor: looped over all parameter indices | ||
| 349 | + | ||
| 350 | + } // endif: parameter indices were available | ||
| 351 | + | ||
| 352 | + // ... otherwise loop over all parameter indices | ||
| 353 | + else { | ||
| 354 | + | ||
| 355 | + // Loop over all parameters | ||
| 356 | + for (int ipar = 0; ipar < mptr->size(); ++ipar) { | ||
| 357 | + | ||
| 358 | + // Get reference to model parameter | ||
| 359 | + const GModelPar& par = (*mptr)[ipar]; | ||
| 360 | + | ||
| 361 | + // Set gradient | ||
| 362 | + if (par.is_free()) { | ||
| 363 | + if (par.has_grad() && !response()->use_edisp()) { | ||
| 364 | + (*gradient)[igrad+ipar] = par.factor_gradient(); | ||
| 365 | + } | ||
| 366 | + else { | ||
| 367 | + (*gradient)[igrad+ipar] = model_grad(*mptr, par, event); | ||
| 368 | + } | ||
| 369 | + } | ||
| 370 | + else { | ||
| 371 | + (*gradient)[igrad+ipar] = 0.0; | ||
| 372 | + } | ||
| 373 | + | ||
| 374 | + } // endfor: looped over all parameter indices | ||
| 375 | + | ||
| 376 | + } // endelse: no parameter indices were available | ||
| 377 | + | ||
| 378 | + } // endif: use model gradients | ||
| 338 | 379 | ||
| 339 | } // endif: model component was valid for instrument | 380 | } // endif: model component was valid for instrument |
| 340 | 381 |