Mantid
Loading...
Searching...
No Matches
ConvolutionFit.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
13#include "MantidAPI/Progress.h"
14#include "MantidAPI/Run.h"
15#include "MantidAPI/TextAxis.h"
17
21
27
28#include <algorithm>
29#include <cmath>
30#include <utility>
31
32namespace {
33using namespace Mantid::API;
34using namespace Mantid::Kernel;
36
37std::size_t numberOfFunctions(const IFunction_sptr &function, const std::string &functionName);
38
39std::size_t numberOfFunctions(const CompositeFunction_sptr &composite, const std::string &functionName) {
40 std::size_t count = 0;
41 for (auto i = 0u; i < composite->nFunctions(); ++i)
42 count += numberOfFunctions(composite->getFunction(i), functionName);
43 return count;
44}
45
46std::size_t numberOfFunctions(const IFunction_sptr &function, const std::string &functionName) {
47 const auto composite = std::dynamic_pointer_cast<CompositeFunction>(function);
48 if (composite)
49 return numberOfFunctions(composite, functionName);
50 return function->name() == functionName ? 1 : 0;
51}
52
53bool containsFunction(const IFunction_sptr &function, const std::string &functionName);
54
55bool containsFunction(const CompositeFunction_sptr &composite, const std::string &functionName) {
56 for (auto i = 0u; i < composite->nFunctions(); ++i) {
57 if (containsFunction(composite->getFunction(i), functionName))
58 return true;
59 }
60 return false;
61}
62
63bool containsFunction(const IFunction_sptr &function, const std::string &functionName) {
64 const auto composite = std::dynamic_pointer_cast<CompositeFunction>(function);
65 if (function->name() == functionName)
66 return true;
67 else if (composite)
68 return containsFunction(composite, functionName);
69 return false;
70}
71
72template <typename T, typename F, typename... Ts>
73std::vector<T, Ts...> transformVector(const std::vector<T, Ts...> &vec, F const &functor) {
74 auto target = std::vector<T, Ts...>();
75 target.reserve(vec.size());
76 std::transform(vec.begin(), vec.end(), std::back_inserter(target), functor);
77 return target;
78}
79
80template <typename T, typename F, typename... Ts>
81std::vector<T, Ts...> combineVectors(const std::vector<T, Ts...> &vec, const std::vector<T, Ts...> &vec2,
82 F const &combinator) {
83 auto combined = std::vector<T, Ts...>();
84 combined.reserve(vec.size());
85 std::transform(vec.begin(), vec.end(), vec2.begin(), std::back_inserter(combined), combinator);
86 return combined;
87}
88
89template <typename T, typename... Ts>
90std::vector<T, Ts...> divideVectors(const std::vector<T, Ts...> &dividend, const std::vector<T, Ts...> &divisor) {
91 return combineVectors(dividend, divisor, std::divides<T>());
92}
93
94template <typename T, typename... Ts>
95std::vector<T, Ts...> addVectors(const std::vector<T, Ts...> &vec, const std::vector<T, Ts...> &vec2) {
96 return combineVectors(vec, vec2, std::plus<T>());
97}
98
99template <typename T, typename... Ts>
100std::vector<T, Ts...> multiplyVectors(const std::vector<T, Ts...> &vec, const std::vector<T, Ts...> &vec2) {
101 return combineVectors(vec, vec2, std::multiplies<T>());
102}
103
104template <typename T, typename... Ts> std::vector<T, Ts...> squareVector(const std::vector<T, Ts...> &vec) {
105 return transformVector(vec, VectorHelper::Squares<T>());
106}
107
108template <typename T, typename... Ts> std::vector<T, Ts...> squareRootVector(const std::vector<T, Ts...> &vec) {
109 return transformVector(vec, static_cast<T (*)(T)>(sqrt));
110}
111
112IFunction_sptr extractFirstBackground(IFunction_sptr function);
113
114IFunction_sptr extractFirstBackground(const CompositeFunction_sptr &composite) {
115 for (auto i = 0u; i < composite->nFunctions(); ++i) {
116 auto background = extractFirstBackground(composite->getFunction(i));
117 if (background)
118 return background;
119 }
120 return nullptr;
121}
122
123IFunction_sptr extractFirstBackground(IFunction_sptr function) {
124 auto composite = std::dynamic_pointer_cast<CompositeFunction>(function);
125
126 if (composite)
127 return extractFirstBackground(composite);
128 else if (function->category() == "Background")
129 return function;
130 return nullptr;
131}
132
133std::string extractBackgroundType(IFunction_sptr function) {
134 auto background = extractFirstBackground(std::move(function));
135 if (!background)
136 return "None";
137
138 auto backgroundType = background->name();
139 auto position = backgroundType.rfind("Background");
140
141 if (position != std::string::npos)
142 backgroundType = backgroundType.substr(0, position);
143
144 if (background->isFixed(0))
145 backgroundType = "Fixed " + backgroundType;
146 else
147 backgroundType = "Fit " + backgroundType;
148 return backgroundType;
149}
150
151std::vector<std::size_t> searchForFitParameters(const std::string &suffix, const ITableWorkspace_sptr &tableWorkspace) {
152 auto indices = std::vector<std::size_t>();
153
154 for (auto i = 0u; i < tableWorkspace->columnCount(); ++i) {
155 auto name = tableWorkspace->getColumn(i)->name();
156 auto position = name.rfind(suffix);
157 if (position != std::string::npos && position + suffix.size() == name.size())
158 indices.emplace_back(i);
159 }
160 return indices;
161}
162
163std::pair<MantidVec, MantidVec> calculateEISFAndError(const MantidVec &height, const MantidVec &heightError,
164 const MantidVec &amplitude, const MantidVec &amplitudeError) {
165 auto total = addVectors(height, amplitude);
166 auto eisfY = divideVectors(height, total);
167
168 auto heightESq = squareVector(heightError);
169
170 auto ampErrSq = squareVector(amplitudeError);
171 auto totalErr = addVectors(heightESq, ampErrSq);
172
173 auto heightYSq = squareVector(height);
174 auto totalSq = squareVector(total);
175
176 auto errOverTotalSq = divideVectors(totalErr, totalSq);
177 auto heightESqOverYSq = divideVectors(heightESq, heightYSq);
178
179 auto sqrtESqOverYSq = squareRootVector(heightESqOverYSq);
180 auto eisfYSumRoot = multiplyVectors(eisfY, sqrtESqOverYSq);
181
182 return {eisfY, addVectors(eisfYSumRoot, errOverTotalSq)};
183}
184
185void addEISFToTable(ITableWorkspace_sptr &tableWs) {
186 // Get height data from parameter table
187 const auto height = searchForFitParameters("Height", tableWs).at(0);
188 const auto heightErr = searchForFitParameters("Height_Err", tableWs).at(0);
189 const auto heightY = tableWs->getColumn(height)->numeric_fill();
190 const auto heightE = tableWs->getColumn(heightErr)->numeric_fill();
191
192 // Get amplitude column names
193 const auto ampIndices = searchForFitParameters("Amplitude", tableWs);
194 const auto ampErrorIndices = searchForFitParameters("Amplitude_Err", tableWs);
195
196 // For each lorentzian, calculate EISF
197 auto maxSize = ampIndices.size();
198 if (ampErrorIndices.size() > maxSize)
199 maxSize = ampErrorIndices.size();
200
201 for (auto i = 0u; i < maxSize; ++i) {
202 // Get amplitude from column in table workspace
203 auto ampY = tableWs->getColumn(ampIndices[i])->numeric_fill();
204 auto ampErr = tableWs->getColumn(ampErrorIndices[i])->numeric_fill();
205 auto eisfAndError = calculateEISFAndError(heightY, heightE, ampY, ampErr);
206
207 // Append the calculated values to the table workspace
208 auto ampName = tableWs->getColumn(ampIndices[i])->name();
209 auto ampErrorName = tableWs->getColumn(ampErrorIndices[i])->name();
210 auto columnName = ampName.substr(0, (ampName.size() - std::string("Amplitude").size()));
211 columnName += "EISF";
212 auto errorColumnName = ampErrorName.substr(0, (ampErrorName.size() - std::string("Amplitude_Err").size()));
213 errorColumnName += "EISF_Err";
214
215 tableWs->addColumn("double", columnName);
216 tableWs->addColumn("double", errorColumnName);
217 auto maxEisf = eisfAndError.first.size();
218 if (eisfAndError.second.size() > maxEisf) {
219 maxEisf = eisfAndError.second.size();
220 }
221
222 auto col = tableWs->getColumn(columnName);
223 auto errCol = tableWs->getColumn(errorColumnName);
224 for (auto j = 0u; j < maxEisf; j++) {
225 col->cell<double>(j) = eisfAndError.first.at(j);
226 errCol->cell<double>(j) = eisfAndError.second.at(j);
227 }
228 }
229}
230} // namespace
231
233
234using namespace API;
235using namespace Kernel;
236
237//----------------------------------------------------------------------------------------------
238
240template <> const std::string ConvolutionFit<QENSFitSequential>::name() const { return "ConvolutionFitSequential"; }
241
242template <> const std::string ConvolutionFit<QENSFitSimultaneous>::name() const { return "ConvolutionFitSimultaneous"; }
243
244template <typename Base> const std::string ConvolutionFit<Base>::name() const { return "ConvolutionFit"; }
245
247template <typename Base> int ConvolutionFit<Base>::version() const { return 1; }
248
250template <typename Base> const std::string ConvolutionFit<Base>::category() const { return "Workflow\\MIDAS"; }
251
253template <> const std::string ConvolutionFit<QENSFitSequential>::summary() const {
254 return "Performs a sequential fit for a convolution workspace";
255}
256
257template <> const std::string ConvolutionFit<QENSFitSimultaneous>::summary() const {
258 return "Performs a simultaneous fit across convolution workspaces";
259}
260
261template <typename Base> const std::string ConvolutionFit<Base>::summary() const {
262 return "Performs a convolution fit";
263}
264
266template <> const std::vector<std::string> ConvolutionFit<QENSFitSequential>::seeAlso() const {
267 return {"QENSFitSequential"};
268}
269
270template <> const std::vector<std::string> ConvolutionFit<QENSFitSimultaneous>::seeAlso() const {
271 return {"QENSFitSimultaneous"};
272}
273
274template <typename Base> const std::vector<std::string> ConvolutionFit<Base>::seeAlso() const { return {}; }
275
276template <typename Base> std::map<std::string, std::string> ConvolutionFit<Base>::validateInputs() {
277 auto errors = Base::validateInputs();
278 IFunction_sptr function = Base::getProperty("Function");
279 if (!containsFunction(function, "Convolution") || !containsFunction(function, "Resolution"))
280 errors["Function"] = "Function provided does not contain convolution with "
281 "a resolution function.";
282 return errors;
283}
284
285template <typename Base> bool ConvolutionFit<Base>::isFitParameter(const std::string &name) const {
286 bool isBackgroundParameter = name.rfind("A0") != std::string::npos || name.rfind("A1") != std::string::npos;
287 return name.rfind("Centre") == std::string::npos && !isBackgroundParameter;
288}
289
290template <typename Base> bool ConvolutionFit<Base>::throwIfElasticQConversionFails() const { return true; }
291
292template <typename Base>
294 IFunction_sptr function = Base::getProperty("Function");
295 m_deltaUsed = containsFunction(function, "DeltaFunction");
296 if (m_deltaUsed)
297 addEISFToTable(parameterTable);
298 return parameterTable;
299}
300
301template <typename Base> std::map<std::string, std::string> ConvolutionFit<Base>::getAdditionalLogStrings() const {
302 IFunction_sptr function = Base::getProperty("Function");
303 auto logs = Base::getAdditionalLogStrings();
304 logs["delta_function"] = m_deltaUsed ? "true" : "false";
305 logs["background"] = extractBackgroundType(function);
306 return logs;
307}
308
309template <typename Base> std::map<std::string, std::string> ConvolutionFit<Base>::getAdditionalLogNumbers() const {
310 auto logs = Base::getAdditionalLogNumbers();
311 IFunction_sptr function = Base::getProperty("Function");
312 logs["lorentzians"] = boost::lexical_cast<std::string>(numberOfFunctions(function, "Lorentzian"));
313 return logs;
314}
315
316template <typename Base> std::vector<std::string> ConvolutionFit<Base>::getFitParameterNames() const {
317 auto names = Base::getFitParameterNames();
318 if (m_deltaUsed)
319 names.emplace_back("EISF");
320 return names;
321}
322
323// Register the algorithms into the AlgorithmFactory
326
329
332
333} // namespace Mantid::CurveFitting::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
double height
Definition: GetAllEi.cpp:155
double position
Definition: GetAllEi.cpp:154
int count
counter
Definition: Matrix.cpp:37
ConvolutionFit : Performs a QENS convolution fit.
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
Definition: IFunction.h:732
std::shared_ptr< CompositeFunction > CompositeFunction_sptr
shared pointer to the composite function base class
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
Definition: cow_ptr.h:172