NumericalErrorPropagation.cc
Go to the documentation of this file.
1 #include <iostream>
2 #include <vector>
3 
4 #include <boost/numeric/ublas/matrix.hpp>
5 #include <boost/numeric/ublas/io.hpp>
6 
7 #include <utl/ErrorLogger.h>
8 #include <utl/AugerException.h>
9 #include <utl/NumericalErrorPropagation.h>
10 #include <utl/CorrelationMatrix.h>
11 
12 using namespace std;
13 using namespace boost::numeric;
16 using utl::FCNCalculator;
17 using utl::Parameter;
18 
19 
20 NumericalErrorPropagation::NumericalErrorPropagation(const FCNCalculator& fcn,
21  const vector<Parameter>& par,
22  const CorrelationMatrix& corr) :
23  fFcn(fcn),
24  fParameter(par),
25  fCorrelation(corr)
26 {
27  if (par.size() != corr.GetNParameter()) {
28  ostringstream err;
29  err << "ERROR "
30  "#parameter: " << par.size() << " is different from size of "
31  "correlation matrix " << corr.GetNParameter();
32  ERROR(err);
33  throw OutOfBoundException(err.str());
34  }
35 
36  Propagate();
37 }
38 
39 
41 {
43 }
44 
45 
46 void
48 {
49  /*
50  calculate Jacobi-Matrix
51 
52  alpha_j: input parameter j
53  q_i (alpha): output-parameter i for set of input parameters
54  q_i (alpha_1, alpha_2, ... , alpha_n)
55 
56  J_ij = partial ( d(q_i) / d(alpha_j) )
57  */
58 
59  const unsigned int J_cols = fParameter.size(); // alpha_j input-parameter
60 
61  vector<double> x(J_cols),xm(J_cols),xmm(J_cols),xp(J_cols),xpp(J_cols);
62 
63  for (unsigned int i = 0; i < J_cols; ++i) // initialize
64  x[i] = xm[i] = xmm[i] = xp[i] = xpp[i] = fParameter[i].value;
65 
66  fResult = fFcn(x);
67 
68  const unsigned int J_rows = fResult.size(); // q_i output-parameter
69 
70  ublas::matrix<double> J(J_rows, J_cols);
71 
72  for (unsigned col = 0; col < J_cols; ++col) { // alpha_j
73 
74  if (col > 0) {
75  // reset previous change to vectors, x is untouched
76  xpp[col-1] = x[col-1];
77  xp [col-1] = x[col-1];
78  xm [col-1] = x[col-1];
79  xmm[col-1] = x[col-1];
80  }
81 
82  /* if error of alpha_j is zero, we can skip calculation of all
83  d q_i / d alpha_j, they are multiplied with zero later -
84  still guard against uninitialized values in J, though */
85  if (fParameter[col].error) {
86  /* try to guess dx which is small compared to curvature of fFcn, but large compared
87  to machine precision, since we don't want to see numerical round off errors */
88  double dx = fParameter[col].error * 1e-3;
89 
90  // derivative numerically calculated with five-point stencil (see e.g. Wikipedia)
91  xpp[col] += 2*dx;
92  xp[col] += dx;
93  xm[col] -= dx;
94  xmm[col] -= 2*dx;
95 
96  vector<double> fpp = fFcn(xpp);
97  vector<double> fp = fFcn(xp);
98  vector<double> fm = fFcn(xm);
99  vector<double> fmm = fFcn(xmm);
100 
101  for (unsigned row = 0; row < J_rows; ++row) // q_i
102  J(row, col) = (-fpp[row] + 8*fp[row] - 8*fm[row] + fmm[row]) / (12*dx);
103 
104  } else {
105 
106  for (unsigned row = 0; row < J_rows; ++row) // q_i
107  J(row, col) = 0;
108 
109  }
110  }
111 
112  /*
113  calculate the covariance function of the output parameters q_i
114  V' = J * V * J^T
115  */
116 
117  ublas::matrix<double> V_input(J_cols, J_cols);
118 
119  for (unsigned row = 0; row < J_cols; ++row)
120  for (unsigned col = 0; col < J_cols; ++col)
121  V_input(row,col) =
122  fCorrelation.Get(row, col) * fParameter[row].error * fParameter[col].error;
123 
124  const ublas::matrix<double> temp = ublas::prod(V_input, trans(J));
125  ublas::matrix<double> V_output = ublas::prod(J, temp);
126 
127  /*
128  now retrieve the output parameter errors and their correlations
129  */
130 
131  fPropagatedErrors.clear();
132  fPropagatedErrors.reserve(J_rows);
133  for (unsigned i = 0; i < J_rows; ++i) {
134  const double V = V_output(i, i);
135 
136  if (V < 0 || std::isnan(V)) {
137  ostringstream err;
138  err << "invalid variance " << V;
139  ERROR(err);
140  fPropagatedErrors.push_back(0);
141  V_output(i, i) = 0;
142  } else
143  fPropagatedErrors.push_back(sqrt(V));
144  }
145 
147 
148  for (unsigned i = 0; i < J_rows; ++i) {
149  for (unsigned j = i+1; j < J_rows; ++j) {
150 
151  const double tmp = V_output(i, i) * V_output(j, j);
152 
153  const double correlation = tmp > 0 ? V_output(i, j) / sqrt(tmp) : 0;
154 
155  if (correlation < -1 || correlation > 1 || std::isnan(correlation)) {
156  ostringstream err;
157  err << "correlation = " << correlation << " is invalid, converted to 0 (!)";
158  ERROR(err);
159  fPropagatedCorrelation->Set(i, j, 0);
160  } else
161  fPropagatedCorrelation->Set(i, j, correlation);
162  }
163  }
164 }
const std::vector< Parameter > fParameter
constexpr double V
Definition: AugerUnits.h:233
unsigned int GetNParameter() const
Exception for reporting variable out of valid range.
void Set(const int iPar, const int jPar, const double corr)
double Get(const int iPar, const int jPar) const
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
const CorrelationMatrix & fCorrelation

, generated on Tue Sep 26 2023.