Mantid
Loading...
Searching...
No Matches
PlotPeakByLogValue.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#include <algorithm>
9#include <boost/algorithm/string/replace.hpp>
10#include <boost/lexical_cast.hpp>
11#include <cmath>
12#include <fstream>
13#include <sstream>
14#include <vector>
15
24#include "MantidAPI/IFunction.h"
26#include "MantidAPI/Progress.h"
27#include "MantidAPI/Run.h"
28#include "MantidAPI/TableRow.h"
29#include "MantidAPI/TextAxis.h"
38
39namespace {
40Mantid::Kernel::Logger g_log("PlotPeakByLogValue");
41}
42
44
45using namespace Kernel;
46using namespace API;
47
48// Register the class into the algorithm factory
49DECLARE_ALGORITHM(PlotPeakByLogValue)
50
51
54void PlotPeakByLogValue::init() {
55 declareProperty("Input", "", std::make_shared<MandatoryValidator<std::string>>(),
56 "A list of sources of data to fit. \n"
57 "Sources can be either workspace names or file names followed optionally "
58 "by a list of spectra/workspace-indices \n"
59 "or values using the notation described in the description section of "
60 "the help page.");
61
62 declareProperty("Spectrum", 1,
63 "Set a spectrum to fit. \n"
64 "However, if spectra lists (or workspace-indices/values "
65 "lists) are specified in the Input parameter string these "
66 "take precedence.");
67 declareProperty("WorkspaceIndex", 0,
68 "Set a workspace-index to fit (alternative option to Spectrum). "
69 "However, if spectra lists (or workspace-indices/values lists) are "
70 "specified in the Input parameter string, \n"
71 "or the Spectrum parameter integer, these take precedence.");
72 declareProperty(std::make_unique<WorkspaceProperty<ITableWorkspace>>("OutputWorkspace", "", Direction::Output),
73 "The output TableWorkspace");
74 declareProperty(std::make_unique<API::FunctionProperty>("Function", Direction::InOut),
75 "Parameters defining the fitting function and its initial values");
76 declareProperty("LogValue", "",
77 "Name of the log value to plot the "
78 "parameters against. Default: use spectra "
79 "numbers.");
80 declareProperty(std::make_unique<ArrayProperty<double>>("StartX"), "A value of x in, or on the low x "
81 "boundary of, the first bin to "
82 "include in\n"
83 "the fit (default lowest value of x)");
84 declareProperty(std::make_unique<ArrayProperty<double>>("EndX"), "A value in, or on the high x boundary "
85 "of, the last bin the fitting range\n"
86 "(default the highest value of x)");
87
88 std::vector<std::string> fitOptions{"Sequential", "Individual"};
89 declareProperty("FitType", "Sequential", std::make_shared<StringListValidator>(fitOptions),
90 "Defines the way of setting initial values. \n"
91 "If set to 'Sequential' every next fit starts with "
92 "parameters returned by the previous fit. \n"
93 "If set to 'Individual' each fit starts with the same "
94 "initial values defined in the Function property.");
95
96 declareProperty("PassWSIndexToFunction", false,
97 "For each spectrum in Input pass its workspace index to all "
98 "functions that"
99 "have attribute WorkspaceIndex.");
100
101 declareProperty("Minimizer", "Levenberg-Marquardt",
102 "Minimizer to use for fitting. Minimizers available are "
103 "'Levenberg-Marquardt', 'Simplex', 'FABADA',\n"
104 "'Conjugate gradient (Fletcher-Reeves imp.)', 'Conjugate "
105 "gradient (Polak-Ribiere imp.)' and 'BFGS'");
106
107 std::vector<std::string> costFuncOptions = CostFunctionFactory::Instance().getKeys();
108 declareProperty("CostFunction", "Least squares", std::make_shared<StringListValidator>(costFuncOptions),
109 "Cost functions to use for fitting. Cost functions available "
110 "are 'Least squares' and 'Ignore positive peaks'",
112
113 declareProperty("MaxIterations", 500,
114 "Stop after this number of iterations if a good fit is not "
115 "found");
116 declareProperty("PeakRadius", 0,
117 "A value of the peak radius the peak functions should use. A "
118 "peak radius defines an interval on the x axis around the "
119 "centre of the peak where its values are calculated. Values "
120 "outside the interval are not calculated and assumed zeros."
121 "Numerically the radius is a whole number of peak widths "
122 "(FWHM) that fit into the interval on each side from the "
123 "centre. The default value of 0 means the whole x axis.");
124
125 declareProperty("CreateOutput", false,
126 "Set to true to create output "
127 "workspaces with the results of the "
128 "fit(default is false).");
129
130 declareProperty("OutputCompositeMembers", false,
131 "If true and CreateOutput is true then the value of each "
132 "member of a Composite Function is also output.");
133
134 declareProperty("AppendIdxToOutputName", false,
135 "If true and CreateOutput is true then append either spectrum index, workspace index, or numeric "
136 "axis value depending on the input format.");
137
138 declareProperty(
139 "Output2D", false,
140 "If true and CreateOutput is true then create a new output of the result table in workspace 2D format.");
141
142 declareProperty(std::make_unique<Kernel::PropertyWithValue<bool>>("ConvolveMembers", false),
143 "If true and OutputCompositeMembers is true members of any "
144 "Convolution are output convolved\n"
145 "with corresponding resolution");
146
147 std::array<std::string, 2> evaluationTypes = {{"CentrePoint", "Histogram"}};
148 declareProperty("EvaluationType", "CentrePoint",
150 "The way the function is evaluated: CentrePoint or Histogram.", Kernel::Direction::Input);
151
152 declareProperty(std::make_unique<ArrayProperty<double>>("Exclude", ""),
153 "A list of pairs of real numbers, defining the regions to "
154 "exclude from the fit for all spectra.");
155
156 declareProperty(std::make_unique<ArrayProperty<std::string>>("ExcludeMultiple", ""),
157 "A list of Exclusion ranges, defining the regions to "
158 "exclude from the fit for each spectra. Must have the "
159 "same number of sets as the number of the spectra.");
160
161 declareProperty("IgnoreInvalidData", false, "Flag to ignore infinities, NaNs and data with zero errors.");
162
163 declareProperty("OutputFitStatus", false,
164 "Flag to output fit status information which consists of the fit "
165 "OutputStatus and the OutputChiSquared");
166}
167
168std::map<std::string, std::string> PlotPeakByLogValue::validateInputs() {
169 std::map<std::string, std::string> errors;
170 std::string inputList = getPropertyValue("Input");
171 int default_wi = getProperty("WorkspaceIndex");
172 int default_spec = getProperty("Spectrum");
173 const std::vector<InputSpectraToFit> wsNames = makeNames(inputList, default_wi, default_spec);
174 for (const auto &wsName : wsNames) {
175 if (wsName.wsIdx == -1 && wsName.spectrumNum == -1 && wsName.numericValue == -1) {
176 errors["InvalidRange"] = "Range is out of bounds. Please make sure the selected range is within the boundaries.";
177 }
178 }
179 std::vector<std::string> excludeList = getProperty("ExcludeMultiple");
180 if (!excludeList.empty() && excludeList.size() != wsNames.size()) {
181 errors["ExcludeMultiple"] = "ExcludeMultiple must be the same size has the number of spectra.";
182 }
183 return errors;
184}
185
189void PlotPeakByLogValue::exec() {
190
191 // Create a list of the input workspace
192 std::string inputList = getPropertyValue("Input");
193 int default_wi = getProperty("WorkspaceIndex");
194 int default_spec = getProperty("Spectrum");
195 const std::vector<InputSpectraToFit> wsNames = makeNames(inputList, default_wi, default_spec);
196
197 std::string logName = getProperty("LogValue");
198 bool individual = getPropertyValue("FitType") == "Individual";
199 bool passWSIndexToFunction = getProperty("PassWSIndexToFunction");
200 bool createFitOutput = getProperty("CreateOutput");
201 bool appendIdxToOutput = getProperty("AppendIdxToOutputName");
202 bool output2D = getProperty("Output2D");
203 bool outputCompositeMembers = getProperty("OutputCompositeMembers");
204 bool outputConvolvedMembers = getProperty("ConvolveMembers");
205 bool outputFitStatus = getProperty("OutputFitStatus");
206 m_baseName = getPropertyValue("OutputWorkspace");
207 std::vector<double> startX = getProperty("StartX");
208 std::vector<double> endX = getProperty("EndX");
209 std::vector<std::string> exclude = getExclude(wsNames.size());
210
211 bool isDataName = false; // if true first output column is of type string and
212 // is the data source name
213 // Create an instance of the fitting function to obtain the names of fitting
214 // parameters
215 IFunction_sptr inputFunction = getProperty("Function");
216 if (!inputFunction) {
217 throw std::invalid_argument("Fitting function failed to initialize");
218 }
219 bool isMultiDomainFunction = std::dynamic_pointer_cast<MultiDomainFunction>(inputFunction) != nullptr;
220
221 IFunction_sptr ifunSingle = isMultiDomainFunction ? inputFunction->getFunction(0) : inputFunction;
222
223 // for inidividual fittings store the initial parameters
224 std::vector<double> initialParams(ifunSingle->nParams());
225 if (individual) {
226 for (size_t i = 0; i < initialParams.size(); ++i) {
227 initialParams[i] = ifunSingle->getParameter(i);
228 }
229 }
230 ITableWorkspace_sptr result = createResultsTable(logName, ifunSingle, isDataName);
231
232 std::vector<std::string> fitNames;
233 std::vector<std::string> parameterNames;
234 std::vector<std::string> covarianceNames;
235 std::vector<MatrixWorkspace_sptr> fitWorkspaces;
236 std::vector<ITableWorkspace_sptr> parameterWorkspaces;
237 std::vector<ITableWorkspace_sptr> covarianceWorkspaces;
238
239 std::vector<std::string> fitStatus;
240 std::vector<double> fitChiSquared;
241 if (outputFitStatus) {
242 declareProperty(std::make_unique<ArrayProperty<std::string>>("OutputStatus", Direction::Output));
243 declareProperty(std::make_unique<ArrayProperty<double>>("OutputChiSquared", Direction::Output));
244 fitStatus.reserve(wsNames.size());
245 fitChiSquared.reserve(wsNames.size());
246 }
247
248 double dProg = 1. / static_cast<double>(wsNames.size());
249 double Prog = 0.;
250 for (int i = 0; i < static_cast<int>(wsNames.size()); ++i) {
251 InputSpectraToFit data = wsNames[i];
252
253 if (!data.ws) {
254 g_log.warning() << "Cannot access workspace " << data.name << '\n';
255 continue;
256 }
257
258 if (data.wsIdx < 0) {
259 g_log.warning() << "Zero spectra selected for fitting in workspace " << wsNames[i].name << '\n';
260 continue;
261 }
262
263 IFunction_sptr ifun =
264 setupFunction(individual, passWSIndexToFunction, inputFunction, initialParams, isMultiDomainFunction, i, data);
265 std::shared_ptr<Algorithm> fit;
266 if (startX.size() == 0) {
267 fit = runSingleFit(createFitOutput, outputCompositeMembers, outputConvolvedMembers, appendIdxToOutput, ifun, data,
268 EMPTY_DBL(), EMPTY_DBL(), exclude[i]);
269 } else if (startX.size() == 1) {
270 fit = runSingleFit(createFitOutput, outputCompositeMembers, outputConvolvedMembers, appendIdxToOutput, ifun, data,
271 startX[0], endX[0], exclude[i]);
272 } else {
273 fit = runSingleFit(createFitOutput, outputCompositeMembers, outputConvolvedMembers, appendIdxToOutput, ifun, data,
274 startX[i], endX[i], exclude[i]);
275 }
276
277 ifun = fit->getProperty("Function");
278 double chi2 = fit->getProperty("OutputChi2overDoF");
279
280 if (createFitOutput) {
281 if (appendIdxToOutput) {
282 fitNames.emplace_back(fit->getPropertyValue("OutputWorkspace"));
283 parameterNames.emplace_back(fit->getPropertyValue("OutputParameters"));
284 covarianceNames.emplace_back(fit->getPropertyValue("OutputNormalisedCovarianceMatrix"));
285 } else {
286 fitWorkspaces.emplace_back(fit->getProperty("OutputWorkspace"));
287 parameterWorkspaces.emplace_back(fit->getProperty("OutputParameters"));
288 covarianceWorkspaces.emplace_back(fit->getProperty("OutputNormalisedCovarianceMatrix"));
289 }
290 }
291 if (outputFitStatus) {
292 fitStatus.push_back(fit->getProperty("OutputStatus"));
293 fitChiSquared.push_back(chi2);
294 }
295
296 g_log.debug() << "Fit result " << fit->getPropertyValue("OutputStatus") << ' ' << chi2 << '\n';
297
298 // Find the log value: it is either a log-file value or
299 // simply the workspace number
300 double logValue = calculateLogValue(logName, data);
301 appendTableRow(isDataName, result, ifun, data, logValue, chi2);
302
303 Prog += dProg;
304 std::string current = std::to_string(i);
305 progress(Prog, ("Fitting Workspace: (" + current + ") - "));
307 }
308
309 if (outputFitStatus) {
310 setProperty("OutputStatus", fitStatus);
311 setProperty("OutputChiSquared", fitChiSquared);
312 }
313
314 if (createFitOutput) {
315 if (output2D) {
316 groupResParams(parameterWorkspaces, parameterNames);
317 }
318
319 if (appendIdxToOutput) {
320 finaliseOutputWorkspacesWithAppend(fitNames, parameterNames, covarianceNames, wsNames);
321 } else {
322 finaliseOutputWorkspaces(fitWorkspaces, parameterWorkspaces, covarianceWorkspaces);
323 }
324 }
325
327}
328
329void PlotPeakByLogValue::groupResParams(const std::vector<ITableWorkspace_sptr> &paramsWs,
330 const std::vector<std::string> &paramsNames) {
331 std::vector<ITableWorkspace_sptr> params;
332
333 if (paramsWs.size() > 0) {
334 params = paramsWs;
335 } else if (paramsNames.size() > 0) {
336 std::transform(paramsNames.cbegin(), paramsNames.cend(), std::back_inserter(params),
337 [](std::string name) { return AnalysisDataService::Instance().retrieveWS<ITableWorkspace>(name); });
338 } else {
339 return;
340 }
341
342 std::map<std::string, std::vector<double>> parameterValues;
343 std::map<std::string, std::vector<double>> parameterErrors;
344
345 for (size_t i = 0; i < params.size(); ++i) {
346 for (size_t rowNo = 0; rowNo < params[i]->rowCount(); ++rowNo) {
347 TableRow row = params[i]->getRow(rowNo);
348
349 auto paramName = row.String(0);
350 auto value = row.Double(1);
351 auto error = row.Double(2);
352
353 parameterValues[paramName].push_back(value);
354 parameterErrors[paramName].push_back(error);
355 }
356 }
357
358 if (!parameterValues.empty()) {
359 size_t numParams = parameterValues.size();
360 size_t numDataPoints = parameterValues.begin()->second.size();
361
362 auto matrixWs =
363 Mantid::API::WorkspaceFactory::Instance().create("Workspace2D", numParams, numDataPoints, numDataPoints);
364
365 auto textAxis = std::make_unique<Mantid::API::TextAxis>(numParams);
366
367 size_t spectrumIndex = 0;
368 for (const auto &paramPair : parameterValues) {
369 const std::string &paramName = paramPair.first;
370 const std::vector<double> &values = paramPair.second;
371 const std::vector<double> &errors = parameterErrors[paramName];
372
373 auto &xData = matrixWs->mutableX(spectrumIndex);
374 for (size_t i = 0; i < numDataPoints; ++i) {
375 xData[i] = static_cast<double>(i);
376 }
377
378 auto &yData = matrixWs->mutableY(spectrumIndex);
379 std::copy(values.begin(), values.end(), yData.begin());
380
381 auto &eData = matrixWs->mutableE(spectrumIndex);
382 std::copy(errors.begin(), errors.end(), eData.begin());
383
384 textAxis->setLabel(spectrumIndex, paramName);
385
386 ++spectrumIndex;
387 }
388
389 matrixWs->replaceAxis(1, std::move(textAxis));
390 matrixWs->setTitle("Grouped Parameter Results");
391 matrixWs->getAxis(0)->setUnit("Empty");
392 matrixWs->setYUnitLabel("Parameter Value");
393
394 std::string outputWsName = this->m_baseName + "_ws";
395 Mantid::API::AnalysisDataService::Instance().addOrReplace(outputWsName, matrixWs);
396 }
397}
398
399IFunction_sptr PlotPeakByLogValue::setupFunction(bool individual, bool passWSIndexToFunction,
400 const IFunction_sptr &inputFunction,
401 const std::vector<double> &initialParams, bool isMultiDomainFunction,
402 int i, const InputSpectraToFit &data) const {
403 IFunction_sptr ifun;
404 if (isMultiDomainFunction) {
405 ifun = inputFunction->getFunction(i);
406 if (!individual && i != 0) {
407 IFunction_sptr prevFunction = inputFunction->getFunction(i - 1);
408 for (size_t k = 0; k < ifun->nParams(); ++k) {
409 ifun->setParameter(k, prevFunction->getParameter(k));
410 }
411 }
412
413 } else {
414 ifun = inputFunction;
415 }
416 if (passWSIndexToFunction) {
417 this->setWorkspaceIndexAttribute(ifun, data.wsIdx);
418 }
419
420 if (individual && !isMultiDomainFunction) {
421 for (size_t k = 0; k < initialParams.size(); ++k) {
422 ifun->setParameter(k, initialParams[k]);
423 }
424 }
425 return ifun;
426}
427
428void PlotPeakByLogValue::finaliseOutputWorkspaces(const std::vector<MatrixWorkspace_sptr> &fitWorkspaces,
429 const std::vector<ITableWorkspace_sptr> &paramsWorkspaces,
430 const std::vector<ITableWorkspace_sptr> &covarianceWorkspaces) {
431
432 // collect output of fit for each spectrum into workspace groups
433 WorkspaceGroup_sptr covarianceGroup = std::make_shared<WorkspaceGroup>();
434 for (auto const &workspace : covarianceWorkspaces)
435 covarianceGroup->addWorkspace(workspace);
436 AnalysisDataService::Instance().addOrReplace(this->m_baseName + "_NormalisedCovarianceMatrices", covarianceGroup);
437
438 WorkspaceGroup_sptr parameterGroup = std::make_shared<WorkspaceGroup>();
439 for (auto const &workspace : paramsWorkspaces)
440 parameterGroup->addWorkspace(workspace);
441 AnalysisDataService::Instance().addOrReplace(this->m_baseName + "_Parameters", parameterGroup);
442
443 WorkspaceGroup_sptr fitGroup = std::make_shared<WorkspaceGroup>();
444 for (auto const &workspace : fitWorkspaces)
445 fitGroup->addWorkspace(workspace);
446 AnalysisDataService::Instance().addOrReplace(this->m_baseName + "_Workspaces", fitGroup);
447
448 for (auto &minimizerWorkspace : this->m_minimizerWorkspaces) {
449 const std::string paramName = minimizerWorkspace.first;
450 auto groupAlg = this->createChildAlgorithm("GroupWorkspaces");
451 groupAlg->initialize();
452 groupAlg->setProperty("InputWorkspaces", minimizerWorkspace.second);
453 groupAlg->setProperty("OutputWorkspace", this->m_baseName + "_" + paramName);
454 groupAlg->execute();
455 }
456}
457
458void PlotPeakByLogValue::finaliseOutputWorkspacesWithAppend(const std::vector<std::string> &fitNames,
459 const std::vector<std::string> &paramsNames,
460 const std::vector<std::string> &covarianceNames,
461 const std::vector<InputSpectraToFit> &wsNames) {
462
463 std::string range;
464
465 auto start = wsNames[0];
466 auto end = wsNames[wsNames.size() - 1];
467 if (start.spectrumNum != -1) {
468 range = wsNames.size() > 1 && start.spectrumNum != end.spectrumNum
469 ? std::format("sp{:g}-{:g}", start.spectrumNum, end.spectrumNum)
470 : std::format("sp{:g}", start.spectrumNum);
471 } else if (start.numericValue != -1) {
472 range = wsNames.size() > 1 && start.numericValue != end.numericValue
473 ? std::format("v{:g}-{:g}", start.numericValue, end.numericValue)
474 : std::format("v{:g}", start.numericValue);
475 } else {
476 range = wsNames.size() > 1 && start.wsIdx != end.wsIdx ? std::format("i{}-{}", start.wsIdx, end.wsIdx)
477 : "i" + std::to_string(start.wsIdx);
478 }
479
480 // collect output of fit for each spectrum into workspace groups
481 auto const groupAlg = this->createChildAlgorithm("GroupWorkspaces");
482 std::vector<std::pair<std::vector<std::string>, std::string>> groupingOperations = {
483 {covarianceNames, std::format("{}_{}_NormalisedCovarianceMatrices", m_baseName, range)},
484 {paramsNames, std::format("{}_{}_Parameters", m_baseName, range)},
485 {fitNames, std::format("{}_{}_Workspaces", m_baseName, range)}};
486
487 for (const auto &[inputWorkspaces, outputName] : groupingOperations) {
488 groupAlg->initialize();
489 groupAlg->setProperty("InputWorkspaces", inputWorkspaces);
490 groupAlg->setProperty("OutputWorkspace", outputName);
491 groupAlg->setAlwaysStoreInADS(true);
492 groupAlg->execute();
493 }
494}
495
496void PlotPeakByLogValue::finaliseMinimizerOutput() {
497 for (auto &minimizerWorkspace : this->m_minimizerWorkspaces) {
498 const std::string paramName = minimizerWorkspace.first;
499 auto groupAlg = this->createChildAlgorithm("GroupWorkspaces");
500 groupAlg->initialize();
501 groupAlg->setProperty("InputWorkspaces", minimizerWorkspace.second);
502 groupAlg->setProperty("OutputWorkspace", this->m_baseName + "_" + paramName);
503 groupAlg->execute();
504 }
505}
506
507void PlotPeakByLogValue::appendTableRow(
508 bool isDataName, ITableWorkspace_sptr &result, const IFunction_sptr &ifun, const InputSpectraToFit &data,
509 double logValue, double chi2) const { // Extract the fitted parameters and put them into the result table
510 TableRow row = result->appendRow();
511 if (isDataName) {
512 row << data.name;
513 } else {
514 row << logValue;
515 }
516
517 auto p = std::dynamic_pointer_cast<API::CompositeFunction>(ifun);
518 if (p) {
519 for (size_t i = 0; i < p->nFunctions(); ++i) {
520 auto f = ifun->getFunction(i);
521 for (size_t j = 0; j < f->nParams(); ++j) {
522 row << p->getParameter(i, j) << p->getError(i, j);
523 }
524
525 /* Output integrated intensity */
526 auto intensity_handle = std::dynamic_pointer_cast<API::IPeakFunction>(f);
527 if (intensity_handle) {
528 row << intensity_handle->intensity() << intensity_handle->intensityError();
529 }
530 }
531 }
532
533 else {
534 for (size_t iPar = 0; iPar < ifun->nParams(); ++iPar) {
535 row << ifun->getParameter(iPar) << ifun->getError(iPar);
536 }
537
538 /* Output integrated intensity */
539 auto intensity_handle = std::dynamic_pointer_cast<API::IPeakFunction>(ifun);
540 if (intensity_handle) {
541 row << intensity_handle->intensity() << intensity_handle->intensityError();
542 }
543 }
544
545 row << chi2;
546}
547
548ITableWorkspace_sptr PlotPeakByLogValue::createResultsTable(const std::string &logName,
549 const IFunction_sptr &ifunSingle, bool &isDataName) {
550 ITableWorkspace_sptr result = WorkspaceFactory::Instance().createTable("TableWorkspace");
551 if (logName == "SourceName") {
552 result->addColumn("str", "SourceName");
553 isDataName = true;
554 } else if (logName.empty()) {
555 auto col = result->addColumn("double", "axis-1");
556 col->setPlotType(1); // X-values inplots
557 } else {
558 auto col = result->addColumn("double", logName);
559 col->setPlotType(1); // X-values inplots
560 }
561
562 auto p = std::dynamic_pointer_cast<API::CompositeFunction>(ifunSingle);
563 if (p) {
564 for (size_t i = 0; i < p->nFunctions(); ++i) {
565 auto f = ifunSingle->getFunction(i);
566 for (size_t j = 0; j < f->nParams(); ++j) {
567 result->addColumn("double", p->parameterName(i, j));
568 result->addColumn("double", p->parameterName(i, j) + "_Err");
569 }
570
571 auto intensity_handle = std::dynamic_pointer_cast<API::IPeakFunction>(f);
572 if (intensity_handle) {
573 result->addColumn("double", "f" + std::to_string(i) + ".Integrated Intensity");
574 result->addColumn("double", "f" + std::to_string(i) + ".Integrated Intensity_Err");
575 }
576 }
577 }
578
579 else {
580 for (size_t iPar = 0; iPar < ifunSingle->nParams(); ++iPar) {
581 result->addColumn("double", ifunSingle->parameterName(iPar));
582 result->addColumn("double", ifunSingle->parameterName(iPar) + "_Err");
583 }
584
585 auto intensity_handle = std::dynamic_pointer_cast<API::IPeakFunction>(ifunSingle);
586 if (intensity_handle) {
587 result->addColumn("double", "Integrated Intensity");
588 result->addColumn("double", "Integrated Intensity_Err");
589 }
590 }
591
592 result->addColumn("double", "Chi_squared");
593
594 this->setProperty("OutputWorkspace", result);
595 return result;
596}
597
598std::shared_ptr<Algorithm> PlotPeakByLogValue::runSingleFit(bool createFitOutput, bool outputCompositeMembers,
599 bool outputConvolvedMembers, bool appendIdx,
600 const IFunction_sptr &ifun, const InputSpectraToFit &data,
601 double startX, double endX, const std::string &exclude) {
602 g_log.debug() << "Fitting " << data.ws->getName() << " index " << data.wsIdx << " with \n";
603 g_log.debug() << ifun->asString() << '\n';
604
605 std::string wsBaseName;
606
607 if (createFitOutput) {
608 wsBaseName = data.name;
609 if (appendIdx) {
610 if (data.spectrumNum != -1) {
611 wsBaseName += "_" + std::format("sp{:g}", data.spectrumNum);
612 } else if (data.numericValue != -1) {
613 wsBaseName += "_" + std::format("v{:g}", data.numericValue);
614 } else {
615 wsBaseName += "_i" + std::to_string(data.wsIdx);
616 }
617 }
618 }
619
620 bool histogramFit = this->getPropertyValue("EvaluationType") == "Histogram";
621 bool ignoreInvalidData = this->getProperty("IgnoreInvalidData");
622
623 // Fit the function
624 auto fit = this->createChildAlgorithm("Fit");
625 fit->initialize();
626 fit->setPropertyValue("EvaluationType", this->getPropertyValue("EvaluationType"));
627 fit->setProperty("Function", ifun);
628 fit->setProperty("InputWorkspace", data.ws);
629 fit->setProperty("WorkspaceIndex", data.wsIdx);
630 fit->setProperty("StartX", startX);
631 fit->setProperty("EndX", endX);
632 fit->setProperty("IgnoreInvalidData", ignoreInvalidData);
633 fit->setPropertyValue("Minimizer", this->getMinimizerString(data.name, std::to_string(data.wsIdx)));
634 fit->setPropertyValue("CostFunction", this->getPropertyValue("CostFunction"));
635 fit->setPropertyValue("MaxIterations", this->getPropertyValue("MaxIterations"));
636 fit->setPropertyValue("PeakRadius", this->getPropertyValue("PeakRadius"));
637 fit->setProperty("CalcErrors", true);
638 fit->setProperty("CreateOutput", createFitOutput);
639 fit->setAlwaysStoreInADS(createFitOutput && appendIdx);
640 if (!histogramFit) {
641 fit->setProperty("OutputCompositeMembers", outputCompositeMembers);
642 fit->setProperty("ConvolveMembers", outputConvolvedMembers);
643 fit->setProperty("Exclude", exclude);
644 }
645 fit->setProperty("Output", wsBaseName);
646 fit->setRethrows(true);
647 fit->execute();
648 return fit;
649}
650
651double PlotPeakByLogValue::calculateLogValue(const std::string &logName, const InputSpectraToFit &data) {
652 double logValue = 0;
653 if (logName.empty() || logName == "axis-1") {
654 API::Axis *axis = data.ws->getAxis(1);
655 if (dynamic_cast<BinEdgeAxis *>(axis)) {
656 double lowerEdge((*axis)(data.wsIdx));
657 double upperEdge((*axis)(data.wsIdx + 1));
658 logValue = lowerEdge + (upperEdge - lowerEdge) / 2;
659 } else
660 logValue = (*axis)(data.wsIdx);
661 } else if (logName != "SourceName") {
662 Kernel::Property *prop = data.ws->run().getLogData(logName);
663 if (!prop) {
664 throw std::invalid_argument("Log value " + logName + " does not exist");
665 }
666 const auto *logp = dynamic_cast<TimeSeriesProperty<double> *>(prop);
667 if (!logp) {
668 throw std::runtime_error("Failed to cast " + logName + " to TimeSeriesProperty");
669 }
670 logValue = logp->lastValue();
671 }
672 return logValue;
673}
674
675void PlotPeakByLogValue::setWorkspaceIndexAttribute(const IFunction_sptr &fun, int wsIndex) const {
676 const std::string attName = "WorkspaceIndex";
677 if (fun->hasAttribute(attName)) {
678 fun->setAttributeValue(attName, wsIndex);
679 }
680
681 API::CompositeFunction_sptr cf = std::dynamic_pointer_cast<API::CompositeFunction>(fun);
682 if (cf) {
683 for (size_t i = 0; i < cf->nFunctions(); ++i) {
684 setWorkspaceIndexAttribute(cf->getFunction(i), wsIndex);
685 }
686 }
687}
688
689std::string PlotPeakByLogValue::getMinimizerString(const std::string &wsName, const std::string &wsIndex) {
690 std::string format = getPropertyValue("Minimizer");
691 std::string wsBaseName = wsName + "_" + wsIndex;
692 boost::replace_all(format, "$wsname", wsName);
693 boost::replace_all(format, "$wsindex", wsIndex);
694 boost::replace_all(format, "$basename", wsBaseName);
695 boost::replace_all(format, "$outputname", m_baseName);
696
697 auto minimizer = FuncMinimizerFactory::Instance().createMinimizer(format);
698 auto minimizerProps = minimizer->getProperties();
699 for (auto &minimizerProp : minimizerProps) {
700 const auto *wsProp = dynamic_cast<Mantid::API::WorkspaceProperty<> *>(minimizerProp);
701 if (wsProp) {
702 const std::string &wsPropValue = minimizerProp->value();
703 if (!wsPropValue.empty()) {
704 const std::string &wsPropName = minimizerProp->name();
705 m_minimizerWorkspaces[wsPropName].emplace_back(wsPropValue);
706 }
707 }
708 }
709
710 return format;
711}
712
713std::vector<std::string> PlotPeakByLogValue::getExclude(const size_t numSpectra) {
714 std::vector<std::string> excludeList = getProperty("ExcludeMultiple");
715 if (excludeList.empty()) {
716 std::string exclude = getPropertyValue("Exclude");
717 std::vector<std::string> excludeVector(numSpectra, exclude);
718 return excludeVector;
719 } else {
720 return excludeList;
721 }
722}
723
724} // namespace Mantid::CurveFitting::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
double value
The value of the point.
Definition FitMW.cpp:51
double error
IPeaksWorkspace_sptr workspace
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
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.
Kernel::Logger & g_log
Definition Algorithm.h:422
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
void interruption_point()
This is called during long-running operations, and check if the algorithm has requested that it be ca...
Class to represent the axis of a workspace.
Definition Axis.h:30
Stores numeric values that are assumed to be bin edge values.
Definition BinEdgeAxis.h:20
TableRow represents a row in a TableWorkspace.
Definition TableRow.h:39
std::string & String(size_t col)
Returns a reference to the element in position col if its type is std::string.
Definition TableRow.h:150
double & Double(size_t col)
Returns a reference to the element in position col if its type is double.
Definition TableRow.h:137
A property class for workspaces.
std::string value() const override
Get the name of the workspace.
Takes a workspace group and fits the same spectrum in all workspaces with the same function.
std::shared_ptr< Algorithm > runSingleFit(bool createFitOutput, bool outputCompositeMembers, bool outputConvolvedMembers, bool appendIdx, const API::IFunction_sptr &ifun, const InputSpectraToFit &data, double startX, double endX, const std::string &exclude)
std::map< std::string, std::vector< std::string > > m_minimizerWorkspaces
Record of workspaces output by the minimizer.
void finaliseOutputWorkspaces(const std::vector< API::MatrixWorkspace_sptr > &fitWorkspaces, const std::vector< API::ITableWorkspace_sptr > &parameterWorkspaces, const std::vector< API::ITableWorkspace_sptr > &covarianceWorkspaces)
API::IFunction_sptr setupFunction(bool individual, bool passWSIndexToFunction, const API::IFunction_sptr &inputFunction, const std::vector< double > &initialParams, bool isMultiDomainFunction, int i, const InputSpectraToFit &data) const
void finaliseOutputWorkspacesWithAppend(const std::vector< std::string > &fitWorkspaces, const std::vector< std::string > &parameterWorkspaces, const std::vector< std::string > &covarianceWorkspaces, const std::vector< InputSpectraToFit > &wsNames)
std::string m_baseName
Base name of output workspace.
double calculateLogValue(const std::string &logName, const InputSpectraToFit &data)
std::string getMinimizerString(const std::string &wsName, const std::string &wsIndex)
Create a minimizer string based on template string provided.
const std::string name() const override
Structure to identify data for fitting.
API::ITableWorkspace_sptr createResultsTable(const std::string &logName, const API::IFunction_sptr &ifunSingle, bool &isDataName)
void setWorkspaceIndexAttribute(const API::IFunction_sptr &fun, int wsIndex) const
Set any WorkspaceIndex attributes in the fitting function.
void groupResParams(const std::vector< API::ITableWorkspace_sptr > &paramsWs, const std::vector< std::string > &paramsNames)
std::vector< std::string > getExclude(const size_t numSpectra)
Create a vector of linked exclude starts and ends.
void appendTableRow(bool isDataName, API::ITableWorkspace_sptr &result, const API::IFunction_sptr &ifun, const InputSpectraToFit &data, double logValue, double chi2) const
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...
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition Logger.h:51
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
Validator to check that a property is not left empty.
The concrete, templated class for properties.
Base class for properties.
Definition Property.h:94
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
A specialised Property class for holding a series of time-value pairs.
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< IFunction > IFunction_sptr
shared pointer to the function base class
Definition IFunction.h:743
std::shared_ptr< CompositeFunction > CompositeFunction_sptr
shared pointer to the composite function base class
Kernel::Logger g_log("DetermineSpinStateOrder")
MANTID_CURVEFITTING_DLL std::vector< InputSpectraToFit > makeNames(const std::string &inputList, int default_wi, int default_spec)
Create a list of input workspace names.
std::shared_ptr< IValidator > IValidator_sptr
A shared_ptr to an IValidator.
Definition IValidator.h:26
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
std::string to_string(const wide_integer< Bits, Signed > &n)
double spectrumNum
Spectrum number of the spectra to fit.
int wsIdx
Workspace index of the spectra to fit.
API::MatrixWorkspace_sptr ws
shared pointer to the workspace
double numericValue
Numerix axis value associated with the spectra to fit.
@ 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