Mantid
Loading...
Searching...
No Matches
IFittingAlgorithm.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
18
26
28
29namespace Mantid::CurveFitting {
30
31using namespace Mantid::Kernel;
32using namespace Mantid::API;
33
34//----------------------------------------------------------------------------------------------
35namespace {
37std::unique_ptr<IDomainCreator> createDomainCreator(const IFunction *fun, const std::string &workspacePropertyName,
38 IPropertyManager *manager, IDomainCreator::DomainType domainType) {
39
40 std::unique_ptr<IDomainCreator> creator;
42
43 try {
44 ws = manager->getProperty("InputWorkspace");
45 } catch (...) {
46 // InputWorkspace is not needed for some fit function so continue
47 }
48
49 // ILatticeFunction requires API::LatticeDomain.
50 if (dynamic_cast<const ILatticeFunction *>(fun)) {
51 creator = std::make_unique<LatticeDomainCreator>(manager, workspacePropertyName);
52 } else if (dynamic_cast<const IFunctionMD *>(fun)) {
53 creator = std::unique_ptr<IDomainCreator>(
54 API::DomainCreatorFactory::Instance().createDomainCreator("FitMD", manager, workspacePropertyName, domainType));
55 } else if (dynamic_cast<const IFunction1DSpectrum *>(fun)) {
56 creator = std::make_unique<SeqDomainSpectrumCreator>(manager, workspacePropertyName);
57 } else if (auto gfun = dynamic_cast<const IFunctionGeneral *>(fun)) {
58 creator = std::make_unique<GeneralDomainCreator>(*gfun, *manager, workspacePropertyName);
59 } else if (std::dynamic_pointer_cast<ITableWorkspace>(ws)) {
60 creator = std::make_unique<TableWorkspaceDomainCreator>(manager, workspacePropertyName, domainType);
61 } else {
62 bool histogramFit = manager->getPropertyValue("EvaluationType") == "Histogram";
63 if (histogramFit) {
64 creator = std::make_unique<HistogramDomainCreator>(*manager, workspacePropertyName);
65 } else {
66 creator = std::make_unique<FitMW>(manager, workspacePropertyName, domainType);
67 }
68 }
69 return creator;
70}
71} // namespace
72
73//----------------------------------------------------------------------------------------------
74
76const std::string IFittingAlgorithm::category() const { return "Optimization"; }
77
78//----------------------------------------------------------------------------------------------
82 declareProperty(std::make_unique<API::FunctionProperty>("Function", Direction::InOut),
83 "Parameters defining the fitting function and its initial values");
84
86 std::make_unique<API::WorkspaceProperty<API::Workspace>>("InputWorkspace", "", Kernel::Direction::Input),
87 "Name of the input Workspace");
88 declareProperty("IgnoreInvalidData", false, "Flag to ignore infinities, NaNs and data with zero errors.");
89
90 std::array<std::string, 3> domainTypes = {{"Simple", "Sequential", "Parallel"}};
91 declareProperty("DomainType", "Simple", Kernel::IValidator_sptr(new Kernel::ListValidator<std::string>(domainTypes)),
92 "The type of function domain to use: Simple, Sequential, or Parallel.", Kernel::Direction::Input);
93
94 std::array<std::string, 2> evaluationTypes = {{"CentrePoint", "Histogram"}};
95 declareProperty("EvaluationType", "CentrePoint",
97 "The way the function is evaluated on histogram data sets. "
98 "If value is \"CentrePoint\" then function is evaluated at "
99 "centre of each bin. If it is \"Histogram\" then function is "
100 "integrated within the bin and the integrals returned.",
102 const std::array<std::string, 3> stepSizes = {{DEFAULT_STEP_SIZE, SQRT_EPSILON_STEP_SIZE, CUSTOM_STEP_SIZE}};
104 "StepSizeMethod", "Default", Kernel::IValidator_sptr(new Kernel::ListValidator<std::string>(stepSizes)),
105 "The way the step size is calculated for numerical derivatives. See the section about step sizes in the Fit "
106 "algorithm documentation to understand the difference between \"" +
107 DEFAULT_STEP_SIZE + "\", \"" + SQRT_EPSILON_STEP_SIZE + "\" and \"" + CUSTOM_STEP_SIZE + "\".",
109 declareProperty("PeakRadius", 0,
110 "A value of the peak radius the peak functions should use. A "
111 "peak radius defines an interval on the x axis around the "
112 "centre of the peak where its values are calculated. Values "
113 "outside the interval are not calculated and assumed zeros."
114 "Numerically the radius is a whole number of peak widths "
115 "(FWHM) that fit into the interval on each side from the "
116 "centre. The default value of 0 means the whole x axis.");
117
118 initConcrete();
119}
120
126void IFittingAlgorithm::afterPropertySet(const std::string &propName) {
127 if (propName == "Function") {
128 setFunction();
129 } else if (propName.size() >= 14 && propName.substr(0, 14) == "InputWorkspace") {
130 if (getPointerToProperty("Function")->isDefault()) {
131 throw std::invalid_argument("Function must be set before InputWorkspace");
132 }
133 addWorkspace(propName);
134 } else if (propName == "DomainType") {
136 } else if (propName == "StepSizeMethod") {
138 }
139}
140
145 std::string domainType = getPropertyValue("DomainType");
146 if (domainType == "Simple") {
148 } else if (domainType == "Sequential") {
150 } else if (domainType == "Parallel") {
152 } else {
154 }
155}
156
158 // get the function
159 m_function = getProperty("Function");
160 size_t ndom = m_function->getNumberDomains();
161 if (ndom > 1) {
162 m_workspacePropertyNames.resize(ndom);
164 m_workspacePropertyNames[0] = "InputWorkspace";
165 m_workspaceIndexPropertyNames[0] = "WorkspaceIndex";
166 for (size_t i = 1; i < ndom; ++i) {
167 std::string workspacePropertyName = "InputWorkspace_" + std::to_string(i);
168 m_workspacePropertyNames[i] = workspacePropertyName;
169 std::string workspaceIndexPropertyName = "WorkspaceIndex_" + std::to_string(i);
170 m_workspaceIndexPropertyNames[i] = workspaceIndexPropertyName;
171 if (!existsProperty(workspacePropertyName)) {
172 declareProperty(std::make_unique<API::WorkspaceProperty<API::Workspace>>(workspacePropertyName, "",
174 "Name of the input Workspace");
175 }
176 }
177 } else {
178 m_workspacePropertyNames.resize(1, "InputWorkspace");
179 m_workspaceIndexPropertyNames.resize(1, "WorkspaceIndex");
180 }
181}
182
187 if (m_function) {
188 const std::string stepSizeMethod = getProperty("StepSizeMethod");
189 if (stepSizeMethod == SQRT_EPSILON_STEP_SIZE) {
190 m_function->setStepSizeMethod(IFunction::StepSizeMethod::SQRT_EPSILON);
191 } else if (stepSizeMethod == CUSTOM_STEP_SIZE) {
192 m_function->setStepSizeMethod(IFunction::StepSizeMethod::CUSTOM);
193 const std::vector<double> customStepSizes = getProperty("CustomStepSizes");
194 m_function->setCustomStepSizes(customStepSizes);
195 } else {
196 m_function->setStepSizeMethod(IFunction::StepSizeMethod::DEFAULT);
197 }
198 }
199}
200
209void IFittingAlgorithm::addWorkspace(const std::string &workspacePropertyName, bool addProperties) {
210 // m_function->setWorkspace(ws);
211 const size_t n = std::string("InputWorkspace").size();
212 const std::string suffix = (workspacePropertyName.size() > n) ? workspacePropertyName.substr(n) : "";
213 const size_t index = suffix.empty() ? 0 : boost::lexical_cast<size_t>(suffix.substr(1));
214
215 IFunction_sptr fun = getProperty("Function");
217
218 auto creator = createDomainCreator(fun.get(), workspacePropertyName, this, m_domainType);
219
220 if (!m_domainCreator) {
221 if (m_workspacePropertyNames.empty()) {
222 // this defines the function and fills in m_workspacePropertyNames with
223 // names of the sort InputWorkspace_#
224 setFunction();
225 }
226 if (fun->getNumberDomains() > 1) {
227 auto multiCreator = std::make_shared<MultiDomainCreator>(this, m_workspacePropertyNames);
228 creator->declareDatasetProperties(suffix, addProperties);
229 multiCreator->setCreator(index, creator.release());
230 m_domainCreator = multiCreator;
231 } else {
232 creator->declareDatasetProperties(suffix, addProperties);
233 m_domainCreator.reset(creator.release());
234 }
235 } else {
236 if (fun->getNumberDomains() > 1) {
237 std::shared_ptr<MultiDomainCreator> multiCreator = std::dynamic_pointer_cast<MultiDomainCreator>(m_domainCreator);
238 if (!multiCreator) {
239 auto const &reference = *m_domainCreator;
240 throw std::runtime_error(std::string("MultiDomainCreator expected, found ") + typeid(reference).name());
241 }
242 if (!multiCreator->hasCreator(index)) {
243 creator->declareDatasetProperties(suffix, addProperties);
244 }
245 multiCreator->setCreator(index, creator.release());
246 } else {
247 creator->declareDatasetProperties(suffix, addProperties);
248 }
249 }
250}
251
258 if (m_function->getNumberDomains() > 1) {
260 }
261 auto props = getProperties();
262 for (auto &prop : props) {
263 if ((*prop).direction() == Kernel::Direction::Input && dynamic_cast<API::IWorkspaceProperty *>(prop)) {
264 const std::string workspacePropertyName = (*prop).name();
265 auto creator = createDomainCreator(m_function.get(), workspacePropertyName, this, m_domainType);
266
267 const size_t n = std::string("InputWorkspace").size();
268 const std::string suffix = (workspacePropertyName.size() > n) ? workspacePropertyName.substr(n) : "";
269 const size_t index = suffix.empty() ? 0 : boost::lexical_cast<size_t>(suffix.substr(1));
270 creator->declareDatasetProperties(suffix, false);
271 if (!m_domainCreator) {
272 m_domainCreator.reset(creator.release());
273 }
274 auto multiCreator = std::dynamic_pointer_cast<MultiDomainCreator>(m_domainCreator);
275 if (multiCreator) {
276 multiCreator->setCreator(index, creator.release());
277 }
278 }
279 }
280
281 // If domain creator wasn't created it's probably because
282 // InputWorkspace property was deleted. Try without the workspace
283 if (!m_domainCreator) {
284 auto creator = createDomainCreator(m_function.get(), "", this, m_domainType);
285 creator->declareDatasetProperties("", true);
286 m_domainCreator.reset(creator.release());
289 }
290}
291
294std::vector<std::string> IFittingAlgorithm::getCostFunctionNames() const {
295 std::vector<std::string> out;
296 auto &factory = CostFunctionFactory::Instance();
297 auto names = factory.getKeys();
298 out.reserve(names.size());
299 for (auto &name : names) {
300 if (std::dynamic_pointer_cast<CostFunctions::CostFuncFitting>(factory.create(name))) {
301 out.emplace_back(name);
302 }
303 }
304 return out;
305}
306
309 Kernel::IValidator_sptr costFuncValidator =
310 std::make_shared<Kernel::ListValidator<std::string>>(getCostFunctionNames());
311 declareProperty("CostFunction", "Least squares", costFuncValidator,
312 "The cost function to be used for the fit, default is Least squares", Kernel::Direction::InOut);
313}
314
317std::shared_ptr<CostFunctions::CostFuncFitting> IFittingAlgorithm::getCostFunctionInitialized() const {
318 // Function may need some preparation.
319 m_function->sortTies();
320 m_function->setUpForFit();
321
324 const bool ignoreInvalidData = getProperty("IgnoreInvalidData");
325 m_domainCreator->ignoreInvalidData(ignoreInvalidData);
326 m_domainCreator->createDomain(domain, values);
327
328 // Set peak radius to the values which will be passed to
329 // all IPeakFunctions
330 int peakRadius = getProperty("PeakRadius");
331 if (auto d1d = dynamic_cast<API::FunctionDomain1D *>(domain.get())) {
332 if (peakRadius != 0) {
333 d1d->setPeakRadius(peakRadius);
334 }
335 }
336
337 // Do something with the function which may depend on workspace.
338 m_domainCreator->initFunction(m_function);
339
340 // get the cost function which must be a CostFuncFitting
341 auto costFunction = std::dynamic_pointer_cast<CostFunctions::CostFuncFitting>(
342 API::CostFunctionFactory::Instance().create(getPropertyValue("CostFunction")));
343
344 costFunction->setIgnoreInvalidData(ignoreInvalidData);
345 costFunction->setFittingFunction(m_function, domain, values);
346
347 return costFunction;
348}
349
350//----------------------------------------------------------------------------------------------
353 if (!m_domainCreator) {
354 setFunction();
356 }
357 m_domainCreator->ignoreInvalidData(getProperty("IgnoreInvalidData"));
358 // Execute the concrete algorithm.
359 this->execConcrete();
360}
361
362} // namespace Mantid::CurveFitting
std::map< DeltaEMode::Type, std::string > index
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.
bool existsProperty(const std::string &name) const override
Checks whether the named property is already in the list of managed property.
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.
bool isDefault(const std::string &name) const
const std::vector< Kernel::Property * > & getProperties() const override
Get the list of managed properties.
const std::string name() const override=0
function to return a name of the algorithm, must be overridden in all algorithms
Represent a domain for functions of one real argument.
DomainType
Type of domain to create.
IFunctionGeneral: a very general function definition.
This is a specialization of IFunction for functions defined on an IMDWorkspace.
Definition IFunctionMD.h:50
This is an interface to a fitting function - a semi-abstarct class.
Definition IFunction.h:166
An interface that is implemented by WorkspaceProperty.
A property class for workspaces.
void declareCostFunctionProperty()
Declare a "CostFunction" property.
virtual void execConcrete()=0
Child classes implement the algorithm logic here.
void setDomainType()
Read domain type property and cache the value.
std::shared_ptr< API::IDomainCreator > m_domainCreator
Pointer to a domain creator.
void addWorkspace(const std::string &workspacePropertyName, bool addProperties=true)
Add a new workspace to the fit.
const std::string category() const override
Algorithm's category for identification.
std::vector< std::string > m_workspacePropertyNames
std::shared_ptr< CostFunctions::CostFuncFitting > getCostFunctionInitialized() const
Create a cost function from the "CostFunction" property and make it ready for evaluation.
void exec() override
Execute the algorithm.
std::shared_ptr< API::IFunction > m_function
Pointer to the fitting function.
std::vector< std::string > getCostFunctionNames() const
Return names of registered cost function for CostFuncFitting dynamic type.
void init() override
Initialize the algorithm's properties.
void setStepSizeMethod()
Sets the method to use when calculating the step size for the numerical derivative.
virtual void initConcrete()=0
Child classes declare their properties here.
void afterPropertySet(const std::string &propName) override
Examine "Function" and "InputWorkspace" properties to decide which domain creator to use.
API::IDomainCreator::DomainType m_domainType
Keep the domain type.
void addWorkspaces()
Collect all input workspace property names in the m_workspacePropertyNames vector.
std::vector< std::string > m_workspaceIndexPropertyNames
Interface to PropertyManager.
virtual TypedValue getProperty(const std::string &name) const =0
Get the value of a property.
virtual std::string getPropertyValue(const std::string &name) const =0
Get the value of a property as a string.
ListValidator is a validator that requires the value of a property to be one of a defined list of pos...
std::shared_ptr< FunctionValues > FunctionValues_sptr
typedef for a shared pointer
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
Definition IFunction.h:748
std::shared_ptr< FunctionDomain > FunctionDomain_sptr
typedef for a shared pointer
const std::string CUSTOM_STEP_SIZE
const std::string SQRT_EPSILON_STEP_SIZE
const std::string DEFAULT_STEP_SIZE
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.
std::shared_ptr< IValidator > IValidator_sptr
A shared_ptr to an IValidator.
Definition IValidator.h:26
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