Commit 6017f6708bbe55603ec5632c3997e1500437ea20
1 parent
a133c400
Restructure GModel::eval() method for vectorised computations and implement a st…
…ack for model parameters with analytical gradients at the level of the GObservation class.
Showing
12 changed files
with
351 additions
and
193 deletions
include/GModel.hpp
| ... | ... | @@ -121,16 +121,14 @@ public: |
| 121 | 121 | virtual double eval(const GEvent& event, |
| 122 | 122 | const GObservation& obs, |
| 123 | 123 | const bool& gradients = false) const = 0; |
| 124 | + virtual GVector eval(const GObservation& obs, | |
| 125 | + GMatrixSparse* gradients = NULL) const = 0; | |
| 124 | 126 | virtual double npred(const GEnergy& obsEng, const GTime& obsTime, |
| 125 | 127 | const GObservation& obs) const = 0; |
| 126 | 128 | virtual void read(const GXmlElement& xml) = 0; |
| 127 | 129 | virtual void write(GXmlElement& xml) const = 0; |
| 128 | 130 | virtual std::string print(const GChatter& chatter = NORMAL) const = 0; |
| 129 | 131 | |
| 130 | - // Virtual methods | |
| 131 | - virtual GVector eval(const GObservation& obs, | |
| 132 | - GMatrixSparse* gradients = NULL) const; | |
| 133 | - | |
| 134 | 132 | // Implemented methods |
| 135 | 133 | int size(void) const; |
| 136 | 134 | int scales(void) const; | ... | ... |
include/GModelData.hpp
| 1 | 1 | /*************************************************************************** |
| 2 | 2 | * GModelData.hpp - Abstract virtual data model class * |
| 3 | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2011-2016 by Juergen Knoedlseder * | |
| 4 | + * copyright (C) 2011-2020 by Juergen Knoedlseder * | |
| 5 | 5 | * ----------------------------------------------------------------------- * |
| 6 | 6 | * * |
| 7 | 7 | * This program is free software: you can redistribute it and/or modify * |
| ... | ... | @@ -40,6 +40,8 @@ class GEvents; |
| 40 | 40 | class GObservation; |
| 41 | 41 | class GRan; |
| 42 | 42 | class GXmlElement; |
| 43 | +class GVector; | |
| 44 | +class GMatrixSparse; | |
| 43 | 45 | |
| 44 | 46 | |
| 45 | 47 | /***********************************************************************//** |
| ... | ... | @@ -78,6 +80,10 @@ public: |
| 78 | 80 | virtual void write(GXmlElement& xml) const = 0; |
| 79 | 81 | virtual std::string print(const GChatter& chatter = NORMAL) const = 0; |
| 80 | 82 | |
| 83 | + // Implemented pure virtual base class methods | |
| 84 | + virtual GVector eval(const GObservation& obs, | |
| 85 | + GMatrixSparse* gradients = NULL) const; | |
| 86 | + | |
| 81 | 87 | protected: |
| 82 | 88 | // Protected methods |
| 83 | 89 | void init_members(void); | ... | ... |
include/GModelSky.hpp
| ... | ... | @@ -40,7 +40,6 @@ |
| 40 | 40 | #include "GPhoton.hpp" |
| 41 | 41 | #include "GPhotons.hpp" |
| 42 | 42 | #include "GRan.hpp" |
| 43 | -#include "GVector.hpp" | |
| 44 | 43 | #include "GEvent.hpp" |
| 45 | 44 | #include "GObservation.hpp" |
| 46 | 45 | #include "GXmlElement.hpp" |
| ... | ... | @@ -48,6 +47,8 @@ |
| 48 | 47 | /* __ Forward declarations _______________________________________________ */ |
| 49 | 48 | class GEvent; |
| 50 | 49 | class GObservation; |
| 50 | +class GVector; | |
| 51 | +class GMatrixSparse; | |
| 51 | 52 | |
| 52 | 53 | |
| 53 | 54 | /***********************************************************************//** |
| ... | ... | @@ -149,6 +150,8 @@ public: |
| 149 | 150 | virtual double eval(const GEvent& event, |
| 150 | 151 | const GObservation& obs, |
| 151 | 152 | const bool& gradients = false) const; |
| 153 | + virtual GVector eval(const GObservation& obs, | |
| 154 | + GMatrixSparse* gradients = NULL) const; | |
| 152 | 155 | virtual double npred(const GEnergy& obsEng, |
| 153 | 156 | const GTime& obsTime, |
| 154 | 157 | const GObservation& obs) const; |
| ... | ... | @@ -156,10 +159,6 @@ public: |
| 156 | 159 | virtual void write(GXmlElement& xml) const; |
| 157 | 160 | virtual std::string print(const GChatter& chatter = NORMAL) const; |
| 158 | 161 | |
| 159 | - // Reimplemented virtual base class methods | |
| 160 | - virtual GVector eval(const GObservation& obs, | |
| 161 | - GMatrixSparse* gradients = NULL) const; | |
| 162 | - | |
| 163 | 162 | // Other methods |
| 164 | 163 | GModelSpatial* spatial(void) const; |
| 165 | 164 | GModelSpectral* spectral(void) const; |
| ... | ... | @@ -182,6 +181,7 @@ protected: |
| 182 | 181 | void free_members(void); |
| 183 | 182 | void set_pointers(void); |
| 184 | 183 | void set_type(void); |
| 184 | + void signal_analytical_gradients(const GObservation& obs) const; | |
| 185 | 185 | GModelSpatial* xml_spatial(const GXmlElement& spatial) const; |
| 186 | 186 | GModelSpectral* xml_spectral(const GXmlElement& spectral) const; |
| 187 | 187 | GModelTemporal* xml_temporal(const GXmlElement& temporal) const; | ... | ... |
include/GObservation.hpp
| ... | ... | @@ -29,17 +29,18 @@ |
| 29 | 29 | |
| 30 | 30 | /* __ Includes ___________________________________________________________ */ |
| 31 | 31 | #include <string> |
| 32 | +#include <vector> | |
| 32 | 33 | #include "GBase.hpp" |
| 33 | 34 | #include "GEvents.hpp" |
| 34 | 35 | #include "GTime.hpp" |
| 35 | 36 | #include "GFunction.hpp" |
| 37 | +#include "GModelPar.hpp" | |
| 36 | 38 | |
| 37 | 39 | /* __ Forward declarations _______________________________________________ */ |
| 38 | 40 | class GVector; |
| 39 | 41 | class GMatrixSparse; |
| 40 | 42 | class GModel; |
| 41 | 43 | class GModels; |
| 42 | -class GModelPar; | |
| 43 | 44 | class GResponse; |
| 44 | 45 | class GXmlElement; |
| 45 | 46 | |
| ... | ... | @@ -119,12 +120,14 @@ public: |
| 119 | 120 | |
| 120 | 121 | // Implemented methods |
| 121 | 122 | bool has_events(void) const; |
| 123 | + bool has_gradient(const GModelPar& par) const; | |
| 122 | 124 | void name(const std::string& name); |
| 123 | 125 | void id(const std::string& id); |
| 124 | 126 | void statistic(const std::string& statistic); |
| 125 | 127 | const std::string& name(void) const; |
| 126 | 128 | const std::string& id(void) const; |
| 127 | 129 | const std::string& statistic(void) const; |
| 130 | + void computed_gradient(const GModelPar& par) const; | |
| 128 | 131 | |
| 129 | 132 | protected: |
| 130 | 133 | // Protected methods |
| ... | ... | @@ -217,6 +220,9 @@ protected: |
| 217 | 220 | std::string m_id; //!< Observation identifier |
| 218 | 221 | std::string m_statistic; //!< Optimizer statistic |
| 219 | 222 | GEvents* m_events; //!< Pointer to event container |
| 223 | + | |
| 224 | + // Stack of pointers to spatial parameters with gradients | |
| 225 | + mutable std::vector<GModelPar*> m_spat_pars_with_gradients; | |
| 220 | 226 | }; |
| 221 | 227 | |
| 222 | 228 | ... | ... |
pyext/GModel.i
| ... | ... | @@ -53,6 +53,8 @@ public: |
| 53 | 53 | virtual double eval(const GEvent& event, |
| 54 | 54 | const GObservation& obs, |
| 55 | 55 | const bool& gradients = false) const = 0; |
| 56 | + virtual GVector eval(const GObservation& obs, | |
| 57 | + GMatrixSparse* gradients = NULL) const = 0; | |
| 56 | 58 | virtual double npred(const GEnergy& obsEng, const GTime& obsTime, |
| 57 | 59 | const GObservation& obs) const = 0; |
| 58 | 60 | virtual void read(const GXmlElement& xml) = 0; | ... | ... |
pyext/GModelData.i
| 1 | 1 | /*************************************************************************** |
| 2 | 2 | * GModelData.i - Abstract virtual data model class * |
| 3 | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2011-2016 by Juergen Knoedlseder * | |
| 4 | + * copyright (C) 2011-2020 by Juergen Knoedlseder * | |
| 5 | 5 | * ----------------------------------------------------------------------- * |
| 6 | 6 | * * |
| 7 | 7 | * This program is free software: you can redistribute it and/or modify * |
| ... | ... | @@ -57,6 +57,10 @@ public: |
| 57 | 57 | virtual GEvents* mc(const GObservation& obs, GRan& ran) const = 0; |
| 58 | 58 | virtual void read(const GXmlElement& xml) = 0; |
| 59 | 59 | virtual void write(GXmlElement& xml) const = 0; |
| 60 | + | |
| 61 | + // Implemented pure virtual base class methods | |
| 62 | + virtual GVector eval(const GObservation& obs, | |
| 63 | + GMatrixSparse* gradients = NULL) const; | |
| 60 | 64 | }; |
| 61 | 65 | |
| 62 | 66 | ... | ... |
pyext/GModelSky.i
| 1 | 1 | /*************************************************************************** |
| 2 | 2 | * GModelSky.i - Sky model class * |
| 3 | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2011-2018 by Juergen Knoedlseder * | |
| 4 | + * copyright (C) 2011-2020 by Juergen Knoedlseder * | |
| 5 | 5 | * ----------------------------------------------------------------------- * |
| 6 | 6 | * * |
| 7 | 7 | * This program is free software: you can redistribute it and/or modify * |
| ... | ... | @@ -63,6 +63,8 @@ public: |
| 63 | 63 | virtual double eval(const GEvent& event, |
| 64 | 64 | const GObservation& obs, |
| 65 | 65 | const bool& gradients = false) const; |
| 66 | + virtual GVector eval(const GObservation& obs, | |
| 67 | + GMatrixSparse* gradients = NULL) const; | |
| 66 | 68 | virtual double npred(const GEnergy& obsEng, |
| 67 | 69 | const GTime& obsTime, |
| 68 | 70 | const GObservation& obs) const; | ... | ... |
pyext/GObservation.i
| 1 | 1 | /*************************************************************************** |
| 2 | 2 | * GObservation.i - 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 | 7 | * This program is free software: you can redistribute it and/or modify * |
| ... | ... | @@ -94,12 +94,14 @@ public: |
| 94 | 94 | |
| 95 | 95 | // Implemented methods |
| 96 | 96 | bool has_events(void) const; |
| 97 | + bool has_gradient(const GModelPar& par) const; | |
| 97 | 98 | void name(const std::string& name); |
| 98 | 99 | void id(const std::string& id); |
| 99 | 100 | void statistic(const std::string& statistic); |
| 100 | 101 | const std::string& name(void) const; |
| 101 | 102 | const std::string& id(void) const; |
| 102 | 103 | const std::string& statistic(void) const; |
| 104 | + void computed_gradient(const GModelPar& par) const; | |
| 103 | 105 | }; |
| 104 | 106 | |
| 105 | 107 | ... | ... |
src/model/GModel.cpp
| ... | ... | @@ -31,13 +31,9 @@ |
| 31 | 31 | #include "GTools.hpp" |
| 32 | 32 | #include "GException.hpp" |
| 33 | 33 | #include "GModel.hpp" |
| 34 | -#include "GVector.hpp" | |
| 35 | -#include "GMatrixSparse.hpp" | |
| 36 | -#include "GObservation.hpp" | |
| 37 | 34 | |
| 38 | 35 | /* __ Method name definitions ____________________________________________ */ |
| 39 | 36 | #define G_ACCESS "GModel::operator[](std::string&)" |
| 40 | -#define G_EVAL "GModel::eval(GObservation&, GMatrixSparse*)" | |
| 41 | 37 | #define G_AT "GModel::at(int&)" |
| 42 | 38 | #define G_SCALE "GModelPar& GModel::scale(int&)" |
| 43 | 39 | #define G_WRITE_SCALES "GModel::write_scales(GXmlElement&)" |
| ... | ... | @@ -225,106 +221,6 @@ const GModelPar& GModel::operator[](const std::string& name) const |
| 225 | 221 | ==========================================================================*/ |
| 226 | 222 | |
| 227 | 223 | /***********************************************************************//** |
| 228 | - * @brief Return model values and gradients | |
| 229 | - * | |
| 230 | - * @param[in] obs Observation. | |
| 231 | - * @param[out] gradients Pointer to matrix of gradients. | |
| 232 | - * @return Model values. | |
| 233 | - * | |
| 234 | - * Evaluates the model values and parameter gradients for all events in an | |
| 235 | - * observation. Gradients are only returned if the @p gradients pointer is | |
| 236 | - * not NULL. | |
| 237 | - * | |
| 238 | - * The matrix of gradients is a sparse matrix where the number of rows | |
| 239 | - * corresponds to the number of model parameters and the number of columns | |
| 240 | - * corresponds to the number of events. An exception is thrown if the | |
| 241 | - * dimension of the @p gradients matrix is not compatible with the model | |
| 242 | - * and the observations. | |
| 243 | - ***************************************************************************/ | |
| 244 | -GVector GModel::eval(const GObservation& obs, | |
| 245 | - GMatrixSparse* gradients) const | |
| 246 | -{ | |
| 247 | - // Get number of model parameters and number of events | |
| 248 | - int npars = size(); | |
| 249 | - int nevents = obs.events()->size(); | |
| 250 | - | |
| 251 | - // Initialise gradients flag | |
| 252 | - bool grad = (gradients != NULL); | |
| 253 | - | |
| 254 | - // Check matrix consistency | |
| 255 | - if (grad) { | |
| 256 | - if (gradients->columns() != npars) { | |
| 257 | - std::string msg = "Number of "+gammalib::str(gradients->columns())+ | |
| 258 | - " columns in gradient matrix differs from number " | |
| 259 | - "of "+gammalib::str(npars)+" parameters " | |
| 260 | - "in model. Please provide a compatible gradient " | |
| 261 | - "matrix."; | |
| 262 | - throw GException::invalid_argument(G_EVAL, msg); | |
| 263 | - } | |
| 264 | - if (gradients->rows() != nevents) { | |
| 265 | - std::string msg = "Number of "+gammalib::str(gradients->rows())+ | |
| 266 | - " rows in gradient matrix differs from number " | |
| 267 | - "of "+gammalib::str(nevents)+" events in " | |
| 268 | - "observation. Please provide a compatible " | |
| 269 | - "gradient matrix."; | |
| 270 | - throw GException::invalid_argument(G_EVAL, msg); | |
| 271 | - } | |
| 272 | - } | |
| 273 | - | |
| 274 | - // Initialise values | |
| 275 | - GVector values(nevents); | |
| 276 | - | |
| 277 | - // Initialise temporary vectors to hold gradients | |
| 278 | - GVector* tmp_gradients = new GVector[npars]; | |
| 279 | - for (int i = 0; i < npars; ++i) { | |
| 280 | - tmp_gradients[i] = GVector(nevents); | |
| 281 | - } | |
| 282 | - | |
| 283 | - // Loop over events | |
| 284 | - for (int k = 0; k < nevents; ++k) { | |
| 285 | - | |
| 286 | - // Get reference to event | |
| 287 | - const GEvent& event = *((*obs.events())[k]); | |
| 288 | - | |
| 289 | - // Evaluate probability | |
| 290 | - values[k] = eval(event, obs, grad); | |
| 291 | - | |
| 292 | - // Set gradients | |
| 293 | - if (grad) { | |
| 294 | - | |
| 295 | - // Initialise gradient vector | |
| 296 | - //GVector gradient(npars); | |
| 297 | - | |
| 298 | - // Extract relevant parameter gradients | |
| 299 | - for (int i = 0; i < npars; ++i) { | |
| 300 | - const GModelPar& par = (*this)[i]; | |
| 301 | - if (par.is_free() && par.has_grad()) { | |
| 302 | - //gradient[i] = par.factor_gradient(); | |
| 303 | - tmp_gradients[i][k] = par.factor_gradient(); | |
| 304 | - } | |
| 305 | - } | |
| 306 | - | |
| 307 | - // Insert gradient vector into matrix | |
| 308 | - //gradients->add_to_column(k, gradient); | |
| 309 | - | |
| 310 | - } // endif: looped over gradients | |
| 311 | - | |
| 312 | - } // endfor: looped over events | |
| 313 | - | |
| 314 | - // Fill gradients into matrix | |
| 315 | - for (int i = 0; i < npars; ++i) { | |
| 316 | - gradients->column(i, tmp_gradients[i]); | |
| 317 | - } | |
| 318 | - | |
| 319 | - // Delete temporal gradients | |
| 320 | - delete [] tmp_gradients; | |
| 321 | - | |
| 322 | - // Return values | |
| 323 | - return values; | |
| 324 | -} | |
| 325 | - | |
| 326 | - | |
| 327 | -/***********************************************************************//** | |
| 328 | 224 | * @brief Returns reference to model parameter by index |
| 329 | 225 | * |
| 330 | 226 | * @param[in] index Parameter index [0,...,size()-1]. | ... | ... |
src/model/GModelData.cpp
| 1 | 1 | /*************************************************************************** |
| 2 | - * GModelData.cpp - Abstract virtual data model class * | |
| 2 | + * GModelData.cpp - Abstract virtual data model class * | |
| 3 | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2011 by Jurgen Knodlseder * | |
| 4 | + * copyright (C) 2011-2020 by Juergen Knoedlseder * | |
| 5 | 5 | * ----------------------------------------------------------------------- * |
| 6 | 6 | * * |
| 7 | 7 | * This program is free software: you can redistribute it and/or modify * |
| ... | ... | @@ -21,7 +21,7 @@ |
| 21 | 21 | /** |
| 22 | 22 | * @file GModelData.cpp |
| 23 | 23 | * @brief GModelData class implementation. |
| 24 | - * @author J. Knodlseder | |
| 24 | + * @author Juergen Knoedlseder | |
| 25 | 25 | */ |
| 26 | 26 | |
| 27 | 27 | /* __ Includes ___________________________________________________________ */ |
| ... | ... | @@ -31,8 +31,12 @@ |
| 31 | 31 | #include "GTools.hpp" |
| 32 | 32 | #include "GException.hpp" |
| 33 | 33 | #include "GModelData.hpp" |
| 34 | +#include "GVector.hpp" | |
| 35 | +#include "GMatrixSparse.hpp" | |
| 36 | +#include "GObservation.hpp" | |
| 34 | 37 | |
| 35 | 38 | /* __ Method name definitions ____________________________________________ */ |
| 39 | +#define G_EVAL "GModel::eval(GObservation&, GMatrixSparse*)" | |
| 36 | 40 | |
| 37 | 41 | /* __ Macros _____________________________________________________________ */ |
| 38 | 42 | |
| ... | ... | @@ -116,8 +120,9 @@ GModelData::~GModelData(void) |
| 116 | 120 | * @brief Assignment operator |
| 117 | 121 | * |
| 118 | 122 | * @param[in] model Data model. |
| 123 | + * @return Data model. | |
| 119 | 124 | ***************************************************************************/ |
| 120 | -GModelData& GModelData::operator= (const GModelData& model) | |
| 125 | +GModelData& GModelData::operator=(const GModelData& model) | |
| 121 | 126 | { |
| 122 | 127 | // Execute only if object is not identical |
| 123 | 128 | if (this != &model) { |
| ... | ... | @@ -147,6 +152,120 @@ GModelData& GModelData::operator= (const GModelData& model) |
| 147 | 152 | = = |
| 148 | 153 | ==========================================================================*/ |
| 149 | 154 | |
| 155 | +/***********************************************************************//** | |
| 156 | + * @brief Return model values and gradients | |
| 157 | + * | |
| 158 | + * @param[in] obs Observation. | |
| 159 | + * @param[out] gradients Pointer to matrix of gradients. | |
| 160 | + * @return Model values. | |
| 161 | + * | |
| 162 | + * Evaluates the model values and parameter gradients for all events in an | |
| 163 | + * observation. Gradients are only returned if the @p gradients pointer is | |
| 164 | + * not NULL. | |
| 165 | + * | |
| 166 | + * The matrix of gradients is a sparse matrix where the number of rows | |
| 167 | + * corresponds to the number of model parameters and the number of columns | |
| 168 | + * corresponds to the number of events. An exception is thrown if the | |
| 169 | + * dimension of the @p gradients matrix is not compatible with the model | |
| 170 | + * and the observations. | |
| 171 | + ***************************************************************************/ | |
| 172 | +GVector GModelData::eval(const GObservation& obs, | |
| 173 | + GMatrixSparse* gradients) const | |
| 174 | +{ | |
| 175 | + // Get number of model parameters and number of events | |
| 176 | + int npars = size(); | |
| 177 | + int nevents = obs.events()->size(); | |
| 178 | + | |
| 179 | + // Initialise gradients flag | |
| 180 | + bool grad = ((gradients != NULL) && (npars > 0)); | |
| 181 | + | |
| 182 | + // Check matrix consistency | |
| 183 | + if (grad) { | |
| 184 | + if (gradients->columns() != npars) { | |
| 185 | + std::string msg = "Number of "+gammalib::str(gradients->columns())+ | |
| 186 | + " columns in gradient matrix differs from number " | |
| 187 | + "of "+gammalib::str(npars)+" parameters " | |
| 188 | + "in model. Please provide a compatible gradient " | |
| 189 | + "matrix."; | |
| 190 | + throw GException::invalid_argument(G_EVAL, msg); | |
| 191 | + } | |
| 192 | + if (gradients->rows() != nevents) { | |
| 193 | + std::string msg = "Number of "+gammalib::str(gradients->rows())+ | |
| 194 | + " rows in gradient matrix differs from number " | |
| 195 | + "of "+gammalib::str(nevents)+" events in " | |
| 196 | + "observation. Please provide a compatible " | |
| 197 | + "gradient matrix."; | |
| 198 | + throw GException::invalid_argument(G_EVAL, msg); | |
| 199 | + } | |
| 200 | + } | |
| 201 | + | |
| 202 | + // Initialise values | |
| 203 | + GVector values(nevents); | |
| 204 | + | |
| 205 | + // Initialise temporary vectors to hold gradients | |
| 206 | + GVector* tmp_gradients = NULL; | |
| 207 | + if (grad) { | |
| 208 | + | |
| 209 | + // Allocate temporary vectors to hold the gradients | |
| 210 | + tmp_gradients = new GVector[npars]; | |
| 211 | + for (int i = 0; i < npars; ++i) { | |
| 212 | + tmp_gradients[i] = GVector(nevents); | |
| 213 | + } | |
| 214 | + | |
| 215 | + // Signal all parameters that will have analytical gradients. These | |
| 216 | + // are all parameters that are free and for which the model provides | |
| 217 | + // analytical gradients. | |
| 218 | + for (int i = 0; i < npars; ++i) { | |
| 219 | + const GModelPar& par = (*this)[i]; | |
| 220 | + if (par.is_free() && par.has_grad()) { | |
| 221 | + obs.computed_gradient(par); | |
| 222 | + } | |
| 223 | + } | |
| 224 | + | |
| 225 | + } // endif: gradients were requested | |
| 226 | + | |
| 227 | + // Loop over events | |
| 228 | + for (int k = 0; k < nevents; ++k) { | |
| 229 | + | |
| 230 | + // Get reference to event | |
| 231 | + const GEvent& event = *((*obs.events())[k]); | |
| 232 | + | |
| 233 | + // Evaluate probability | |
| 234 | + values[k] = eval(event, obs, grad); | |
| 235 | + | |
| 236 | + // Set gradients | |
| 237 | + if (grad) { | |
| 238 | + | |
| 239 | + // Extract relevant parameter gradients | |
| 240 | + for (int i = 0; i < npars; ++i) { | |
| 241 | + const GModelPar& par = (*this)[i]; | |
| 242 | + if (par.is_free() && par.has_grad()) { | |
| 243 | + tmp_gradients[i][k] = par.factor_gradient(); | |
| 244 | + } | |
| 245 | + } | |
| 246 | + | |
| 247 | + } // endif: looped over gradients | |
| 248 | + | |
| 249 | + } // endfor: looped over events | |
| 250 | + | |
| 251 | + // Post-process gradients | |
| 252 | + if (grad) { | |
| 253 | + | |
| 254 | + // Fill gradients into matrix | |
| 255 | + for (int i = 0; i < npars; ++i) { | |
| 256 | + gradients->column(i, tmp_gradients[i]); | |
| 257 | + } | |
| 258 | + | |
| 259 | + // Delete temporal gradients | |
| 260 | + delete [] tmp_gradients; | |
| 261 | + | |
| 262 | + } // endif: post-processed gradients | |
| 263 | + | |
| 264 | + // Return values | |
| 265 | + return values; | |
| 266 | +} | |
| 267 | + | |
| 268 | + | |
| 150 | 269 | /*========================================================================== |
| 151 | 270 | = = |
| 152 | 271 | = Private methods = |
| ... | ... | @@ -183,10 +302,3 @@ void GModelData::free_members(void) |
| 183 | 302 | // Return |
| 184 | 303 | return; |
| 185 | 304 | } |
| 186 | - | |
| 187 | - | |
| 188 | -/*========================================================================== | |
| 189 | - = = | |
| 190 | - = Friends = | |
| 191 | - = = | |
| 192 | - ==========================================================================*/ | ... | ... |
src/model/GModelSky.cpp
| ... | ... | @@ -568,6 +568,12 @@ double GModelSky::eval(const GEvent& event, |
| 568 | 568 | // Evaluate model |
| 569 | 569 | double value = obs.response()->convolve(*this, event, obs, gradients); |
| 570 | 570 | |
| 571 | + // If gradients were requested then signal all computed analytical | |
| 572 | + // gradients | |
| 573 | + if (gradients) { | |
| 574 | + signal_analytical_gradients(obs); | |
| 575 | + } | |
| 576 | + | |
| 571 | 577 | // Return |
| 572 | 578 | return value; |
| 573 | 579 | } |
| ... | ... | @@ -592,6 +598,12 @@ GVector GModelSky::eval(const GObservation& obs, |
| 592 | 598 | // Evaluate model |
| 593 | 599 | GVector values = obs.response()->convolve(*this, obs, gradients); |
| 594 | 600 | |
| 601 | + // If gradients were requested then signal all computed analytical | |
| 602 | + // gradients | |
| 603 | + if (gradients) { | |
| 604 | + signal_analytical_gradients(obs); | |
| 605 | + } | |
| 606 | + | |
| 595 | 607 | // Return |
| 596 | 608 | return values; |
| 597 | 609 | } |
| ... | ... | @@ -1276,6 +1288,63 @@ void GModelSky::set_type(void) |
| 1276 | 1288 | |
| 1277 | 1289 | |
| 1278 | 1290 | /***********************************************************************//** |
| 1291 | + * @brief Signal all parameters that have analytical gradients for a given | |
| 1292 | + * observation | |
| 1293 | + * | |
| 1294 | + * @param[in] obs Observation. | |
| 1295 | + * | |
| 1296 | + * This method signals all spectral, temporal and model scaling parameters | |
| 1297 | + * for which analytical gradients exist for a given observation. Analytical | |
| 1298 | + * gradients will be signalled for all of these parameters that are free | |
| 1299 | + * and for which `has_grad()` is `true`. | |
| 1300 | + * | |
| 1301 | + * Note that spatial analytical gradients are excluded. These will be | |
| 1302 | + * signalled by the underlying convolution method as analytical gradients | |
| 1303 | + * are not (yet) supported by all convolution methods. | |
| 1304 | + ***************************************************************************/ | |
| 1305 | +void GModelSky::signal_analytical_gradients(const GObservation& obs) const | |
| 1306 | +{ | |
| 1307 | + // If the model has a spectral component then signal all free parameters | |
| 1308 | + // with analytical gradients | |
| 1309 | + if (spectral() != NULL) { | |
| 1310 | + for (int i = 0; i < spectral()->size(); ++i) { | |
| 1311 | + GModelPar& par = (*(spectral()))[i]; | |
| 1312 | + if (par.is_free() && par.has_grad()) { | |
| 1313 | + obs.computed_gradient(par); | |
| 1314 | + } | |
| 1315 | + } | |
| 1316 | + } | |
| 1317 | + | |
| 1318 | + // If the model has a temporal component then signal all free parameters | |
| 1319 | + // with analytical gradients | |
| 1320 | + if (temporal() != NULL) { | |
| 1321 | + for (int i = 0; i < temporal()->size(); ++i) { | |
| 1322 | + GModelPar& par = (*(temporal()))[i]; | |
| 1323 | + if (par.is_free() && par.has_grad()) { | |
| 1324 | + obs.computed_gradient(par); | |
| 1325 | + } | |
| 1326 | + } | |
| 1327 | + } | |
| 1328 | + | |
| 1329 | + // If the model has a scales then signal all free parameters with | |
| 1330 | + // analytical gradients | |
| 1331 | + if (has_scales()) { | |
| 1332 | + for (int i = 0; i < scales(); ++i) { | |
| 1333 | + const GModelPar& par = scale(i); | |
| 1334 | + if (par.name() == obs.instrument()) { | |
| 1335 | + if (par.is_free() && par.has_grad()) { | |
| 1336 | + obs.computed_gradient(par); | |
| 1337 | + } | |
| 1338 | + } | |
| 1339 | + } | |
| 1340 | + } | |
| 1341 | + | |
| 1342 | + // Return | |
| 1343 | + return; | |
| 1344 | +} | |
| 1345 | + | |
| 1346 | + | |
| 1347 | +/***********************************************************************//** | |
| 1279 | 1348 | * @brief Return pointer to spatial model from XML element |
| 1280 | 1349 | * |
| 1281 | 1350 | * @param[in] spatial XML element. | ... | ... |
src/obs/GObservation.cpp
| ... | ... | @@ -161,6 +161,72 @@ GObservation& GObservation::operator=(const GObservation& obs) |
| 161 | 161 | ==========================================================================*/ |
| 162 | 162 | |
| 163 | 163 | /***********************************************************************//** |
| 164 | + * @brief Return events | |
| 165 | + * | |
| 166 | + * @exception GException::no_events | |
| 167 | + * No events allocated for observation. | |
| 168 | + * | |
| 169 | + * Returns pointer to events. | |
| 170 | + ***************************************************************************/ | |
| 171 | +GEvents* GObservation::events(void) | |
| 172 | +{ | |
| 173 | + // Throw an exception if the event container is not valid | |
| 174 | + if (m_events == NULL) { | |
| 175 | + std::string msg = "No events allocated for observation."; | |
| 176 | + throw GException::invalid_value(G_EVENTS, msg); | |
| 177 | + } | |
| 178 | + | |
| 179 | + // Return pointer to events | |
| 180 | + return (m_events); | |
| 181 | +} | |
| 182 | + | |
| 183 | + | |
| 184 | +/***********************************************************************//** | |
| 185 | + * @brief Return events (const version) | |
| 186 | + * | |
| 187 | + * @exception GException::no_events | |
| 188 | + * No events allocated for observation. | |
| 189 | + * | |
| 190 | + * Returns const pointer to events. | |
| 191 | + ***************************************************************************/ | |
| 192 | +const GEvents* GObservation::events(void) const | |
| 193 | +{ | |
| 194 | + // Throw an exception if the event container is not valid | |
| 195 | + if (m_events == NULL) { | |
| 196 | + std::string msg = "No events allocated for observation."; | |
| 197 | + throw GException::invalid_value(G_EVENTS, msg); | |
| 198 | + } | |
| 199 | + | |
| 200 | + // Return pointer to events | |
| 201 | + return (m_events); | |
| 202 | +} | |
| 203 | + | |
| 204 | + | |
| 205 | +/***********************************************************************//** | |
| 206 | + * @brief Set event container | |
| 207 | + * | |
| 208 | + * @param[in] events Event container. | |
| 209 | + * | |
| 210 | + * Set the event container for this observation by cloning the container | |
| 211 | + * specified in the argument. | |
| 212 | + ***************************************************************************/ | |
| 213 | +void GObservation::events(const GEvents& events) | |
| 214 | +{ | |
| 215 | + // Free existing event container only if it differs from current event | |
| 216 | + // container. This prevents unintential deallocation of the argument | |
| 217 | + if ((m_events != NULL) && (m_events != &events)) { | |
| 218 | + delete m_events; | |
| 219 | + } | |
| 220 | + | |
| 221 | + // Clone events | |
| 222 | + m_events = events.clone(); | |
| 223 | + | |
| 224 | + // Return | |
| 225 | + return; | |
| 226 | +} | |
| 227 | + | |
| 228 | + | |
| 229 | +/***********************************************************************//** | |
| 164 | 230 | * @brief Compute likelihood function |
| 165 | 231 | * |
| 166 | 232 | * @param[in] models Models. |
| ... | ... | @@ -330,7 +396,7 @@ double GObservation::model(const GModels& models, |
| 330 | 396 | |
| 331 | 397 | // Set gradient |
| 332 | 398 | if (par.is_free()) { |
| 333 | - if (par.has_grad()) { | |
| 399 | + if (has_gradient(par)) { | |
| 334 | 400 | (*gradient)[igrad+ipar] = par.factor_gradient(); |
| 335 | 401 | } |
| 336 | 402 | else { |
| ... | ... | @@ -356,7 +422,7 @@ double GObservation::model(const GModels& models, |
| 356 | 422 | |
| 357 | 423 | // Set gradient |
| 358 | 424 | if (par.is_free()) { |
| 359 | - if (par.has_grad()) { | |
| 425 | + if (has_gradient(par)) { | |
| 360 | 426 | (*gradient)[igrad+ipar] = par.factor_gradient(); |
| 361 | 427 | } |
| 362 | 428 | else { |
| ... | ... | @@ -463,11 +529,9 @@ GVector GObservation::model(const GModels& models, |
| 463 | 529 | else { |
| 464 | 530 | |
| 465 | 531 | // Allocate gradient matrix |
| 466 | - //GMatrixSparse gradients(mptr->size(), nevents); | |
| 467 | 532 | GMatrixSparse gradients(nevents, mptr->size()); |
| 468 | 533 | |
| 469 | 534 | // Initialise sparse matrix stack |
| 470 | - //gradients.stack_init(mptr->size()*1000, 1000); | |
| 471 | 535 | gradients.stack_init(nevents*mptr->size(), mptr->size()); |
| 472 | 536 | |
| 473 | 537 | // Evaluate model and add to values |
| ... | ... | @@ -495,14 +559,11 @@ GVector GObservation::model(const GModels& models, |
| 495 | 559 | |
| 496 | 560 | // Determine gradient |
| 497 | 561 | GVector grad(nevents); |
| 498 | - if (par.is_free()) { | |
| 499 | - if (par.has_grad()) { | |
| 500 | - //grad = gradients.row(ipar); | |
| 501 | - grad = gradients.column(ipar); | |
| 502 | - } | |
| 503 | - else { | |
| 504 | - grad = model_grad(*mptr, par); | |
| 505 | - } | |
| 562 | + if (has_gradient(par)) { | |
| 563 | + grad = gradients.column(ipar); | |
| 564 | + } | |
| 565 | + else { | |
| 566 | + grad = model_grad(*mptr, par); | |
| 506 | 567 | } |
| 507 | 568 | |
| 508 | 569 | // Set gradient |
| ... | ... | @@ -523,10 +584,8 @@ GVector GObservation::model(const GModels& models, |
| 523 | 584 | |
| 524 | 585 | // Determine gradient |
| 525 | 586 | GVector grad(nevents); |
| 526 | - if (par.is_free()) { | |
| 527 | - if (par.has_grad()) { | |
| 528 | - //grad = gradients.row(ipar); | |
| 529 | - grad = gradients.column(ipar); | |
| 587 | + if (has_gradient(par)) { | |
| 588 | + grad = gradients.column(ipar); | |
| 530 | 589 | // Debugging |
| 531 | 590 | /* |
| 532 | 591 | if (ipar < 3) { |
| ... | ... | @@ -542,10 +601,9 @@ if (ipar < 3) { |
| 542 | 601 | } |
| 543 | 602 | } |
| 544 | 603 | */ |
| 545 | - } | |
| 546 | - else { | |
| 547 | - grad = model_grad(*mptr, par); | |
| 548 | - } | |
| 604 | + } | |
| 605 | + else { | |
| 606 | + grad = model_grad(*mptr, par); | |
| 549 | 607 | } |
| 550 | 608 | |
| 551 | 609 | // Set gradient |
| ... | ... | @@ -1110,68 +1168,65 @@ void GObservation::remove_response_cache(const std::string& name) |
| 1110 | 1168 | |
| 1111 | 1169 | |
| 1112 | 1170 | /***********************************************************************//** |
| 1113 | - * @brief Set event container | |
| 1171 | + * @brief Check whether a model parameter has an analytical gradient | |
| 1114 | 1172 | * |
| 1115 | - * @param[in] events Event container. | |
| 1173 | + * @param[in] par Model parameter. | |
| 1174 | + * @returns True if model parameter is free and has an analytical gradient. | |
| 1116 | 1175 | * |
| 1117 | - * Set the event container for this observation by cloning the container | |
| 1118 | - * specified in the argument. | |
| 1176 | + * Checks whether a model parameter is free and has an analytical gradient. | |
| 1119 | 1177 | ***************************************************************************/ |
| 1120 | -void GObservation::events(const GEvents& events) | |
| 1178 | +bool GObservation::has_gradient(const GModelPar& par) const | |
| 1121 | 1179 | { |
| 1122 | - // Free existing event container only if it differs from current event | |
| 1123 | - // container. This prevents unintential deallocation of the argument | |
| 1124 | - if ((m_events != NULL) && (m_events != &events)) { | |
| 1125 | - delete m_events; | |
| 1126 | - } | |
| 1180 | + // Initialise flag | |
| 1181 | + bool has_gradient = false; | |
| 1182 | + | |
| 1183 | + // Only consider free parameters | |
| 1184 | + if (par.is_free()) { | |
| 1127 | 1185 | |
| 1128 | - // Clone events | |
| 1129 | - m_events = events.clone(); | |
| 1186 | + // Search for parameter address in stack and set flag to true if | |
| 1187 | + // parameter address was found | |
| 1188 | + for (int i = 0; i < m_spat_pars_with_gradients.size(); ++i) { | |
| 1189 | + if (m_spat_pars_with_gradients[i] == &par) { | |
| 1190 | + has_gradient = true; | |
| 1191 | + break; | |
| 1192 | + } | |
| 1193 | + } | |
| 1130 | 1194 | |
| 1131 | - // Return | |
| 1132 | - return; | |
| 1195 | + } // endif: parameter was free | |
| 1196 | + | |
| 1197 | + // Return flag | |
| 1198 | + return has_gradient; | |
| 1133 | 1199 | } |
| 1134 | 1200 | |
| 1135 | 1201 | |
| 1136 | 1202 | /***********************************************************************//** |
| 1137 | - * @brief Return events | |
| 1203 | + * @brief Signals that an analytical gradient was computed for a model | |
| 1204 | + * parameter | |
| 1138 | 1205 | * |
| 1139 | - * @exception GException::no_events | |
| 1140 | - * No events allocated for observation. | |
| 1206 | + * @param[in] par Model parameter. | |
| 1141 | 1207 | * |
| 1142 | - * Returns pointer to events. | |
| 1208 | + * Signals that an analytical gradient was computed for a model parameter. | |
| 1143 | 1209 | ***************************************************************************/ |
| 1144 | -GEvents* GObservation::events(void) | |
| 1210 | +void GObservation::computed_gradient(const GModelPar& par) const | |
| 1145 | 1211 | { |
| 1146 | - // Throw an exception if the event container is not valid | |
| 1147 | - if (m_events == NULL) { | |
| 1148 | - std::string msg = "No events allocated for observation."; | |
| 1149 | - throw GException::invalid_value(G_EVENTS, msg); | |
| 1212 | + // Initialise flag | |
| 1213 | + bool in_stack = false; | |
| 1214 | + | |
| 1215 | + // Check if parameter is already in stack | |
| 1216 | + for (int i = 0; i < m_spat_pars_with_gradients.size(); ++i) { | |
| 1217 | + if (m_spat_pars_with_gradients[i] == &par) { | |
| 1218 | + in_stack = true; | |
| 1219 | + break; | |
| 1220 | + } | |
| 1150 | 1221 | } |
| 1151 | 1222 | |
| 1152 | - // Return pointer to events | |
| 1153 | - return (m_events); | |
| 1154 | -} | |
| 1155 | - | |
| 1156 | - | |
| 1157 | -/***********************************************************************//** | |
| 1158 | - * @brief Return events (const version) | |
| 1159 | - * | |
| 1160 | - * @exception GException::no_events | |
| 1161 | - * No events allocated for observation. | |
| 1162 | - * | |
| 1163 | - * Returns const pointer to events. | |
| 1164 | - ***************************************************************************/ | |
| 1165 | -const GEvents* GObservation::events(void) const | |
| 1166 | -{ | |
| 1167 | - // Throw an exception if the event container is not valid | |
| 1168 | - if (m_events == NULL) { | |
| 1169 | - std::string msg = "No events allocated for observation."; | |
| 1170 | - throw GException::invalid_value(G_EVENTS, msg); | |
| 1223 | + // If parameter is not yet in stack the push it on the stack | |
| 1224 | + if (!in_stack) { | |
| 1225 | + m_spat_pars_with_gradients.push_back(const_cast<GModelPar*>(&par)); | |
| 1171 | 1226 | } |
| 1172 | 1227 | |
| 1173 | - // Return pointer to events | |
| 1174 | - return (m_events); | |
| 1228 | + // Return | |
| 1229 | + return; | |
| 1175 | 1230 | } |
| 1176 | 1231 | |
| 1177 | 1232 | |
| ... | ... | @@ -1192,6 +1247,9 @@ void GObservation::init_members(void) |
| 1192 | 1247 | m_statistic = "cstat"; |
| 1193 | 1248 | m_events = NULL; |
| 1194 | 1249 | |
| 1250 | + // Initialise stack of pointers to spatial parameters with gradients | |
| 1251 | + m_spat_pars_with_gradients.clear(); | |
| 1252 | + | |
| 1195 | 1253 | // Return |
| 1196 | 1254 | return; |
| 1197 | 1255 | } |
| ... | ... | @@ -1211,6 +1269,9 @@ void GObservation::copy_members(const GObservation& obs) |
| 1211 | 1269 | m_id = obs.m_id; |
| 1212 | 1270 | m_statistic = obs.m_statistic; |
| 1213 | 1271 | |
| 1272 | + // Copy stack of pointers to spatial parameters with gradients | |
| 1273 | + m_spat_pars_with_gradients = obs.m_spat_pars_with_gradients; | |
| 1274 | + | |
| 1214 | 1275 | // Clone members |
| 1215 | 1276 | m_events = (obs.m_events != NULL) ? obs.m_events->clone() : NULL; |
| 1216 | 1277 | ... | ... |