Commit ed1c51d0bdf9d2cfc1975d047740d02579c037fe

Authored by Jürgen Knödlseder
1 parent 15c02402

Preliminary implementation of new model parameter interface.

A new model parameter interface has been implemented that puts the internal workings of the class more in the background. For example, the real_xxx() methods have been replaced by Xxx() methods, and the xxx() methods became factor_xxx(). For example, real_value() becomes Value() and value() becomes factor_value(). For the moment, upper case letters are used so that no mix with the former xxx() methods occur. This is for validating the change, and will be modified in a future commit.
include/GModelPar.hpp
... ... @@ -38,70 +38,116 @@
38 38 *
39 39 * @brief Model parameter class
40 40 *
41   - * This method implements a model parameter. The model parameter is
42   - * factorised into a "value" and a "scale" factor, the real parameter value
43   - * being the product of both. Parameter optimization is only done on the
44   - * "value" part of the parameter. This allows scaling of the parameter to
45   - * have a "value" around unity (which makes the optimizer routines better
46   - * behave). Methods that work on the real value (i.e. the product of
47   - * "value" and "scale") are prefixed with "real_".
  41 + * This class implements a model parameter. A model parameter is a numerical
  42 + * value that is used to describe a model. A model parameter has the
  43 + * following attributes:
  44 + * - @p value gives the numerical value of the parameter
  45 + * - @p error gives the statistical uncertainty in the parameter value
  46 + * - @p gradient gives the gradient of a the model with respect to the
  47 + * parameter
  48 + * - @p min gives the minimum value that the parameter value can take
  49 + * - @p max gives the maximum value that the parameter value can take
48 50 *
49   - * The parameter "value" can optionally by bounded by a minimum and/or
50   - * maximum value. Note that the boundaries apply to "value".
  51 + * The parameter attributes are set and retrieved using the value(),
  52 + * error(), gradient(), min() and max() methods, respectively. Furthermore,
  53 + * the range() method is used to simultaneously set the minimum and maximum
  54 + * value of a parameter.
51 55 *
52   - * Each parameter has a name, and holds optionally information about its
53   - * gradient (if "hasgrad" is true).
  56 + * The minimum and maximum values are optional, and existence of these
  57 + * attributes is tested using the hasmin() and hasmax() methods,
  58 + * respectively. The minimum value, maximum value are removed using the
  59 + * remove_min() and remove_max() methods. Simultaneous removal of minimum
  60 + * and maximum values is done using the remove_range() method.
  61 + *
  62 + * Each parameter has furthermore the following properties:
  63 + * - @p free specifies whether the parameter should be fitted
  64 + * - @p grad specifies whether the parameter gradient is computed
  65 + * analytically (true) or numerically (false)
  66 + *
  67 + * The parameter property @p free is set using the free() and fix()
  68 + * methods and it is retrieved using the isfree() and isfixed() methods.
  69 + * The attribute @p grad is set and retrieved using the has hasgrad()
  70 + * methods.
  71 + *
  72 + * Each model parameter is factorized into a @p factor and a @p scale
  73 + * term. The GModelPar class stores the factors and the scale factor has
  74 + * data members, and the true values are computed using the following
  75 + * relations:
  76 + *
  77 + * value = m_factor_value * m_scale
  78 + * error = m_factor_error * m_scale
  79 + * gradient = m_factor_gradient * m_scale
  80 + * min = m_factor_min * m_scale
  81 + * max = m_factor_max * m_scale
  82 + *
  83 + * The @p factor and @p scale terms can be set and retrieved using the
  84 + * factor_value(), factor_error(), factor_gradient(), factor_min(),
  85 + * factor_max() and scale() methods.
54 86 ***************************************************************************/
55 87 class GModelPar : public GBase {
56 88  
57 89 public:
58 90 // Constructors and destructors
59 91 GModelPar(void);
60   - GModelPar(const std::string& name, const double& value,
61   - const double& scale = 1.0);
  92 + explicit GModelPar(const std::string& name, const double& value, int i);
  93 + explicit GModelPar(const std::string& name, const double& factor, const double& scale);
62 94 GModelPar(const GModelPar& par);
63 95 virtual ~GModelPar(void);
64 96  
65 97 // Operators
66 98 GModelPar& operator=(const GModelPar& par);
67 99  
68   - // Methods
69   - void clear(void);
70   - GModelPar* clone(void) const;
71   - std::string name(void) const { return m_name; }
72   - std::string unit(void) const { return m_unit; }
73   - double real_value(void) const { return m_value*m_scale; }
74   - double real_error(void) const { return m_error*m_scale; }
75   - double real_gradient(void) const { return m_gradient*m_scale; }
76   - double real_min(void) const { return m_min*m_scale; }
77   - double real_max(void) const { return m_max*m_scale; }
78   - double value(void) const { return m_value; }
79   - double error(void) const { return m_error; }
80   - double gradient(void) const { return m_gradient; }
81   - double min(void) const { return m_min; }
82   - double max(void) const { return m_max; }
83   - double scale(void) const { return m_scale; }
84   - bool isfree(void) const { return m_free; }
  100 + // Attribute methods
  101 + double Value(void) const;
  102 + double Error(void) const { return m_factor_error*m_scale; }
  103 + double Gradient(void) const { return m_factor_gradient*m_scale; }
  104 + double Min(void) const { return m_factor_min*m_scale; }
  105 + double Max(void) const { return m_factor_max*m_scale; }
  106 + void Value(const double& value);
  107 + void Error(const double& error);
  108 + void Gradient(const double& gradient);
  109 + void Min(const double& min);
  110 + void Max(const double& max);
  111 + void Range(const double& min, const double& max);
  112 +
  113 + // Factorization methods
  114 + const double& factor_value(void) const { return m_factor_value; }
  115 + const double& factor_error(void) const { return m_factor_error; }
  116 + const double& factor_gradient(void) const { return m_factor_gradient; }
  117 + const double& factor_min(void) const { return m_factor_min; }
  118 + const double& factor_max(void) const { return m_factor_max; }
  119 + const double& scale(void) const { return m_scale; }
  120 + void factor_value(const double& value);
  121 + void factor_error(const double& error) { m_factor_error=error; }
  122 + void factor_gradient(const double& gradient) { m_factor_gradient=gradient; }
  123 + void factor_min(const double& min);
  124 + void factor_max(const double& max);
  125 + void factor_range(const double& min, const double& max);
  126 + void Scale(const double& scale);
  127 +
  128 + // Boundary methods
85 129 bool hasmin(void) const { return m_hasmin; }
86 130 bool hasmax(void) const { return m_hasmax; }
87   - bool hasgrad(void) const { return m_hasgrad; }
88   - void name(const std::string& name) { m_name=name; }
89   - void unit(const std::string& unit) { m_unit=unit; }
90   - void real_value(const double& value);
91   - void real_error(const double& error);
92   - void value(const double& value);
93   - void error(const double& error) { m_error=error; }
94   - void gradient(const double& gradient) { m_gradient=gradient; }
95   - void min(const double& min);
96   - void max(const double& max);
97   - void scale(const double& scale) { m_scale=scale; }
98   - void range(const double& min, const double& max);
  131 + bool hasrange(void) const { return m_hasmin && m_hasmax; }
99 132 void remove_min(void) { m_hasmin=false; }
100 133 void remove_max(void) { m_hasmax=false; }
101 134 void remove_range(void) { m_hasmin=false; m_hasmax=false; }
  135 +
  136 + // Property methods
  137 + bool isfree(void) const { return m_free; }
  138 + bool isfixed(void) const { return !m_free; }
  139 + bool hasgrad(void) const { return m_hasgrad; }
102 140 void free(void) { m_free=true; }
103 141 void fix(void) { m_free=false; }
104 142 void hasgrad(const bool& grad) { m_hasgrad=grad; }
  143 +
  144 + // Other methods
  145 + void clear(void);
  146 + GModelPar* clone(void) const;
  147 + std::string name(void) const { return m_name; }
  148 + std::string unit(void) const { return m_unit; }
  149 + void name(const std::string& name) { m_name=name; }
  150 + void unit(const std::string& unit) { m_unit=unit; }
105 151 void autoscale(void);
106 152 void read(const GXmlElement& xml);
107 153 void write(GXmlElement& xml) const;
... ... @@ -114,18 +160,32 @@ protected:
114 160 void free_members(void);
115 161  
116 162 // Proteced data members
117   - std::string m_name; //!< Parameter name
118   - std::string m_unit; //!< Parameter unit
119   - double m_value; //!< Parameter value
120   - double m_error; //!< Uncertainty in parameter value
121   - double m_gradient; //!< Model gradient
122   - double m_min; //!< Parameter minimum
123   - double m_max; //!< Parameter maximum
124   - double m_scale; //!< Parameter scale (real = m_value * m_scale)
125   - bool m_free; //!< Parameter is free
126   - bool m_hasmin; //!< Parameter has minimum boundary
127   - bool m_hasmax; //!< Parameter has maximum boundary
128   - bool m_hasgrad; //!< Parameter has analytic gradient
  163 + std::string m_name; //!< Parameter name
  164 + std::string m_unit; //!< Parameter unit
  165 + double m_factor_value; //!< Parameter value factor
  166 + double m_factor_error; //!< Uncertainty in parameter value factor
  167 + double m_factor_gradient; //!< Model gradient factor
  168 + double m_factor_min; //!< Parameter minimum factor
  169 + double m_factor_max; //!< Parameter maximum factor
  170 + double m_scale; //!< Parameter scaling (true = factor * scale)
  171 + bool m_free; //!< Parameter is free
  172 + bool m_hasmin; //!< Parameter has minimum boundary
  173 + bool m_hasmax; //!< Parameter has maximum boundary
  174 + bool m_hasgrad; //!< Parameter has analytic gradient
129 175 };
130 176  
  177 +
  178 +/***********************************************************************//**
  179 + * @brief Return parameter value
  180 + *
  181 + * @return True parameter value.
  182 + *
  183 + * Returns the true parameter value
  184 + ***************************************************************************/
  185 +inline
  186 +double GModelPar::Value(void) const
  187 +{
  188 + return (m_factor_value*m_scale);
  189 +}
  190 +
131 191 #endif /* GMODELPAR_HPP */
... ...
pyext/GModelPar.i
... ... @@ -40,48 +40,61 @@ class GModelPar : public GBase {
40 40 public:
41 41 // Constructors and destructors
42 42 GModelPar(void);
43   - GModelPar(const std::string& name, const double& value,
44   - const double& scale = 1.0);
45   - GModelPar(const GModelPar& par);
  43 + explicit GModelPar(const std::string& name, const double& value, int i);
  44 + explicit GModelPar(const std::string& name, const double& factor, const double& scale);
46 45 virtual ~GModelPar(void);
47 46  
48   - // Methods
  47 + // Attribute methods
  48 + double Value(void) const;
  49 + double Error(void) const { return m_factor_error*m_scale; }
  50 + double Gradient(void) const { return m_factor_gradient*m_scale; }
  51 + double Min(void) const { return m_factor_min*m_scale; }
  52 + double Max(void) const { return m_factor_max*m_scale; }
  53 + void Value(const double& value);
  54 + void Error(const double& error);
  55 + void Gradient(const double& min);
  56 + void Min(const double& min);
  57 + void Max(const double& max);
  58 + void Range(const double& min, const double& max);
  59 +
  60 + // Factorization methods
  61 + const double& factor_value(void) const { return m_factor_value; }
  62 + const double& factor_error(void) const { return m_factor_error; }
  63 + const double& factor_gradient(void) const { return m_factor_gradient; }
  64 + const double& factor_min(void) const { return m_factor_min; }
  65 + const double& factor_max(void) const { return m_factor_max; }
  66 + const double& scale(void) const { return m_scale; }
  67 + void factor_value(const double& value);
  68 + void factor_error(const double& error) { m_factor_error=error; }
  69 + void factor_gradient(const double& gradient) { m_factor_gradient=gradient; }
  70 + void factor_min(const double& min);
  71 + void factor_max(const double& max);
  72 + void factor_range(const double& min, const double& max);
  73 + void Scale(const double& scale);
  74 +
  75 + // Boundary methods
  76 + bool hasmin(void) const { return m_hasmin; }
  77 + bool hasmax(void) const { return m_hasmax; }
  78 + bool hasrange(void) const { return m_hasmin && m_hasmax; }
  79 + void remove_min(void) { m_hasmin=false; }
  80 + void remove_max(void) { m_hasmax=false; }
  81 + void remove_range(void) { m_hasmin=false; m_hasmax=false; }
  82 +
  83 + // Property methods
  84 + bool isfree(void) const { return m_free; }
  85 + bool isfixed(void) const { return !m_free; }
  86 + bool hasgrad(void) const { return m_hasgrad; }
  87 + void free(void) { m_free=true; }
  88 + void fix(void) { m_free=false; }
  89 + void hasgrad(const bool& grad) { m_hasgrad=grad; }
  90 +
  91 + // Other methods
49 92 void clear(void);
50 93 GModelPar* clone(void) const;
51   - std::string name(void) const;
52   - std::string unit(void) const;
53   - double real_value(void) const;
54   - double real_error(void) const;
55   - double real_gradient(void) const;
56   - double real_min(void) const;
57   - double real_max(void) const;
58   - double value(void) const;
59   - double error(void) const;
60   - double gradient(void) const;
61   - double min(void) const;
62   - double max(void) const;
63   - double scale(void) const;
64   - bool isfree(void) const;
65   - bool hasmin(void) const;
66   - bool hasmax(void) const;
67   - bool hasgrad(void) const;
68   - void name(const std::string& name);
69   - void unit(const std::string& unit);
70   - void real_value(const double& value);
71   - void real_error(const double& error);
72   - void value(const double& value);
73   - void error(const double& error);
74   - void gradient(const double& gradient);
75   - void min(const double& min);
76   - void max(const double& max);
77   - void scale(const double& scale);
78   - void range(const double& min, const double& max);
79   - void remove_min(void);
80   - void remove_max(void);
81   - void remove_range(void);
82   - void free(void);
83   - void fix(void);
84   - void hasgrad(const bool& grad);
  94 + std::string name(void) const { return m_name; }
  95 + std::string unit(void) const { return m_unit; }
  96 + void name(const std::string& name) { m_name=name; }
  97 + void unit(const std::string& unit) { m_unit=unit; }
85 98 void autoscale(void);
86 99 void read(const GXmlElement& xml);
87 100 void write(GXmlElement& xml) const;
... ...
src/model/GModelPar.cpp
... ... @@ -33,12 +33,14 @@
33 33 #include "GTools.hpp"
34 34  
35 35 /* __ Method name definitions ____________________________________________ */
36   -#define G_REAL_VALUE "GModelPar::real_value(double&)"
37   -#define G_REAL_ERROR "GModelPar::real_error(double&)"
38   -#define G_VALUE "GModelPar::value(double&)"
39   -#define G_MIN "GModelPar::min(double&)"
40   -#define G_MAX "GModelPar::max(double&)"
41   -#define G_RANGE "GModelPar::range(double&, double&)"
  36 +#define G_VALUE "GModelPar::Value(double&)"
  37 +#define G_ERROR "GModelPar::Error(double&)"
  38 +#define G_FACTOR_VALUE "GModelPar::factor_value(double&)"
  39 +#define G_FACTOR_MIN "GModelPar::factor_min(double&)"
  40 +#define G_FACTOR_MAX "GModelPar::factor_max(double&)"
  41 +#define G_FACTOR_RANGE "GModelPar::factor_range(double&, double&)"
  42 +#define G_SCALE "GModelPar::Scale(double&)"
  43 +#define G_READ "GModelPar::read(GXmlElement&)"
42 44  
43 45 /* __ Macros _____________________________________________________________ */
44 46  
... ... @@ -71,22 +73,59 @@ GModelPar::GModelPar(void)
71 73 *
72 74 * @param[in] name Parameter name.
73 75 * @param[in] value Parameter value.
74   - * @param[in] scale Parameter scaling (default = 1.0).
75 76 *
76   - * Constructs a model parameter from parameter name, value and scaling. The
77   - * real value of the parameter is the specified value times the scaling.
  77 + * Constructs a model parameter from a parameter @p name and a parameter
  78 + * @p value.
  79 + *
  80 + * The parameter is auto-scaled, which for a @p value that differs from zero
  81 + * sets the scale factor to @p value and the @p factor_value to unity. For a
  82 + * @p value of zero, the scale factor will be set to unity and the
  83 + * @p factor_value will be set to @p value.
  84 + ***************************************************************************/
  85 +GModelPar::GModelPar(const std::string& name, const double& value, int i)
  86 +{
  87 + // Initialise members
  88 + init_members();
  89 +
  90 + // Set name attribute
  91 + m_name = name;
  92 +
  93 + // Set auto-scaled factor and scale attributes
  94 + if (value != 0.0) {
  95 + m_factor_value = 1.0;
  96 + m_scale = value;
  97 + }
  98 + else {
  99 + m_factor_value = value;
  100 + m_scale = 1.0;
  101 + }
  102 +
  103 + // Return
  104 + return;
  105 +}
  106 +
  107 +
  108 +/***********************************************************************//**
  109 + * @brief Parameter constructor
  110 + *
  111 + * @param[in] name Parameter name.
  112 + * @param[in] factor Parameter factor.
  113 + * @param[in] scale Parameter scaling.
  114 + *
  115 + * Constructs a model parameter from a parameter @p name, @p factor and
  116 + * @p scale factor.
78 117 ***************************************************************************/
79 118 GModelPar::GModelPar(const std::string& name,
80   - const double& value,
  119 + const double& factor,
81 120 const double& scale)
82 121 {
83 122 // Initialise members
84 123 init_members();
85 124  
86 125 // Set attributes
87   - this->name(name);
88   - this->value(value);
89   - this->scale(scale);
  126 + m_name = name;
  127 + m_factor_value = factor;
  128 + m_scale = scale;
90 129  
91 130 // Return
92 131 return;
... ... @@ -192,28 +231,40 @@ GModelPar* GModelPar::clone(void) const
192 231  
193 232  
194 233 /***********************************************************************//**
195   - * @brief Set real parameter value
  234 + * @brief Set parameter value
196 235 *
197   - * @param[in] value Real parameter value.
  236 + * @param[in] value Parameter value.
198 237 *
199   - * @exception GException::model_invalid_parscale
200   - * Parameter has a zero scale factor
  238 + * Sets the parameter value. The method stores the value factor which is
  239 + * obtained by dividing the @p value by the scale factor.
201 240 *
202   - * Assigns the real parameter value by dividing by the parameter scale.
  241 + * The method calls factor_value() for assigning the value factor, and this
  242 + * method will verify that the value lies within the specified boundaries.
203 243 ***************************************************************************/
204   -void GModelPar::real_value(const double& value)
  244 +void GModelPar::Value(const double& value)
205 245 {
206   - // Throw error if scale is 0
207   - if (m_scale == 0.0) {
208   - throw GException::model_invalid_parscale(G_REAL_VALUE, m_scale,
209   - "Zero scale not allowed for model parameter.");
210   - }
211   -
212   - // Compute value
213   - double val = value / m_scale;
  246 + // Set value factor. The GModelPar class makes sure that m_scale is
  247 + // never 0, so no test is needed here
  248 + factor_value(value / m_scale);
  249 +
  250 + // Return
  251 + return;
  252 +}
214 253  
215   - // Assign value
216   - this->value(val);
  254 +
  255 +/***********************************************************************//**
  256 + * @brief Set parameter error
  257 + *
  258 + * @param[in] error Parameter error.
  259 + *
  260 + * Sets the parameter error. The method stores the error factor which is
  261 + * obtained by dividing the @p error by the scale factor.
  262 + ***************************************************************************/
  263 +void GModelPar::Error(const double& error)
  264 +{
  265 + // Set error factor. The GModelPar class makes sure that m_scale is
  266 + // never 0, so no test is needed here
  267 + factor_error(error / m_scale);
217 268  
218 269 // Return
219 270 return;
... ... @@ -221,28 +272,56 @@ void GModelPar::real_value(const double&amp; value)
221 272  
222 273  
223 274 /***********************************************************************//**
224   - * @brief Set real parameter error
  275 + * @brief Set parameter gradient
225 276 *
226   - * @param[in] error Real parameter error.
  277 + * @param[in] gradient Parameter gradient.
  278 + *
  279 + * Sets the parameter gradient. The method stores the gradient factor which
  280 + * is obtained by dividing @p gradient by the scale factor.
  281 + ***************************************************************************/
  282 +void GModelPar::Gradient(const double& gradient)
  283 +{
  284 + // Set gradient factor. The GModelPar class makes sure that m_scale is
  285 + // never 0, so no test is needed here
  286 + factor_gradient(gradient / m_scale);
  287 +
  288 + // Return
  289 + return;
  290 +}
  291 +
  292 +
  293 +/***********************************************************************//**
  294 + * @brief Set minimum parameter boundary
227 295 *
228   - * @exception GException::model_invalid_parscale
229   - * Parameter has a zero scale factor
  296 + * @param[in] min Parameter minimum.
230 297 *
231   - * Assigns the real parameter error by dividing by the parameter scale.
  298 + * Sets the minimum parameter boundary. The method stores the minimum
  299 + * boundary factor which is obtained by dividing @p min by the scale factor.
232 300 ***************************************************************************/
233   -void GModelPar::real_error(const double& error)
  301 +void GModelPar::Min(const double& min)
234 302 {
235   - // Throw error if scale is 0
236   - if (m_scale == 0.0) {
237   - throw GException::model_invalid_parscale(G_REAL_ERROR, m_scale,
238   - "Zero scale not allowed for model parameter.");
239   - }
240   -
241   - // Compute error
242   - double err = error / m_scale;
  303 + // Set minimum boundary factor. The GModelPar class makes sure that
  304 + // m_scale is never 0, so no test is needed here
  305 + factor_min(min / m_scale);
  306 +
  307 + // Return
  308 + return;
  309 +}
243 310  
244   - // Assign error
245   - this->error(err);
  311 +
  312 +/***********************************************************************//**
  313 + * @brief Set maximum parameter boundary
  314 + *
  315 + * @param[in] max Parameter maximum.
  316 + *
  317 + * Sets the maximum parameter boundary. The method stores the maximum
  318 + * boundary factor which is obtained by dividing @p max by the scale factor.
  319 + ***************************************************************************/
  320 +void GModelPar::Max(const double& max)
  321 +{
  322 + // Set maximum boundary factor. The GModelPar class makes sure that
  323 + // m_scale is never 0, so no test is needed here
  324 + factor_max(max / m_scale);
246 325  
247 326 // Return
248 327 return;
... ... @@ -250,29 +329,58 @@ void GModelPar::real_error(const double&amp; error)
250 329  
251 330  
252 331 /***********************************************************************//**
253   - * @brief Set parameter value
  332 + * @brief Set minimum and maximum parameter boundaries
254 333 *
255   - * @param[in] value Parameter value.
  334 + * @param[in] min Parameter minimum.
  335 + * @param[in] max Parameter maximum.
256 336 *
257   - * @exception GException::out_of_range
258   - * Parameter value outside valid range
  337 + * Sets the minimum and maximum parameter boundaries. The method calls the
  338 + * min() and max() methods to set the boundaries.
259 339 ***************************************************************************/
260   -void GModelPar::value(const double& value)
  340 +void GModelPar::Range(const double& min, const double& max)
  341 +{
  342 + // Set minimum and maximum
  343 + this->Min(min);
  344 + this->Max(max);
  345 +
  346 + // Return
  347 + return;
  348 +}
  349 +
  350 +
  351 +/***********************************************************************//**
  352 + * @brief Set parameter value factor
  353 + *
  354 + * @param[in] value Value factor.
  355 + *
  356 + * @exception GException::invalid_argument
  357 + * Parameter @p value outside [min,max] boundaries.
  358 + *
  359 + * Sets the value factor of the model parameter. The method makes sure that
  360 + * none of the boundaries is violated. Otherwise, exceptions are thrown.
  361 + ***************************************************************************/
  362 +void GModelPar::factor_value(const double& value)
261 363 {
262 364 // If there is a minimum boundary and if value is below this boundary
263   - // then throw an error
264   - if (m_hasmin && value < m_min) {
265   - throw GException::out_of_range(G_VALUE, value, m_min, m_max);
  365 + // then throw an exception
  366 + if (m_hasmin && value < m_factor_min) {
  367 + std::string msg = "Specified value factor "+str(value)+
  368 + " is smaller than the minimum boundary "+
  369 + str(m_factor_min)+".";
  370 + throw GException::invalid_argument(G_FACTOR_VALUE, msg);
266 371 }
267 372  
268 373 // If there is a maximum boundary and if value is above this boundary
269   - // then throw an error
270   - if (m_hasmax && value > m_max) {
271   - throw GException::out_of_range(G_VALUE, value, m_min, m_max);
  374 + // then throw an exception
  375 + if (m_hasmax && value > m_factor_max) {
  376 + std::string msg = "Specified value factor "+str(value)+
  377 + " is larger than the maximum boundary "+
  378 + str(m_factor_max)+".";
  379 + throw GException::invalid_argument(G_FACTOR_VALUE, msg);
272 380 }
273 381  
274 382 // Assign value
275   - m_value = value;
  383 + m_factor_value = value;
276 384  
277 385 // Return
278 386 return;
... ... @@ -280,22 +388,29 @@ void GModelPar::value(const double&amp; value)
280 388  
281 389  
282 390 /***********************************************************************//**
283   - * @brief Set parameter minimum
  391 + * @brief Set parameter minimum factor
284 392 *
285   - * @param[in] min Parameter minimum.
  393 + * @param[in] min Minimum factor.
  394 + *
  395 + * @exception GException::invalid_argument
  396 + * Parameter @p min larger than value factor.
286 397 *
287   - * @exception GException::out_of_range
288   - * Parameter minimum is larger than actual parameter value.
  398 + * Sets the minimum boundary factor of the model parameter. The method makes
  399 + * sure that the minimum is not larger than the actual value factor.
  400 + * Otherwise, an exception is thrown.
289 401 ***************************************************************************/
290   -void GModelPar::min(const double& min)
  402 +void GModelPar::factor_min(const double& min)
291 403 {
292   - // If minimum is above actual value then throw error
293   - if (m_value < min) {
294   - throw GException::out_of_range(G_MIN, m_value, min, m_max);
  404 + // Check if minimum is larger than value
  405 + if (min > m_factor_value) {
  406 + std::string msg = "Specified minimum factor "+str(min)+
  407 + " is larger than the value factor "+
  408 + str(m_factor_value)+".";
  409 + throw GException::invalid_argument(G_FACTOR_VALUE, msg);
295 410 }
296 411  
297   - // Assign minimum
298   - m_min = min;
  412 + // Assign minimum factor
  413 + m_factor_min = min;
299 414  
300 415 // Flag that minimum was set
301 416 m_hasmin = true;
... ... @@ -306,22 +421,29 @@ void GModelPar::min(const double&amp; min)
306 421  
307 422  
308 423 /***********************************************************************//**
309   - * @brief Set parameter maximum
  424 + * @brief Set parameter maximum factor
310 425 *
311   - * @param[in] max Parameter maximum.
  426 + * @param[in] max Maximum factor.
  427 + *
  428 + * @exception GException::invalid_argument
  429 + * Parameter @p max smaller than value factor.
312 430 *
313   - * @exception GException::out_of_range
314   - * Parameter maximum is smaller than actual parameter value.
  431 + * Sets the maximum boundary factor of the model parameter. The method makes
  432 + * sure that the maximum is not smaller than the actual value factor.
  433 + * Otherwise, an exception is thrown.
315 434 ***************************************************************************/
316   -void GModelPar::max(const double& max)
  435 +void GModelPar::factor_max(const double& max)
317 436 {
318   - // If maximum is below value then throw error
319   - if (m_value > max) {
320   - throw GException::out_of_range(G_MAX, m_value, m_min, max);
  437 + // Check if maximum is smaller than value
  438 + if (max < m_factor_value) {
  439 + std::string msg = "Specified maximum factor "+str(max)+
  440 + " is smaller than the value factor "+
  441 + str(m_factor_value)+".";
  442 + throw GException::invalid_argument(G_FACTOR_VALUE, msg);
321 443 }
322 444  
323 445 // Assign maximum
324   - m_max = max;
  446 + m_factor_max = max;
325 447  
326 448 // Flag that maximum was set
327 449 m_hasmax = true;
... ... @@ -332,29 +454,91 @@ void GModelPar::max(const double&amp; max)
332 454  
333 455  
334 456 /***********************************************************************//**
335   - * @brief Set parameter minimum and maximum
  457 + * @brief Set parameter minimum and maximum factors
336 458 *
337   - * @param[in] min Parameter minimum.
338   - * @param[in] max Parameter maximum.
  459 + * @param[in] min Minimum factor.
  460 + * @param[in] max Maximum factor.
339 461 *
340   - * @exception GException::out_of_range
341   - * Parameter boundaries are in conflict with actual parameter
342   - * value.
  462 + * Sets the minimum and maximum boundary factors. The method calls the
  463 + * factor_min() and factor_max() methods which perform validity checking
  464 + * of the arguments.
343 465 ***************************************************************************/
344   -void GModelPar::range(const double& min, const double& max)
  466 +void GModelPar::factor_range(const double& min, const double& max)
345 467 {
346   - // If maximum is below value then throw error
347   - if (m_value < min || m_value > max || min > max) {
348   - throw GException::out_of_range(G_RANGE, m_value, min, max);
  468 + // Set minimum and maximum
  469 + factor_min(min);
  470 + factor_max(max);
  471 +
  472 + // Return
  473 + return;
  474 +}
  475 +
  476 +
  477 +/***********************************************************************//**
  478 + * @brief Set scale factor
  479 + *
  480 + * @param[in] scale Scale factor.
  481 + *
  482 + * @exception GException::invalid_argument
  483 + * Sacle factor of 0 specified.
  484 + *
  485 + * Sets the scale factor of the model parameter. All parameter attributes are
  486 + * rescaled accordingly.
  487 + *
  488 + * Special care is taken for value boundaries, that need swaping if the scale
  489 + * factor changes its sign. In case of sign change the following logic applies:
  490 + * - if minimum and maximum boundaries are set they are swapped
  491 + * - if only a minimum boundary exists it will be replaced by a maximum boundary
  492 + * - if only a maximum boundary exists it will be replaced by a minimum boundary
  493 + *
  494 + * An exception is thrown if a scale factor of 0 is specified.
  495 + ***************************************************************************/
  496 +void GModelPar::Scale(const double& scale)
  497 +{
  498 + // Make sure that scale is not zero
  499 + if (scale == 0.0) {
  500 + std::string msg = "Specified scale factor of 0.\n"
  501 + "Model parameters need a non-zero scale factor.";
  502 + throw GException::invalid_argument(G_SCALE, msg);
349 503 }
350 504  
351   - // Assign range
352   - m_min = min;
353   - m_max = max;
354   -
355   - // Flag that range was set
356   - m_hasmin = true;
357   - m_hasmax = true;
  505 + // Set rescaling
  506 + double rescale = m_scale/scale;
  507 +
  508 + // Set new scale factor
  509 + m_scale = scale;
  510 +
  511 + // Set values, error, gradient, min and max
  512 + m_factor_value *= rescale;
  513 + m_factor_error *= rescale;
  514 + m_factor_gradient *= rescale;
  515 + if (m_hasmin) {
  516 + m_factor_min *= rescale;
  517 + }
  518 + if (m_hasmax) {
  519 + m_factor_max *= rescale;
  520 + }
  521 +
  522 + // Takes care of boundaries in case of sign change
  523 + if (rescale < 0.0) {
  524 + if (m_hasmin && m_hasmax) {
  525 + double swap = m_factor_min;
  526 + m_factor_min = m_factor_max;
  527 + m_factor_max = swap;
  528 + }
  529 + else if (m_hasmin) {
  530 + m_factor_max = m_factor_min;
  531 + m_hasmax = true;
  532 + m_factor_min = 0.0;
  533 + m_hasmin = false;
  534 + }
  535 + else if (m_hasmax) {
  536 + m_factor_min = m_factor_max;
  537 + m_hasmin = true;
  538 + m_factor_max = 0.0;
  539 + m_hasmax = false;
  540 + }
  541 + }
358 542  
359 543 // Return
360 544 return;
... ... @@ -364,35 +548,61 @@ void GModelPar::range(const double&amp; min, const double&amp; max)
364 548 /***********************************************************************//**
365 549 * @brief Autoscale parameter
366 550 *
367   - * Sets the value to unity and the scale factor to the real value of the
368   - * parameter. The method will also adjust the error and the gradient
369   - * accodringly. If parameter boundaries exist they will also be adjusted
370   - * accordingly.
  551 + * Sets the value factor to unity and the scale factor to the real value
  552 + * of the parameter. The method will also adjust the error factor and
  553 + * gradient factor, as well as the minimum and maximum factors if they
  554 + * exist.
371 555 *
372   - * The method does nothing if the actual value is zero.
  556 + * Special care is taken for value boundaries, that need swaping if the scale
  557 + * factor changes its sign. In case of sign change the following logic applies:
  558 + * - if minimum and maximum boundaries are set they are swapped
  559 + * - if only a minimum boundary exists it will be replaced by a maximum boundary
  560 + * - if only a maximum boundary exists it will be replaced by a minimum boundary
  561 + *
  562 + * The method does nothing if the actual value factor is zero.
373 563 ***************************************************************************/
374 564 void GModelPar::autoscale(void)
375 565 {
376   - // Continue only if the value is non-zero
377   - if (m_value != 0.0) {
  566 + // Continue only if the value factor is non-zero
  567 + if (m_factor_value != 0.0) {
378 568  
379 569 // Set the scale factor
380   - m_scale *= m_value;
  570 + m_scale *= m_factor_value;
381 571  
382 572 // Get inverse scaling factor
383   - double invscale = 1.0 / m_value;
  573 + double invscale = 1.0 / m_factor_value;
384 574  
385 575 // Set values, error, gradient, min and max
386   - m_value *= invscale;
387   - m_error *= invscale;
388   - m_gradient *= invscale;
  576 + m_factor_value *= invscale;
  577 + m_factor_error *= invscale;
  578 + m_factor_gradient *= invscale;
389 579 if (m_hasmin) {
390   - m_min *= invscale;
  580 + m_factor_min *= invscale;
391 581 }
392 582 if (m_hasmax) {
393   - m_max *= invscale;
  583 + m_factor_max *= invscale;
394 584 }
395 585  
  586 + // Takes care of boundaries in case of sign change
  587 + if (invscale < 0.0) {
  588 + if (m_hasmin && m_hasmax) {
  589 + double swap = m_factor_min;
  590 + m_factor_min = m_factor_max;
  591 + m_factor_max = swap;
  592 + }
  593 + else if (m_hasmin) {
  594 + m_factor_max = m_factor_min;
  595 + m_hasmax = true;
  596 + m_factor_min = 0.0;
  597 + m_hasmin = false;
  598 + }
  599 + else if (m_hasmax) {
  600 + m_factor_min = m_factor_max;
  601 + m_hasmin = true;
  602 + m_factor_max = 0.0;
  603 + m_hasmax = false;
  604 + }
  605 + }
396 606  
397 607 } // endif: value was non-zero
398 608  
... ... @@ -406,50 +616,112 @@ void GModelPar::autoscale(void)
406 616 *
407 617 * @param[in] xml XML element
408 618 *
409   - * The following parameter attributes may exist (they take the default
410   - * values when they are not found in the XML element):
411   - * "value" (default=0.0), "error" (default=0.0), "scale" (default=1.0),
412   - * "min" (default=INDEF), "max" (default=INDEF), "free" (default=0).
  619 + * @exception GException::invalid_value
  620 + * Invalid combination of parameter attributes encountered.
  621 + *
  622 + * Extracts the parameter attributes from an XML element of the form
  623 + *
  624 + * <parameter name=".." value=".." error=".." scale=".." min=".." max="..' free="..">
  625 + *
  626 + * Each of the attributes are optional, with the following scheme for
  627 + * assigning default values in case that the attribute was not found:
  628 + * - @p value sets @p m_factor_value (defaults to 0.0)
  629 + * - @p error sets @p m_factor_error (defaults to 0.0)
  630 + * - @p scale sets @p m_scale (defaults to 1.0)
  631 + * - @p min sets @p m_factor_min (will remove_min() if not found)
  632 + * - @p max sets @p m_factor_max (will remove_max() if not found)
  633 + * - @p free sets @p m_free (papameter will be fixed if not found)
413 634 ***************************************************************************/
414 635 void GModelPar::read(const GXmlElement& xml)
415 636 {
416 637 // Get value
417 638 std::string arg = xml.attribute("value");
418   - if (arg != "")
419   - m_value = todouble(arg);
420   - else
421   - m_value = 0.0;
  639 + if (arg != "") {
  640 + m_factor_value = todouble(arg);
  641 + }
  642 + else {
  643 + m_factor_value = 0.0;
  644 + }
422 645  
423 646 // Get error
424 647 arg = xml.attribute("error");
425   - if (arg != "")
426   - m_error = todouble(arg);
427   - else
428   - m_error = 0.0;
  648 + if (arg != "") {
  649 + m_factor_error = todouble(arg);
  650 + }
  651 + else {
  652 + m_factor_error = 0.0;
  653 + }
429 654  
430 655 // Get scale factor
431 656 arg = xml.attribute("scale");
432   - if (arg != "")
  657 + if (arg != "") {
433 658 m_scale = todouble(arg);
434   - else
  659 + }
  660 + else {
435 661 m_scale = 1.0;
  662 + }
436 663  
437 664 // Get min
438 665 arg = xml.attribute("min");
439   - if (arg != "")
440   - min(todouble(arg));
  666 + if (arg != "") {
  667 + m_factor_min = todouble(arg);
  668 + m_hasmin = true;
  669 + }
  670 + else {
  671 + remove_min();
  672 + }
441 673  
442 674 // Get max
443 675 arg = xml.attribute("max");
444   - if (arg != "")
445   - max(todouble(arg));
  676 + if (arg != "") {
  677 + m_factor_max = todouble(arg);
  678 + m_hasmax = true;
  679 + }
  680 + else {
  681 + remove_max();
  682 + }
446 683  
447 684 // Get free
448 685 if (xml.attribute("free") == "1" ||
449   - tolower(xml.attribute("free")) == "true")
  686 + tolower(xml.attribute("free")) == "true") {
450 687 free();
451   - else
  688 + }
  689 + else {
452 690 fix();
  691 + }
  692 +
  693 + // If there is a minimum and maximum, make sure that the maximum is
  694 + // not smaller than the minimum
  695 + if (m_hasmin && m_hasmax) {
  696 + if (m_factor_min > m_factor_max) {
  697 + std::string msg = "The model parameter "+m_name+
  698 + " in the XML document has a minimum boundary "+
  699 + str(m_factor_min)+
  700 + " that is larger than the maximum boundary "+
  701 + str(m_factor_max)+".\n"+xml.print();
  702 + throw GException::invalid_value(G_READ, msg);
  703 + }
  704 + }
  705 +
  706 + // If there is a minimum, make sure that the value is not below it
  707 + if (m_hasmin && m_factor_value < m_factor_min) {
  708 + std::string msg = "The model parameter "+m_name+
  709 + " in the XML document has a value "+
  710 + str(m_factor_value)+
  711 + " that is smaller than the minimum boundary "+
  712 + str(m_factor_min)+".\n"+xml.print();
  713 + throw GException::invalid_value(G_READ, msg);
  714 + }
  715 +
  716 + // If there is a maximum, make sure that the value is not above it
  717 + if (m_hasmax && m_factor_value > m_factor_max) {
  718 + std::string msg = "The model parameter "+m_name+
  719 + " in the XML document has a value "+
  720 + str(m_factor_value)+
  721 + " that is larger than the maximum boundary "+
  722 + str(m_factor_max)+".\n"+xml.print();
  723 + throw GException::invalid_value(G_READ, msg);
  724 + }
453 725  
454 726 // Return
455 727 return;
... ... @@ -461,36 +733,48 @@ void GModelPar::read(const GXmlElement&amp; xml)
461 733 *
462 734 * @param[in] xml XML element.
463 735 *
464   - * The following parameter attributes may exist (they take the default
465   - * values when they are not found in the XML element):
466   - * "value" (default=0.0), "error" (default=0.0), "scale" (default=1.0),
467   - * "min" (default=INDEF), "max" (default=INDEF), "free" (default=0).
  736 + * Sets or updates the parameter attributes in an XML element of the form
  737 + *
  738 + * <parameter name=".." value=".." error=".." scale=".." min=".." max="..' free="..">
  739 + *
  740 + * The following attributes will be set:
  741 + * - @p value
  742 + * - @p error (only in case that the parameter is free)
  743 + * - @p scale
  744 + * - @p min (only in case that a minimum exists)
  745 + * - @p max (only in case that a maximum exists)
  746 + * - @p free
468 747 ***************************************************************************/
469 748 void GModelPar::write(GXmlElement& xml) const
470 749 {
471 750 // Set value
472   - xml.attribute("value", str(m_value));
  751 + xml.attribute("value", str(m_factor_value));
473 752  
474 753 // Set error (only if parameter is free)
475   - if (isfree())
476   - xml.attribute("error", str(m_error));
  754 + if (isfree()) {
  755 + xml.attribute("error", str(m_factor_error));
  756 + }
477 757  
478 758 // Set scale
479 759 xml.attribute("scale", str(m_scale));
480 760  
481 761 // Set minimum
482   - if (hasmin())
483   - xml.attribute("min", str(m_min));
  762 + if (hasmin()) {
  763 + xml.attribute("min", str(m_factor_min));
  764 + }
484 765  
485 766 // Set maximum
486   - if (hasmax())
487   - xml.attribute("max", str(m_max));
  767 + if (hasmax()) {
  768 + xml.attribute("max", str(m_factor_max));
  769 + }
488 770  
489 771 // Set free/fix flag
490   - if (isfree())
  772 + if (isfree()) {
491 773 xml.attribute("free", "1");
492   - else
  774 + }
  775 + else {
493 776 xml.attribute("free", "0");
  777 + }
494 778  
495 779 // Return
496 780 return;
... ... @@ -499,6 +783,8 @@ void GModelPar::write(GXmlElement&amp; xml) const
499 783  
500 784 /***********************************************************************//**
501 785 * @brief Print parameter information
  786 + *
  787 + * @return String with model parameter information.
502 788 ***************************************************************************/
503 789 std::string GModelPar::print(void) const
504 790 {
... ... @@ -508,38 +794,46 @@ std::string GModelPar::print(void) const
508 794 // Append parameter name
509 795 result.append(parformat(" "+name()));
510 796  
511   - // Append real value
512   - result.append(str(real_value()));
  797 + // Append value
  798 + result.append(str(Value()));
513 799  
514 800 // For free parameters, append statistical uncertainty
515   - if (m_free)
516   - result.append(" +/- "+str(fabs(real_error())));
  801 + if (m_free) {
  802 + result.append(" +/- "+str(std::abs(Error())));
  803 + }
517 804  
518 805 // Append parameter limites if they exist
519   - if (m_hasmin && m_hasmax)
520   - result.append(" ["+str(real_min()) + ","+str(real_max())+"]");
521   - else if (m_hasmin)
522   - result.append(" ["+str(real_min()) + ",infty[");
523   - else if (m_hasmax)
524   - result.append(" ]-infty,"+str(real_max())+"]");
  806 + if (m_hasmin && m_hasmax) {
  807 + result.append(" ["+str(Min()) + ","+str(Max())+"]");
  808 + }
  809 + else if (m_hasmin) {
  810 + result.append(" ["+str(Min()) + ",infty[");
  811 + }
  812 + else if (m_hasmax) {
  813 + result.append(" ]-infty,"+str(Max())+"]");
  814 + }
525 815  
526 816 // Append parameter unit
527 817 result.append(" "+m_unit);
528 818  
529 819 // Signal if parameter was free or fixed
530   - if (m_free)
  820 + if (m_free) {
531 821 result.append(" (free");
532   - else
  822 + }
  823 + else {
533 824 result.append(" (fixed");
  825 + }
534 826  
535 827 // Append parameter scale
536 828 result.append(",scale="+str(m_scale));
537 829  
538 830 // Signal if parameter has analytic gradient
539   - if (m_hasgrad)
  831 + if (m_hasgrad) {
540 832 result.append(",gradient)");
541   - else
  833 + }
  834 + else {
542 835 result.append(")");
  836 + }
543 837  
544 838 // Return result
545 839 return result;
... ... @@ -560,16 +854,16 @@ void GModelPar::init_members(void)
560 854 // Initialise members
561 855 m_name.clear();
562 856 m_unit.clear();
563   - m_value = 0.0;
564   - m_error = 0.0;
565   - m_gradient = 0.0;
566   - m_min = 0.0;
567   - m_max = 0.0;
568   - m_scale = 1.0;
569   - m_free = true;
570   - m_hasmin = false;
571   - m_hasmax = false;
572   - m_hasgrad = false;
  857 + m_factor_value = 0.0;
  858 + m_factor_error = 0.0;
  859 + m_factor_gradient = 0.0;
  860 + m_factor_min = 0.0;
  861 + m_factor_max = 0.0;
  862 + m_scale = 1.0;
  863 + m_free = true;
  864 + m_hasmin = false;
  865 + m_hasmax = false;
  866 + m_hasgrad = false;
573 867  
574 868 // Return
575 869 return;
... ... @@ -584,18 +878,18 @@ void GModelPar::init_members(void)
584 878 void GModelPar::copy_members(const GModelPar& par)
585 879 {
586 880 // Copy members
587   - m_name = par.m_name;
588   - m_unit = par.m_unit;
589   - m_value = par.m_value;
590   - m_error = par.m_error;
591   - m_gradient = par.m_gradient;
592   - m_min = par.m_min;
593   - m_max = par.m_max;
594   - m_scale = par.m_scale;
595   - m_free = par.m_free;
596   - m_hasmin = par.m_hasmin;
597   - m_hasmax = par.m_hasmax;
598   - m_hasgrad = par.m_hasgrad;
  881 + m_name = par.m_name;
  882 + m_unit = par.m_unit;
  883 + m_factor_value = par.m_factor_value;
  884 + m_factor_error = par.m_factor_error;
  885 + m_factor_gradient = par.m_factor_gradient;
  886 + m_factor_min = par.m_factor_min;
  887 + m_factor_max = par.m_factor_max;
  888 + m_scale = par.m_scale;
  889 + m_free = par.m_free;
  890 + m_hasmin = par.m_hasmin;
  891 + m_hasmax = par.m_hasmax;
  892 + m_hasgrad = par.m_hasgrad;
599 893  
600 894 // Return
601 895 return;
... ...