Mantid
Loading...
Searching...
No Matches
QENSFitSequential.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 +
8
10#include "MantidAPI/Axis.h"
14#include "MantidAPI/IFunction.h"
20
21#include <boost/cast.hpp>
22#include <boost/regex.hpp>
23
24#include <sstream>
25#include <stdexcept>
26#include <unordered_map>
27#include <utility>
28
29namespace {
30using namespace Mantid::API;
31using namespace Mantid::Kernel;
32
33WorkspaceGroup_sptr getADSGroupWorkspace(const std::string &workspaceName) {
34 return AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(workspaceName);
35}
36
37MatrixWorkspace_sptr getADSMatrixWorkspace(const std::string &workspaceName) {
38 return AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(workspaceName);
39}
40
41MatrixWorkspace_sptr convertSpectrumAxis(const MatrixWorkspace_sptr &inputWorkspace, const std::string &outputName) {
42 auto convSpec = AlgorithmManager::Instance().create("ConvertSpectrumAxis");
43 convSpec->setLogging(false);
44 convSpec->setProperty("InputWorkspace", inputWorkspace);
45 convSpec->setProperty("OutputWorkspace", outputName);
46 convSpec->setProperty("Target", "ElasticQ");
47 convSpec->setProperty("EMode", "Indirect");
48 convSpec->execute();
49 // Attempting to use getProperty("OutputWorkspace") on algorithm results in a
50 // nullptr being returned
51 return getADSMatrixWorkspace(outputName);
52}
53
54MatrixWorkspace_sptr cloneWorkspace(const MatrixWorkspace_sptr &inputWorkspace, const std::string &outputName) {
55 Workspace_sptr workspace = inputWorkspace->clone();
56 AnalysisDataService::Instance().addOrReplace(outputName, workspace);
57 return std::dynamic_pointer_cast<MatrixWorkspace>(workspace);
58}
59
60MatrixWorkspace_sptr convertToElasticQ(const MatrixWorkspace_sptr &inputWorkspace, const std::string &outputName,
61 bool doThrow) {
62 auto axis = inputWorkspace->getAxis(1);
63 if (axis->isSpectra())
64 return convertSpectrumAxis(inputWorkspace, outputName);
65 else if (axis->isNumeric()) {
66 if (axis->unit()->unitID() != "MomentumTransfer" && doThrow)
67 throw std::runtime_error("Input must have axis values of Q");
68 return cloneWorkspace(inputWorkspace, outputName);
69 } else if (doThrow)
70 throw std::runtime_error("Input workspace must have either spectra or numeric axis.");
71 return cloneWorkspace(inputWorkspace, outputName);
72}
73
74struct ElasticQAppender {
75 explicit ElasticQAppender(std::vector<MatrixWorkspace_sptr> &elasticInput)
76 : m_elasticInput(elasticInput), m_converted() {}
77
78 void operator()(const MatrixWorkspace_sptr &workspace, const std::string &outputBase, bool doThrow) {
79 auto it = m_converted.find(workspace.get());
80 if (it != m_converted.end())
81 m_elasticInput.emplace_back(it->second);
82 else {
83 auto elasticQ = convertToElasticQ(workspace, outputBase + std::to_string(m_converted.size() + 1), doThrow);
84 m_elasticInput.emplace_back(elasticQ);
85 m_converted[workspace.get()] = elasticQ;
86 }
87 }
88
89private:
90 std::vector<MatrixWorkspace_sptr> &m_elasticInput;
91 std::unordered_map<MatrixWorkspace *, MatrixWorkspace_sptr> m_converted;
92};
93
94std::vector<MatrixWorkspace_sptr> convertToElasticQ(const std::vector<MatrixWorkspace_sptr> &workspaces,
95 const std::string &outputBaseName, bool doThrow) {
96 std::vector<MatrixWorkspace_sptr> elasticInput;
97 auto appendElasticQWorkspace = ElasticQAppender(elasticInput);
98 appendElasticQWorkspace(workspaces[0], outputBaseName, doThrow);
99
100 for (auto i = 1u; i < workspaces.size(); ++i)
101 appendElasticQWorkspace(workspaces[i], outputBaseName, doThrow);
102 return elasticInput;
103}
104
105void extractFunctionNames(const CompositeFunction_sptr &composite, std::vector<std::string> &names) {
106 for (auto i = 0u; i < composite->nFunctions(); ++i)
107 names.emplace_back(composite->getFunction(i)->name());
108}
109
110void extractFunctionNames(const IFunction_sptr &function, std::vector<std::string> &names) {
111 auto composite = std::dynamic_pointer_cast<CompositeFunction>(function);
112 if (composite)
113 extractFunctionNames(composite, names);
114 else
115 names.emplace_back(function->name());
116}
117
118void extractConvolvedNames(const IFunction_sptr &function, std::vector<std::string> &names);
119
120void extractConvolvedNames(const CompositeFunction_sptr &composite, std::vector<std::string> &names) {
121 for (auto i = 0u; i < composite->nFunctions(); ++i)
122 extractConvolvedNames(composite->getFunction(i), names);
123}
124
125void extractConvolvedNames(const IFunction_sptr &function, std::vector<std::string> &names) {
126 auto composite = std::dynamic_pointer_cast<CompositeFunction>(function);
127 if (composite) {
128 if (composite->name() == "Convolution" && composite->nFunctions() > 1 &&
129 composite->getFunction(0)->name() == "Resolution")
130 extractFunctionNames(composite->getFunction(1), names);
131 else
132 extractConvolvedNames(composite, names);
133 }
134}
135
136std::string constructInputString(const MatrixWorkspace_sptr &workspace, int specMin, int specMax) {
137 std::ostringstream input;
138 for (auto i = specMin; i < specMax + 1; ++i)
139 input << workspace->getName() << ",i" << std::to_string(i) << ";";
140 return input.str();
141}
142
143std::vector<std::string> extractWorkspaceNames(const std::string &input) {
144 std::vector<std::string> v;
145 boost::regex reg("([^,;]+),");
146 std::for_each(boost::sregex_token_iterator(input.begin(), input.end(), reg, 1), boost::sregex_token_iterator(),
147 [&v](const std::string &name) { v.emplace_back(name); });
148 return v;
149}
150
151std::vector<std::string> getUniqueWorkspaceNames(const std::string &input) {
152 auto workspaceNames = extractWorkspaceNames(input);
153 std::set<std::string> uniqueNames(workspaceNames.begin(), workspaceNames.end());
154 workspaceNames.assign(uniqueNames.begin(), uniqueNames.end());
155 return workspaceNames;
156}
157
158std::vector<MatrixWorkspace_sptr> extractWorkspaces(const std::string &input) {
159 const auto workspaceNames = extractWorkspaceNames(input);
160
161 std::vector<MatrixWorkspace_sptr> workspaces;
162
163 std::transform(workspaceNames.begin(), workspaceNames.end(), std::back_inserter(workspaces),
164 [](const auto &wsName) { return getADSMatrixWorkspace(wsName); });
165
166 return workspaces;
167}
168
169std::vector<std::string> getSpectra(const std::string &input) {
170 std::vector<std::string> spectra;
171 boost::regex reg(",[i|sp](0|[1-9][0-9]*);?");
172 std::copy(boost::sregex_token_iterator(input.begin(), input.end(), reg, 1), boost::sregex_token_iterator(),
173 std::back_inserter(spectra));
174 return spectra;
175}
176
177std::vector<std::string> getSuffices(const std::string &input) {
178 std::vector<std::string> suffices;
179 boost::regex reg(",[i|sp](0|[1-9][0-9]*);?");
180 std::copy(boost::sregex_token_iterator(input.begin(), input.end(), reg, 0), boost::sregex_token_iterator(),
181 std::back_inserter(suffices));
182 return suffices;
183}
184
185std::string replaceWorkspaces(const std::string &input, const std::vector<MatrixWorkspace_sptr> &workspaces) {
186 const auto suffices = getSuffices(input);
187 std::stringstream newInput;
188 for (auto i = 0u; i < workspaces.size(); ++i)
189 newInput << workspaces[i]->getName() << suffices[i];
190 return newInput.str();
191}
192
193void renameWorkspace(const Algorithm_sptr &renamer, const Workspace_sptr &workspace, const std::string &newName) {
194 renamer->setProperty("InputWorkspace", workspace);
195 renamer->setProperty("OutputWorkspace", newName);
196 renamer->executeAsChildAlg();
197}
198
199void deleteTemporaries(const Algorithm_sptr &deleter, const std::string &base) {
200 auto name = base + std::to_string(1);
201 std::size_t i = 2;
202
203 while (AnalysisDataService::Instance().doesExist(name)) {
204 deleter->setProperty("Workspace", name);
205 deleter->executeAsChildAlg();
206 name = base + std::to_string(i++);
207 }
208}
209
210std::string shortParameterName(const std::string &longName) {
211 return longName.substr(longName.rfind('.') + 1, longName.size());
212}
213
214bool containsMultipleData(const std::vector<MatrixWorkspace_sptr> &workspaces) {
215 const auto &first = workspaces.front();
216 return std::any_of(workspaces.cbegin(), workspaces.cend(),
217 [&first](const auto &workspace) { return workspace != first; });
218}
219
220template <typename F, typename Renamer>
221void renameWorkspacesWith(const WorkspaceGroup_sptr &groupWorkspace, F const &getName, Renamer const &renamer) {
222 std::unordered_map<std::string, std::size_t> nameCount;
223 for (auto i = 0u; i < groupWorkspace->size(); ++i) {
224 const auto name = getName(i);
225 auto count = nameCount.find(name);
226
227 if (count == nameCount.end()) {
228 renamer(groupWorkspace->getItem(i), name);
229 nameCount[name] = 1;
230 } else
231 renamer(groupWorkspace->getItem(i), name + "(" + std::to_string(++count->second) + ")");
232 }
233}
234
235template <typename F>
236void renameWorkspacesInQENSFit(Algorithm *qensFit, const Algorithm_sptr &renameAlgorithm,
237 WorkspaceGroup_sptr outputGroup, std::string const &outputBaseName,
238 const F &getNameSuffix) {
239 Progress renamerProg(qensFit, 0.98, 1.0, outputGroup->size() + 1);
240 renamerProg.report("Renaming group workspaces...");
241
242 auto getName = [&](std::size_t i) { return outputBaseName + "_" + getNameSuffix(i); };
243
244 auto renamer = [&](const Workspace_sptr &workspace, const std::string &name) {
245 renameWorkspace(renameAlgorithm, workspace, name);
246 renamerProg.report("Renamed workspace in group.");
247 };
248 renameWorkspacesWith(outputGroup, getName, renamer);
249}
250
251std::vector<std::size_t> createDatasetGrouping(const std::vector<MatrixWorkspace_sptr> &workspaces,
252 std::size_t maximum) {
253 std::vector<std::size_t> grouping;
254 grouping.emplace_back(0);
255 for (auto i = 1u; i < workspaces.size(); ++i) {
256 if (workspaces[i] != workspaces[i - 1])
257 grouping.emplace_back(i);
258 }
259 grouping.emplace_back(maximum);
260 return grouping;
261}
262
263std::vector<std::size_t> createDatasetGrouping(const std::vector<MatrixWorkspace_sptr> &workspaces) {
264 return createDatasetGrouping(workspaces, workspaces.size());
265}
266
267WorkspaceGroup_sptr createGroup(const std::vector<MatrixWorkspace_sptr> &workspaces) {
269 for (auto &&workspace : workspaces)
271 return group;
272}
273
274WorkspaceGroup_sptr runParameterProcessingWithGrouping(Algorithm &processingAlgorithm,
275 const std::vector<std::size_t> &grouping) {
276 std::vector<MatrixWorkspace_sptr> results;
277 results.reserve(grouping.size() - 1);
278 for (auto i = 0u; i < grouping.size() - 1; ++i) {
279 processingAlgorithm.setProperty("StartRowIndex", static_cast<int>(grouping[i]));
280 processingAlgorithm.setProperty("EndRowIndex", static_cast<int>(grouping[i + 1]) - 1);
281 processingAlgorithm.setProperty("OutputWorkspace", "__Result");
282 processingAlgorithm.execute();
283 results.emplace_back(processingAlgorithm.getProperty("OutputWorkspace"));
284 }
285 return createGroup(results);
286}
287
288} // namespace
289
291
292using namespace API;
293using namespace Kernel;
294
295// Register the algorithm into the AlgorithmFactory
296DECLARE_ALGORITHM(QENSFitSequential)
297
298
299const std::string QENSFitSequential::name() const { return "QENSFitSequential"; }
300
302int QENSFitSequential::version() const { return 1; }
303
305const std::string QENSFitSequential::category() const { return "Workflow\\MIDAS"; }
306
308const std::string QENSFitSequential::summary() const { return "Performs a sequential fit for QENS data"; }
309
311const std::vector<std::string> QENSFitSequential::seeAlso() const {
312 return {"ConvolutionFitSequential", "IqtFitSequential", "PlotPeakByLogValue"};
313}
314
315void QENSFitSequential::init() {
316 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Direction::Input, PropertyMode::Optional),
317 "The input workspace for the fit. This property will be ignored if "
318 "'Input' is provided.");
319
320 auto boundedV = std::make_shared<BoundedValidator<int>>();
321 boundedV->setLower(0);
322
323 declareProperty("SpecMin", 0, boundedV,
324 "The first spectrum to be used in "
325 "the fit. Spectra values can not be "
326 "negative. This property will be ignored if 'Input' is provided.",
328
329 declareProperty("SpecMax", 0, boundedV,
330 "The final spectrum to be used in "
331 "the fit. Spectra values can not be "
332 "negative. This property will be ignored if 'Input' is provided.",
334
335 declareProperty("Input", "",
336 "A list of sources of data to fit. \n"
337 "Sources can be either workspace names or file names followed optionally "
338 "by a list of spectra/workspace-indices \n"
339 "or values using the notation described in the description section of "
340 "the help page.");
341
342 std::vector<std::string> unitOptions = UnitFactory::Instance().getKeys();
343 unitOptions.emplace_back("");
344 declareProperty("ResultXAxisUnit", "MomentumTransfer", std::make_shared<StringListValidator>(unitOptions),
345 "The unit to assign to the X Axis of the result workspace, "
346 "defaults to MomentumTransfer");
347
348 declareProperty(std::make_unique<WorkspaceProperty<WorkspaceGroup>>("OutputWorkspace", "", Direction::Output),
349 "The output result workspace(s)");
350 declareProperty(std::make_unique<WorkspaceProperty<ITableWorkspace>>("OutputParameterWorkspace", "",
352 "The output parameter workspace");
353 declareProperty(std::make_unique<WorkspaceProperty<WorkspaceGroup>>("OutputWorkspaceGroup", "", Direction::Output,
355 "The output group workspace");
356
357 declareProperty(std::make_unique<FunctionProperty>("Function", Direction::InOut),
358 "The fitting function, common for all workspaces in the input.");
359 declareProperty("LogName", "axis-1",
360 "Name of the log value to plot the "
361 "parameters against. Default: use spectra "
362 "numbers.");
363 declareProperty(std::make_unique<ArrayProperty<double>>("StartX"), "A value of x in, or on the low x "
364 "boundary of, the first bin to "
365 "include in\n"
366 "the fit (default lowest value of x)");
367 declareProperty(std::make_unique<ArrayProperty<double>>("EndX"), "A value in, or on the high x boundary "
368 "of, the last bin the fitting range\n"
369 "(default the highest value of x)");
370
371 declareProperty("PassWSIndexToFunction", false,
372 "For each spectrum in Input pass its workspace index to all "
373 "functions that"
374 "have attribute WorkspaceIndex.");
375
376 declareProperty("Minimizer", "Levenberg-Marquardt",
377 "Minimizer to use for fitting. Minimizers available are "
378 "'Levenberg-Marquardt', 'Simplex', 'FABADA',\n"
379 "'Conjugate gradient (Fletcher-Reeves imp.)', 'Conjugate "
380 "gradient (Polak-Ribiere imp.)' and 'BFGS'");
381
382 const std::vector<std::string> costFuncOptions = CostFunctionFactory::Instance().getKeys();
383 declareProperty("CostFunction", "Least squares", std::make_shared<StringListValidator>(costFuncOptions),
384 "Cost functions to use for fitting. Cost functions available "
385 "are 'Least squares' and 'Ignore positive peaks'",
387
388 declareProperty("MaxIterations", 500, boundedV,
389 "Stop after this number of iterations if a good fit is not "
390 "found");
391 declareProperty("PeakRadius", 0,
392 "A value of the peak radius the peak functions should use. A "
393 "peak radius defines an interval on the x axis around the "
394 "centre of the peak where its values are calculated. Values "
395 "outside the interval are not calculated and assumed zeros."
396 "Numerically the radius is a whole number of peak widths "
397 "(FWHM) that fit into the interval on each side from the "
398 "centre. The default value of 0 means the whole x axis.");
399
400 declareProperty("ExtractMembers", false,
401 "If true, then each member of the fit will be extracted"
402 ", into their own workspace. These workspaces will have a histogram"
403 " for each spectrum (Q-value) and will be grouped.",
405
406 declareProperty("OutputCompositeMembers", false,
407 "If true and CreateOutput is true then the value of each "
408 "member of a Composite Function is also output.");
409
410 declareProperty(std::make_unique<Kernel::PropertyWithValue<bool>>("ConvolveMembers", false),
411 "If true and OutputCompositeMembers is true members of any "
412 "Convolution are output convolved\n"
413 "with corresponding resolution");
414
415 const std::array<std::string, 2> evaluationTypes = {{"CentrePoint", "Histogram"}};
416 declareProperty("EvaluationType", "CentrePoint",
418 "The way the function is evaluated: CentrePoint or Histogram.", Kernel::Direction::Input);
419
420 const std::array<std::string, 2> fitTypes = {{"Sequential", "Individual"}};
421 declareProperty("FitType", "Sequential", Kernel::IValidator_sptr(new Kernel::ListValidator<std::string>(fitTypes)),
422 "Defines the way of setting initial values. If set to Sequential every "
423 "next fit starts with parameters returned by the previous fit. If set to "
424 "Individual each fit starts with the same initial values defined in "
425 "the Function property. Allowed values: [Sequential, Individual]",
427
428 declareProperty(std::make_unique<ArrayProperty<double>>("Exclude", ""),
429 "A list of pairs of real numbers, defining the regions to "
430 "exclude from the fit.");
431
432 declareProperty(std::make_unique<ArrayProperty<std::string>>("ExcludeMultiple", ""),
433 "A list of Exclusion ranges, defining the regions to "
434 "exclude from the fit for each spectra. Must have the "
435 "same number of sets as the number of the spectra.");
436
437 declareProperty("IgnoreInvalidData", false, "Flag to ignore infinities, NaNs and data with zero errors.");
438
439 declareProperty("OutputFitStatus", false,
440 "Flag to output fit status information, which consists of the fit "
441 "OutputStatus and the OutputChiSquared");
442}
443
444std::map<std::string, std::string> QENSFitSequential::validateInputs() {
445 std::map<std::string, std::string> errors;
446
447 if (getPropertyValue("Input").empty()) {
448 MatrixWorkspace_sptr workspace = getProperty("InputWorkspace");
449 if (!workspace)
450 errors["InputWorkspace"] = "No input string or input workspace was provided.";
451
452 const int specMin = getProperty("SpecMin");
453 const int specMax = getProperty("SpecMax");
454 if (specMin > specMax)
455 errors["SpecMin"] = "SpecMin must be less than or equal to SpecMax.";
456 }
457 const auto inputWorkspaces = getWorkspaces();
458 const auto workspaces = convertInputToElasticQ(inputWorkspaces);
459 const auto inputString = getInputString(workspaces);
460 const auto spectra = getSpectra(inputString);
461 const std::vector<double> startX = getProperty("StartX");
462 const std::vector<double> endX = getProperty("EndX");
463 if (startX.size() != endX.size()) {
464 errors["StartX"] = "StartX have the same size as EndX";
465 } else if (startX.size() != spectra.size() && startX.size() != 1) {
466 errors["StartX"] = "StartX must be a single value or have a value for each spectra.";
467 } else {
468 for (size_t i = 0; i < startX.size(); i++) {
469 if (startX[i] >= endX[i]) {
470 errors["StartX"] = "StartX must be less than EndX";
471 }
472 }
473 }
474 return errors;
475}
476
477void QENSFitSequential::exec() {
478 const auto outputBaseName = getOutputBaseName();
479
480 if (getPropertyValue("OutputParameterWorkspace").empty())
481 setProperty("OutputParameterWorkspace", outputBaseName + "_Parameters");
482
483 if (getPropertyValue("OutputWorkspaceGroup").empty())
484 setProperty("OutputWorkspaceGroup", outputBaseName + "_Workspaces");
485
486 const auto inputWorkspaces = getWorkspaces();
487 const auto workspaces = convertInputToElasticQ(inputWorkspaces);
488 const auto inputString = getInputString(workspaces);
489 const auto spectra = getSpectra(inputString);
490
491 if (workspaces.empty() || spectra.empty() || (workspaces.size() > 1 && workspaces.size() != spectra.size()))
492 throw std::invalid_argument("A malformed input string was provided.");
493
494 const auto parameterWs = processParameterTable(performFit(inputString, outputBaseName));
495 const auto resultWs = processIndirectFitParameters(parameterWs, getDatasetGrouping(workspaces));
496 const auto groupWs = getADSGroupWorkspace(outputBaseName + "_Workspaces");
497 AnalysisDataService::Instance().addOrReplace(getPropertyValue("OutputWorkspace"), resultWs);
498
499 if (containsMultipleData(workspaces)) {
500 const auto inputStringProp = getPropertyValue("Input");
501 renameWorkspaces(groupWs, spectra, outputBaseName, "_Workspace", extractWorkspaceNames(inputStringProp));
502 auto inputWorkspaceNames = getUniqueWorkspaceNames(inputStringProp);
503 renameWorkspaces(resultWs, std::vector<std::string>(inputWorkspaceNames.size(), ""), outputBaseName, "_Result",
504 inputWorkspaceNames);
505 } else {
506 renameWorkspaces(groupWs, spectra, outputBaseName, "_Workspace");
507 renameWorkspaces(resultWs, std::vector<std::string>({""}), outputBaseName, "_Result");
508 }
509
510 copyLogs(resultWs, workspaces);
511
512 const bool doExtractMembers = getProperty("ExtractMembers");
513 if (doExtractMembers)
514 extractMembers(groupWs, workspaces, outputBaseName + "_Members");
515
516 renameGroupWorkspace("__PDF_Workspace", spectra, outputBaseName, "_PDF");
517
518 deleteTemporaryWorkspaces(outputBaseName);
519
520 size_t itter = 0;
521 for (auto results : resultWs->getAllItems()) {
522 addAdditionalLogs(results);
523 std::string resultWsName = results->getName();
524 auto endLoc = resultWsName.find("__Result");
525 std::string baseName = resultWsName.erase(endLoc);
526 for (auto &workspace : groupWs->getAllItems()) {
527 const std::string wsName = workspace->getName();
528 if (wsName.find(baseName) != wsName.npos) {
529 copyLogs(std::dynamic_pointer_cast<MatrixWorkspace>(results), groupWs);
531 itter++;
532 }
533 }
534 addFitRangeLogs(results, itter - 1);
535 }
536
537 setProperty("OutputWorkspace", resultWs);
538 setProperty("OutputParameterWorkspace", parameterWs);
539 // Copy the group to prevent the ADS having two entries for one workspace
540 auto outGroupWs = WorkspaceGroup_sptr(new WorkspaceGroup);
541 for (auto item : groupWs->getAllItems()) {
542 outGroupWs->addWorkspace(item);
543 }
544 setProperty("OutputWorkspaceGroup", outGroupWs);
545}
546
547std::map<std::string, std::string> QENSFitSequential::getAdditionalLogStrings() const {
548 const bool convolve = getProperty("ConvolveMembers");
549 auto fitProgram = name();
550 fitProgram = fitProgram.substr(0, fitProgram.rfind("Sequential"));
551
552 auto logs = std::map<std::string, std::string>();
553 logs["sample_filename"] = getPropertyValue("InputWorkspace");
554 logs["convolve_members"] = convolve ? "true" : "false";
555 logs["fit_program"] = fitProgram;
556 logs["fit_mode"] = "Sequential";
557 return logs;
558}
559
560std::map<std::string, std::string> QENSFitSequential::getAdditionalLogNumbers() const {
561 return std::map<std::string, std::string>();
562}
563
564void QENSFitSequential::addAdditionalLogs(const WorkspaceGroup_sptr &resultWorkspace) {
565 for (const auto &workspace : *resultWorkspace)
567}
568
569void QENSFitSequential::addAdditionalLogs(const Workspace_sptr &resultWorkspace) {
570 auto logAdder = createChildAlgorithm("AddSampleLog", -1.0, -1.0, false);
571 logAdder->setProperty("Workspace", resultWorkspace);
572 Progress logAdderProg(this, 0.99, 1.00, 6);
573 logAdder->setProperty("LogType", "String");
574 for (const auto &log : getAdditionalLogStrings()) {
575 logAdder->setProperty("LogName", log.first);
576 logAdder->setProperty("LogText", log.second);
577 logAdder->executeAsChildAlg();
578 logAdderProg.report("Add text logs");
579 }
580 logAdderProg.report("Add number logs");
581 for (const auto &log : getAdditionalLogNumbers()) {
582 logAdder->setProperty("LogName", log.first);
583 logAdder->setProperty("LogText", log.second);
584 logAdder->executeAsChildAlg();
585 logAdderProg.report("Add number logs");
586 }
587}
588
589void QENSFitSequential::addFitRangeLogs(const API::Workspace_sptr &resultWorkspace, size_t itter) {
590 auto logAdder = createChildAlgorithm("AddSampleLog", -1.0, -1.0, false);
591 logAdder->setProperty("Workspace", resultWorkspace);
592 Progress logAdderProg(this, 0.99, 1.00, 6);
593 logAdder->setProperty("LogType", "String");
594
595 std::vector<double> startX = getProperty("StartX");
596 logAdder->setProperty("LogName", "start_x");
597 if (startX.size() == 1) {
598 logAdder->setProperty("LogText", std::to_string(startX[0]));
599 } else {
600 logAdder->setProperty("LogText", std::to_string(startX[itter]));
601 }
602 logAdder->executeAsChildAlg();
603
604 std::vector<double> endX = getProperty("EndX");
605 logAdder->setProperty("LogName", "end_x");
606 if (endX.size() == 1) {
607 logAdder->setProperty("LogText", std::to_string(endX[0]));
608 } else {
609 logAdder->setProperty("LogText", std::to_string(endX[itter]));
610 }
611 logAdder->executeAsChildAlg();
612}
613
614std::string QENSFitSequential::getOutputBaseName() const {
615 const auto base = getPropertyValue("OutputWorkspace");
616 const auto position = base.rfind("_Result");
617 if (position != std::string::npos)
618 return base.substr(0, position);
619 return base;
620}
621
622bool QENSFitSequential::throwIfElasticQConversionFails() const { return false; }
623
624bool QENSFitSequential::isFitParameter(const std::string & /*unused*/) const { return true; }
625
626std::vector<std::string> QENSFitSequential::getFitParameterNames() const {
627 const auto uniqueParameters = getUniqueParameterNames();
628 std::vector<std::string> parameters;
629 parameters.reserve(uniqueParameters.size());
630 std::copy_if(uniqueParameters.begin(), uniqueParameters.end(), std::back_inserter(parameters),
631 [&](const std::string &parameter) { return isFitParameter(parameter); });
632 return parameters;
633}
634
635std::set<std::string> QENSFitSequential::getUniqueParameterNames() const {
636 IFunction_sptr function = getProperty("Function");
637 std::set<std::string> nameSet;
638 for (auto i = 0u; i < function->nParams(); ++i)
639 nameSet.insert(shortParameterName(function->parameterName(i)));
640 return nameSet;
641}
642
643void QENSFitSequential::deleteTemporaryWorkspaces(const std::string &outputBaseName) {
644 auto deleter = createChildAlgorithm("DeleteWorkspace", -1.0, -1.0, false);
645 deleter->setProperty("Workspace", outputBaseName + "_NormalisedCovarianceMatrices");
646 deleter->executeAsChildAlg();
647
648 deleter->setProperty("Workspace", outputBaseName + "_Parameters");
649 deleter->executeAsChildAlg();
650
651 deleteTemporaries(deleter, getTemporaryName());
652}
653
654std::vector<std::size_t>
655QENSFitSequential::getDatasetGrouping(const std::vector<API::MatrixWorkspace_sptr> &workspaces) const {
656 if (getPropertyValue("Input").empty()) {
657 int maximum = getProperty("SpecMax");
658 return createDatasetGrouping(workspaces, static_cast<std::size_t>(maximum + 1));
659 }
660 return createDatasetGrouping(workspaces);
661}
662
663WorkspaceGroup_sptr QENSFitSequential::processIndirectFitParameters(const ITableWorkspace_sptr &parameterWorkspace,
664 const std::vector<std::size_t> &grouping) {
665 std::string const columnX = getProperty("LogName");
666 std::string const xAxisUnit = getProperty("ResultXAxisUnit");
667 auto pifp = createChildAlgorithm("ProcessIndirectFitParameters", 0.91, 0.95, false);
668 pifp->setAlwaysStoreInADS(false);
669 pifp->setProperty("InputWorkspace", parameterWorkspace);
670 pifp->setProperty("ColumnX", columnX);
671 pifp->setProperty("XAxisUnit", xAxisUnit);
672 pifp->setProperty("ParameterNames", getFitParameterNames());
673 pifp->setProperty("IncludeChiSquared", true);
674 return runParameterProcessingWithGrouping(*pifp, grouping);
675}
676
677ITableWorkspace_sptr QENSFitSequential::processParameterTable(ITableWorkspace_sptr parameterTable) {
678 return parameterTable;
679}
680
681void QENSFitSequential::renameWorkspaces(WorkspaceGroup_sptr outputGroup, std::vector<std::string> const &spectra,
682 std::string const &outputBaseName, std::string const &endOfSuffix,
683 std::vector<std::string> const &inputWorkspaceNames) {
684 auto rename = createChildAlgorithm("RenameWorkspace", -1.0, -1.0, false);
685 const auto getNameSuffix = [&](std::size_t i) {
686 std::string workspaceName = inputWorkspaceNames[i] + "_" + spectra[i] + endOfSuffix;
687 return workspaceName;
688 };
689 return renameWorkspacesInQENSFit(this, rename, std::move(outputGroup), outputBaseName, getNameSuffix);
690}
691
692void QENSFitSequential::renameWorkspaces(WorkspaceGroup_sptr outputGroup, std::vector<std::string> const &spectra,
693 std::string const &outputBaseName, std::string const &endOfSuffix) {
694 auto rename = createChildAlgorithm("RenameWorkspace", -1.0, -1.0, false);
695 auto getNameSuffix = [&](std::size_t i) { return spectra[i] + endOfSuffix; };
696 return renameWorkspacesInQENSFit(this, rename, std::move(outputGroup), outputBaseName, getNameSuffix);
697}
698
699void QENSFitSequential::renameGroupWorkspace(std::string const &currentName, std::vector<std::string> const &spectra,
700 std::string const &outputBaseName, std::string const &endOfSuffix) {
701 if (AnalysisDataService::Instance().doesExist(currentName)) {
702 auto const group = getADSGroupWorkspace(currentName);
703 if (group)
704 renameWorkspaces(group, spectra, outputBaseName, endOfSuffix);
705 }
706}
707
708ITableWorkspace_sptr QENSFitSequential::performFit(const std::string &input, const std::string &output) {
709 const std::vector<double> exclude = getProperty("Exclude");
710 const std::vector<std::string> excludeMultiple = getProperty("ExcludeMultiple");
711 const bool convolveMembers = getProperty("ConvolveMembers");
712 const bool outputCompositeMembers = getProperty("OutputCompositeMembers");
713 const bool passWsIndex = getProperty("PassWSIndexToFunction");
714 const bool ignoreInvalidData = getProperty("IgnoreInvalidData");
715 const bool outputFitStatus = getProperty("OutputFitStatus");
716 IFunction_sptr inputFunction = getProperty("Function");
717
718 // Run PlotPeaksByLogValue
719 auto plotPeaks = createChildAlgorithm("PlotPeakByLogValue", 0.05, 0.90, true);
720 plotPeaks->setProperty("Input", input);
721 plotPeaks->setProperty("OutputWorkspace", output);
722 plotPeaks->setProperty("Function", inputFunction);
723 plotPeaks->setProperty("StartX", getPropertyValue("StartX"));
724 plotPeaks->setProperty("EndX", getPropertyValue("EndX"));
725 plotPeaks->setProperty("Exclude", exclude);
726 plotPeaks->setProperty("ExcludeMultiple", excludeMultiple);
727 plotPeaks->setProperty("IgnoreInvalidData", ignoreInvalidData);
728 plotPeaks->setProperty("FitType", "Sequential");
729 plotPeaks->setProperty("CreateOutput", true);
730 plotPeaks->setProperty("OutputCompositeMembers", outputCompositeMembers);
731 plotPeaks->setProperty("ConvolveMembers", convolveMembers);
732 plotPeaks->setProperty("MaxIterations", getPropertyValue("MaxIterations"));
733 plotPeaks->setProperty("Minimizer", getPropertyValue("Minimizer"));
734 plotPeaks->setProperty("PassWSIndexToFunction", passWsIndex);
735 plotPeaks->setProperty("PeakRadius", getPropertyValue("PeakRadius"));
736 plotPeaks->setProperty("LogValue", getPropertyValue("LogName"));
737 plotPeaks->setProperty("EvaluationType", getPropertyValue("EvaluationType"));
738 plotPeaks->setProperty("FitType", getPropertyValue("FitType"));
739 plotPeaks->setProperty("CostFunction", getPropertyValue("CostFunction"));
740 plotPeaks->setProperty("OutputFitStatus", outputFitStatus);
741
742 plotPeaks->executeAsChildAlg();
743
744 if (outputFitStatus) {
745 declareProperty(std::make_unique<ArrayProperty<std::string>>("OutputStatus", Direction::Output));
746 declareProperty(std::make_unique<ArrayProperty<double>>("OutputChiSquared", Direction::Output));
747 std::vector<std::string> outputStatus = plotPeaks->getProperty("OutputStatus");
748 std::vector<double> outputChiSquared = plotPeaks->getProperty("OutputChiSquared");
749 setProperty("OutputStatus", outputStatus);
750 setProperty("OutputChiSquared", outputChiSquared);
751 }
752
753 return plotPeaks->getProperty("OutputWorkspace");
754}
755
756std::string QENSFitSequential::getInputString(const std::vector<MatrixWorkspace_sptr> &workspaces) const {
757 const auto inputString = getPropertyValue("Input");
758 if (!inputString.empty())
759 return replaceWorkspaces(inputString, workspaces);
760 return constructInputString(workspaces[0], getProperty("SpecMin"), getProperty("SpecMax"));
761}
762
763std::vector<MatrixWorkspace_sptr> QENSFitSequential::getWorkspaces() const {
764 const auto inputString = getPropertyValue("Input");
765 if (!inputString.empty()) {
766 auto workspaceList = extractWorkspaces(inputString);
767 return workspaceList;
768 }
769 // The static_cast should not be necessary but it is required to avoid a
770 // "internal compiler error: segmentation fault" when compiling with gcc
771 // and std=c++1z
772 return std::vector<MatrixWorkspace_sptr>{static_cast<MatrixWorkspace_sptr>(getProperty("InputWorkspace"))};
773}
774
775std::vector<MatrixWorkspace_sptr>
776QENSFitSequential::convertInputToElasticQ(const std::vector<MatrixWorkspace_sptr> &workspaces) const {
777 return convertToElasticQ(workspaces, getTemporaryName(), throwIfElasticQConversionFails());
778}
779
780void QENSFitSequential::extractMembers(const WorkspaceGroup_sptr &resultGroupWs,
781 const std::vector<API::MatrixWorkspace_sptr> &workspaces,
782 const std::string &outputWsName) {
783 std::vector<std::string> workspaceNames;
784 std::transform(workspaces.begin(), workspaces.end(), std::back_inserter(workspaceNames),
785 [](const API::MatrixWorkspace_sptr &workspace) { return workspace->getName(); });
786
787 auto extractAlgorithm = extractMembersAlgorithm(resultGroupWs, outputWsName);
788 extractAlgorithm->setProperty("InputWorkspaces", workspaceNames);
789 extractAlgorithm->execute();
790}
791
792void QENSFitSequential::copyLogs(const WorkspaceGroup_sptr &resultWorkspaces,
793 std::vector<MatrixWorkspace_sptr> const &workspaces) {
794 for (auto const &resultWorkspace : *resultWorkspaces)
795 copyLogs(resultWorkspace, workspaces);
796}
797
798void QENSFitSequential::copyLogs(const Workspace_sptr &resultWorkspace,
799 std::vector<MatrixWorkspace_sptr> const &workspaces) {
800 auto logCopier = createChildAlgorithm("CopyLogs", -1.0, -1.0, false);
801 logCopier->setProperty("OutputWorkspace", resultWorkspace->getName());
802 for (auto const &workspace : workspaces) {
803 logCopier->setProperty("InputWorkspace", workspace);
804 logCopier->executeAsChildAlg();
805 }
806}
807
808void QENSFitSequential::copyLogs(const MatrixWorkspace_sptr &resultWorkspace, const WorkspaceGroup_sptr &resultGroup) {
809 for (auto const &workspace : *resultGroup)
810 copyLogs(resultWorkspace, workspace);
811}
812
813void QENSFitSequential::copyLogs(const MatrixWorkspace_sptr &resultWorkspace, const Workspace_sptr &resultGroup) {
814 auto logCopier = createChildAlgorithm("CopyLogs", -1.0, -1.0, false);
815 logCopier->setProperty("InputWorkspace", resultWorkspace);
816 logCopier->setProperty("OutputWorkspace", resultGroup->getName());
817 logCopier->executeAsChildAlg();
818}
819
820IAlgorithm_sptr QENSFitSequential::extractMembersAlgorithm(const WorkspaceGroup_sptr &resultGroupWs,
821 const std::string &outputWsName) const {
822 const bool convolved = getProperty("ConvolveMembers");
823 std::vector<std::string> convolvedMembers;
824 IFunction_sptr function = getProperty("Function");
825
826 if (convolved)
827 extractConvolvedNames(function, convolvedMembers);
828
829 auto extractMembersAlg = AlgorithmManager::Instance().create("ExtractQENSMembers");
830 extractMembersAlg->setProperty("ResultWorkspace", resultGroupWs);
831 extractMembersAlg->setProperty("OutputWorkspace", outputWsName);
832 extractMembersAlg->setProperty("RenameConvolvedMembers", convolved);
833 extractMembersAlg->setProperty("ConvolvedMembers", convolvedMembers);
834 return extractMembersAlg;
835}
836
837std::string QENSFitSequential::getTemporaryName() const { return "__" + name() + "_ws"; }
838
839} // namespace Mantid::CurveFitting::Algorithms
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
double position
Definition GetAllEi.cpp:154
IPeaksWorkspace_sptr workspace
int count
counter
Definition Matrix.cpp:37
void addWorkspace(WorkspaceGroup &self, const boost::python::object &pyobj)
std::string getName(const IMDDimension &self)
Base class from which all concrete algorithm classes should be derived.
Definition Algorithm.h:76
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
bool execute() override final
The actions to be performed by the algorithm on a dataset.
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) override
Create a Child Algorithm.
Kernel::IPropertyManager::TypedValue getProperty(const std::string &name) const override
Get the property held by this object.
std::string getPropertyValue(const std::string &name) const override
Get the property held by this object.
Base MatrixWorkspace Abstract Class.
Helper class for reporting progress from algorithms.
Definition Progress.h:25
Class to hold a set of workspaces.
A property class for workspaces.
QENSFitSequential - Performs a sequential QENS fit.
std::vector< std::size_t > getDatasetGrouping(const std::vector< API::MatrixWorkspace_sptr > &workspaces) const
std::vector< API::MatrixWorkspace_sptr > convertInputToElasticQ(const std::vector< API::MatrixWorkspace_sptr > &workspaces) const
virtual std::map< std::string, std::string > getAdditionalLogNumbers() const
API::IAlgorithm_sptr extractMembersAlgorithm(const API::WorkspaceGroup_sptr &resultGroupWs, const std::string &outputWsName) const
void addFitRangeLogs(const API::Workspace_sptr &resultWorkspace, size_t itter)
void renameWorkspaces(API::WorkspaceGroup_sptr outputGroup, std::vector< std::string > const &spectra, std::string const &outputBaseName, std::string const &endOfSuffix)
std::string getInputString(const std::vector< API::MatrixWorkspace_sptr > &workspaces) const
virtual std::vector< std::string > getFitParameterNames() const
virtual std::vector< API::MatrixWorkspace_sptr > getWorkspaces() const
void renameGroupWorkspace(std::string const &currentName, std::vector< std::string > const &spectra, std::string const &outputBaseName, std::string const &endOfSuffix)
void copyLogs(const API::WorkspaceGroup_sptr &resultWorkspaces, std::vector< API::MatrixWorkspace_sptr > const &workspaces)
virtual std::map< std::string, std::string > getAdditionalLogStrings() const
API::WorkspaceGroup_sptr processIndirectFitParameters(const API::ITableWorkspace_sptr &parameterWorkspace, const std::vector< std::size_t > &grouping)
virtual API::ITableWorkspace_sptr processParameterTable(API::ITableWorkspace_sptr parameterTable)
void deleteTemporaryWorkspaces(const std::string &outputBaseName)
const std::string name() const override
Algorithms name for identification.
API::ITableWorkspace_sptr performFit(const std::string &input, const std::string &output)
void addAdditionalLogs(const API::WorkspaceGroup_sptr &resultWorkspace)
void extractMembers(const API::WorkspaceGroup_sptr &resultGroupWs, const std::vector< API::MatrixWorkspace_sptr > &workspaces, const std::string &outputWsName)
Support for a property that holds an array of values.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
ListValidator is a validator that requires the value of a property to be one of a defined list of pos...
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
The concrete, templated class for properties.
std::shared_ptr< IAlgorithm > IAlgorithm_sptr
shared pointer to Mantid::API::IAlgorithm
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
void renameWorkspacesInQENSFit(Algorithm *qensFit, IAlgorithm_sptr renameAlgorithm, const WorkspaceGroup_sptr &outputGroup, std::string const &outputBaseName, std::function< std::string(std::size_t)> const &getNameSuffix)
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
Definition IFunction.h:743
void renameWorkspacesWith(const WorkspaceGroup_sptr &groupWorkspace, std::function< std::string(std::size_t)> const &getName, std::function< void(Workspace_sptr, const std::string &)> const &renamer)
void renameWorkspace(const IAlgorithm_sptr &renamer, const Workspace_sptr &workspace, const std::string &newName)
std::shared_ptr< Algorithm > Algorithm_sptr
Typedef for a shared pointer to an Algorithm.
Definition Algorithm.h:52
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
bool containsMultipleData(const std::vector< MatrixWorkspace_sptr > &workspaces)
std::shared_ptr< CompositeFunction > CompositeFunction_sptr
shared pointer to the composite function base class
std::shared_ptr< IValidator > IValidator_sptr
A shared_ptr to an IValidator.
Definition IValidator.h:26
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ InOut
Both an input & output workspace.
Definition Property.h:55
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54