27#include <boost/algorithm/string/join.hpp>
36 for (
auto i = 0u; i < composite->nFunctions(); ++i)
37 names.emplace_back(composite->getFunction(i)->name());
40void extractFunctionNames(
const IFunction_sptr &function, std::vector<std::string> &names) {
41 auto composite = std::dynamic_pointer_cast<CompositeFunction>(function);
43 extractFunctionNames(composite, names);
45 names.emplace_back(function->name());
48void extractConvolvedNames(
const IFunction_sptr &function, std::vector<std::string> &names);
51 for (
auto i = 0u; i < composite->nFunctions(); ++i)
52 extractConvolvedNames(composite->getFunction(i), names);
55void extractConvolvedNames(
const IFunction_sptr &function, std::vector<std::string> &names) {
56 auto composite = std::dynamic_pointer_cast<CompositeFunction>(function);
58 if (composite->name() ==
"Convolution" && composite->nFunctions() > 1 &&
59 composite->getFunction(0)->name() ==
"Resolution")
60 extractFunctionNames(composite->getFunction(1), names);
62 extractConvolvedNames(composite, names);
68 convSpec->setLogging(
false);
69 convSpec->setChild(
true);
70 convSpec->setProperty(
"InputWorkspace", inputWorkspace);
71 convSpec->setProperty(
"OutputWorkspace",
"__converted");
72 convSpec->setProperty(
"Target",
"ElasticQ");
73 convSpec->setProperty(
"EMode",
"Indirect");
75 return convSpec->getProperty(
"OutputWorkspace");
79 auto axis = inputWorkspace->getAxis(1);
80 if (axis->isSpectra())
81 return convertSpectrumAxis(inputWorkspace);
82 else if (axis->isNumeric()) {
83 if (axis->unit()->unitID() !=
"MomentumTransfer" && doThrow)
84 throw std::runtime_error(
"Input must have axis values of Q");
85 return inputWorkspace->clone();
87 throw std::runtime_error(
"Input workspace must have either spectra or numeric axis.");
88 return inputWorkspace->clone();
91struct ElasticQAppender {
92 explicit ElasticQAppender(std::vector<MatrixWorkspace_sptr> &elasticInput)
93 : m_elasticInput(elasticInput), m_converted() {}
96 auto it = m_converted.find(
workspace.get());
97 if (it != m_converted.end())
98 m_elasticInput.emplace_back(it->second);
100 auto elasticQ = convertToElasticQ(
workspace, doThrow);
101 m_elasticInput.emplace_back(elasticQ);
107 std::vector<MatrixWorkspace_sptr> &m_elasticInput;
108 std::unordered_map<MatrixWorkspace *, MatrixWorkspace_sptr> m_converted;
111std::vector<MatrixWorkspace_sptr> convertToElasticQ(
const std::vector<MatrixWorkspace_sptr> &workspaces,
bool doThrow) {
112 std::vector<MatrixWorkspace_sptr> elasticInput;
113 auto appendElasticQWorkspace = ElasticQAppender(elasticInput);
114 appendElasticQWorkspace(workspaces[0], doThrow);
116 for (
auto i = 1u; i < workspaces.size(); ++i)
117 appendElasticQWorkspace(workspaces[i], doThrow);
121std::string shortParameterName(
const std::string &longName) {
122 return longName.substr(longName.rfind(
'.') + 1, longName.size());
126 const std::string &suffix) {
129 int workspaceIndex = qensFit.
getProperty(
"WorkspaceIndex" + suffix);
130 fit.
setProperty(
"WorkspaceIndex" + suffix, workspaceIndex);
132 double startX = qensFit.
getProperty(
"StartX" + suffix);
133 double endX = qensFit.
getProperty(
"EndX" + suffix);
137 std::vector<double> exclude = qensFit.
getProperty(
"Exclude" + suffix);
142 const std::vector<MatrixWorkspace_sptr> &workspaces) {
145 for (
auto i = 1u; i < workspaces.size(); ++i)
150 auto composite = std::dynamic_pointer_cast<CompositeFunction>(function);
151 if (composite && composite->getNumberDomains() > 1)
152 return composite->getFunction(0);
157 auto group = std::dynamic_pointer_cast<WorkspaceGroup>(
workspace);
166 const std::string &yAxisType) {
168 transposed->addColumn(yAxisType,
"axis-1");
171 for (
const auto ¶meter : parameters) {
172 transposed->addColumn(
"double", parameter);
173 transposed->addColumn(
"double", parameter +
"_Err");
176 auto numberOfParameters = parameters.size();
177 for (std::size_t i = 0; i < table->rowCount() - 1; i += numberOfParameters) {
178 auto row = transposed->appendRow().m_row;
180 for (
auto j = 0u; j < numberOfParameters; ++j) {
181 auto column = 1 + j * 2;
182 transposed->Double(row, column) = table->Double(i + j, 1);
183 transposed->Double(row, column + 1) = table->Double(i + j, 2);
190 return workspace.getAxis(axisIndex)->isNumeric() ?
"double" :
"str";
201std::vector<std::string> getUniqueWorkspaceNames(std::vector<std::string> &&workspaceNames) {
202 std::set<std::string> uniqueNames(workspaceNames.begin(), workspaceNames.end());
203 workspaceNames.assign(uniqueNames.begin(), uniqueNames.end());
204 return std::move(workspaceNames);
207auto getNumericAxisValueReader(std::size_t axisIndex) {
210 return axis->getValue(
index);
215auto getTextAxisValueReader(std::size_t axisIndex) {
218 return axis->label(
index);
219 return std::string();
223template <
typename T,
typename GetValue>
224void addValuesToColumn(
Column &column,
const std::vector<MatrixWorkspace_sptr> &workspaces,
226 const std::string prefix =
"WorkspaceIndex";
229 column.
cell<T>(0) = getValue(*workspaces.front(),
static_cast<std::size_t
>(
index));
231 for (
auto i = 1u; i < workspaces.size(); ++i) {
234 column.
cell<T>(i) = getValue(*workspaces[i],
static_cast<std::size_t
>(
index));
238void addValuesToTableColumn(
ITableWorkspace &table,
const std::vector<MatrixWorkspace_sptr> &workspaces,
240 if (workspaces.empty())
243 const auto column = table.
getColumn(columnIndex);
245 addValuesToColumn<double>(*column, workspaces, indexProperties, getNumericAxisValueReader(1));
247 addValuesToColumn<std::string>(*column, workspaces, indexProperties, getTextAxisValueReader(1));
250std::vector<std::size_t> createDatasetGrouping(
const std::vector<MatrixWorkspace_sptr> &workspaces) {
251 std::vector<std::size_t> grouping;
252 grouping.emplace_back(0);
253 for (
auto i = 1u; i < workspaces.size(); ++i) {
254 if (workspaces[i] != workspaces[i - 1])
255 grouping.emplace_back(i);
257 grouping.emplace_back(workspaces.size());
269 const std::vector<std::size_t> &grouping) {
270 std::vector<MatrixWorkspace_sptr> results;
271 results.reserve(grouping.size() - 1);
272 for (
auto i = 0u; i < grouping.size() - 1; ++i) {
273 processingAlgorithm.
setProperty(
"StartRowIndex",
static_cast<int>(grouping[i]));
274 processingAlgorithm.
setProperty(
"EndRowIndex",
static_cast<int>(grouping[i + 1]) - 1);
275 processingAlgorithm.
setProperty(
"OutputWorkspace",
"__Result");
277 results.emplace_back(processingAlgorithm.
getProperty(
"OutputWorkspace"));
279 return createGroup(results);
286using namespace Kernel;
295int QENSFitSimultaneous::version()
const {
return 1; }
298const std::string QENSFitSimultaneous::category()
const {
return "Workflow\\MIDAS"; }
301const std::string QENSFitSimultaneous::summary()
const {
return "Performs a simultaneous QENS fit"; }
304const std::vector<std::string> QENSFitSimultaneous::seeAlso()
const {
305 return {
"ConvolutionFitSimultaneous",
"IqtFitSimultaneous",
"Fit"};
308void QENSFitSimultaneous::initConcrete() {
311 "the fitting function.");
314 auto mustBePositive = std::make_shared<Kernel::BoundedValidator<int>>();
315 mustBePositive->setLower(0);
317 "Stop after this number of iterations if a good fit is not found");
322 declareProperty(
"Minimizer",
"Levenberg-Marquardt", minimizerValidator,
"Minimizer to use for fitting.");
324 "Set to true to calcuate errors when output isn't created "
325 "(default is false).");
327 "If true, then each member of the fit will be extracted"
328 ", into their own workspace. These workspaces will have a histogram"
329 " for each spectrum (Q-value) and will be grouped.",
332 "If true members of any "
333 "Convolution are output convolved\n"
334 "with corresponding resolution");
336 "If true and CreateOutput is true then the value of each "
337 "member of a Composite Function is also output.");
340 unitOptions.emplace_back(
"");
341 declareProperty(
"ResultXAxisUnit",
"MomentumTransfer", std::make_shared<StringListValidator>(unitOptions),
342 "The unit to assign to the X Axis of the result workspace, "
343 "defaults to MomentumTransfer");
346 "The output result workspace(s)");
349 "The output parameter workspace");
352 "The output group workspace");
355 "Flag to output fit status information, which consists of the fit "
356 "OutputStatus and the OutputChiSquared");
360 for (
auto &costFuncOption : costFuncOptions) {
361 auto costFunc = std::dynamic_pointer_cast<CostFunctions::CostFuncFitting>(
367 Kernel::IValidator_sptr costFuncValidator = std::make_shared<Kernel::ListValidator<std::string>>(costFuncOptions);
372void QENSFitSimultaneous::execConcrete() {
375 if (!outputBaseName.empty()) {
377 setProperty(
"OutputParameterWorkspace", outputBaseName +
"_Parameters");
380 setProperty(
"OutputWorkspaceGroup", outputBaseName +
"_Workspaces");
385 const auto singleDomainFunction = convertToSingleDomain(
getProperty(
"Function"));
387 const auto fitResult =
performFit(inputWorkspaces, outputBaseName);
388 const auto yAxisType = getAxisType(*workspaces.front(), 1);
389 auto transposedTable = transposeFitTable(fitResult.first, *singleDomainFunction, yAxisType);
390 addValuesToTableColumn(*transposedTable, workspaces, *
this, 0);
392 const auto groupWs = makeGroup(fitResult.second);
399 renameWorkspaces(resultWs, std::vector<std::string>(inputWorkspaceNames.size(),
""), outputBaseName,
"_Result",
400 inputWorkspaceNames);
402 renameWorkspaces(resultWs, std::vector<std::string>({
""}), outputBaseName,
"_Result");
407 const bool doExtractMembers =
getProperty(
"ExtractMembers");
408 if (doExtractMembers)
412 copyLogs(std::dynamic_pointer_cast<MatrixWorkspace>(resultWs->getItem(0)), groupWs);
415 setProperty(
"OutputParameterWorkspace", parameterWs);
419std::pair<API::ITableWorkspace_sptr, API::Workspace_sptr>
420QENSFitSimultaneous::performFit(
const std::vector<MatrixWorkspace_sptr> &workspaces,
const std::string &output) {
422 const bool convolveMembers =
getProperty(
"ConvolveMembers");
423 const bool outputCompositeMembers =
getProperty(
"OutputCompositeMembers");
424 const bool ignoreInvalidData =
getProperty(
"IgnoreInvalidData");
430 fit->
setProperty(
"IgnoreInvalidData", ignoreInvalidData);
440 fit->
setProperty(
"OutputCompositeMembers", outputCompositeMembers);
441 fit->
setProperty(
"ConvolveMembers", convolveMembers);
446 std::string status = fit->
getProperty(
"OutputStatus");
447 double chiSquared = fit->
getProperty(
"OutputChi2overDoF");
449 const bool outputFitStatus =
getProperty(
"OutputFitStatus");
450 if (outputFitStatus) {
457 if (workspaces.size() == 1) {
459 return {fit->
getProperty(
"OutputParameters"), outputWS};
463 return {fit->
getProperty(
"OutputParameters"), outputWS};
467 const std::vector<std::size_t> &grouping) {
468 std::string
const xAxisUnit =
getProperty(
"ResultXAxisUnit");
470 pifp->setAlwaysStoreInADS(
false);
471 pifp->setProperty(
"InputWorkspace", parameterWorkspace);
472 pifp->setProperty(
"ColumnX",
"axis-1");
473 pifp->setProperty(
"XAxisUnit", xAxisUnit);
475 pifp->setProperty(
"IncludeChiSquared",
true);
476 return runParameterProcessingWithGrouping(*pifp, grouping);
480 const std::vector<MatrixWorkspace_sptr> &workspaces) {
482 for (
auto &&result : *resultWorkspace) {
483 logCopier->setProperty(
"OutputWorkspace", std::dynamic_pointer_cast<MatrixWorkspace>(result));
484 for (
const auto &
workspace : workspaces) {
485 logCopier->setProperty(
"InputWorkspace",
workspace);
486 logCopier->executeAsChildAlg();
494 logCopier->setProperty(
"InputWorkspace", resultWorkspace);
496 for (
const auto &
workspace : *resultGroup) {
497 logCopier->setProperty(
"OutputWorkspace", std::dynamic_pointer_cast<MatrixWorkspace>(
workspace));
498 logCopier->executeAsChildAlg();
503 const std::vector<MatrixWorkspace_sptr> &workspaces,
504 const std::string &outputWsName) {
505 std::vector<std::string> workspaceNames;
506 for (
auto i = 0u; i < workspaces.size(); ++i) {
509 workspaceNames.emplace_back(
name);
513 extractAlgorithm->setProperty(
"InputWorkspaces", workspaceNames);
514 extractAlgorithm->execute();
516 for (
const auto &workspaceName : workspaceNames)
525void QENSFitSimultaneous::addAdditionalLogs(
const Workspace_sptr &resultWorkspace) {
527 logAdder->setProperty(
"Workspace", resultWorkspace);
529 Progress logAdderProg(
this, 0.99, 1.00, 6);
530 logAdder->setProperty(
"LogType",
"String");
532 logAdder->setProperty(
"LogName", log.first);
533 logAdder->setProperty(
"LogText", log.second);
534 logAdder->executeAsChildAlg();
535 logAdderProg.
report(
"Add text logs");
538 logAdder->setProperty(
"LogType",
"Number");
540 logAdder->setProperty(
"LogName", log.first);
541 logAdder->setProperty(
"LogText", log.second);
542 logAdder->executeAsChildAlg();
543 logAdderProg.
report(
"Add number logs");
548 const std::string &outputWsName)
const {
549 const bool convolved =
getProperty(
"ConvolveMembers");
550 std::vector<std::string> convolvedMembers;
554 extractConvolvedNames(function, convolvedMembers);
557 extractMembersAlg->setProperty(
"ResultWorkspace", resultGroupWs);
558 extractMembersAlg->setProperty(
"OutputWorkspace", outputWsName);
559 extractMembersAlg->setProperty(
"RenameConvolvedMembers", convolved);
560 extractMembersAlg->setProperty(
"ConvolvedMembers", convolvedMembers);
561 return extractMembersAlg;
564std::vector<MatrixWorkspace_sptr> QENSFitSimultaneous::getWorkspaces()
const {
565 std::vector<MatrixWorkspace_sptr> workspaces;
569 workspaces.emplace_back(std::dynamic_pointer_cast<MatrixWorkspace>(
workspace));
574std::vector<std::string> QENSFitSimultaneous::getWorkspaceIndices()
const {
575 std::vector<std::string> workspaceIndices;
579 workspaceIndices.emplace_back(workspaceIndex);
581 return workspaceIndices;
584std::vector<std::string> QENSFitSimultaneous::getWorkspaceNames()
const {
585 std::vector<std::string> workspaceNames;
589 workspaceNames.emplace_back(workspaceName);
591 return workspaceNames;
594std::vector<MatrixWorkspace_sptr>
595QENSFitSimultaneous::convertInputToElasticQ(
const std::vector<MatrixWorkspace_sptr> &workspaces)
const {
599std::string QENSFitSimultaneous::getOutputBaseName()
const {
601 auto position = base.rfind(
"_Result");
607bool QENSFitSimultaneous::throwIfElasticQConversionFails()
const {
return false; }
609bool QENSFitSimultaneous::isFitParameter(
const std::string & )
const {
return true; }
611std::vector<std::string> QENSFitSimultaneous::getFitParameterNames()
const {
613 std::vector<std::string> parameters;
614 parameters.reserve(uniqueParameters.size());
615 std::copy_if(uniqueParameters.begin(), uniqueParameters.end(), std::back_inserter(parameters),
616 [&](
const std::string ¶meter) { return isFitParameter(parameter); });
620std::set<std::string> QENSFitSimultaneous::getUniqueParameterNames()
const {
622 std::set<std::string> nameSet;
623 for (
auto i = 0u; i < function->nParams(); ++i)
624 nameSet.insert(shortParameterName(function->parameterName(i)));
628std::map<std::string, std::string> QENSFitSimultaneous::getAdditionalLogStrings()
const {
629 const bool convolve =
getProperty(
"ConvolveMembers");
630 auto fitProgram =
name();
631 fitProgram = fitProgram.substr(0, fitProgram.rfind(
"Simultaneous"));
633 auto logs = std::map<std::string, std::string>();
634 logs[
"convolve_members"] = convolve ?
"true" :
"false";
635 logs[
"fit_program"] = fitProgram;
636 logs[
"fit_mode"] =
"Simultaneous";
640std::map<std::string, std::string> QENSFitSimultaneous::getAdditionalLogNumbers()
const {
641 return std::map<std::string, std::string>();
645 return parameterTable;
649 std::vector<std::string>
const &spectra, std::string
const &outputBaseName,
650 std::string
const &endOfSuffix,
651 std::vector<std::string>
const &inputWorkspaceNames) {
653 const auto getNameSuffix = [&](std::size_t i) {
654 std::string workspaceName = inputWorkspaceNames[i] +
"_" + spectra[i] + endOfSuffix;
655 return workspaceName;
661 std::vector<std::string>
const &spectra, std::string
const &outputBaseName,
662 std::string
const &endOfSuffix) {
664 auto getNameSuffix = [&](std::size_t i) {
return spectra[i] + endOfSuffix; };
#define DECLARE_ALGORITHM(classname)
IPeaksWorkspace_sptr workspace
std::map< DeltaEMode::Type, std::string > index
Base class from which all concrete algorithm classes should be derived.
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Kernel::Property * getPointerToProperty(const std::string &name) const override
Get a property by name.
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.
Column is the base class for columns of TableWorkspace.
T & cell(size_t index)
Templated method for returning a value. No type checks are done.
IAlgorithm is the interface implemented by the Algorithm base class.
virtual void executeAsChildAlg()=0
Execute as a Child Algorithm, with try/catch.
virtual bool execute()=0
System execution.
This is an interface to a fitting function - a semi-abstarct class.
std::vector< std::string > getParameterNames() const
Return a vector with all parameter names.
ITableWorkspace is an implementation of Workspace in which the data are organised in columns of same ...
virtual Column_sptr getColumn(const std::string &name)=0
Gets the shared pointer to a column by name.
Base MatrixWorkspace Abstract Class.
Class to represent a numeric axis of a workspace.
Helper class for reporting progress from algorithms.
Class to represent a text axis of a workspace.
Class to hold a set of workspaces.
A property class for workspaces.
QENSFitSimultaneous - Algorithm for performing a simultaneous QENS fit.
void copyLogs(const API::WorkspaceGroup_sptr &resultWorkspace, const std::vector< API::MatrixWorkspace_sptr > &workspaces)
std::string getOutputBaseName() const
void renameWorkspaces(const API::WorkspaceGroup_sptr &outputGroup, std::vector< std::string > const &spectra, std::string const &outputBaseName, std::string const &endOfSuffix, std::vector< std::string > const &inputWorkspaceNames)
std::vector< API::MatrixWorkspace_sptr > convertInputToElasticQ(const std::vector< API::MatrixWorkspace_sptr > &workspaces) const
virtual std::vector< std::string > getFitParameterNames() const
void addAdditionalLogs(const API::WorkspaceGroup_sptr &group)
std::vector< std::string > getWorkspaceNames() const
std::pair< API::ITableWorkspace_sptr, API::Workspace_sptr > performFit(const std::vector< API::MatrixWorkspace_sptr > &workspaces, const std::string &output)
virtual std::vector< API::MatrixWorkspace_sptr > getWorkspaces() const
void extractMembers(const API::WorkspaceGroup_sptr &resultGroupWs, const std::vector< API::MatrixWorkspace_sptr > &workspaces, const std::string &outputWsName)
virtual std::map< std::string, std::string > getAdditionalLogStrings() const
std::vector< std::string > getWorkspaceIndices() const
std::set< std::string > getUniqueParameterNames() const
virtual std::map< std::string, std::string > getAdditionalLogNumbers() const
API::IAlgorithm_sptr extractMembersAlgorithm(const API::WorkspaceGroup_sptr &resultGroupWs, const std::string &outputWsName) const
const std::string name() const override
Algorithms name for identification.
API::WorkspaceGroup_sptr processIndirectFitParameters(const API::ITableWorkspace_sptr ¶meterWorkspace, const std::vector< std::size_t > &grouping)
virtual API::ITableWorkspace_sptr processParameterTable(API::ITableWorkspace_sptr parameterTable)
virtual bool throwIfElasticQConversionFails() const
std::vector< std::string > m_workspacePropertyNames
std::vector< std::string > m_workspaceIndexPropertyNames
virtual void setPropertyValue(const std::string &name, const std::string &value)=0
Sets property value from a string.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
virtual TypedValue getProperty(const std::string &name) const =0
Get the value of a property.
The Logger class is in charge of the publishing messages from the framework through various channels.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
The concrete, templated class for properties.
void setDocumentation(const std::string &documentation)
Sets the user level description of the property.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< IAlgorithm > IAlgorithm_sptr
shared pointer to Mantid::API::IAlgorithm
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
void renameWorkspacesInQENSFit(Algorithm *qensFit, IAlgorithm_sptr renameAlgorithm, const WorkspaceGroup_sptr &outputGroup, std::string const &outputBaseName, std::string const &groupSuffix, std::function< std::string(std::size_t)> const &getNameSuffix)
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
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
bool containsMultipleData(const std::vector< MatrixWorkspace_sptr > &workspaces)
std::shared_ptr< CompositeFunction > CompositeFunction_sptr
shared pointer to the composite function base class
void setMultiDataProperties(const Mantid::API::IAlgorithm &fittingAlgorithm, Mantid::API::IAlgorithm &fit, const Mantid::API::MatrixWorkspace_sptr &workspace, const std::string &suffix)
std::unique_ptr< T > create(const P &parent, const IndexArg &indexArg, const HistArg &histArg)
This is the create() method that all the other create() methods call.
Mantid::API::NumericAxis * getNumericAxis(int const &numberOfLabels, std::vector< double > const &values)
Mantid::API::TextAxis * getTextAxis(int const &numberOfSpectra, std::vector< std::string > const &labels)
std::shared_ptr< IValidator > IValidator_sptr
A shared_ptr to an IValidator.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ InOut
Both an input & output workspace.
@ Input
An input workspace.
@ Output
An output workspace.