Mantid
Loading...
Searching...
No Matches
CalculateIqt.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 +
11#include "MantidAPI/Progress.h"
12#include "MantidHistogramData/HistogramY.h"
14
15#include <boost/numeric/conversion/cast.hpp>
16#include <cmath>
17#include <functional>
18#include <utility>
19
20using namespace Mantid::Algorithms;
21using namespace Mantid::API;
22using namespace Mantid::Kernel;
23using namespace Mantid::HistogramData;
24
25namespace {
26constexpr int DEFAULT_ITERATIONS = 100;
27constexpr int DEFAULT_SEED = 89631139;
28
29std::string createRebinString(double minimum, double maximum, double width) {
30 std::stringstream rebinStream;
31 rebinStream.precision(14);
32 rebinStream << minimum << ", " << width << ", " << maximum;
33 return rebinStream.str();
34}
35
36template <typename Generator>
37void randomizeHistogramWithinError(HistogramY &row, const HistogramE &errors, Generator &generator) {
38 for (auto i = 0u; i < row.size(); ++i)
39 row[i] += generator(errors[i]);
40}
41
42MatrixWorkspace_sptr randomizeWorkspaceWithinError(MatrixWorkspace_sptr workspace, MersenneTwister &mTwister) {
43 auto randomNumberGenerator = [&mTwister](const double error) { return mTwister.nextValue(-error, error); };
44 for (auto i = 0u; i < workspace->getNumberHistograms(); ++i)
45 randomizeHistogramWithinError(workspace->mutableY(i), workspace->e(i), randomNumberGenerator);
46 return workspace;
47}
48
49double standardDeviation(const std::vector<double> &inputValues) {
50 const auto inputSize = boost::numeric_cast<double>(inputValues.size());
51 const auto mean = std::accumulate(inputValues.begin(), inputValues.end(), 0.0) / inputSize;
52 const double sumOfXMinusMeanSquared =
53 std::accumulate(inputValues.cbegin(), inputValues.cend(), 0.,
54 [mean](const auto sum, const auto x) { return sum + std::pow(x - mean, 2); });
55 return sqrt(sumOfXMinusMeanSquared / (inputSize - 1));
56}
57
58std::vector<double> standardDeviationArray(const std::vector<std::vector<double>> &yValues) {
59 std::vector<double> standardDeviations;
60 standardDeviations.reserve(yValues.size());
61 std::transform(yValues.begin(), yValues.end(), std::back_inserter(standardDeviations), standardDeviation);
62 return standardDeviations;
63}
64
70std::vector<std::vector<double>> allYValuesAtIndex(const std::vector<MatrixWorkspace_sptr> &workspaces,
71 const std::size_t index) {
72 std::vector<std::vector<double>> yValues(workspaces[0]->getDimension(0)->getNBins());
73 for (auto &&workspace : workspaces) {
74 const auto values = workspace->y(index).rawData();
75 for (auto j = 0u; j < values.size(); ++j)
76 yValues[j].emplace_back(values[j]);
77 }
78 return yValues;
79}
80
81int getWorkspaceNumberOfHistograms(const MatrixWorkspace_sptr &workspace) {
82 return boost::numeric_cast<int>(workspace->getNumberHistograms());
83}
84
85} // namespace
86
87namespace Mantid::Algorithms {
88
90
91const std::string CalculateIqt::name() const { return "CalculateIqt"; }
92
93int CalculateIqt::version() const { return 1; }
94
95const std::vector<std::string> CalculateIqt::seeAlso() const { return {"TransformToIqt"}; }
96
97const std::string CalculateIqt::category() const { return "Inelastic\\Indirect"; }
98
99const std::string CalculateIqt::summary() const {
100 return "Calculates I(Q,t) from S(Q,w) and computes the errors using a "
101 "monte-carlo routine.";
102}
103
105
106 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Direction::Input),
107 "The name of the sample workspace.");
108 declareProperty(std::make_unique<WorkspaceProperty<>>("ResolutionWorkspace", "", Direction::Input),
109 "The name of the resolution workspace.");
110
111 declareProperty("EnergyMin", -0.5, "Minimum energy for fit. Default = -0.5.");
112 declareProperty("EnergyMax", 0.5, "Maximum energy for fit. Default = 0.5.");
113 declareProperty("EnergyWidth", 0.1, "Width of energy bins for fit.");
114
115 auto positiveInt = std::make_shared<Kernel::BoundedValidator<int>>();
116 positiveInt->setLower(1);
117
118 declareProperty("NumberOfIterations", DEFAULT_ITERATIONS, positiveInt,
119 "Number of randomised simulations within error to run.");
120 declareProperty("SeedValue", DEFAULT_SEED, positiveInt,
121 "Seed the random number generator for monte-carlo error calculation.");
122
123 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output),
124 "The name to use for the output workspace.");
125
126 declareProperty("CalculateErrors", true, "Calculate monte-carlo errors.");
127
128 // option for enforcing the "Divide" operation for SampleWorkspace and ResolutionWorkspace at the last step
129 // default is True
130 declareProperty("EnforceNormalization", true, "Normalization to enforce I(t=0)");
131}
132
134 const auto rebinParams = rebinParamsAsString();
135 const MatrixWorkspace_sptr sampleWorkspace = getProperty("InputWorkspace");
136 MatrixWorkspace_sptr resolution = getProperty("ResolutionWorkspace");
137 bool calculateErrors = getProperty("CalculateErrors");
138 bool enforceNormalization = getProperty("EnforceNormalization");
139 const int nIterations = getProperty("NumberOfIterations");
140 const int seed = getProperty("SeedValue");
141
142 m_sampleIntegral = integration(rebin(sampleWorkspace, rebinParams));
143 m_resolutionIntegral = integration(rebin(resolution, rebinParams));
144
145 resolution = fourierTransform(resolution, rebinParams);
146 if (enforceNormalization) {
147 resolution = divide(resolution, m_resolutionIntegral);
148 }
149
150 auto outputWorkspace = monteCarloErrorCalculation(sampleWorkspace, resolution, rebinParams, seed, calculateErrors,
151 nIterations, enforceNormalization);
152
153 outputWorkspace = replaceSpecialValues(outputWorkspace);
154 setProperty("OutputWorkspace", outputWorkspace);
155}
156
158 const double e_min = getProperty("EnergyMin");
159 const double e_max = getProperty("EnergyMax");
160 const double e_width = getProperty("EnergyWidth");
161 return createRebinString(e_min, e_max, e_width);
162}
163
165 const MatrixWorkspace_sptr &resolution,
166 const std::string &rebinParams, const int seed,
167 const bool calculateErrors, const int nIterations,
168 const bool enforceNormalization) {
169 auto outputWorkspace = calculateIqt(sample, resolution, rebinParams, enforceNormalization);
170 std::vector<MatrixWorkspace_sptr> simulatedWorkspaces;
171 simulatedWorkspaces.reserve(nIterations);
172 simulatedWorkspaces.emplace_back(outputWorkspace);
173
174 MersenneTwister mTwister(seed);
175 if (calculateErrors) {
176 Progress errorCalculationProg(this, 0.0, 1.0, nIterations);
177 PARALLEL_FOR_IF(Kernel::threadSafe(*sample, *resolution))
178 for (auto i = 0; i < nIterations - 1; ++i) {
179 errorCalculationProg.report("Calculating Monte Carlo errors...");
181 auto simulated = doSimulation(sample->clone(), resolution, rebinParams, mTwister, enforceNormalization);
182 PARALLEL_CRITICAL(emplace_back)
183 simulatedWorkspaces.emplace_back(simulated);
185 }
187 return setErrorsToStandardDeviation(simulatedWorkspaces);
188 }
189 return setErrorsToZero(simulatedWorkspaces);
190}
191
192std::map<std::string, std::string> CalculateIqt::validateInputs() {
193 std::map<std::string, std::string> issues;
194 const double eMin = getProperty("EnergyMin");
195 const double eMax = getProperty("EnergyMax");
196 if (eMin > eMax) {
197 auto energy_swapped = "EnergyMin is greater than EnergyMax";
198 issues["EnergyMin"] = energy_swapped;
199 issues["EnergyMax"] = energy_swapped;
200 }
201 return issues;
202}
203
205 auto rebinAlgorithm = createChildAlgorithm("Rebin");
206 rebinAlgorithm->initialize();
207 rebinAlgorithm->setProperty("InputWorkspace", workspace);
208 rebinAlgorithm->setProperty("Params", params);
209 rebinAlgorithm->execute();
210 return rebinAlgorithm->getProperty("OutputWorkspace");
211}
212
214 auto integrationAlgorithm = createChildAlgorithm("Integration");
215 integrationAlgorithm->initialize();
216 integrationAlgorithm->setProperty("InputWorkspace", workspace);
217 integrationAlgorithm->execute();
218 return integrationAlgorithm->getProperty("OutputWorkspace");
219}
220
222 auto pointDataAlgorithm = createChildAlgorithm("ConvertToPointData");
223 pointDataAlgorithm->initialize();
224 pointDataAlgorithm->setProperty("InputWorkspace", workspace);
225 pointDataAlgorithm->execute();
226 return pointDataAlgorithm->getProperty("OutputWorkspace");
227}
228
230 auto FFTAlgorithm = createChildAlgorithm("ExtractFFTSpectrum");
231 FFTAlgorithm->initialize();
232 FFTAlgorithm->setProperty("InputWorkspace", workspace);
233 FFTAlgorithm->setProperty("FFTPart", 2);
234 FFTAlgorithm->execute();
235 return FFTAlgorithm->getProperty("OutputWorkspace");
236}
237
239 const MatrixWorkspace_sptr &rhsWorkspace) {
240 auto divideAlgorithm = createChildAlgorithm("Divide");
241 divideAlgorithm->initialize();
242 divideAlgorithm->setProperty("LHSWorkspace", lhsWorkspace);
243 divideAlgorithm->setProperty("RHSWorkspace", rhsWorkspace);
244 divideAlgorithm->execute();
245 return divideAlgorithm->getProperty("OutputWorkspace");
246}
247
249 auto cropAlgorithm = createChildAlgorithm("CropWorkspace");
250 cropAlgorithm->initialize();
251 cropAlgorithm->setProperty("InputWorkspace", workspace);
252 cropAlgorithm->setProperty("XMax", xMax);
253 cropAlgorithm->execute();
254 return cropAlgorithm->getProperty("OutputWorkspace");
255}
256
258 auto specialValuesAlgorithm = createChildAlgorithm("ReplaceSpecialValues");
259 specialValuesAlgorithm->initialize();
260 specialValuesAlgorithm->setProperty("InputWorkspace", workspace);
261 specialValuesAlgorithm->setProperty("InfinityValue", 0.0);
262 specialValuesAlgorithm->setProperty("BigNumberThreshold", 1.0001);
263 specialValuesAlgorithm->setProperty("NaNValue", 0.0);
264 specialValuesAlgorithm->execute();
265 return specialValuesAlgorithm->getProperty("OutputWorkspace");
266}
267
274
276 const MatrixWorkspace_sptr &resolutionWorkspace,
277 const std::string &rebinParams, const bool enforceNormalization) {
278 workspace = fourierTransform(workspace, rebinParams);
279 if (enforceNormalization) {
281 }
282 return divide(workspace, resolutionWorkspace);
283}
284
286 const std::string &rebinParams, MersenneTwister &mTwister,
287 const bool enforceNormalization) {
288 auto simulatedWorkspace = randomizeWorkspaceWithinError(std::move(sample), mTwister);
289 return calculateIqt(simulatedWorkspace, resolution, rebinParams, enforceNormalization);
290}
291
293CalculateIqt::setErrorsToStandardDeviation(const std::vector<MatrixWorkspace_sptr> &simulatedWorkspaces) {
294 auto outputWorkspace = simulatedWorkspaces.front();
296 for (auto i = 0; i < getWorkspaceNumberOfHistograms(outputWorkspace); ++i) {
298 outputWorkspace->mutableE(i) = standardDeviationArray(allYValuesAtIndex(simulatedWorkspaces, i));
300 }
302 return outputWorkspace;
303}
304
305MatrixWorkspace_sptr CalculateIqt::setErrorsToZero(const std::vector<MatrixWorkspace_sptr> &simulatedWorkspaces) {
306 auto outputWorkspace = simulatedWorkspaces.front();
308 for (auto i = 0; i < getWorkspaceNumberOfHistograms(outputWorkspace); ++i) {
310 outputWorkspace->mutableE(i) = 0;
312 }
314 return outputWorkspace;
315}
316
317} // namespace Mantid::Algorithms
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
double error
IPeaksWorkspace_sptr workspace
std::map< DeltaEMode::Type, std::string > index
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_CRITICAL(name)
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
Helper class for reporting progress from algorithms.
Definition Progress.h:25
A property class for workspaces.
int version() const override
function to return a version of the algorithm, must be overridden in all algorithms
const std::string summary() const override
function returns a summary message that will be displayed in the default GUI, and in the help.
API::MatrixWorkspace_sptr cropWorkspace(const API::MatrixWorkspace_sptr &workspace, const double xMax)
API::MatrixWorkspace_sptr extractFFTSpectrum(const API::MatrixWorkspace_sptr &workspace)
API::MatrixWorkspace_sptr replaceSpecialValues(const API::MatrixWorkspace_sptr &workspace)
const std::vector< std::string > seeAlso() const override
Function to return all of the seeAlso algorithms related to this algorithm.
const std::string category() const override
function to return a category of the algorithm.
API::MatrixWorkspace_sptr rebin(const API::MatrixWorkspace_sptr &workspace, const std::string &params)
API::MatrixWorkspace_sptr calculateIqt(API::MatrixWorkspace_sptr workspace, const API::MatrixWorkspace_sptr &resolutionWorkspace, const std::string &rebinParams, const bool enforceNormalization)
API::MatrixWorkspace_sptr convertToPointData(const API::MatrixWorkspace_sptr &workspace)
void init() override
Virtual method - must be overridden by concrete algorithm.
API::MatrixWorkspace_sptr divide(const API::MatrixWorkspace_sptr &lhsWorkspace, const API::MatrixWorkspace_sptr &rhsWorkspace)
API::MatrixWorkspace_sptr setErrorsToStandardDeviation(const std::vector< API::MatrixWorkspace_sptr > &simulatedWorkspaces)
API::MatrixWorkspace_sptr m_resolutionIntegral
API::MatrixWorkspace_sptr integration(const API::MatrixWorkspace_sptr &workspace)
void exec() override
Virtual method - must be overridden by concrete algorithm.
API::MatrixWorkspace_sptr monteCarloErrorCalculation(const API::MatrixWorkspace_sptr &sample, const API::MatrixWorkspace_sptr &resolution, const std::string &rebinParams, const int seed, const bool calculateErrors, const int nIterations, const bool enforceNormalization)
API::MatrixWorkspace_sptr setErrorsToZero(const std::vector< API::MatrixWorkspace_sptr > &simulatedWorkspaces)
std::map< std::string, std::string > validateInputs() override
Method checking errors on ALL the inputs, before execution.
API::MatrixWorkspace_sptr doSimulation(API::MatrixWorkspace_sptr sample, const API::MatrixWorkspace_sptr &resolution, const std::string &rebinParams, Kernel::MersenneTwister &mTwister, const bool enforceNormalization)
API::MatrixWorkspace_sptr m_sampleIntegral
API::MatrixWorkspace_sptr fourierTransform(API::MatrixWorkspace_sptr workspace, const std::string &rebinParams)
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
This implements the Mersenne Twister 19937 pseudo-random number generator algorithm as a specialzatio...
double nextValue() override
Generate the next random number in the sequence within the given range default range.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
STL namespace.
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54