30 return FunctionFactory::Instance().createInitialized(functionString);
33std::string removeTopFunctionIndex(std::string
const &functionIndex) {
34 auto resultPrefix = functionIndex;
35 auto const firstDotIndex = resultPrefix.find(
".");
36 if (firstDotIndex != std::string::npos)
37 resultPrefix.erase(0, firstDotIndex + 1);
41std::string replaceTopFunctionIndexWith(std::string
const &functionIndex, std::size_t
const &newIndex) {
42 return "f" +
std::to_string(newIndex) +
"." + removeTopFunctionIndex(functionIndex);
45std::string getTieRHS(std::string
const &tie) {
47 return tieSplit.size() > 1 ? tieSplit[1] : tieSplit[0];
50std::string getLocalTie(std::string
const &tie,
FittingMode const &fittingMode) {
51 if (!tie.empty() && fittingMode == FittingMode::SIMULTANEOUS)
52 return removeTopFunctionIndex(getTieRHS(tie));
56bool isFunctionIndex(std::string
const &str) {
58 if (subStrings.size() == 1)
63bool isSameDomain(std::size_t
const &domainIndex, std::string
const &fullParameter) {
64 if (!fullParameter.empty() && !
isNumber(fullParameter))
73std::string getParameterName(std::string
const &constraint) {
77std::string getFunctionIndex(std::string
const ¶meter) {
return splitFunctionPrefix(parameter).first; }
79std::string getAdjustedConstraint(std::string
const &constraint) {
80 auto const parameterName = getParameterName(constraint);
82 return limits.first +
"<" + parameterName +
"<" + limits.second;
90 : m_presenter(), m_outputBaseName(
"Output_Fit"), m_fitDomains(), m_globalParameters(), m_globalTies(),
113 double startX,
double endX) {
115 throw std::invalid_argument(
"The '" + workspaceName +
" (" +
std::to_string(workspaceIndex.
value) +
116 ")' domain already exists.");
118 m_fitDomains.emplace_back(std::make_unique<FitDomain>(workspaceName, workspaceIndex, startX, endX));
128 if (fitDomain->workspaceName() == workspaceName)
129 fitDomain->setWorkspaceName(newName);
139 throw std::invalid_argument(
"The domain '" + workspaceName +
" (" +
std::to_string(workspaceIndex.
value) +
140 ")' could not be found.");
143std::vector<std::unique_ptr<FitDomain>>::const_iterator
145 auto const isMatch = [&](
auto const &fitDomain) {
146 return fitDomain->workspaceName() == workspaceName && fitDomain->workspaceIndex() == workspaceIndex;
154 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
155 return m_fitDomains[domainIndex.value]->setStartX(startX);
159 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
164 std::string
const &function) {
165 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
166 m_fitDomains[domainIndex.value]->removeFunction(function);
171 std::string
const &function) {
172 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
173 m_fitDomains[domainIndex.value]->addFunction(createIFunction(function));
178 std::string
const &function) {
179 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
180 m_fitDomains[domainIndex.value]->setFunction(createIFunction(function));
186 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
187 return m_fitDomains[domainIndex.value]->getFunctionCopy();
192 std::string
const &functionIndex)
const {
193 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
198 std::string
const &functionIndex)
const {
200 throw std::invalid_argument(
"The domain index provided does not exist.");
203 return replaceTopFunctionIndexWith(functionIndex, domainIndex.
value);
204 return functionIndex;
209 std::string
const &fullParameter,
210 std::string
const &fullTie)
const {
217 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
222 std::string
const &fullParameter,
223 std::string
const &fullTie)
const {
226 if (parameterDomainIndex == tieDomainIndex)
227 return replaceTopFunctionIndexWith(fullTie, domainIndex.
value);
232 if (parameter.empty() ||
isNumber(parameter))
237 return removeTopFunctionIndex(parameter);
253 std::string
const &fullParameter,
double newValue) {
254 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
257 m_fitDomains[domainIndex.value]->setParameterValue(parameter, newValue);
267 std::string
const ¶meter,
double newValue) {
268 for (
auto const &tiedParameterName :
m_fitDomains[domainIndex.
value]->getParametersTiedTo(parameter)) {
277 for (
auto const &globalTie : globalTies)
278 if (fullParameter == globalTie.m_tie)
292 std::string
const &fullAttribute,
294 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
299 std::string
const &fullParameter, std::string
const &tie) {
301 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
309 std::string
const &fullTie) {
319 std::string
const &fullTie) {
323 if (parameter != tie &&
validParameter(domainIndex, fullParameter)) {
327 g_log.
warning(
"Invalid tie '" + fullTie +
"' provided.");
332 std::string
const &fullTie) {
345 g_log.
warning(
"Invalid tie '" + fullTie +
"' provided.");
351 std::string
const &fullParameter) {
352 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
357 std::string
const &functionIndex,
358 std::string
const &constraint) {
359 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
362 getParameterName(constraint), constraint);
366 return validParameter(getDomainIndexOf(fullParameter), fullParameter);
384 return 1 <= subStrings.size() && subStrings.size() <= 2;
386 return 2 <= subStrings.size() && subStrings.size() <= 3 && isFunctionIndex(subStrings[0]);
388 throw std::invalid_argument(
"Fitting mode must be SEQUENTIAL or SIMULTANEOUS.");
394 auto const domainIndex = getDomainIndexOf(fullParameter);
395 auto const tieDomainIndex = getDomainIndexOf(fullTie);
402 std::string
const &fullParameter,
double value)
const {
419 auto const isTieInvalid = [&](
GlobalTie &globalTie) {
453 globalTie.
m_tie = promotedTie;
455 globalTie.
m_tie = demotedTie;
466 [&fullParameter](
GlobalTie const &globalTie) { return globalTie.m_parameter == fullParameter; });
471 for (
auto const &fullParameter : parameters) {
472 auto const globalParameter = removeTopFunctionIndex(fullParameter);
486 throw std::invalid_argument(
"Fitting mode must be SEQUENTIAL or SIMULTANEOUS.");
501 throw std::runtime_error(
"The domain index provided does not exist.");
512 throw std::runtime_error(
"The domain index provided does not exist.");
521 throw std::runtime_error(
"The domain index provided does not exist.");
527 std::string
const &tie) {
529 throw std::runtime_error(
"The domain index provided does not exist.");
531 auto const fullTie =
getFullTie(domainIndex, tie);
537 std::string
const &constraint) {
540 throw std::runtime_error(
"The domain index provided does not exist.");
542 if (!constraint.empty()) {
544 getFunctionIndex(parameter), getParameterName(constraint), getAdjustedConstraint(constraint));
559 std::string
const &fullParameter)
const {
564 std::string
const &fullParameter)
const {
569 auto const domainHasParameter = [&globalParameter](
auto const &fitDomain) {
570 return fitDomain->hasParameter(globalParameter);
574 throw std::invalid_argument(globalParameter +
" cannot be global because it doesn't exist for ALL domains.");
578 auto const isNotActive = [&globalParameter](
auto const &fitDomain) {
579 return !fitDomain->isParameterActive(globalParameter);
582 auto const parameterHasGlobalTie = [&globalParameter](
GlobalTie const &globalTie) {
583 return globalParameter == removeTopFunctionIndex(globalTie.m_parameter);
588 throw std::invalid_argument(globalParameter +
" cannot be global because it already has a "
589 "tie in at least one of the domains.");
594 auto const isGlobal = [¶meter](
GlobalParameter const &globalParameter) {
595 return parameter == globalParameter.m_parameter;
599 throw std::invalid_argument(fullParameter +
" cannot be tied because it is a global parameter.");
604 auto const hasFunction = [](
auto const &fitDomain) {
return fitDomain->getFunctionCopy() !=
nullptr; };
613 auto const functionString =
m_fitDomains[0u]->getFunctionCopy()->asString();
614 auto const hasSameFunction = [&functionString](
auto const &fitDomain) {
615 return fitDomain->getFunctionCopy()->asString() == functionString;
623 message =
"Domain data must be loaded before generating a python script.";
625 message =
"A function must exist in ALL domains to generate a python script.";
628 message =
"The Output Base Name must not be empty, please provide an Output Base Name.";
630 bool valid(message.empty());
634 return {valid, message};
639 return "Note that each domain should have the same fit function, including ties and constraints, for a sequential "
640 "fit. This is not the case for the fit functions you have provided. \n\nThe sequential fit script will be "
641 "generated using the fit function in the first domain.";
647 std::tuple<std::string, std::string, std::string, std::string, std::string, bool>
const &fitOptions,
648 std::string
const &filepath) {
649 auto generateScript = AlgorithmManager::Instance().create(
"GeneratePythonFitScript");
650 generateScript->initialize();
653 generateScript->setProperty(
"StartXs",
getStartXs());
654 generateScript->setProperty(
"EndXs",
getEndXs());
657 generateScript->setProperty(
"Function",
getFunction());
659 auto const [maxIterations, minimizer, costFunction, evaluationType, outputBaseName, plotOutput] = fitOptions;
660 generateScript->setProperty(
"MaxIterations", maxIterations);
661 generateScript->setProperty(
"Minimizer", minimizer);
662 generateScript->setProperty(
"CostFunction", costFunction);
663 generateScript->setProperty(
"EvaluationType", evaluationType);
664 generateScript->setProperty(
"OutputBaseName", outputBaseName);
665 generateScript->setProperty(
"PlotOutput", plotOutput);
667 generateScript->setProperty(
"Filepath", filepath);
668 generateScript->execute();
670 return generateScript->getPropertyValue(
"ScriptText");
674 auto const getWSName = [](std::unique_ptr<FitDomain>
const &domain) {
return domain->workspaceName(); };
675 return transformDomains<std::string>(getWSName);
679 auto const getWSIndex = [](std::unique_ptr<FitDomain>
const &domain) {
return domain->workspaceIndex().value; };
680 return transformDomains<std::size_t>(getWSIndex);
684 auto const getStartX = [](std::unique_ptr<FitDomain>
const &domain) {
return domain->startX(); };
685 return transformDomains<double>(getStartX);
689 auto const getEndX = [](std::unique_ptr<FitDomain>
const &domain) {
return domain->endX(); };
690 return transformDomains<double>(getEndX);
693template <
typename T,
typename Function>
695 std::vector<T> domainData;
706 return "Simultaneous";
708 throw std::invalid_argument(
"Fitting mode must be SEQUENTIAL or SIMULTANEOUS.");
719 throw std::invalid_argument(
"Fitting mode must be SEQUENTIAL or SIMULTANEOUS.");
724 auto multiDomainFunction = std::make_shared<MultiDomainFunction>();
727 multiDomainFunction->addFunction(
m_fitDomains[i]->getFunctionCopy());
728 multiDomainFunction->setDomainIndex(i, i);
733 return multiDomainFunction;
742 std::string tie =
"f0." + globalParameter.
m_parameter;
750 function->addTies(globalTie.asString());
double value
The value of the point.
std::string getParameterTie(std::string const ¶meter) const
double getParameterValue(std::string const ¶meter) const
bool hasParameter(std::string const ¶meter) const
std::string getParameterConstraint(std::string const ¶meter) const
bool isParameterFixed(std::string const ¶meter) const
Attribute is a non-fitting parameter.
The Logger class is in charge of the publishing messages from the framework through various channels.
void warning(const std::string &msg)
Logs at warning level.
std::shared_ptr< MultiDomainFunction > MultiDomainFunction_sptr
Shared pointer to Mantid::API::MultiDomainFunction.
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
std::string to_string(const wide_integer< Bits, Signed > &n)