-
Notifications
You must be signed in to change notification settings - Fork 122
/
EstimatePeakErrors.cpp
167 lines (142 loc) · 6.01 KB
/
EstimatePeakErrors.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source,
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
// SPDX - License - Identifier: GPL - 3.0 +
#include "MantidCurveFitting/Algorithms/EstimatePeakErrors.h"
#include "MantidCurveFitting/Functions/PeakParameterFunction.h"
#include "MantidCurveFitting/GSLMatrix.h"
#include "MantidAPI/CompositeFunction.h"
#include "MantidAPI/FunctionProperty.h"
#include "MantidAPI/IPeakFunction.h"
#include "MantidAPI/ITableWorkspace.h"
#include "MantidAPI/TableRow.h"
#include "MantidAPI/WorkspaceFactory.h"
namespace Mantid {
namespace CurveFitting {
namespace Algorithms {
using namespace API;
using namespace Kernel;
using namespace std;
// Subscription
DECLARE_ALGORITHM(EstimatePeakErrors)
//--------------------------------------------------------------------------------------------------------
// Public members
//--------------------------------------------------------------------------------------------------------
/// Default constructor
EstimatePeakErrors::EstimatePeakErrors() : Algorithm() {}
/// Summary of algorithms purpose
const std::string EstimatePeakErrors::summary() const {
return "Calculates error estimates for peak parameters: "
"centre, height, FWHM and intensity.";
}
const std::string EstimatePeakErrors::name() const { return "EstimatePeakErrors"; }
int EstimatePeakErrors::version() const { return 1; }
const std::string EstimatePeakErrors::category() const { return "Optimization"; }
//--------------------------------------------------------------------------------------------------------
// Private members
//--------------------------------------------------------------------------------------------------------
namespace {
/// Calculate a Jacobian of transformations from the normal function's
/// parameters to the 4 general peak parameters: centre, height, FWHM and
/// intensity (integral).
/// Also calculate the values for the peak parameters.
/// @param peak :: The function for which the Jacobian to be calculated.
/// @param centre :: Output receiving value of peak centre.
/// @param height :: Output receiving value of peak height.
/// @param fwhm :: Output receiving value of peak FWHM.
/// @param intensity :: Output receiving value of peak intensity.
GSLMatrix makeJacobian(IPeakFunction &peak, double ¢re, double &height, double &fwhm, double &intensity) {
GSLMatrix jacobian(4, peak.nParams());
centre = peak.centre();
height = peak.height();
fwhm = peak.fwhm();
intensity = peak.intensity();
for (size_t ip = 0; ip < peak.nParams(); ++ip) {
double p = peak.getParameter(ip);
double dp = 1e-9;
if (p != 0.0) {
dp *= p;
}
peak.setParameter(ip, p + dp);
jacobian.set(0, ip, (peak.centre() - centre) / dp);
jacobian.set(1, ip, (peak.height() - height) / dp);
jacobian.set(2, ip, (peak.fwhm() - fwhm) / dp);
jacobian.set(3, ip, (peak.intensity() - intensity) / dp);
peak.setParameter(ip, p);
}
return jacobian;
}
/// Calculate the errors for a peak and add them to the result table.
/// @param peak :: A function for which errors are calculated.
/// @param results :: The table with results
/// @param covariance :: The covariance matrix for the parameters of the peak.
/// @param prefix :: A prefix for the parameter names.
void calculatePeakValues(IPeakFunction &peak, ITableWorkspace &results, const GSLMatrix &covariance,
const std::string &prefix) {
double centre, height, fwhm, intensity;
GSLMatrix J = makeJacobian(peak, centre, height, fwhm, intensity);
// CHECK_OUT_GSL_MATRIX("J=", J);
GSLMatrix JCJ = J * covariance * J.tr();
// CHECK_OUT_GSL_MATRIX("JCJ=", JCJ);
TableRow row = results.appendRow();
row << prefix + "Centre" << centre << sqrt(JCJ.get(0, 0));
row = results.appendRow();
row << prefix + "Height" << height << sqrt(JCJ.get(1, 1));
row = results.appendRow();
row << prefix + "FWHM" << fwhm << sqrt(JCJ.get(2, 2));
row = results.appendRow();
row << prefix + "Intensity" << intensity << sqrt(JCJ.get(3, 3));
}
} // namespace
/// Initialize
void EstimatePeakErrors::init() {
declareProperty(std::make_unique<FunctionProperty>("Function", Direction::InOut),
"Fitting function containing peaks. Must have a covariance "
"matrix attached.");
declareProperty(
std::make_unique<API::WorkspaceProperty<API::ITableWorkspace>>("OutputWorkspace", "", Kernel::Direction::Output),
"The name of the TableWorkspace with the output values and errors.");
}
/// Execute
void EstimatePeakErrors::exec() {
IFunction_sptr function = getProperty("Function");
ITableWorkspace_sptr results = WorkspaceFactory::Instance().createTable("TableWorkspace");
results->addColumn("str", "Parameter");
results->addColumn("double", "Value");
results->addColumn("double", "Error");
auto matrix = function->getCovarianceMatrix();
if (!matrix) {
g_log.warning() << "Function doesn't have covariance matrix.\n";
setProperty("OutputWorkspace", results);
return;
}
auto *peak = dynamic_cast<IPeakFunction *>(function.get());
if (peak) {
GSLMatrix covariance(*matrix);
calculatePeakValues(*peak, *results, covariance, "");
} else {
auto *cf = dynamic_cast<CompositeFunction *>(function.get());
if (cf) {
size_t ip = 0;
for (size_t i = 0; i < cf->nFunctions(); ++i) {
IFunction *fun = cf->getFunction(i).get();
size_t np = fun->nParams();
peak = dynamic_cast<IPeakFunction *>(fun);
if (peak) {
std::string prefix = "f" + std::to_string(i) + ".";
GSLMatrix covariance(*matrix, ip, ip, np, np);
calculatePeakValues(*peak, *results, covariance, prefix);
}
ip += np;
}
} else {
g_log.warning() << "Function has no peaks.\n";
}
}
setProperty("OutputWorkspace", results);
}
} // namespace Algorithms
} // namespace CurveFitting
} // namespace Mantid