9#include <boost/algorithm/string/replace.hpp>
10#include <boost/lexical_cast.hpp>
44using namespace Kernel;
55 "A list of sources of data to fit. \n"
56 "Sources can be either workspace names or file names followed optionally "
57 "by a list of spectra/workspace-indices \n"
58 "or values using the notation described in the description section of "
61 declareProperty(
"Spectrum", 1,
62 "Set a spectrum to fit. \n"
63 "However, if spectra lists (or workspace-indices/values "
64 "lists) are specified in the Input parameter string these "
66 declareProperty(
"WorkspaceIndex", 0,
67 "Set a workspace-index to fit (alternative option to Spectrum). "
68 "However, if spectra lists (or workspace-indices/values lists) are "
69 "specified in the Input parameter string, \n"
70 "or the Spectrum parameter integer, these take precedence.");
72 "The output TableWorkspace");
73 declareProperty(std::make_unique<API::FunctionProperty>(
"Function",
Direction::InOut),
74 "Parameters defining the fitting function and its initial values");
75 declareProperty(
"LogValue",
"",
76 "Name of the log value to plot the "
77 "parameters against. Default: use spectra "
79 declareProperty(std::make_unique<
ArrayProperty<double>>(
"StartX"),
"A value of x in, or on the low x "
80 "boundary of, the first bin to "
82 "the fit (default lowest value of x)");
83 declareProperty(std::make_unique<
ArrayProperty<double>>(
"EndX"),
"A value in, or on the high x boundary "
84 "of, the last bin the fitting range\n"
85 "(default the highest value of x)");
87 std::vector<std::string> fitOptions{
"Sequential",
"Individual"};
88 declareProperty(
"FitType",
"Sequential", std::make_shared<StringListValidator>(fitOptions),
89 "Defines the way of setting initial values. \n"
90 "If set to 'Sequential' every next fit starts with "
91 "parameters returned by the previous fit. \n"
92 "If set to 'Individual' each fit starts with the same "
93 "initial values defined in the Function property.");
95 declareProperty(
"PassWSIndexToFunction",
false,
96 "For each spectrum in Input pass its workspace index to all "
98 "have attribute WorkspaceIndex.");
100 declareProperty(
"Minimizer",
"Levenberg-Marquardt",
101 "Minimizer to use for fitting. Minimizers available are "
102 "'Levenberg-Marquardt', 'Simplex', 'FABADA',\n"
103 "'Conjugate gradient (Fletcher-Reeves imp.)', 'Conjugate "
104 "gradient (Polak-Ribiere imp.)' and 'BFGS'");
107 declareProperty(
"CostFunction",
"Least squares", std::make_shared<StringListValidator>(costFuncOptions),
108 "Cost functions to use for fitting. Cost functions available "
109 "are 'Least squares' and 'Ignore positive peaks'",
112 declareProperty(
"MaxIterations", 500,
113 "Stop after this number of iterations if a good fit is not "
115 declareProperty(
"PeakRadius", 0,
116 "A value of the peak radius the peak functions should use. A "
117 "peak radius defines an interval on the x axis around the "
118 "centre of the peak where its values are calculated. Values "
119 "outside the interval are not calculated and assumed zeros."
120 "Numerically the radius is a whole number of peak widths "
121 "(FWHM) that fit into the interval on each side from the "
122 "centre. The default value of 0 means the whole x axis.");
124 declareProperty(
"CreateOutput",
false,
125 "Set to true to create output "
126 "workspaces with the results of the "
127 "fit(default is false).");
129 declareProperty(
"OutputCompositeMembers",
false,
130 "If true and CreateOutput is true then the value of each "
131 "member of a Composite Function is also output.");
134 "If true and OutputCompositeMembers is true members of any "
135 "Convolution are output convolved\n"
136 "with corresponding resolution");
138 std::array<std::string, 2> evaluationTypes = {{
"CentrePoint",
"Histogram"}};
139 declareProperty(
"EvaluationType",
"CentrePoint",
144 "A list of pairs of real numbers, defining the regions to "
145 "exclude from the fit for all spectra.");
148 "A list of Exclusion ranges, defining the regions to "
149 "exclude from the fit for each spectra. Must have the "
150 "same number of sets as the number of the spectra.");
152 declareProperty(
"IgnoreInvalidData",
false,
"Flag to ignore infinities, NaNs and data with zero errors.");
154 declareProperty(
"OutputFitStatus",
false,
155 "Flag to output fit status information which consists of the fit "
156 "OutputStatus and the OutputChiSquared");
159std::map<std::string, std::string> PlotPeakByLogValue::validateInputs() {
160 std::map<std::string, std::string> errors;
164 const std::vector<InputSpectraToFit> wsNames =
makeNames(inputList, default_wi, default_spec);
165 std::vector<std::string> excludeList =
getProperty(
"ExcludeMultiple");
166 if (!excludeList.empty() && excludeList.size() != wsNames.size()) {
167 errors[
"ExcludeMultiple"] =
"ExcludeMultiple must be the same size has the number of spectra.";
175void PlotPeakByLogValue::exec() {
181 const std::vector<InputSpectraToFit> wsNames =
makeNames(inputList, default_wi, default_spec);
185 bool passWSIndexToFunction =
getProperty(
"PassWSIndexToFunction");
186 bool createFitOutput =
getProperty(
"CreateOutput");
187 bool outputCompositeMembers =
getProperty(
"OutputCompositeMembers");
188 bool outputConvolvedMembers =
getProperty(
"ConvolveMembers");
189 bool outputFitStatus =
getProperty(
"OutputFitStatus");
191 std::vector<double> startX =
getProperty(
"StartX");
193 std::vector<std::string> exclude =
getExclude(wsNames.size());
195 bool isDataName =
false;
200 if (!inputFunction) {
201 throw std::invalid_argument(
"Fitting function failed to initialize");
203 bool isMultiDomainFunction = std::dynamic_pointer_cast<MultiDomainFunction>(inputFunction) !=
nullptr;
205 IFunction_sptr ifunSingle = isMultiDomainFunction ? inputFunction->getFunction(0) : inputFunction;
208 std::vector<double> initialParams(ifunSingle->nParams());
210 for (
size_t i = 0; i < initialParams.size(); ++i) {
211 initialParams[i] = ifunSingle->getParameter(i);
216 std::vector<MatrixWorkspace_sptr> fitWorkspaces;
217 std::vector<ITableWorkspace_sptr> parameterWorkspaces;
218 std::vector<ITableWorkspace_sptr> covarianceWorkspaces;
219 if (createFitOutput) {
220 covarianceWorkspaces.reserve(wsNames.size());
221 fitWorkspaces.reserve(wsNames.size());
222 parameterWorkspaces.reserve(wsNames.size());
225 std::vector<std::string> fitStatus;
226 std::vector<double> fitChiSquared;
227 if (outputFitStatus) {
230 fitStatus.reserve(wsNames.size());
231 fitChiSquared.reserve(wsNames.size());
234 double dProg = 1. /
static_cast<double>(wsNames.size());
236 for (
int i = 0; i < static_cast<int>(wsNames.size()); ++i) {
245 g_log.
warning() <<
"Zero spectra selected for fitting in workspace " << wsNames[i].name <<
'\n';
250 setupFunction(individual, passWSIndexToFunction, inputFunction, initialParams, isMultiDomainFunction, i, data);
251 std::shared_ptr<Algorithm> fit;
252 if (startX.size() == 0) {
253 fit =
runSingleFit(createFitOutput, outputCompositeMembers, outputConvolvedMembers, ifun, data,
EMPTY_DBL(),
255 }
else if (startX.size() == 1) {
256 fit =
runSingleFit(createFitOutput, outputCompositeMembers, outputConvolvedMembers, ifun, data, startX[0],
257 endX[0], exclude[i]);
259 fit =
runSingleFit(createFitOutput, outputCompositeMembers, outputConvolvedMembers, ifun, data, startX[i],
260 endX[i], exclude[i]);
263 ifun = fit->getProperty(
"Function");
264 double chi2 = fit->getProperty(
"OutputChi2overDoF");
266 if (createFitOutput) {
269 ITableWorkspace_sptr outputCovarianceWorkspace = fit->getProperty(
"OutputNormalisedCovarianceMatrix");
270 fitWorkspaces.emplace_back(outputFitWorkspace);
271 parameterWorkspaces.emplace_back(outputParamWorkspace);
272 covarianceWorkspaces.emplace_back(outputCovarianceWorkspace);
274 if (outputFitStatus) {
275 fitStatus.push_back(fit->getProperty(
"OutputStatus"));
276 fitChiSquared.push_back(chi2);
279 g_log.
debug() <<
"Fit result " << fit->getPropertyValue(
"OutputStatus") <<
' ' << chi2 <<
'\n';
288 progress(Prog, (
"Fitting Workspace: (" + current +
") - "));
292 if (outputFitStatus) {
300IFunction_sptr PlotPeakByLogValue::setupFunction(
bool individual,
bool passWSIndexToFunction,
302 const std::vector<double> &initialParams,
bool isMultiDomainFunction,
305 if (isMultiDomainFunction) {
306 ifun = inputFunction->getFunction(i);
307 if (!individual && i != 0) {
309 for (
size_t k = 0; k < ifun->nParams(); ++k) {
310 ifun->setParameter(k, prevFunction->getParameter(k));
315 ifun = inputFunction;
317 if (passWSIndexToFunction) {
321 if (individual && !isMultiDomainFunction) {
322 for (
size_t k = 0; k < initialParams.size(); ++k) {
323 ifun->setParameter(k, initialParams[k]);
329void PlotPeakByLogValue::finaliseOutputWorkspaces(
bool createFitOutput,
330 const std::vector<MatrixWorkspace_sptr> &fitWorkspaces,
331 const std::vector<ITableWorkspace_sptr> ¶meterWorkspaces,
332 const std::vector<ITableWorkspace_sptr> &covarianceWorkspaces) {
333 if (createFitOutput) {
336 for (
auto const &
workspace : covarianceWorkspaces)
337 covarianceGroup->addWorkspace(
workspace);
341 for (
auto const &
workspace : parameterWorkspaces)
346 for (
auto const &
workspace : fitWorkspaces)
352 const std::string paramName = minimizerWorkspace.first;
354 groupAlg->initialize();
355 groupAlg->setProperty(
"InputWorkspaces", minimizerWorkspace.second);
356 groupAlg->setProperty(
"OutputWorkspace", this->
m_baseName +
"_" + paramName);
361void PlotPeakByLogValue::appendTableRow(
363 double logValue,
double chi2)
const {
371 auto p = std::dynamic_pointer_cast<API::CompositeFunction>(ifun);
373 for (
size_t i = 0; i < p->nFunctions(); ++i) {
374 auto f = ifun->getFunction(i);
375 for (
size_t j = 0; j < f->nParams(); ++j) {
376 row << p->getParameter(i, j) << p->getError(i, j);
380 auto intensity_handle = std::dynamic_pointer_cast<API::IPeakFunction>(f);
381 if (intensity_handle) {
382 row << intensity_handle->intensity() << intensity_handle->intensityError();
388 for (
size_t iPar = 0; iPar < ifun->nParams(); ++iPar) {
389 row << ifun->getParameter(iPar) << ifun->getError(iPar);
393 auto intensity_handle = std::dynamic_pointer_cast<API::IPeakFunction>(ifun);
394 if (intensity_handle) {
395 row << intensity_handle->intensity() << intensity_handle->intensityError();
405 if (logName ==
"SourceName") {
406 result->addColumn(
"str",
"SourceName");
408 }
else if (logName.empty()) {
409 auto col = result->addColumn(
"double",
"axis-1");
412 auto col = result->addColumn(
"double", logName);
416 auto p = std::dynamic_pointer_cast<API::CompositeFunction>(ifunSingle);
418 for (
size_t i = 0; i < p->nFunctions(); ++i) {
419 auto f = ifunSingle->getFunction(i);
420 for (
size_t j = 0; j < f->nParams(); ++j) {
421 result->addColumn(
"double", p->parameterName(i, j));
422 result->addColumn(
"double", p->parameterName(i, j) +
"_Err");
425 auto intensity_handle = std::dynamic_pointer_cast<API::IPeakFunction>(f);
426 if (intensity_handle) {
427 result->addColumn(
"double",
"f" +
std::to_string(i) +
".Integrated Intensity");
428 result->addColumn(
"double",
"f" +
std::to_string(i) +
".Integrated Intensity_Err");
434 for (
size_t iPar = 0; iPar < ifunSingle->nParams(); ++iPar) {
435 result->addColumn(
"double", ifunSingle->parameterName(iPar));
436 result->addColumn(
"double", ifunSingle->parameterName(iPar) +
"_Err");
439 auto intensity_handle = std::dynamic_pointer_cast<API::IPeakFunction>(ifunSingle);
440 if (intensity_handle) {
441 result->addColumn(
"double",
"Integrated Intensity");
442 result->addColumn(
"double",
"Integrated Intensity_Err");
446 result->addColumn(
"double",
"Chi_squared");
452std::shared_ptr<Algorithm> PlotPeakByLogValue::runSingleFit(
bool createFitOutput,
bool outputCompositeMembers,
455 const std::string &exclude) {
456 g_log.
debug() <<
"Fitting " << data.
ws->getName() <<
" index " << data.
i <<
" with \n";
460 std::string wsBaseName;
463 wsBaseName = data.
name +
"_" + spectrum_index;
464 bool histogramFit = this->
getPropertyValue(
"EvaluationType") ==
"Histogram";
465 bool ignoreInvalidData = this->
getProperty(
"IgnoreInvalidData");
470 fit->setPropertyValue(
"EvaluationType", this->
getPropertyValue(
"EvaluationType"));
471 fit->setProperty(
"Function", ifun);
472 fit->setProperty(
"InputWorkspace", data.
ws);
473 fit->setProperty(
"WorkspaceIndex", data.
i);
474 fit->setProperty(
"StartX", startX);
475 fit->setProperty(
"EndX", endX);
476 fit->setProperty(
"IgnoreInvalidData", ignoreInvalidData);
478 fit->setPropertyValue(
"CostFunction", this->
getPropertyValue(
"CostFunction"));
479 fit->setPropertyValue(
"MaxIterations", this->
getPropertyValue(
"MaxIterations"));
481 fit->setProperty(
"CalcErrors",
true);
482 fit->setProperty(
"CreateOutput", createFitOutput);
484 fit->setProperty(
"OutputCompositeMembers", outputCompositeMembers);
485 fit->setProperty(
"ConvolveMembers", outputConvolvedMembers);
486 fit->setProperty(
"Exclude", exclude);
488 fit->setProperty(
"Output", wsBaseName);
489 fit->setRethrows(
true);
494double PlotPeakByLogValue::calculateLogValue(
const std::string &logName,
const InputSpectraToFit &data) {
496 if (logName.empty() || logName ==
"axis-1") {
499 double lowerEdge((*axis)(data.
i));
500 double upperEdge((*axis)(data.
i + 1));
501 logValue = lowerEdge + (upperEdge - lowerEdge) / 2;
503 logValue = (*axis)(data.
i);
504 }
else if (logName !=
"SourceName") {
507 throw std::invalid_argument(
"Log value " + logName +
" does not exist");
511 throw std::runtime_error(
"Failed to cast " + logName +
" to TimeSeriesProperty");
513 logValue = logp->lastValue();
518void PlotPeakByLogValue::setWorkspaceIndexAttribute(
const IFunction_sptr &fun,
int wsIndex)
const {
519 const std::string attName =
"WorkspaceIndex";
520 if (fun->hasAttribute(attName)) {
521 fun->setAttributeValue(attName, wsIndex);
526 for (
size_t i = 0; i < cf->nFunctions(); ++i) {
532std::string PlotPeakByLogValue::getMinimizerString(
const std::string &wsName,
const std::string &wsIndex) {
534 std::string wsBaseName = wsName +
"_" + wsIndex;
535 boost::replace_all(format,
"$wsname", wsName);
536 boost::replace_all(format,
"$wsindex", wsIndex);
537 boost::replace_all(format,
"$basename", wsBaseName);
538 boost::replace_all(format,
"$outputname",
m_baseName);
541 auto minimizerProps = minimizer->getProperties();
542 for (
auto &minimizerProp : minimizerProps) {
545 const std::string &wsPropValue = minimizerProp->
value();
546 if (!wsPropValue.empty()) {
547 const std::string &wsPropName = minimizerProp->name();
556std::vector<std::string> PlotPeakByLogValue::getExclude(
const size_t numSpectra) {
558 std::vector<std::string> excludeList =
getProperty(
"ExcludeMultiple");
559 if (excludeList.empty()) {
560 std::vector<std::string> excludeVector;
561 excludeVector.reserve(numSpectra);
562 for (
size_t i = 0; i < numSpectra; i++) {
563 excludeVector.emplace_back(exclude);
565 return excludeVector;
#define DECLARE_ALGORITHM(classname)
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.
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.
Stores numeric values that are assumed to be bin edge values.
TableRow represents a row in a TableWorkspace.
A property class for workspaces.
std::string value() const override
Returns the value of the property as a string.
Takes a workspace group and fits the same spectrum in all workspaces with the same function.
std::map< std::string, std::vector< std::string > > m_minimizerWorkspaces
Record of workspaces output by the minimizer.
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
std::string m_baseName
Base name of output workspace.
double calculateLogValue(const std::string &logName, const InputSpectraToFit &data)
void finaliseOutputWorkspaces(bool createFitOutput, const std::vector< API::MatrixWorkspace_sptr > &fitWorkspaces, const std::vector< API::ITableWorkspace_sptr > ¶meterWorkspaces, const std::vector< API::ITableWorkspace_sptr > &covarianceWorkspaces)
std::string getMinimizerString(const std::string &wsName, const std::string &wsIndex)
Create a minimizer string based on template string provided.
API::ITableWorkspace_sptr createResultsTable(const std::string &logName, const API::IFunction_sptr &ifunSingle, bool &isDataName)
std::shared_ptr< Algorithm > runSingleFit(bool createFitOutput, bool outputCompositeMembers, bool outputConvolvedMembers, const API::IFunction_sptr &ifun, const InputSpectraToFit &data, double startX, double endX, const std::string &exclude)
void setWorkspaceIndexAttribute(const API::IFunction_sptr &fun, int wsIndex) const
Set any WorkspaceIndex attributes in the fitting function.
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.
void debug(const std::string &msg)
Logs at debug level.
void warning(const std::string &msg)
Logs at warning level.
Validator to check that a property is not left empty.
The concrete, templated class for properties.
Base class for properties.
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
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< CompositeFunction > CompositeFunction_sptr
shared pointer to the composite function base class
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.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ InOut
Both an input & output workspace.
@ Input
An input workspace.
@ Output
An output workspace.