Mantid
Loading...
Searching...
No Matches
FitScriptGeneratorModel.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2020 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 +
10
16#include "MantidKernel/Logger.h"
17
18#include <algorithm>
19#include <iterator>
20#include <stdexcept>
21
22using namespace Mantid::API;
23using namespace Mantid::Kernel;
24using namespace MantidQt::MantidWidgets;
25
26namespace {
27Mantid::Kernel::Logger g_log("FitScriptGeneratorModel");
28
29IFunction_sptr createIFunction(std::string const &functionString) {
30 return FunctionFactory::Instance().createInitialized(functionString);
31}
32
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);
38 return resultPrefix;
39}
40
41std::string replaceTopFunctionIndexWith(std::string const &functionIndex, std::size_t const &newIndex) {
42 return "f" + std::to_string(newIndex) + "." + removeTopFunctionIndex(functionIndex);
43}
44
45std::string getTieRHS(std::string const &tie) {
46 auto const tieSplit = splitStringBy(tie, "=");
47 return tieSplit.size() > 1 ? tieSplit[1] : tieSplit[0];
48}
49
50std::string getLocalTie(std::string const &tie, FittingMode const &fittingMode) {
51 if (!tie.empty() && fittingMode == FittingMode::SIMULTANEOUS)
52 return removeTopFunctionIndex(getTieRHS(tie));
53 return tie;
54}
55
56bool isFunctionIndex(std::string const &str) {
57 auto const subStrings = splitStringBy(str, "f");
58 if (subStrings.size() == 1)
59 return isNumber(subStrings[0]);
60 return false;
61}
62
63bool isSameDomain(std::size_t const &domainIndex, std::string const &fullParameter) {
64 if (!fullParameter.empty() && !isNumber(fullParameter))
65 return domainIndex == getFunctionIndexAt(fullParameter, 0);
66 return true;
67}
68
69FitDomainIndex getDomainIndexOf(std::string const &fullParameter) {
70 return FitDomainIndex(getFunctionIndexAt(fullParameter, 0));
71}
72
73std::string getParameterName(std::string const &constraint) {
74 return splitParameterName(splitConstraintString(constraint).first).second.toStdString();
75}
76
77std::string getFunctionIndex(std::string const &parameter) {
78 return splitFunctionPrefix(parameter).first.toStdString();
79}
80
81std::string getAdjustedConstraint(std::string const &constraint) {
82 auto const parameterName = getParameterName(constraint);
83 auto const limits = splitConstraintString(constraint).second;
84 return limits.first.toStdString() + "<" + parameterName + "<" + limits.second.toStdString();
85}
86
87} // namespace
88
90
92 : m_presenter(), m_outputBaseName("Output_Fit"), m_fitDomains(), m_globalParameters(), m_globalTies(),
93 m_fittingMode(FittingMode::SEQUENTIAL) {}
94
96 m_fitDomains.clear();
97 m_globalTies.clear();
98 m_globalParameters.clear();
99}
100
102
104 if (domainIndex.value > m_fitDomains.size())
105 return;
106
107 auto const removeIter = m_fitDomains.begin() + domainIndex.value;
108 if (removeIter != m_fitDomains.cend()) {
109 m_fitDomains.erase(removeIter);
111 }
112}
113
114void FitScriptGeneratorModel::addWorkspaceDomain(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
115 double startX, double endX) {
116 if (hasWorkspaceDomain(workspaceName, workspaceIndex))
117 throw std::invalid_argument("The '" + workspaceName + " (" + std::to_string(workspaceIndex.value) +
118 ")' domain already exists.");
119
120 m_fitDomains.emplace_back(std::make_unique<FitDomain>(workspaceName, workspaceIndex, startX, endX));
121}
122
123bool FitScriptGeneratorModel::hasWorkspaceDomain(std::string const &workspaceName,
124 WorkspaceIndex workspaceIndex) const {
125 return findWorkspaceDomain(workspaceName, workspaceIndex) != m_fitDomains.cend();
126}
127
128void FitScriptGeneratorModel::renameWorkspace(std::string const &workspaceName, std::string const &newName) {
129 for (auto const &fitDomain : m_fitDomains) {
130 if (fitDomain->workspaceName() == workspaceName)
131 fitDomain->setWorkspaceName(newName);
132 }
133}
134
136 WorkspaceIndex workspaceIndex) const {
137 auto const iter = findWorkspaceDomain(workspaceName, workspaceIndex);
138 if (iter != m_fitDomains.cend())
139 return FitDomainIndex(std::distance(m_fitDomains.cbegin(), iter));
140
141 throw std::invalid_argument("The domain '" + workspaceName + " (" + std::to_string(workspaceIndex.value) +
142 ")' could not be found.");
143}
144
145std::vector<std::unique_ptr<FitDomain>>::const_iterator
146FitScriptGeneratorModel::findWorkspaceDomain(std::string const &workspaceName, WorkspaceIndex workspaceIndex) const {
147 auto const isMatch = [&](auto const &fitDomain) {
148 return fitDomain->workspaceName() == workspaceName && fitDomain->workspaceIndex() == workspaceIndex;
149 };
150
151 return std::find_if(m_fitDomains.cbegin(), m_fitDomains.cend(), isMatch);
152}
153
154bool FitScriptGeneratorModel::updateStartX(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
155 double startX) {
156 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
157 return m_fitDomains[domainIndex.value]->setStartX(startX);
158}
159
160bool FitScriptGeneratorModel::updateEndX(std::string const &workspaceName, WorkspaceIndex workspaceIndex, double endX) {
161 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
162 return m_fitDomains[domainIndex.value]->setEndX(endX);
163}
164
165void FitScriptGeneratorModel::removeFunction(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
166 std::string const &function) {
167 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
168 m_fitDomains[domainIndex.value]->removeFunction(function);
170}
171
172void FitScriptGeneratorModel::addFunction(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
173 std::string const &function) {
174 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
175 m_fitDomains[domainIndex.value]->addFunction(createIFunction(function));
177}
178
179void FitScriptGeneratorModel::setFunction(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
180 std::string const &function) {
181 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
182 m_fitDomains[domainIndex.value]->setFunction(createIFunction(function));
184}
185
187 WorkspaceIndex workspaceIndex) const {
188 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
189 return m_fitDomains[domainIndex.value]->getFunctionCopy();
190}
191
192std::string FitScriptGeneratorModel::getEquivalentFunctionIndexForDomain(std::string const &workspaceName,
193 WorkspaceIndex workspaceIndex,
194 std::string const &functionIndex) const {
195 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
196 return getEquivalentFunctionIndexForDomain(domainIndex, functionIndex);
197}
198
200 std::string const &functionIndex) const {
201 if (domainIndex.value >= numberOfDomains())
202 throw std::invalid_argument("The domain index provided does not exist.");
203
204 if (!functionIndex.empty() && m_fittingMode == FittingMode::SIMULTANEOUS)
205 return replaceTopFunctionIndexWith(functionIndex, domainIndex.value);
206 return functionIndex;
207}
208
209std::string FitScriptGeneratorModel::getEquivalentParameterTieForDomain(std::string const &workspaceName,
210 WorkspaceIndex workspaceIndex,
211 std::string const &fullParameter,
212 std::string const &fullTie) const {
213 if (fullTie.empty() || isNumber(fullTie) || !validTie(fullTie))
214 return fullTie;
215
217 return fullTie;
218
219 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
220 return getEquivalentParameterTieForDomain(domainIndex, fullParameter, fullTie);
221}
222
224 std::string const &fullParameter,
225 std::string const &fullTie) const {
226 auto const parameterDomainIndex = getFunctionIndexAt(fullParameter, 0);
227 auto const tieDomainIndex = getFunctionIndexAt(fullTie, 0);
228 if (parameterDomainIndex == tieDomainIndex)
229 return replaceTopFunctionIndexWith(fullTie, domainIndex.value);
230 return fullTie;
231}
232
233std::string FitScriptGeneratorModel::getAdjustedFunctionIndex(std::string const &parameter) const {
234 if (parameter.empty() || isNumber(parameter))
235 return parameter;
236
238 return parameter;
239 return removeTopFunctionIndex(parameter);
240}
241
242std::string FitScriptGeneratorModel::getFullParameter(FitDomainIndex domainIndex, std::string const &parameter) const {
244 return parameter;
245 return "f" + std::to_string(domainIndex.value) + "." + parameter;
246}
247
248std::string FitScriptGeneratorModel::getFullTie(FitDomainIndex domainIndex, std::string const &tie) const {
249 if (tie.empty() || isNumber(tie))
250 return tie;
251 return getFullParameter(domainIndex, tie);
252}
253
254void FitScriptGeneratorModel::updateParameterValue(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
255 std::string const &fullParameter, double newValue) {
256 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
257 if (!hasGlobalTie(fullParameter)) {
258 auto const parameter = getAdjustedFunctionIndex(fullParameter);
259 m_fitDomains[domainIndex.value]->setParameterValue(parameter, newValue);
260
261 updateParameterValuesWithLocalTieTo(domainIndex, parameter, newValue);
263 updateParameterValuesWithGlobalTieTo(fullParameter, newValue);
264 }
265 }
266}
267
269 std::string const &parameter, double newValue) {
270 for (auto const &tiedParameterName : m_fitDomains[domainIndex.value]->getParametersTiedTo(parameter)) {
271 m_fitDomains[domainIndex.value]->setParameterValue(tiedParameterName, newValue);
272 }
273}
274
275void FitScriptGeneratorModel::updateParameterValuesWithGlobalTieTo(std::string const &fullParameter, double newValue) {
276 // Deep copy so that global ties can be removed whilst in this for loop. This
277 // will happen if a global tie has been invalidated.
278 auto const globalTies = m_globalTies;
279 for (auto const &globalTie : globalTies)
280 if (fullParameter == globalTie.m_tie)
281 updateParameterValueInGlobalTie(globalTie, newValue);
282}
283
285 if (validGlobalTie(globalTie.m_parameter, globalTie.m_tie)) {
286 auto const domainIndex = getFunctionIndexAt(globalTie.m_parameter, 0);
287 m_fitDomains[domainIndex]->setParameterValue(getAdjustedFunctionIndex(globalTie.m_parameter), newValue);
288 } else {
289 clearGlobalTie(globalTie.m_parameter);
290 }
291}
292
293void FitScriptGeneratorModel::updateAttributeValue(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
294 std::string const &fullAttribute,
295 IFunction::Attribute const &newValue) {
296 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
297 m_fitDomains[domainIndex.value]->setAttributeValue(getAdjustedFunctionIndex(fullAttribute), newValue);
298}
299
300void FitScriptGeneratorModel::updateParameterTie(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
301 std::string const &fullParameter, std::string const &tie) {
302 if (validTie(tie)) {
303 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
304 updateParameterTie(domainIndex, fullParameter, tie);
305 } else {
306 g_log.warning("Invalid tie '" + tie + "' provided.");
307 }
308}
309
310void FitScriptGeneratorModel::updateParameterTie(FitDomainIndex domainIndex, std::string const &fullParameter,
311 std::string const &fullTie) {
312 checkParameterIsNotGlobal(fullParameter);
313
314 if (m_fittingMode == FittingMode::SEQUENTIAL || isSameDomain(domainIndex.value, fullTie))
315 updateLocalParameterTie(domainIndex, fullParameter, fullTie);
316 else
317 updateGlobalParameterTie(domainIndex, fullParameter, fullTie);
318}
319
320void FitScriptGeneratorModel::updateLocalParameterTie(FitDomainIndex domainIndex, std::string const &fullParameter,
321 std::string const &fullTie) {
322 auto const parameter = getAdjustedFunctionIndex(fullParameter);
323 auto const tie = getLocalTie(fullTie, m_fittingMode);
324
325 if (parameter != tie && validParameter(domainIndex, fullParameter)) {
326 if (m_fitDomains[domainIndex.value]->updateParameterTie(parameter, tie))
327 clearGlobalTie(fullParameter);
328 else
329 g_log.warning("Invalid tie '" + fullTie + "' provided.");
330 }
331}
332
333void FitScriptGeneratorModel::updateGlobalParameterTie(FitDomainIndex domainIndex, std::string const &fullParameter,
334 std::string const &fullTie) {
335 if (validParameter(domainIndex, fullParameter)) {
336 if (validGlobalTie(fullParameter, fullTie)) {
337 clearGlobalTie(fullParameter);
338
339 auto const parameter = getAdjustedFunctionIndex(fullParameter);
340 auto const tieValue = getParameterValue(getDomainIndexOf(fullTie), fullTie);
341
342 m_fitDomains[domainIndex.value]->clearParameterTie(parameter);
343 m_fitDomains[domainIndex.value]->setParameterValue(parameter, tieValue);
344
345 m_globalTies.emplace_back(GlobalTie(fullParameter, fullTie));
346 } else {
347 g_log.warning("Invalid tie '" + fullTie + "' provided.");
348 }
349 }
350}
351
352void FitScriptGeneratorModel::removeParameterConstraint(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
353 std::string const &fullParameter) {
354 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
355 m_fitDomains[domainIndex.value]->removeParameterConstraint(getAdjustedFunctionIndex(fullParameter));
356}
357
358void FitScriptGeneratorModel::updateParameterConstraint(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
359 std::string const &functionIndex,
360 std::string const &constraint) {
361 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
362
363 m_fitDomains[domainIndex.value]->updateParameterConstraint(getAdjustedFunctionIndex(functionIndex),
364 getParameterName(constraint), constraint);
365}
366
367bool FitScriptGeneratorModel::validParameter(std::string const &fullParameter) const {
368 return validParameter(getDomainIndexOf(fullParameter), fullParameter);
369}
370
371bool FitScriptGeneratorModel::validParameter(FitDomainIndex domainIndex, std::string const &fullParameter) const {
372 if (domainIndex.value < numberOfDomains()) {
373 auto const parameter = getAdjustedFunctionIndex(fullParameter);
374 return m_fitDomains[domainIndex.value]->hasParameter(parameter);
375 }
376 return false;
377}
378
379bool FitScriptGeneratorModel::validTie(std::string const &tie) const {
380 if (tie.empty() || isNumber(tie))
381 return true;
382
383 auto const subStrings = splitStringBy(tie, ".");
384 switch (m_fittingMode) {
386 return 1 <= subStrings.size() && subStrings.size() <= 2;
388 return 2 <= subStrings.size() && subStrings.size() <= 3 && isFunctionIndex(subStrings[0]);
389 default:
390 throw std::invalid_argument("Fitting mode must be SEQUENTIAL or SIMULTANEOUS.");
391 }
392}
393
394bool FitScriptGeneratorModel::validGlobalTie(std::string const &fullParameter, std::string const &fullTie) const {
395 if (!fullTie.empty() && !isNumber(fullTie) && validParameter(fullTie)) {
396 auto const domainIndex = getDomainIndexOf(fullParameter);
397 auto const tieDomainIndex = getDomainIndexOf(fullTie);
398 return isParameterValueWithinConstraints(domainIndex, fullParameter, getParameterValue(tieDomainIndex, fullTie));
399 }
400 return false;
401}
402
404 std::string const &fullParameter, double value) const {
405 if (domainIndex.value < numberOfDomains()) {
406 auto const parameter = getAdjustedFunctionIndex(fullParameter);
407 return m_fitDomains[domainIndex.value]->isParameterValueWithinConstraints(parameter, value);
408 }
409 return false;
410}
411
412void FitScriptGeneratorModel::clearGlobalTie(std::string const &fullParameter) {
413 auto const removeIter = findGlobalTie(fullParameter);
414 if (removeIter != m_globalTies.cend()) {
415 m_globalTies.erase(removeIter);
417 }
418}
419
421 auto const isTieInvalid = [&](GlobalTie &globalTie) {
424
425 return !validParameter(globalTie.m_parameter) || !validGlobalTie(globalTie.m_parameter, globalTie.m_tie);
426 };
427
428 auto const iter = std::remove_if(m_globalTies.begin(), m_globalTies.end(), isTieInvalid);
429
430 if (iter != m_globalTies.cend())
431 m_globalTies.erase(iter, m_globalTies.cend());
432
434}
435
437 if (!validParameter(globalTie.m_parameter)) {
438 auto const promotedParam = globalTie.toCompositeParameter(globalTie.m_parameter);
439 auto const demotedParam = globalTie.toNonCompositeParameter(globalTie.m_parameter);
440
441 if (validParameter(promotedParam)) {
442 globalTie.m_parameter = promotedParam;
443 } else if (validParameter(demotedParam)) {
444 globalTie.m_parameter = demotedParam;
445 }
446 }
447}
448
450 if (!validGlobalTie(globalTie.m_parameter, globalTie.m_tie)) {
451 auto const promotedTie = globalTie.toCompositeParameter(globalTie.m_tie);
452 auto const demotedTie = globalTie.toNonCompositeParameter(globalTie.m_tie);
453
454 if (validGlobalTie(globalTie.m_parameter, promotedTie)) {
455 globalTie.m_tie = promotedTie;
456 } else if (validGlobalTie(globalTie.m_parameter, demotedTie)) {
457 globalTie.m_tie = demotedTie;
458 }
459 }
460}
461
462bool FitScriptGeneratorModel::hasGlobalTie(std::string const &fullParameter) const {
463 return findGlobalTie(fullParameter) != m_globalTies.cend();
464}
465
466std::vector<GlobalTie>::const_iterator FitScriptGeneratorModel::findGlobalTie(std::string const &fullParameter) const {
467 return std::find_if(m_globalTies.cbegin(), m_globalTies.cend(),
468 [&fullParameter](GlobalTie const &globalTie) { return globalTie.m_parameter == fullParameter; });
469}
470
471void FitScriptGeneratorModel::setGlobalParameters(std::vector<std::string> const &parameters) {
472 m_globalParameters.clear();
473 for (auto const &fullParameter : parameters) {
474 auto const globalParameter = removeTopFunctionIndex(fullParameter);
475 checkParameterIsInAllDomains(globalParameter);
476 checkGlobalParameterhasNoTies(globalParameter);
477
478 m_globalParameters.emplace_back(GlobalParameter(globalParameter));
479 }
480}
481
482void FitScriptGeneratorModel::setOutputBaseName(std::string const &outputBaseName) {
483 m_outputBaseName = outputBaseName;
484}
485
488 throw std::invalid_argument("Fitting mode must be SEQUENTIAL or SIMULTANEOUS.");
489
490 m_fittingMode = fittingMode;
491 m_globalTies.clear();
493 m_globalParameters.clear();
495}
496
498
500 if (domainIndex.value < numberOfDomains())
501 return m_fitDomains[domainIndex.value]->domainName();
502
503 throw std::runtime_error("The domain index provided does not exist.");
504}
505
506bool FitScriptGeneratorModel::hasParameter(FitDomainIndex domainIndex, std::string const &fullParameter) const {
507 return getParameterProperty(&FitDomain::hasParameter, domainIndex, fullParameter);
508}
509
510void FitScriptGeneratorModel::setParameterValue(FitDomainIndex domainIndex, std::string const &fullParameter,
511 double value) {
512 auto const parameter = getAdjustedFunctionIndex(fullParameter);
513 if (domainIndex.value >= numberOfDomains())
514 throw std::runtime_error("The domain index provided does not exist.");
515
516 m_fitDomains[domainIndex.value]->setParameterValue(parameter, value);
517}
518
519void FitScriptGeneratorModel::setParameterFixed(FitDomainIndex domainIndex, std::string const &fullParameter,
520 bool fix) {
521 auto const parameter = getAdjustedFunctionIndex(fullParameter);
522 if (domainIndex.value >= numberOfDomains())
523 throw std::runtime_error("The domain index provided does not exist.");
524
525 m_fitDomains[domainIndex.value]->setParameterFixed(parameter, fix);
526}
527
528void FitScriptGeneratorModel::setParameterTie(FitDomainIndex domainIndex, std::string const &fullParameter,
529 std::string const &tie) {
530 if (domainIndex.value >= numberOfDomains())
531 throw std::runtime_error("The domain index provided does not exist.");
532
533 auto const fullTie = getFullTie(domainIndex, tie);
534 if (validTie(fullTie))
535 updateParameterTie(domainIndex, fullParameter, fullTie);
536}
537
538void FitScriptGeneratorModel::setParameterConstraint(FitDomainIndex domainIndex, std::string const &fullParameter,
539 std::string const &constraint) {
540 auto const parameter = getAdjustedFunctionIndex(fullParameter);
541 if (domainIndex.value >= numberOfDomains())
542 throw std::runtime_error("The domain index provided does not exist.");
543
544 if (!constraint.empty()) {
545 m_fitDomains[domainIndex.value]->updateParameterConstraint(
546 getFunctionIndex(parameter), getParameterName(constraint), getAdjustedConstraint(constraint));
547 } else {
548 m_fitDomains[domainIndex.value]->removeParameterConstraint(parameter);
549 }
550}
551
552double FitScriptGeneratorModel::getParameterValue(FitDomainIndex domainIndex, std::string const &fullParameter) const {
553 return getParameterProperty(&FitDomain::getParameterValue, domainIndex, fullParameter);
554}
555
556bool FitScriptGeneratorModel::isParameterFixed(FitDomainIndex domainIndex, std::string const &fullParameter) const {
557 return getParameterProperty(&FitDomain::isParameterFixed, domainIndex, fullParameter);
558}
559
561 std::string const &fullParameter) const {
562 return getParameterProperty(&FitDomain::getParameterTie, domainIndex, fullParameter);
563}
564
566 std::string const &fullParameter) const {
567 return getParameterProperty(&FitDomain::getParameterConstraint, domainIndex, fullParameter);
568}
569
570void FitScriptGeneratorModel::checkParameterIsInAllDomains(std::string const &globalParameter) const {
571 auto const hasParameter = [&globalParameter](auto const &fitDomain) {
572 return fitDomain->hasParameter(globalParameter);
573 };
574
575 if (!std::all_of(m_fitDomains.cbegin(), m_fitDomains.cend(), hasParameter))
576 throw std::invalid_argument(globalParameter + " cannot be global because it doesn't exist for ALL domains.");
577}
578
579void FitScriptGeneratorModel::checkGlobalParameterhasNoTies(std::string const &globalParameter) const {
580 auto const isNotActive = [&globalParameter](auto const &fitDomain) {
581 return !fitDomain->isParameterActive(globalParameter);
582 };
583
584 auto const hasGlobalTie = [&globalParameter](GlobalTie const &globalTie) {
585 return globalParameter == removeTopFunctionIndex(globalTie.m_parameter);
586 };
587
588 if (std::any_of(m_fitDomains.cbegin(), m_fitDomains.cend(), isNotActive) ||
589 std::any_of(m_globalTies.cbegin(), m_globalTies.cend(), hasGlobalTie))
590 throw std::invalid_argument(globalParameter + " cannot be global because it already has a "
591 "tie in at least one of the domains.");
592}
593
594void FitScriptGeneratorModel::checkParameterIsNotGlobal(std::string const &fullParameter) const {
595 auto const parameter = getAdjustedFunctionIndex(fullParameter);
596 auto const isGlobal = [&parameter](GlobalParameter const &globalParameter) {
597 return parameter == globalParameter.m_parameter;
598 };
599
600 if (std::any_of(m_globalParameters.cbegin(), m_globalParameters.cend(), isGlobal)) {
601 throw std::invalid_argument(fullParameter + " cannot be tied because it is a global parameter.");
602 }
603}
604
606 auto const hasFunction = [](auto const &fitDomain) { return fitDomain->getFunctionCopy() != nullptr; };
607 return std::all_of(m_fitDomains.cbegin(), m_fitDomains.cend(), hasFunction);
608}
609
611 if (numberOfDomains() == 0u || m_fitDomains[0u]->getFunctionCopy() == nullptr) {
612 return false;
613 }
614
615 auto const functionString = m_fitDomains[0u]->getFunctionCopy()->asString();
616 auto const hasSameFunction = [&functionString](auto const &fitDomain) {
617 return fitDomain->getFunctionCopy()->asString() == functionString;
618 };
619 return std::all_of(m_fitDomains.cbegin(), m_fitDomains.cend(), hasSameFunction);
620}
621
622std::tuple<bool, std::string> FitScriptGeneratorModel::isValid() const {
623 std::string message;
624 if (numberOfDomains() == 0u)
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.";
628
629 if (m_outputBaseName.empty())
630 message = "The Output Base Name must not be empty, please provide an Output Base Name.";
631
632 bool valid(message.empty());
633 if (valid)
634 message = generatePermissibleWarnings();
635
636 return {valid, message};
637}
638
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.";
644 }
645 return "";
646}
647
649 std::tuple<std::string, std::string, std::string, std::string, std::string, bool> const &fitOptions,
650 std::string const &filepath) {
651 auto generateScript = AlgorithmManager::Instance().create("GeneratePythonFitScript");
652 generateScript->initialize();
653 generateScript->setProperty("InputWorkspaces", getInputWorkspaces());
654 generateScript->setProperty("WorkspaceIndices", getWorkspaceIndices());
655 generateScript->setProperty("StartXs", getStartXs());
656 generateScript->setProperty("EndXs", getEndXs());
657
658 generateScript->setProperty("FittingType", getFittingType());
659 generateScript->setProperty("Function", getFunction());
660
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);
668
669 generateScript->setProperty("Filepath", filepath);
670 generateScript->execute();
671
672 return generateScript->getPropertyValue("ScriptText");
673}
674
675std::vector<std::string> FitScriptGeneratorModel::getInputWorkspaces() const {
676 auto const getWSName = [](std::unique_ptr<FitDomain> const &domain) { return domain->workspaceName(); };
677 return transformDomains<std::string>(getWSName);
678}
679
680std::vector<std::size_t> FitScriptGeneratorModel::getWorkspaceIndices() const {
681 auto const getWSIndex = [](std::unique_ptr<FitDomain> const &domain) { return domain->workspaceIndex().value; };
682 return transformDomains<std::size_t>(getWSIndex);
683}
684
685std::vector<double> FitScriptGeneratorModel::getStartXs() const {
686 auto const getStartX = [](std::unique_ptr<FitDomain> const &domain) { return domain->startX(); };
687 return transformDomains<double>(getStartX);
688}
689
690std::vector<double> FitScriptGeneratorModel::getEndXs() const {
691 auto const getEndX = [](std::unique_ptr<FitDomain> const &domain) { return domain->endX(); };
692 return transformDomains<double>(getEndX);
693}
694
695template <typename T, typename Function>
696std::vector<T> FitScriptGeneratorModel::transformDomains(Function const &func) const {
697 std::vector<T> domainData;
698 domainData.reserve(numberOfDomains());
699 std::transform(m_fitDomains.cbegin(), m_fitDomains.cend(), std::back_inserter(domainData), func);
700 return domainData;
701}
702
704 switch (m_fittingMode) {
706 return "Sequential";
708 return "Simultaneous";
709 default:
710 throw std::invalid_argument("Fitting mode must be SEQUENTIAL or SIMULTANEOUS.");
711 }
712}
713
715 switch (m_fittingMode) {
717 return m_fitDomains[0u]->getFunctionCopy();
719 return getMultiDomainFunction();
720 default:
721 throw std::invalid_argument("Fitting mode must be SEQUENTIAL or SIMULTANEOUS.");
722 }
723}
724
726 auto multiDomainFunction = std::make_shared<MultiDomainFunction>();
727
728 for (auto i = 0u; i < numberOfDomains(); ++i) {
729 multiDomainFunction->addFunction(m_fitDomains[i]->getFunctionCopy());
730 multiDomainFunction->setDomainIndex(i, i);
731 }
732
733 addGlobalParameterTies(multiDomainFunction);
734 addGlobalTies(multiDomainFunction);
735 return multiDomainFunction;
736}
737
739 for (auto const &globalParameter : m_globalParameters)
740 function->addTies(constructGlobalParameterTie(globalParameter));
741}
742
744 std::string tie = "f0." + globalParameter.m_parameter;
745 for (auto i = 1u; i < numberOfDomains(); ++i)
746 tie += "=f" + std::to_string(i) + "." + globalParameter.m_parameter;
747 return tie;
748}
749
751 for (auto const &globalTie : m_globalTies)
752 function->addTies(globalTie.asString());
753}
754
755} // namespace MantidQt::MantidWidgets
double value
The value of the point.
Definition: FitMW.cpp:51
std::string getParameterTie(std::string const &parameter) const
Definition: FitDomain.cpp:212
double getParameterValue(std::string const &parameter) const
Definition: FitDomain.cpp:157
bool hasParameter(std::string const &parameter) const
Definition: FitDomain.cpp:182
std::string getParameterConstraint(std::string const &parameter) const
Definition: FitDomain.cpp:226
bool isParameterFixed(std::string const &parameter) const
Definition: FitDomain.cpp:205
void addGlobalParameterTies(Mantid::API::MultiDomainFunction_sptr &function) const
void setOutputBaseName(std::string const &outputBaseName) override
std::vector< T > transformDomains(Function const &func) const
void updateLocalParameterTie(FitDomainIndex domainIndex, std::string const &fullParameter, std::string const &fullTie)
void setParameterTie(FitDomainIndex domainIndex, std::string const &fullParameter, std::string const &tie) override
void updateParameterConstraint(std::string const &workspaceName, WorkspaceIndex workspaceIndex, std::string const &functionIndex, std::string const &constraint) override
void removeFunction(std::string const &workspaceName, WorkspaceIndex workspaceIndex, std::string const &function) override
std::vector< std::unique_ptr< FitDomain > > m_fitDomains
void updateParameterValue(std::string const &workspaceName, WorkspaceIndex workspaceIndex, std::string const &fullParameter, double newValue) override
void updateGlobalParameterTie(FitDomainIndex domainIndex, std::string const &fullParameter, std::string const &fullTie)
void subscribePresenter(IFitScriptGeneratorPresenter *presenter) override
Mantid::API::IFunction_sptr getMultiDomainFunction() const
void removeParameterConstraint(std::string const &workspaceName, WorkspaceIndex workspaceIndex, std::string const &fullParameter) override
std::string getEquivalentFunctionIndexForDomain(std::string const &workspaceName, WorkspaceIndex workspaceIndex, std::string const &functionIndex) const override
std::string getAdjustedFunctionIndex(std::string const &parameter) const override
void setParameterConstraint(FitDomainIndex domainIndex, std::string const &fullParameter, std::string const &constraint) override
void checkParameterIsInAllDomains(std::string const &globalParameter) const
void setFittingMode(FittingMode fittingMode) override
void checkGlobalParameterhasNoTies(std::string const &globalParameter) const
void clearGlobalTie(std::string const &fullParameter)
void updateAttributeValue(std::string const &workspaceName, WorkspaceIndex workspaceIndex, std::string const &fullAttribute, Mantid::API::IFunction::Attribute const &newValue) override
void setGlobalParameters(std::vector< std::string > const &parameters) override
std::string getParameterTie(FitDomainIndex domainIndex, std::string const &fullParameter) const override
void checkParameterIsNotGlobal(std::string const &fullParameter) const
bool updateEndX(std::string const &workspaceName, WorkspaceIndex workspaceIndex, double endX) override
void renameWorkspace(std::string const &workspaceName, std::string const &newName) override
void setParameterFixed(FitDomainIndex domainIndex, std::string const &fullParameter, bool fix) override
std::vector< GlobalTie >::const_iterator findGlobalTie(std::string const &fullParameter) const
void addWorkspaceDomain(std::string const &workspaceName, WorkspaceIndex workspaceIndex, double startX, double endX) override
bool updateStartX(std::string const &workspaceName, WorkspaceIndex workspaceIndex, double startX) override
bool hasParameter(FitDomainIndex domainIndex, std::string const &fullParameter) const override
std::string generatePythonFitScript(std::tuple< std::string, std::string, std::string, std::string, std::string, bool > const &fitOptions, std::string const &filepath="") override
void addFunction(std::string const &workspaceName, WorkspaceIndex workspaceIndex, std::string const &function) override
void setParameterValue(FitDomainIndex domainIndex, std::string const &fullParameter, double value) override
bool isParameterFixed(FitDomainIndex domainIndex, std::string const &fullParameter) const override
std::tuple< bool, std::string > isValid() const override
void setFunction(std::string const &workspaceName, WorkspaceIndex workspaceIndex, std::string const &function) override
std::string constructGlobalParameterTie(GlobalParameter const &globalParameter) const
std::size_t numberOfDomains() const noexcept override
std::string getDomainName(FitDomainIndex domainIndex) const override
std::vector< std::unique_ptr< FitDomain > >::const_iterator findWorkspaceDomain(std::string const &workspaceName, WorkspaceIndex workspaceIndex) const
bool validGlobalTie(std::string const &fullParameter, std::string const &fullTie) const
void updateParameterValueInGlobalTie(GlobalTie const &globalTie, double newValue)
bool validParameter(std::string const &fullParameter) const
void updateParameterValuesWithGlobalTieTo(std::string const &fullParameter, double newValue)
FitDomainIndex findDomainIndex(std::string const &workspaceName, WorkspaceIndex workspaceIndex) const
void addGlobalTies(Mantid::API::MultiDomainFunction_sptr &function) const
std::string getFullTie(FitDomainIndex domainIndex, std::string const &tie) const override
bool hasGlobalTie(std::string const &fullParameter) const
std::string getFullParameter(FitDomainIndex domainIndex, std::string const &parameter) const override
void updateParameterTie(std::string const &workspaceName, WorkspaceIndex workspaceIndex, std::string const &fullParameter, std::string const &tie) override
bool isParameterValueWithinConstraints(FitDomainIndex domainIndex, std::string const &fullParameter, double value) const
std::string getParameterConstraint(FitDomainIndex domainIndex, std::string const &fullParameter) const override
auto getParameterProperty(Getter &&func, FitDomainIndex domainIndex, std::string const &fullParameter) const
std::string getEquivalentParameterTieForDomain(std::string const &workspaceName, WorkspaceIndex workspaceIndex, std::string const &fullParameter, std::string const &fullTie) const override
void updateParameterValuesWithLocalTieTo(FitDomainIndex domainIndex, std::string const &parameter, double newValue)
bool hasWorkspaceDomain(std::string const &workspaceName, WorkspaceIndex workspaceIndex) const override
double getParameterValue(FitDomainIndex domainIndex, std::string const &fullParameter) const override
void removeDomain(FitDomainIndex domainIndex) override
virtual void setGlobalTies(std::vector< MantidQt::MantidWidgets::GlobalTie > const &globalTies)=0
virtual void setGlobalParameters(std::vector< MantidQt::MantidWidgets::GlobalParameter > const &globalParameters)=0
Attribute is a non-fitting parameter.
Definition: IFunction.h:282
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition: Logger.h:52
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
EXPORT_OPT_MANTIDQT_COMMON bool isNumber(std::string const &str)
Checks if a string contains a number, or whether it contains characters.
EXPORT_OPT_MANTIDQT_COMMON std::pair< QString, std::pair< QString, QString > > splitConstraintString(const std::string &constraint)
Split a constraint definition into a parameter name and a pair of bounds, for example -1 < f0....
EXPORT_OPT_MANTIDQT_COMMON std::size_t getFunctionIndexAt(std::string const &parameter, std::size_t const &index)
Returns the function index found at index of a parameter.
EXPORT_OPT_MANTIDQT_COMMON std::pair< QString, int > splitFunctionPrefix(const std::string &prefix)
Split a function (eg f0.f3.f1.) into the parent prefix (f0.f3.) and the index of the child function (...
IndexType< 0 > FitDomainIndex
Definition: IndexTypes.h:59
EXPORT_OPT_MANTIDQT_COMMON std::vector< std::string > splitStringBy(std::string const &str, std::string const &delimiter)
Splits the string by the given delimiters.
EXPORT_OPT_MANTIDQT_COMMON std::pair< QString, QString > splitParameterName(const QString &paramName)
Split a qualified parameter name into function index and local parameter name.
std::shared_ptr< MultiDomainFunction > MultiDomainFunction_sptr
Shared pointer to Mantid::API::MultiDomainFunction.
Definition: IFunction_fwd.h:35
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
Definition: IFunction.h:732
std::string to_string(const wide_integer< Bits, Signed > &n)
This struct stores the name of a global parameter which is shared across ALL domains in a multi datas...
This struct stores the data associated with a global tie.
std::string toNonCompositeParameter(std ::string const &fullParameter) const
std::string toCompositeParameter(std ::string const &fullParameter) const
A struct to impliment strongly typed integers, without implicit conversion.
Definition: IndexTypes.h:24
IntImplementationType value
Definition: IndexTypes.h:26