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) {
81std::string getAdjustedConstraint(std::string
const &constraint) {
82 auto const parameterName = getParameterName(constraint);
84 return limits.first.toStdString() +
"<" + parameterName +
"<" + limits.second.toStdString();
92 : m_presenter(), m_outputBaseName(
"Output_Fit"), m_fitDomains(), m_globalParameters(), m_globalTies(),
115 double startX,
double endX) {
117 throw std::invalid_argument(
"The '" + workspaceName +
" (" +
std::to_string(workspaceIndex.
value) +
118 ")' domain already exists.");
120 m_fitDomains.emplace_back(std::make_unique<FitDomain>(workspaceName, workspaceIndex, startX, endX));
130 if (fitDomain->workspaceName() == workspaceName)
131 fitDomain->setWorkspaceName(newName);
141 throw std::invalid_argument(
"The domain '" + workspaceName +
" (" +
std::to_string(workspaceIndex.
value) +
142 ")' could not be found.");
145std::vector<std::unique_ptr<FitDomain>>::const_iterator
147 auto const isMatch = [&](
auto const &fitDomain) {
148 return fitDomain->workspaceName() == workspaceName && fitDomain->workspaceIndex() == workspaceIndex;
156 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
157 return m_fitDomains[domainIndex.value]->setStartX(startX);
161 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
166 std::string
const &function) {
167 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
168 m_fitDomains[domainIndex.value]->removeFunction(function);
173 std::string
const &function) {
174 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
175 m_fitDomains[domainIndex.value]->addFunction(createIFunction(function));
180 std::string
const &function) {
181 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
182 m_fitDomains[domainIndex.value]->setFunction(createIFunction(function));
188 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
189 return m_fitDomains[domainIndex.value]->getFunctionCopy();
194 std::string
const &functionIndex)
const {
195 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
200 std::string
const &functionIndex)
const {
202 throw std::invalid_argument(
"The domain index provided does not exist.");
205 return replaceTopFunctionIndexWith(functionIndex, domainIndex.
value);
206 return functionIndex;
211 std::string
const &fullParameter,
212 std::string
const &fullTie)
const {
219 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
224 std::string
const &fullParameter,
225 std::string
const &fullTie)
const {
228 if (parameterDomainIndex == tieDomainIndex)
229 return replaceTopFunctionIndexWith(fullTie, domainIndex.
value);
234 if (parameter.empty() ||
isNumber(parameter))
239 return removeTopFunctionIndex(parameter);
255 std::string
const &fullParameter,
double newValue) {
256 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
259 m_fitDomains[domainIndex.value]->setParameterValue(parameter, newValue);
269 std::string
const ¶meter,
double newValue) {
270 for (
auto const &tiedParameterName :
m_fitDomains[domainIndex.
value]->getParametersTiedTo(parameter)) {
279 for (
auto const &globalTie : globalTies)
280 if (fullParameter == globalTie.m_tie)
294 std::string
const &fullAttribute,
296 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
301 std::string
const &fullParameter, std::string
const &tie) {
303 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
311 std::string
const &fullTie) {
321 std::string
const &fullTie) {
325 if (parameter != tie &&
validParameter(domainIndex, fullParameter)) {
329 g_log.
warning(
"Invalid tie '" + fullTie +
"' provided.");
334 std::string
const &fullTie) {
347 g_log.
warning(
"Invalid tie '" + fullTie +
"' provided.");
353 std::string
const &fullParameter) {
354 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
359 std::string
const &functionIndex,
360 std::string
const &constraint) {
361 auto const domainIndex =
findDomainIndex(workspaceName, workspaceIndex);
364 getParameterName(constraint), constraint);
368 return validParameter(getDomainIndexOf(fullParameter), fullParameter);
386 return 1 <= subStrings.size() && subStrings.size() <= 2;
388 return 2 <= subStrings.size() && subStrings.size() <= 3 && isFunctionIndex(subStrings[0]);
390 throw std::invalid_argument(
"Fitting mode must be SEQUENTIAL or SIMULTANEOUS.");
396 auto const domainIndex = getDomainIndexOf(fullParameter);
397 auto const tieDomainIndex = getDomainIndexOf(fullTie);
404 std::string
const &fullParameter,
double value)
const {
421 auto const isTieInvalid = [&](
GlobalTie &globalTie) {
455 globalTie.
m_tie = promotedTie;
457 globalTie.
m_tie = demotedTie;
468 [&fullParameter](
GlobalTie const &globalTie) { return globalTie.m_parameter == fullParameter; });
473 for (
auto const &fullParameter : parameters) {
474 auto const globalParameter = removeTopFunctionIndex(fullParameter);
488 throw std::invalid_argument(
"Fitting mode must be SEQUENTIAL or SIMULTANEOUS.");
503 throw std::runtime_error(
"The domain index provided does not exist.");
514 throw std::runtime_error(
"The domain index provided does not exist.");
523 throw std::runtime_error(
"The domain index provided does not exist.");
529 std::string
const &tie) {
531 throw std::runtime_error(
"The domain index provided does not exist.");
533 auto const fullTie =
getFullTie(domainIndex, tie);
539 std::string
const &constraint) {
542 throw std::runtime_error(
"The domain index provided does not exist.");
544 if (!constraint.empty()) {
546 getFunctionIndex(parameter), getParameterName(constraint), getAdjustedConstraint(constraint));
561 std::string
const &fullParameter)
const {
566 std::string
const &fullParameter)
const {
571 auto const hasParameter = [&globalParameter](
auto const &fitDomain) {
572 return fitDomain->hasParameter(globalParameter);
576 throw std::invalid_argument(globalParameter +
" cannot be global because it doesn't exist for ALL domains.");
580 auto const isNotActive = [&globalParameter](
auto const &fitDomain) {
581 return !fitDomain->isParameterActive(globalParameter);
585 return globalParameter == removeTopFunctionIndex(globalTie.m_parameter);
590 throw std::invalid_argument(globalParameter +
" cannot be global because it already has a "
591 "tie in at least one of the domains.");
596 auto const isGlobal = [¶meter](
GlobalParameter const &globalParameter) {
597 return parameter == globalParameter.m_parameter;
601 throw std::invalid_argument(fullParameter +
" cannot be tied because it is a global parameter.");
606 auto const hasFunction = [](
auto const &fitDomain) {
return fitDomain->getFunctionCopy() !=
nullptr; };
615 auto const functionString =
m_fitDomains[0u]->getFunctionCopy()->asString();
616 auto const hasSameFunction = [&functionString](
auto const &fitDomain) {
617 return fitDomain->getFunctionCopy()->asString() == functionString;
625 message =
"Domain data must be loaded before generating a python script.";
627 message =
"A function must exist in ALL domains to generate a python script.";
630 message =
"The Output Base Name must not be empty, please provide an Output Base Name.";
632 bool valid(message.empty());
636 return {valid, message};
641 return "Note that each domain should have the same fit function, including ties and constraints, for a sequential "
642 "fit. This is not the case for the fit functions you have provided. \n\nThe sequential fit script will be "
643 "generated using the fit function in the first domain.";
649 std::tuple<std::string, std::string, std::string, std::string, std::string, bool>
const &fitOptions,
650 std::string
const &filepath) {
652 generateScript->initialize();
655 generateScript->setProperty(
"StartXs",
getStartXs());
656 generateScript->setProperty(
"EndXs",
getEndXs());
659 generateScript->setProperty(
"Function",
getFunction());
661 auto const [maxIterations, minimizer, costFunction, evaluationType, outputBaseName, plotOutput] = fitOptions;
662 generateScript->setProperty(
"MaxIterations", maxIterations);
663 generateScript->setProperty(
"Minimizer", minimizer);
664 generateScript->setProperty(
"CostFunction", costFunction);
665 generateScript->setProperty(
"EvaluationType", evaluationType);
666 generateScript->setProperty(
"OutputBaseName", outputBaseName);
667 generateScript->setProperty(
"PlotOutput", plotOutput);
669 generateScript->setProperty(
"Filepath", filepath);
670 generateScript->execute();
672 return generateScript->getPropertyValue(
"ScriptText");
676 auto const getWSName = [](std::unique_ptr<FitDomain>
const &domain) {
return domain->workspaceName(); };
677 return transformDomains<std::string>(getWSName);
681 auto const getWSIndex = [](std::unique_ptr<FitDomain>
const &domain) {
return domain->workspaceIndex().value; };
682 return transformDomains<std::size_t>(getWSIndex);
686 auto const getStartX = [](std::unique_ptr<FitDomain>
const &domain) {
return domain->startX(); };
687 return transformDomains<double>(getStartX);
691 auto const getEndX = [](std::unique_ptr<FitDomain>
const &domain) {
return domain->endX(); };
692 return transformDomains<double>(getEndX);
695template <
typename T,
typename Function>
697 std::vector<T> domainData;
708 return "Simultaneous";
710 throw std::invalid_argument(
"Fitting mode must be SEQUENTIAL or SIMULTANEOUS.");
721 throw std::invalid_argument(
"Fitting mode must be SEQUENTIAL or SIMULTANEOUS.");
726 auto multiDomainFunction = std::make_shared<MultiDomainFunction>();
729 multiDomainFunction->addFunction(
m_fitDomains[i]->getFunctionCopy());
730 multiDomainFunction->setDomainIndex(i, i);
735 return multiDomainFunction;
744 std::string tie =
"f0." + globalParameter.
m_parameter;
752 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.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
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)