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;
75}
76
77std::string getFunctionIndex(std::string const &parameter) { return splitFunctionPrefix(parameter).first; }
78
79std::string getAdjustedConstraint(std::string const &constraint) {
80 auto const parameterName = getParameterName(constraint);
81 auto const limits = splitConstraintString(constraint).second;
82 return limits.first + "<" + parameterName + "<" + limits.second;
83}
84
85} // namespace
86
88
90 : m_presenter(), m_outputBaseName("Output_Fit"), m_fitDomains(), m_globalParameters(), m_globalTies(),
91 m_fittingMode(FittingMode::SEQUENTIAL) {}
92
98
100
102 if (domainIndex.value > m_fitDomains.size())
103 return;
104
105 auto const removeIter = m_fitDomains.begin() + domainIndex.value;
106 if (removeIter != m_fitDomains.cend()) {
107 m_fitDomains.erase(removeIter);
109 }
110}
111
112void FitScriptGeneratorModel::addWorkspaceDomain(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
113 double startX, double endX) {
114 if (hasWorkspaceDomain(workspaceName, workspaceIndex))
115 throw std::invalid_argument("The '" + workspaceName + " (" + std::to_string(workspaceIndex.value) +
116 ")' domain already exists.");
117
118 m_fitDomains.emplace_back(std::make_unique<FitDomain>(workspaceName, workspaceIndex, startX, endX));
119}
120
121bool FitScriptGeneratorModel::hasWorkspaceDomain(std::string const &workspaceName,
122 WorkspaceIndex workspaceIndex) const {
123 return findWorkspaceDomain(workspaceName, workspaceIndex) != m_fitDomains.cend();
124}
125
126void FitScriptGeneratorModel::renameWorkspace(std::string const &workspaceName, std::string const &newName) {
127 for (auto const &fitDomain : m_fitDomains) {
128 if (fitDomain->workspaceName() == workspaceName)
129 fitDomain->setWorkspaceName(newName);
130 }
131}
132
134 WorkspaceIndex workspaceIndex) const {
135 auto const iter = findWorkspaceDomain(workspaceName, workspaceIndex);
136 if (iter != m_fitDomains.cend())
137 return FitDomainIndex(std::distance(m_fitDomains.cbegin(), iter));
138
139 throw std::invalid_argument("The domain '" + workspaceName + " (" + std::to_string(workspaceIndex.value) +
140 ")' could not be found.");
141}
142
143std::vector<std::unique_ptr<FitDomain>>::const_iterator
144FitScriptGeneratorModel::findWorkspaceDomain(std::string const &workspaceName, WorkspaceIndex workspaceIndex) const {
145 auto const isMatch = [&](auto const &fitDomain) {
146 return fitDomain->workspaceName() == workspaceName && fitDomain->workspaceIndex() == workspaceIndex;
147 };
148
149 return std::find_if(m_fitDomains.cbegin(), m_fitDomains.cend(), isMatch);
150}
151
152bool FitScriptGeneratorModel::updateStartX(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
153 double startX) {
154 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
155 return m_fitDomains[domainIndex.value]->setStartX(startX);
156}
157
158bool FitScriptGeneratorModel::updateEndX(std::string const &workspaceName, WorkspaceIndex workspaceIndex, double endX) {
159 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
160 return m_fitDomains[domainIndex.value]->setEndX(endX);
161}
162
163void FitScriptGeneratorModel::removeFunction(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
164 std::string const &function) {
165 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
166 m_fitDomains[domainIndex.value]->removeFunction(function);
168}
169
170void FitScriptGeneratorModel::addFunction(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
171 std::string const &function) {
172 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
173 m_fitDomains[domainIndex.value]->addFunction(createIFunction(function));
175}
176
177void FitScriptGeneratorModel::setFunction(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
178 std::string const &function) {
179 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
180 m_fitDomains[domainIndex.value]->setFunction(createIFunction(function));
182}
183
185 WorkspaceIndex workspaceIndex) const {
186 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
187 return m_fitDomains[domainIndex.value]->getFunctionCopy();
188}
189
190std::string FitScriptGeneratorModel::getEquivalentFunctionIndexForDomain(std::string const &workspaceName,
191 WorkspaceIndex workspaceIndex,
192 std::string const &functionIndex) const {
193 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
194 return getEquivalentFunctionIndexForDomain(domainIndex, functionIndex);
195}
196
198 std::string const &functionIndex) const {
199 if (domainIndex.value >= numberOfDomains())
200 throw std::invalid_argument("The domain index provided does not exist.");
201
202 if (!functionIndex.empty() && m_fittingMode == FittingMode::SIMULTANEOUS)
203 return replaceTopFunctionIndexWith(functionIndex, domainIndex.value);
204 return functionIndex;
205}
206
207std::string FitScriptGeneratorModel::getEquivalentParameterTieForDomain(std::string const &workspaceName,
208 WorkspaceIndex workspaceIndex,
209 std::string const &fullParameter,
210 std::string const &fullTie) const {
211 if (fullTie.empty() || isNumber(fullTie) || !validTie(fullTie))
212 return fullTie;
213
215 return fullTie;
216
217 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
218 return getEquivalentParameterTieForDomain(domainIndex, fullParameter, fullTie);
219}
220
222 std::string const &fullParameter,
223 std::string const &fullTie) const {
224 auto const parameterDomainIndex = getFunctionIndexAt(fullParameter, 0);
225 auto const tieDomainIndex = getFunctionIndexAt(fullTie, 0);
226 if (parameterDomainIndex == tieDomainIndex)
227 return replaceTopFunctionIndexWith(fullTie, domainIndex.value);
228 return fullTie;
229}
230
231std::string FitScriptGeneratorModel::getAdjustedFunctionIndex(std::string const &parameter) const {
232 if (parameter.empty() || isNumber(parameter))
233 return parameter;
234
236 return parameter;
237 return removeTopFunctionIndex(parameter);
238}
239
240std::string FitScriptGeneratorModel::getFullParameter(FitDomainIndex domainIndex, std::string const &parameter) const {
242 return parameter;
243 return "f" + std::to_string(domainIndex.value) + "." + parameter;
244}
245
246std::string FitScriptGeneratorModel::getFullTie(FitDomainIndex domainIndex, std::string const &tie) const {
247 if (tie.empty() || isNumber(tie))
248 return tie;
249 return getFullParameter(domainIndex, tie);
250}
251
252void FitScriptGeneratorModel::updateParameterValue(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
253 std::string const &fullParameter, double newValue) {
254 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
255 if (!hasGlobalTie(fullParameter)) {
256 auto const parameter = getAdjustedFunctionIndex(fullParameter);
257 m_fitDomains[domainIndex.value]->setParameterValue(parameter, newValue);
258
259 updateParameterValuesWithLocalTieTo(domainIndex, parameter, newValue);
261 updateParameterValuesWithGlobalTieTo(fullParameter, newValue);
262 }
263 }
264}
265
267 std::string const &parameter, double newValue) {
268 for (auto const &tiedParameterName : m_fitDomains[domainIndex.value]->getParametersTiedTo(parameter)) {
269 m_fitDomains[domainIndex.value]->setParameterValue(tiedParameterName, newValue);
270 }
271}
272
273void FitScriptGeneratorModel::updateParameterValuesWithGlobalTieTo(std::string const &fullParameter, double newValue) {
274 // Deep copy so that global ties can be removed whilst in this for loop. This
275 // will happen if a global tie has been invalidated.
276 auto const globalTies = m_globalTies;
277 for (auto const &globalTie : globalTies)
278 if (fullParameter == globalTie.m_tie)
279 updateParameterValueInGlobalTie(globalTie, newValue);
280}
281
283 if (validGlobalTie(globalTie.m_parameter, globalTie.m_tie)) {
284 auto const domainIndex = getFunctionIndexAt(globalTie.m_parameter, 0);
285 m_fitDomains[domainIndex]->setParameterValue(getAdjustedFunctionIndex(globalTie.m_parameter), newValue);
286 } else {
287 clearGlobalTie(globalTie.m_parameter);
288 }
289}
290
291void FitScriptGeneratorModel::updateAttributeValue(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
292 std::string const &fullAttribute,
293 IFunction::Attribute const &newValue) {
294 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
295 m_fitDomains[domainIndex.value]->setAttributeValue(getAdjustedFunctionIndex(fullAttribute), newValue);
296}
297
298void FitScriptGeneratorModel::updateParameterTie(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
299 std::string const &fullParameter, std::string const &tie) {
300 if (validTie(tie)) {
301 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
302 updateParameterTie(domainIndex, fullParameter, tie);
303 } else {
304 g_log.warning("Invalid tie '" + tie + "' provided.");
305 }
306}
307
308void FitScriptGeneratorModel::updateParameterTie(FitDomainIndex domainIndex, std::string const &fullParameter,
309 std::string const &fullTie) {
310 checkParameterIsNotGlobal(fullParameter);
311
312 if (m_fittingMode == FittingMode::SEQUENTIAL || isSameDomain(domainIndex.value, fullTie))
313 updateLocalParameterTie(domainIndex, fullParameter, fullTie);
314 else
315 updateGlobalParameterTie(domainIndex, fullParameter, fullTie);
316}
317
318void FitScriptGeneratorModel::updateLocalParameterTie(FitDomainIndex domainIndex, std::string const &fullParameter,
319 std::string const &fullTie) {
320 auto const parameter = getAdjustedFunctionIndex(fullParameter);
321 auto const tie = getLocalTie(fullTie, m_fittingMode);
322
323 if (parameter != tie && validParameter(domainIndex, fullParameter)) {
324 if (m_fitDomains[domainIndex.value]->updateParameterTie(parameter, tie))
325 clearGlobalTie(fullParameter);
326 else
327 g_log.warning("Invalid tie '" + fullTie + "' provided.");
328 }
329}
330
331void FitScriptGeneratorModel::updateGlobalParameterTie(FitDomainIndex domainIndex, std::string const &fullParameter,
332 std::string const &fullTie) {
333 if (validParameter(domainIndex, fullParameter)) {
334 if (validGlobalTie(fullParameter, fullTie)) {
335 clearGlobalTie(fullParameter);
336
337 auto const parameter = getAdjustedFunctionIndex(fullParameter);
338 auto const tieValue = getParameterValue(getDomainIndexOf(fullTie), fullTie);
339
340 m_fitDomains[domainIndex.value]->clearParameterTie(parameter);
341 m_fitDomains[domainIndex.value]->setParameterValue(parameter, tieValue);
342
343 m_globalTies.emplace_back(GlobalTie(fullParameter, fullTie));
344 } else {
345 g_log.warning("Invalid tie '" + fullTie + "' provided.");
346 }
347 }
348}
349
350void FitScriptGeneratorModel::removeParameterConstraint(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
351 std::string const &fullParameter) {
352 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
353 m_fitDomains[domainIndex.value]->removeParameterConstraint(getAdjustedFunctionIndex(fullParameter));
354}
355
356void FitScriptGeneratorModel::updateParameterConstraint(std::string const &workspaceName, WorkspaceIndex workspaceIndex,
357 std::string const &functionIndex,
358 std::string const &constraint) {
359 auto const domainIndex = findDomainIndex(workspaceName, workspaceIndex);
360
361 m_fitDomains[domainIndex.value]->updateParameterConstraint(getAdjustedFunctionIndex(functionIndex),
362 getParameterName(constraint), constraint);
363}
364
365bool FitScriptGeneratorModel::validParameter(std::string const &fullParameter) const {
366 return validParameter(getDomainIndexOf(fullParameter), fullParameter);
367}
368
369bool FitScriptGeneratorModel::validParameter(FitDomainIndex domainIndex, std::string const &fullParameter) const {
370 if (domainIndex.value < numberOfDomains()) {
371 auto const parameter = getAdjustedFunctionIndex(fullParameter);
372 return m_fitDomains[domainIndex.value]->hasParameter(parameter);
373 }
374 return false;
375}
376
377bool FitScriptGeneratorModel::validTie(std::string const &tie) const {
378 if (tie.empty() || isNumber(tie))
379 return true;
380
381 auto const subStrings = splitStringBy(tie, ".");
382 switch (m_fittingMode) {
384 return 1 <= subStrings.size() && subStrings.size() <= 2;
386 return 2 <= subStrings.size() && subStrings.size() <= 3 && isFunctionIndex(subStrings[0]);
387 default:
388 throw std::invalid_argument("Fitting mode must be SEQUENTIAL or SIMULTANEOUS.");
389 }
390}
391
392bool FitScriptGeneratorModel::validGlobalTie(std::string const &fullParameter, std::string const &fullTie) const {
393 if (!fullTie.empty() && !isNumber(fullTie) && validParameter(fullTie)) {
394 auto const domainIndex = getDomainIndexOf(fullParameter);
395 auto const tieDomainIndex = getDomainIndexOf(fullTie);
396 return isParameterValueWithinConstraints(domainIndex, fullParameter, getParameterValue(tieDomainIndex, fullTie));
397 }
398 return false;
399}
400
402 std::string const &fullParameter, double value) const {
403 if (domainIndex.value < numberOfDomains()) {
404 auto const parameter = getAdjustedFunctionIndex(fullParameter);
405 return m_fitDomains[domainIndex.value]->isParameterValueWithinConstraints(parameter, value);
406 }
407 return false;
408}
409
410void FitScriptGeneratorModel::clearGlobalTie(std::string const &fullParameter) {
411 auto const removeIter = findGlobalTie(fullParameter);
412 if (removeIter != m_globalTies.cend()) {
413 m_globalTies.erase(removeIter);
415 }
416}
417
419 auto const isTieInvalid = [&](GlobalTie &globalTie) {
422
423 return !validParameter(globalTie.m_parameter) || !validGlobalTie(globalTie.m_parameter, globalTie.m_tie);
424 };
425
426 auto const iter = std::remove_if(m_globalTies.begin(), m_globalTies.end(), isTieInvalid);
427
428 if (iter != m_globalTies.cend())
429 m_globalTies.erase(iter, m_globalTies.cend());
430
432}
433
435 if (!validParameter(globalTie.m_parameter)) {
436 auto const promotedParam = globalTie.toCompositeParameter(globalTie.m_parameter);
437 auto const demotedParam = globalTie.toNonCompositeParameter(globalTie.m_parameter);
438
439 if (validParameter(promotedParam)) {
440 globalTie.m_parameter = promotedParam;
441 } else if (validParameter(demotedParam)) {
442 globalTie.m_parameter = demotedParam;
443 }
444 }
445}
446
448 if (!validGlobalTie(globalTie.m_parameter, globalTie.m_tie)) {
449 auto const promotedTie = globalTie.toCompositeParameter(globalTie.m_tie);
450 auto const demotedTie = globalTie.toNonCompositeParameter(globalTie.m_tie);
451
452 if (validGlobalTie(globalTie.m_parameter, promotedTie)) {
453 globalTie.m_tie = promotedTie;
454 } else if (validGlobalTie(globalTie.m_parameter, demotedTie)) {
455 globalTie.m_tie = demotedTie;
456 }
457 }
458}
459
460bool FitScriptGeneratorModel::hasGlobalTie(std::string const &fullParameter) const {
461 return findGlobalTie(fullParameter) != m_globalTies.cend();
462}
463
464std::vector<GlobalTie>::const_iterator FitScriptGeneratorModel::findGlobalTie(std::string const &fullParameter) const {
465 return std::find_if(m_globalTies.cbegin(), m_globalTies.cend(),
466 [&fullParameter](GlobalTie const &globalTie) { return globalTie.m_parameter == fullParameter; });
467}
468
469void FitScriptGeneratorModel::setGlobalParameters(std::vector<std::string> const &parameters) {
470 m_globalParameters.clear();
471 for (auto const &fullParameter : parameters) {
472 auto const globalParameter = removeTopFunctionIndex(fullParameter);
473 checkParameterIsInAllDomains(globalParameter);
474 checkGlobalParameterhasNoTies(globalParameter);
475
476 m_globalParameters.emplace_back(GlobalParameter(globalParameter));
477 }
478}
479
480void FitScriptGeneratorModel::setOutputBaseName(std::string const &outputBaseName) {
481 m_outputBaseName = outputBaseName;
482}
483
486 throw std::invalid_argument("Fitting mode must be SEQUENTIAL or SIMULTANEOUS.");
487
488 m_fittingMode = fittingMode;
489 m_globalTies.clear();
491 m_globalParameters.clear();
493}
494
496
498 if (domainIndex.value < numberOfDomains())
499 return m_fitDomains[domainIndex.value]->domainName();
500
501 throw std::runtime_error("The domain index provided does not exist.");
502}
503
504bool FitScriptGeneratorModel::hasParameter(FitDomainIndex domainIndex, std::string const &fullParameter) const {
505 return getParameterProperty(&FitDomain::hasParameter, domainIndex, fullParameter);
506}
507
508void FitScriptGeneratorModel::setParameterValue(FitDomainIndex domainIndex, std::string const &fullParameter,
509 double value) {
510 auto const parameter = getAdjustedFunctionIndex(fullParameter);
511 if (domainIndex.value >= numberOfDomains())
512 throw std::runtime_error("The domain index provided does not exist.");
513
514 m_fitDomains[domainIndex.value]->setParameterValue(parameter, value);
515}
516
517void FitScriptGeneratorModel::setParameterFixed(FitDomainIndex domainIndex, std::string const &fullParameter,
518 bool fix) {
519 auto const parameter = getAdjustedFunctionIndex(fullParameter);
520 if (domainIndex.value >= numberOfDomains())
521 throw std::runtime_error("The domain index provided does not exist.");
522
523 m_fitDomains[domainIndex.value]->setParameterFixed(parameter, fix);
524}
525
526void FitScriptGeneratorModel::setParameterTie(FitDomainIndex domainIndex, std::string const &fullParameter,
527 std::string const &tie) {
528 if (domainIndex.value >= numberOfDomains())
529 throw std::runtime_error("The domain index provided does not exist.");
530
531 auto const fullTie = getFullTie(domainIndex, tie);
532 if (validTie(fullTie))
533 updateParameterTie(domainIndex, fullParameter, fullTie);
534}
535
536void FitScriptGeneratorModel::setParameterConstraint(FitDomainIndex domainIndex, std::string const &fullParameter,
537 std::string const &constraint) {
538 auto const parameter = getAdjustedFunctionIndex(fullParameter);
539 if (domainIndex.value >= numberOfDomains())
540 throw std::runtime_error("The domain index provided does not exist.");
541
542 if (!constraint.empty()) {
543 m_fitDomains[domainIndex.value]->updateParameterConstraint(
544 getFunctionIndex(parameter), getParameterName(constraint), getAdjustedConstraint(constraint));
545 } else {
546 m_fitDomains[domainIndex.value]->removeParameterConstraint(parameter);
547 }
548}
549
550double FitScriptGeneratorModel::getParameterValue(FitDomainIndex domainIndex, std::string const &fullParameter) const {
551 return getParameterProperty(&FitDomain::getParameterValue, domainIndex, fullParameter);
552}
553
554bool FitScriptGeneratorModel::isParameterFixed(FitDomainIndex domainIndex, std::string const &fullParameter) const {
555 return getParameterProperty(&FitDomain::isParameterFixed, domainIndex, fullParameter);
556}
557
559 std::string const &fullParameter) const {
560 return getParameterProperty(&FitDomain::getParameterTie, domainIndex, fullParameter);
561}
562
564 std::string const &fullParameter) const {
565 return getParameterProperty(&FitDomain::getParameterConstraint, domainIndex, fullParameter);
566}
567
568void FitScriptGeneratorModel::checkParameterIsInAllDomains(std::string const &globalParameter) const {
569 auto const domainHasParameter = [&globalParameter](auto const &fitDomain) {
570 return fitDomain->hasParameter(globalParameter);
571 };
572
573 if (!std::all_of(m_fitDomains.cbegin(), m_fitDomains.cend(), domainHasParameter))
574 throw std::invalid_argument(globalParameter + " cannot be global because it doesn't exist for ALL domains.");
575}
576
577void FitScriptGeneratorModel::checkGlobalParameterhasNoTies(std::string const &globalParameter) const {
578 auto const isNotActive = [&globalParameter](auto const &fitDomain) {
579 return !fitDomain->isParameterActive(globalParameter);
580 };
581
582 auto const parameterHasGlobalTie = [&globalParameter](GlobalTie const &globalTie) {
583 return globalParameter == removeTopFunctionIndex(globalTie.m_parameter);
584 };
585
586 if (std::any_of(m_fitDomains.cbegin(), m_fitDomains.cend(), isNotActive) ||
587 std::any_of(m_globalTies.cbegin(), m_globalTies.cend(), parameterHasGlobalTie))
588 throw std::invalid_argument(globalParameter + " cannot be global because it already has a "
589 "tie in at least one of the domains.");
590}
591
592void FitScriptGeneratorModel::checkParameterIsNotGlobal(std::string const &fullParameter) const {
593 auto const parameter = getAdjustedFunctionIndex(fullParameter);
594 auto const isGlobal = [&parameter](GlobalParameter const &globalParameter) {
595 return parameter == globalParameter.m_parameter;
596 };
597
598 if (std::any_of(m_globalParameters.cbegin(), m_globalParameters.cend(), isGlobal)) {
599 throw std::invalid_argument(fullParameter + " cannot be tied because it is a global parameter.");
600 }
601}
602
604 auto const hasFunction = [](auto const &fitDomain) { return fitDomain->getFunctionCopy() != nullptr; };
605 return std::all_of(m_fitDomains.cbegin(), m_fitDomains.cend(), hasFunction);
606}
607
609 if (numberOfDomains() == 0u || m_fitDomains[0u]->getFunctionCopy() == nullptr) {
610 return false;
611 }
612
613 auto const functionString = m_fitDomains[0u]->getFunctionCopy()->asString();
614 auto const hasSameFunction = [&functionString](auto const &fitDomain) {
615 return fitDomain->getFunctionCopy()->asString() == functionString;
616 };
617 return std::all_of(m_fitDomains.cbegin(), m_fitDomains.cend(), hasSameFunction);
618}
619
620std::tuple<bool, std::string> FitScriptGeneratorModel::isValid() const {
621 std::string message;
622 if (numberOfDomains() == 0u)
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.";
626
627 if (m_outputBaseName.empty())
628 message = "The Output Base Name must not be empty, please provide an Output Base Name.";
629
630 bool valid(message.empty());
631 if (valid)
632 message = generatePermissibleWarnings();
633
634 return {valid, message};
635}
636
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.";
642 }
643 return "";
644}
645
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();
651 generateScript->setProperty("InputWorkspaces", getInputWorkspaces());
652 generateScript->setProperty("WorkspaceIndices", getWorkspaceIndices());
653 generateScript->setProperty("StartXs", getStartXs());
654 generateScript->setProperty("EndXs", getEndXs());
655
656 generateScript->setProperty("FittingType", getFittingType());
657 generateScript->setProperty("Function", getFunction());
658
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);
666
667 generateScript->setProperty("Filepath", filepath);
668 generateScript->execute();
669
670 return generateScript->getPropertyValue("ScriptText");
671}
672
673std::vector<std::string> FitScriptGeneratorModel::getInputWorkspaces() const {
674 auto const getWSName = [](std::unique_ptr<FitDomain> const &domain) { return domain->workspaceName(); };
675 return transformDomains<std::string>(getWSName);
676}
677
678std::vector<std::size_t> FitScriptGeneratorModel::getWorkspaceIndices() const {
679 auto const getWSIndex = [](std::unique_ptr<FitDomain> const &domain) { return domain->workspaceIndex().value; };
680 return transformDomains<std::size_t>(getWSIndex);
681}
682
683std::vector<double> FitScriptGeneratorModel::getStartXs() const {
684 auto const getStartX = [](std::unique_ptr<FitDomain> const &domain) { return domain->startX(); };
685 return transformDomains<double>(getStartX);
686}
687
688std::vector<double> FitScriptGeneratorModel::getEndXs() const {
689 auto const getEndX = [](std::unique_ptr<FitDomain> const &domain) { return domain->endX(); };
690 return transformDomains<double>(getEndX);
691}
692
693template <typename T, typename Function>
694std::vector<T> FitScriptGeneratorModel::transformDomains(Function const &func) const {
695 std::vector<T> domainData;
696 domainData.reserve(numberOfDomains());
697 std::transform(m_fitDomains.cbegin(), m_fitDomains.cend(), std::back_inserter(domainData), func);
698 return domainData;
699}
700
702 switch (m_fittingMode) {
704 return "Sequential";
706 return "Simultaneous";
707 default:
708 throw std::invalid_argument("Fitting mode must be SEQUENTIAL or SIMULTANEOUS.");
709 }
710}
711
713 switch (m_fittingMode) {
715 return m_fitDomains[0u]->getFunctionCopy();
717 return getMultiDomainFunction();
718 default:
719 throw std::invalid_argument("Fitting mode must be SEQUENTIAL or SIMULTANEOUS.");
720 }
721}
722
724 auto multiDomainFunction = std::make_shared<MultiDomainFunction>();
725
726 for (auto i = 0u; i < numberOfDomains(); ++i) {
727 multiDomainFunction->addFunction(m_fitDomains[i]->getFunctionCopy());
728 multiDomainFunction->setDomainIndex(i, i);
729 }
730
731 addGlobalParameterTies(multiDomainFunction);
732 addGlobalTies(multiDomainFunction);
733 return multiDomainFunction;
734}
735
737 for (auto const &globalParameter : m_globalParameters)
738 function->addTies(constructGlobalParameterTie(globalParameter));
739}
740
742 std::string tie = "f0." + globalParameter.m_parameter;
743 for (auto i = 1u; i < numberOfDomains(); ++i)
744 tie += "=f" + std::to_string(i) + "." + globalParameter.m_parameter;
745 return tie;
746}
747
749 for (auto const &globalTie : m_globalTies)
750 function->addTies(globalTie.asString());
751}
752
753} // namespace MantidQt::MantidWidgets
double value
The value of the point.
Definition FitMW.cpp:51
std::string getParameterTie(std::string const &parameter) const
double getParameterValue(std::string const &parameter) const
bool hasParameter(std::string const &parameter) const
std::string getParameterConstraint(std::string const &parameter) const
bool isParameterFixed(std::string const &parameter) const
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:285
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition Logger.h:51
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
EXPORT_OPT_MANTIDQT_COMMON std::pair< std::string, std::pair< std::string, std::string > > 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::pair< std::string, int > splitFunctionPrefix(std::string const &prefix)
Split a function (eg f0.f3.f1.) into the parent prefix (f0.f3.) and the index of the child function (...
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::size_t getFunctionIndexAt(std::string const &parameter, std::size_t const &index)
Returns the function index found at index of a parameter.
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< std::string, std::string > splitParameterName(std::string const &parameterName)
Split a qualified parameter name into function index and local parameter name.
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
Definition IFunction.h:743
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