Mantid
Loading...
Searching...
No Matches
CrystalFieldFunction.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
15
22
24
25#include <boost/regex.hpp>
26#include <limits>
27#include <memory>
28#include <optional>
29#include <utility>
30
32
33using namespace CurveFitting;
34using namespace Kernel;
35using namespace API;
36
37DECLARE_FUNCTION(CrystalFieldFunction)
38
39namespace {
40
41const std::string ION_PREFIX("ion");
42const std::string SPECTRUM_PREFIX("sp");
43const std::string BACKGROUND_PREFIX("bg");
44const std::string PEAK_PREFIX("pk");
45
46// Regex for names of attributes/parameters for a particular spectrum
47// Example: sp1.FWHMX
48const boost::regex SPECTRUM_ATTR_REGEX(SPECTRUM_PREFIX + "([0-9]+)\\.(.+)");
49// Regex for names of attributes/parameters for a background
50// Example: bg.A1
51const boost::regex BACKGROUND_ATTR_REGEX(BACKGROUND_PREFIX + "\\.(.+)");
52// Regex for names of attributes/parameters for peaks
53// Example: pk1.PeakCentre
54const boost::regex PEAK_ATTR_REGEX(PEAK_PREFIX + "([0-9]+)\\.(.+)");
55// Regex for names of attributes/parameters for peaks
56// Example: ion1.pk0.PeakCentre
57const boost::regex ION_ATTR_REGEX(ION_PREFIX + "([0-9]+)\\.(.+)");
58// Regex for names of attributes/parameters for physical properties
59// Example: cv.ScaleFactor
60const boost::regex PHYS_PROP_ATTR_REGEX("((ion[0-9]+\\.)?(cv|chi|mh|mt))\\.(.+)");
61
64class Peaks : public CrystalFieldPeaksBase, public API::IFunctionGeneral {
65public:
66 Peaks() : CrystalFieldPeaksBase() {}
67 std::string name() const override { return "Peaks"; }
68 size_t getNumberDomainColumns() const override {
69 throw Exception::NotImplementedError("This method is intentionally not implemented.");
70 }
71 size_t getNumberValuesPerArgument() const override {
72 throw Exception::NotImplementedError("This method is intentionally not implemented.");
73 }
74 void functionGeneral(const API::FunctionDomainGeneral & /*domain*/, API::FunctionValues & /*values*/) const override {
75 throw Exception::NotImplementedError("This method is intentionally not implemented.");
76 }
77 std::vector<size_t> m_IntensityScalingIdx;
78 std::vector<size_t> m_PPLambdaIdxChild;
79 std::vector<size_t> m_PPLambdaIdxSelf;
81 void declareIntensityScaling(size_t nSpec) {
83 m_PPLambdaIdxChild.resize(nSpec, -1);
84 m_PPLambdaIdxSelf.resize(nSpec, -1);
85 for (size_t i = 0; i < nSpec; ++i) {
86 auto si = std::to_string(i);
87 try { // If parameter has already been declared, don't declare it.
88 declareParameter("IntensityScaling" + si, 1.0, "Intensity scaling factor for spectrum " + si);
89 } catch (std::invalid_argument &) {
90 }
91 m_IntensityScalingIdx.emplace_back(parameterIndex("IntensityScaling" + si));
92 }
93 }
94};
95
96} // namespace
97
100 : IFunction(), m_nControlParams(0), m_nControlSourceParams(0), m_dirtyTarget(true) {}
101
102// Evaluates the function
105 if (!m_target) {
106 throw std::logic_error("FunctionGenerator failed to generate target function.");
107 }
108 m_target->function(domain, values);
109}
110
113void CrystalFieldFunction::setSource(IFunction_sptr source) const { m_source = std::move(source); }
114
116 if (!m_target)
118 // buildTargetFunction() may fail to set m_target.
119 (void)m_target;
120 if (!m_target)
121 throw std::logic_error("Failed to build target function.");
122 return m_target->getNumberDomains();
123}
124
125std::vector<IFunction_sptr> CrystalFieldFunction::createEquivalentFunctions() const {
127 std::vector<IFunction_sptr> funs;
128 auto &composite = dynamic_cast<CompositeFunction &>(*m_target);
129 for (size_t i = 0; i < composite.nFunctions(); ++i) {
130 auto fun = composite.getFunction(i);
131 auto cfun = dynamic_cast<CompositeFunction *>(fun.get());
132 if (cfun) {
133 cfun->checkFunction();
134 }
135 funs.emplace_back(fun);
136 }
137 return funs;
138}
139
141void CrystalFieldFunction::setParameter(size_t i, const double &value, bool explicitlySet) {
143 if (i < m_nControlParams) {
144 m_control.setParameter(i, value, explicitlySet);
145 m_dirtyTarget = true;
146 } else if (i < m_nControlSourceParams) {
147 m_source->setParameter(i - m_nControlParams, value, explicitlySet);
148 m_dirtyTarget = true;
149 } else {
151 m_target->setParameter(i - m_nControlSourceParams, value, explicitlySet);
152 }
153}
154
156void CrystalFieldFunction::setParameterDescription(size_t i, const std::string &description) {
158 if (i < m_nControlParams) {
159 m_control.setParameterDescription(i, description);
160 } else if (i < m_nControlSourceParams) {
161 m_source->setParameterDescription(i - m_nControlParams, description);
162 } else {
164 m_target->setParameterDescription(i - m_nControlSourceParams, description);
165 }
166}
167
172 if (i < m_nControlParams) {
173 return m_control.getParameter(i);
174 } else if (i < m_nControlSourceParams) {
175 return m_source->getParameter(i - m_nControlParams);
176 } else {
177 return m_target->getParameter(i - m_nControlSourceParams);
178 }
179}
180
182bool CrystalFieldFunction::hasParameter(const std::string &name) const {
183 try {
185 return true;
186 } catch (std::invalid_argument &) {
187 return false;
188 }
189}
190
192void CrystalFieldFunction::setParameter(const std::string &name, const double &value, bool explicitlySet) {
193 try {
194 auto index = parameterIndex(name);
195 setParameter(index, value, explicitlySet);
196 } catch (std::invalid_argument &) {
197 // Allow ignoring peak parameters: the peak may not exist.
198 boost::smatch match;
199 if (!boost::regex_search(name, match, PEAK_ATTR_REGEX)) {
200 throw;
201 }
202 }
203}
204
206void CrystalFieldFunction::setParameterDescription(const std::string &name, const std::string &description) {
207 auto index = parameterIndex(name);
208 setParameterDescription(index, description);
209}
210
212double CrystalFieldFunction::getParameter(const std::string &name) const {
213 auto index = parameterIndex(name);
214 return getParameter(index);
215}
216
219 if (!m_source) {
220 // This method can be called on an uninitialised function (by tests for
221 // example).
222 // Return 0 so no exception is thrown an it should prevent attemts to access
223 // parameters.
224 return 0;
225 }
228 return m_nControlSourceParams + m_target->nParams();
229}
230
233size_t CrystalFieldFunction::parameterIndex(const std::string &name) const {
236 if (nParams() != m_mapIndices2Names.size()) {
237 makeMaps();
238 }
239 auto found = m_mapNames2Indices.find(name);
240 if (found == m_mapNames2Indices.end()) {
241 throw std::invalid_argument("CrystalFieldFunction parameter not found: " + name);
242 }
243 return found->second;
244}
245
247std::string CrystalFieldFunction::parameterName(size_t i) const {
248 if (i >= nParams()) {
249 throw std::invalid_argument("CrystalFieldFunction's parameter index " + std::to_string(i) + " is out of range " +
251 }
254 if (nParams() != m_mapIndices2Names.size()) {
255 makeMaps();
256 }
257 return m_mapIndices2Names[i];
258}
259
264 if (i < m_nControlParams) {
266 } else if (i < m_nControlSourceParams) {
267 return m_source->parameterDescription(i - m_nControlParams);
268 } else {
269 return m_target->parameterDescription(i - m_nControlSourceParams);
270 }
271}
272
277 if (i < m_nControlParams) {
278 return m_control.isExplicitlySet(i);
279 } else if (i < m_nControlSourceParams) {
280 return m_source->isExplicitlySet(i - m_nControlParams);
281 } else {
282 return m_target->isExplicitlySet(i - m_nControlSourceParams);
283 }
284}
285
287double CrystalFieldFunction::getError(size_t i) const {
290 if (i < m_nControlParams) {
291 return m_control.getError(i);
292 } else if (i < m_nControlSourceParams) {
293 return m_source->getError(i - m_nControlParams);
294 } else {
295 return m_target->getError(i - m_nControlSourceParams);
296 }
297}
298
300double CrystalFieldFunction::getError(const std::string &name) const {
301 auto index = parameterIndex(name);
304 if (index < m_nControlParams) {
305 return m_control.getError(index);
306 } else if (index < m_nControlSourceParams) {
307 return m_source->getError(index - m_nControlParams);
308 } else {
309 return m_target->getError(index - m_nControlSourceParams);
310 }
311}
312
314void CrystalFieldFunction::setError(size_t i, double err) {
317 if (i < m_nControlParams) {
318 m_control.setError(i, err);
319 } else if (i < m_nControlSourceParams) {
320 m_source->setError(i - m_nControlParams, err);
321 } else {
322 m_target->setError(i - m_nControlSourceParams, err);
323 }
324}
325
327void CrystalFieldFunction::setError(const std::string &name, double err) {
328 auto index = parameterIndex(name);
331 if (index < m_nControlParams) {
333 } else if (index < m_nControlSourceParams) {
334 m_source->setError(index - m_nControlParams, err);
335 } else {
336 m_target->setError(index - m_nControlSourceParams, err);
337 }
338}
339
344 if (i < m_nControlParams) {
345 m_control.setParameterStatus(i, status);
346 } else if (i < m_nControlSourceParams) {
347 m_source->setParameterStatus(i - m_nControlParams, status);
348 } else {
349 m_target->setParameterStatus(i - m_nControlSourceParams, status);
350 }
351}
352
357 if (i < m_nControlParams) {
359 } else if (i < m_nControlSourceParams) {
360 return m_source->getParameterStatus(i - m_nControlParams);
361 } else {
362 return m_target->getParameterStatus(i - m_nControlSourceParams);
363 }
364}
365
370 if (ref.getLocalFunction() == this) {
371 return ref.getLocalIndex();
372 }
374 if (index < m_nControlParams) {
375 return index;
376 }
377 index = m_source->getParameterIndex(ref);
378 if (index < m_source->nParams()) {
379 return index + m_nControlParams;
380 }
381 return m_target->getParameterIndex(ref) + m_nControlSourceParams;
382}
383
390
392void CrystalFieldFunction::declareParameter(const std::string & /*name*/, double /*initValue*/,
393 const std::string & /*description*/) {
394 throw Kernel::Exception::NotImplementedError("CrystalFieldFunction cannot have its own parameters.");
395}
396
401 if (!m_attributeNames.empty()) {
402 return;
403 }
404 auto numAttributes = IFunction::nAttributes();
405 for (size_t i = 0; i < numAttributes; ++i) {
407 }
408 auto controlAttributeNames = m_control.getAttributeNames();
409
410 // Lambda function that moves a attribute name from controlAttributeNames
411 // to attNames.
412 auto moveAttributeName = [&](const std::string &name) {
413 auto iterFound = std::find(controlAttributeNames.begin(), controlAttributeNames.end(), name);
414 if (iterFound != controlAttributeNames.end()) {
415 controlAttributeNames.erase(iterFound);
416 m_attributeNames.emplace_back(name);
417 }
418 };
419 // Prepend a prefix to attribute names, ignore NumDeriv attribute.
420 auto prependPrefix = [&](const std::string &prefix, const std::vector<std::string> &names) {
421 for (auto name : names) {
422 if (name.find("NumDeriv") != std::string::npos)
423 continue;
424 name.insert(name.begin(), prefix.begin(), prefix.end());
425 m_attributeNames.emplace_back(name);
426 }
427 };
428 // These names must appear first and in this order in the output vector
429 moveAttributeName("Ions");
430 moveAttributeName("Symmetries");
431 moveAttributeName("Temperatures");
432 moveAttributeName("Background");
433
434 // Only copy the unprefixed attributes - as the loop below will include
435 // And modify the prefixed attributes accordingly
436 std::copy_if(controlAttributeNames.begin(), controlAttributeNames.end(), std::back_inserter(m_attributeNames),
437 [](const auto &name) { return name.find(".") == std::string::npos; });
438 // Get
439 for (size_t iSpec = 0; iSpec < m_control.nFunctions(); ++iSpec) {
440 std::string prefix(SPECTRUM_PREFIX);
441 prefix.append(std::to_string(iSpec)).append(".");
442 auto attrNames = m_control.getFunction(iSpec)->getAttributeNames();
443 for (auto &attrName : attrNames) {
444 attrName.insert(attrName.begin(), prefix.begin(), prefix.end());
445 }
446 m_attributeNames.insert(m_attributeNames.end(), attrNames.begin(), attrNames.end());
447 }
448 // Attributes of physical properties
449 for (size_t iSpec = nSpectra(); iSpec < m_target->nFunctions(); ++iSpec) {
450 auto fun = m_target->getFunction(iSpec).get();
451 auto compositePhysProp = dynamic_cast<CompositeFunction *>(fun);
452 if (compositePhysProp) {
453 // Multi-site case
454 std::string physPropPrefix(compositePhysProp->getFunction(0)->name());
455 physPropPrefix.append(".");
456 for (size_t ion = 0; ion < compositePhysProp->nFunctions(); ++ion) {
457 std::string prefix(ION_PREFIX);
458 prefix.append(std::to_string(ion)).append(".").append(physPropPrefix);
459 auto names = compositePhysProp->getFunction(ion)->getAttributeNames();
460 prependPrefix(prefix, names);
461 }
462 } else {
463 // Single-site
464 std::string prefix(fun->name());
465 prefix.append(".");
466 auto names = fun->getAttributeNames();
467 prependPrefix(prefix, names);
468 }
469 }
470}
471
475 return m_attributeNames.size();
476}
477
479std::vector<std::string> CrystalFieldFunction::getAttributeNames() const {
481 return m_attributeNames;
482}
483
487 auto attRef = getAttributeReference(attName);
488 if (attRef.first == nullptr) {
489 // This will throw an exception because attribute doesn't exist
490 return IFunction::getAttribute(attName);
491 }
492 return attRef.first->getAttribute(attRef.second);
493}
494
496void CrystalFieldFunction::setAttribute(const std::string &attName, const Attribute &attr) {
497 auto attRef = getAttributeReference(attName);
498 if (attRef.first == nullptr) {
499 // This will throw an exception because attribute doesn't exist
500 IFunction::setAttribute(attName, attr);
501 } else if (attRef.first == &m_control) {
503 m_source.reset();
504 }
505 attRef.first->setAttribute(attRef.second, attr);
506 if (attName.find("FWHM") != std::string::npos || attName.find("Background") != std::string::npos) {
507 m_dirtyTarget = true;
508 }
509}
510
512bool CrystalFieldFunction::hasAttribute(const std::string &attName) const {
513 auto attRef = getAttributeReference(attName);
514 if (attRef.first == nullptr) {
515 return false;
516 }
517 return attRef.first->hasAttribute(attRef.second);
518}
519
526std::pair<API::IFunction *, std::string> CrystalFieldFunction::getAttributeReference(const std::string &attName) const {
527 boost::smatch match;
528 if (boost::regex_match(attName, match, SPECTRUM_ATTR_REGEX)) {
529 auto index = std::stoul(match[1]);
530 auto attNameNoIndex = match[2].str();
531 if (m_control.nFunctions() == 0) {
533 }
534 if (attNameNoIndex == "FWHMX" || attNameNoIndex == "FWHMY") {
535 if (index < m_control.nFunctions()) {
536 return std::make_pair(m_control.getFunction(index).get(), attNameNoIndex);
537 } else {
538 return std::make_pair(nullptr, "");
539 }
540 }
541 return std::make_pair(nullptr, "");
542 } else if (boost::regex_match(attName, match, PHYS_PROP_ATTR_REGEX)) {
543 auto prop = match[1].str();
544 auto nameRemainder = match[4].str();
545 auto propIt = m_mapPrefixes2PhysProps.find(prop);
546 if (propIt != m_mapPrefixes2PhysProps.end()) {
547 return std::make_pair(propIt->second.get(), nameRemainder);
548 }
549 return std::make_pair(nullptr, "");
550 }
551 return std::make_pair(&m_control, attName);
552}
553
556 auto nFuns = m_control.nFunctions();
557 return nFuns;
558}
559
564 auto tie = IFunction::getTie(i);
565 if (tie) {
566 return tie;
567 }
568 if (i < m_nControlParams) {
569 tie = m_control.getTie(i);
570 } else if (i < m_nControlSourceParams) {
571 tie = m_source->getTie(i - m_nControlParams);
572 } else {
573 tie = m_target->getTie(i - m_nControlSourceParams);
574 }
575 return tie;
576}
577
580 // Ignore height ties for Gaussian peaks as component of a CrystalFieldFunction to avoid problems during tie sorting
581 return tie.ownerFunction()->name() == "Gaussian" && tie.parameterName() == "Height" &&
582 tie.asString().find("/Sigma") != std::string::npos;
583}
584
588 auto constraint = IFunction::getConstraint(i);
589 if (constraint == nullptr) {
590 if (i < m_nControlParams) {
591 constraint = m_control.getConstraint(i);
592 } else if (i < m_nControlSourceParams) {
593 constraint = m_source->getConstraint(i - m_nControlParams);
594 } else {
596 constraint = m_target->getConstraint(i - m_nControlSourceParams);
597 }
598 }
599 return constraint;
600}
601
605
609
612 if (!hasAttribute("Background")) {
613 return false;
614 }
615 return !getAttribute("Background").isEmpty();
616}
617
620
623
626 auto composite = dynamic_cast<CompositeFunction *>(m_source.get());
627 if (composite == nullptr) {
628 throw std::logic_error("Source of CrystalFieldFunction is not composite.");
629 }
630 return *composite;
631}
632
635 if (!m_source) {
637 }
638}
639
645 if (!m_parameterResetCache.empty() && m_parameterResetCache.size() == m_source->nParams()) {
646 for (size_t i = 0; i < m_parameterResetCache.size(); ++i) {
647 m_source->setParameter(i, m_parameterResetCache[i]);
648 if (m_fixResetCache[i])
649 m_source->fix(i);
650 }
651 }
652 m_parameterResetCache.clear();
653 m_fixResetCache.clear();
654}
655
658 if (m_dirtyTarget) {
660 }
661 if (!m_target) {
662 throw std::logic_error("CrystalFieldFunction failed to generate target function.");
663 }
664}
665
670 m_dirtyTarget = false;
671 if (isMultiSite()) {
673 } else {
675 }
676 m_attributeNames.clear();
677}
678
687
696
699 auto spectrum = new CompositeFunction;
700 m_target.reset(spectrum);
701 m_target->setAttributeValue("NumDeriv", true);
702 auto bkgdShape = getAttribute("Background").asUnquotedString();
703 bool fixAllPeaks = getAttribute("FixAllPeaks").asBool();
704
705 if (!bkgdShape.empty()) {
706 auto background = API::FunctionFactory::Instance().createInitialized(bkgdShape);
707 spectrum->addFunction(background);
708 }
709
711 FunctionValues values;
712 m_source->function(domain, values);
713
714 if (values.size() == 0) {
715 return;
716 }
717
718 if (values.size() % 2 != 0) {
719 throw std::runtime_error("CrystalFieldPeaks returned odd number of values.");
720 }
721
722 auto xVec = m_control.getAttribute("FWHMX").asVector();
723 auto yVec = m_control.getAttribute("FWHMY").asVector();
724 const auto &FWHMs = m_control.FWHMs();
725 auto defaultFWHM = FWHMs.empty() ? 0.0 : FWHMs[0];
726
727 auto fwhmVariation = getAttribute("FWHMVariation").asDouble();
728 auto peakShape = getAttribute("PeakShape").asString();
729 size_t nRequiredPeaks = getAttribute("NPeaks").asInt();
730 CrystalFieldUtils::buildSpectrumFunction(*spectrum, peakShape, values, xVec, yVec, fwhmVariation, defaultFWHM,
731 nRequiredPeaks, fixAllPeaks);
732}
733
736 auto fun = new MultiDomainFunction;
737 m_target.reset(fun);
738
739 DoubleFortranVector energies;
740 ComplexFortranMatrix waveFunctions;
741 ComplexFortranMatrix hamiltonian;
742 ComplexFortranMatrix hamiltonianZeeman;
743 int nre = 0;
744 const auto &peakCalculator = dynamic_cast<CrystalFieldPeaksBase &>(*m_source);
745 peakCalculator.calculateEigenSystem(energies, waveFunctions, hamiltonian, hamiltonianZeeman, nre);
746 hamiltonian += hamiltonianZeeman;
747
748 const auto nSpec = nSpectra();
749 const auto &temperatures = m_control.temperatures();
750 const auto &FWHMs = m_control.FWHMs();
751 const bool addBackground = true;
752 for (size_t i = 0; i < nSpec; ++i) {
753 auto intensityScaling = m_control.getFunction(i)->getParameter("IntensityScaling");
754 fun->addFunction(buildSpectrum(nre, energies, waveFunctions, temperatures[i], FWHMs.size() > i ? FWHMs[i] : 0., i,
755 addBackground, intensityScaling));
756 fun->setDomainIndex(i, i);
757 }
758 const auto &physProps = m_control.physProps();
759 size_t i = nSpec;
760 for (const auto &prop : physProps) {
761 auto physPropFun = buildPhysprop(nre, energies, waveFunctions, hamiltonian, prop);
762 fun->addFunction(physPropFun);
763 fun->setDomainIndex(i, i);
764 m_mapPrefixes2PhysProps[prop] = physPropFun;
765 ++i;
766 }
767}
768
771
772 auto spectrum = new CompositeFunction;
773 m_target.reset(spectrum);
774 m_target->setAttributeValue("NumDeriv", true);
775 auto bkgdShape = getAttribute("Background").asUnquotedString();
776 bool fixAllPeaks = getAttribute("FixAllPeaks").asBool();
777
778 if (!bkgdShape.empty()) {
779 auto background = API::FunctionFactory::Instance().createInitialized(bkgdShape);
780 spectrum->addFunction(background);
781 }
782
783 const auto &FWHMs = m_control.FWHMs();
784 auto defaultFWHM = FWHMs.empty() ? 0.0 : FWHMs[0];
785 auto fwhmVariation = getAttribute("FWHMVariation").asDouble();
786 auto peakShape = getAttribute("PeakShape").asString();
787 size_t nRequiredPeaks = getAttribute("NPeaks").asInt();
788 auto xVec = m_control.getAttribute("FWHMX").asVector();
789 auto yVec = m_control.getAttribute("FWHMY").asVector();
790
791 const auto &compSource = compositeSource();
792 for (size_t ionIndex = 0; ionIndex < compSource.nFunctions(); ++ionIndex) {
794 FunctionValues values;
795 compSource.getFunction(ionIndex)->function(domain, values);
796
797 if (values.size() == 0) {
798 continue;
799 }
800
801 if (values.size() % 2 != 0) {
802 throw std::runtime_error("CrystalFieldPeaks returned odd number of values.");
803 }
804
805 auto ionSpectrum = std::make_shared<CompositeFunction>();
806 CrystalFieldUtils::buildSpectrumFunction(*ionSpectrum, peakShape, values, xVec, yVec, fwhmVariation, defaultFWHM,
807 nRequiredPeaks, fixAllPeaks);
808 spectrum->addFunction(ionSpectrum);
809 }
810}
811
814 auto multiDomain = new MultiDomainFunction;
815 m_target.reset(multiDomain);
816
817 const auto nSpec = nSpectra();
818 std::vector<CompositeFunction *> spectra(nSpec);
819 for (size_t i = 0; i < nSpec; ++i) {
820 auto spectrum = std::make_shared<CompositeFunction>();
821 spectra[i] = spectrum.get();
822 multiDomain->addFunction(spectrum);
823 multiDomain->setDomainIndex(i, i);
824 }
825 auto &physProps = m_control.physProps();
826 std::vector<CompositeFunction_sptr> compositePhysProps(physProps.size());
827 std::generate(compositePhysProps.begin(), compositePhysProps.end(),
828 []() { return std::make_shared<CompositeFunction>(); });
829
830 const auto &compSource = compositeSource();
831 for (size_t ionIndex = 0; ionIndex < compSource.nFunctions(); ++ionIndex) {
832 DoubleFortranVector energies;
833 ComplexFortranMatrix waveFunctions;
834 ComplexFortranMatrix hamiltonian;
835 ComplexFortranMatrix hamiltonianZeeman;
836 int nre = 0;
837 const auto &peakCalculator = dynamic_cast<CrystalFieldPeaksBase &>(*compSource.getFunction(ionIndex));
838 peakCalculator.calculateEigenSystem(energies, waveFunctions, hamiltonian, hamiltonianZeeman, nre);
839 hamiltonian += hamiltonianZeeman;
840
841 auto &temperatures = m_control.temperatures();
842 auto &FWHMs = m_control.FWHMs();
843 const bool addBackground = ionIndex == 0;
844 auto ionIntensityScaling = compSource.getFunction(ionIndex)->getParameter("IntensityScaling");
845 for (size_t i = 0; i < nSpec; ++i) {
846 auto spectrumIntensityScaling = m_control.getFunction(i)->getParameter("IntensityScaling");
847 spectra[i]->addFunction(buildSpectrum(nre, energies, waveFunctions, temperatures[i],
848 FWHMs.size() > i ? FWHMs[i] : 0., i, addBackground,
849 ionIntensityScaling * spectrumIntensityScaling));
850 }
851
852 size_t i = 0;
853 for (const auto &prop : physProps) {
854 auto physPropFun = buildPhysprop(nre, energies, waveFunctions, hamiltonian, prop);
855 compositePhysProps[i]->addFunction(physPropFun);
856 std::string propName = "ion";
857 propName.append(std::to_string(ionIndex)).append(".").append(prop);
858 m_mapPrefixes2PhysProps[propName] = physPropFun;
859 ++i;
860 }
861 }
862 m_target->checkFunction();
863 size_t i = nSpec;
864 for (const auto &propFun : compositePhysProps) {
865 multiDomain->addFunction(propFun);
866 multiDomain->setDomainIndex(i, i);
867 ++i;
868 }
869}
870
879 const ComplexFortranMatrix &waveFunctions, double temperature,
880 FunctionValues &values, double intensityScaling) const {
881 IntFortranVector degeneration;
882 DoubleFortranVector eEnergies;
883 DoubleFortranMatrix iEnergies;
884
885 const double toleranceEnergy = getAttribute("ToleranceEnergy").asDouble();
886 const double toleranceIntensity = getAttribute("ToleranceIntensity").asDouble();
887 DoubleFortranVector eExcitations;
888 DoubleFortranVector iExcitations;
889 calculateIntensities(nre, energies, waveFunctions, temperature, toleranceEnergy, degeneration, eEnergies, iEnergies);
890 calculateExcitations(eEnergies, iEnergies, toleranceEnergy, toleranceIntensity, eExcitations, iExcitations);
891 const auto nPeaks = eExcitations.size();
892 values.expand(2 * nPeaks);
893 for (size_t i = 0; i < nPeaks; ++i) {
894 values.setCalculated(i, eExcitations.get(i));
895 values.setCalculated(i + nPeaks, iExcitations.get(i) * intensityScaling);
896 }
897}
898
910 const ComplexFortranMatrix &waveFunctions, double temperature,
911 double fwhm, size_t iSpec, bool addBackground,
912 double intensityScaling) const {
913 FunctionValues values;
914 calcExcitations(nre, energies, waveFunctions, temperature, values, intensityScaling);
915 const auto fwhmVariation = getAttribute("FWHMVariation").asDouble();
916 const auto peakShape = getAttribute("PeakShape").asString();
917 auto bkgdShape = getAttribute("Background").asUnquotedString();
918 const size_t nRequiredPeaks = getAttribute("NPeaks").asInt();
919 const bool fixAllPeaks = getAttribute("FixAllPeaks").asBool();
920
921 auto spectrum = new CompositeFunction;
922
923 if (addBackground && !bkgdShape.empty()) {
924 if (bkgdShape.find("name=") != 0 && bkgdShape.front() != '(') {
925 bkgdShape = "name=" + bkgdShape;
926 }
927 auto background = API::FunctionFactory::Instance().createInitialized(bkgdShape);
928 spectrum->addFunction(background);
929 }
930
931 auto xVec = m_control.getFunction(iSpec)->getAttribute("FWHMX").asVector();
932 auto yVec = m_control.getFunction(iSpec)->getAttribute("FWHMY").asVector();
933 CrystalFieldUtils::buildSpectrumFunction(*spectrum, peakShape, values, xVec, yVec, fwhmVariation, fwhm,
934 nRequiredPeaks, fixAllPeaks);
935 return IFunction_sptr(spectrum);
936}
937
945 const ComplexFortranMatrix &waveFunctions,
946 const ComplexFortranMatrix &hamiltonian,
947 const std::string &propName) const {
948
949 if (propName == "cv") { // HeatCapacity
950 auto propFun = std::make_shared<CrystalFieldHeatCapacityCalculation>();
951 propFun->setEnergy(energies);
952 return propFun;
953 }
954 if (propName == "chi") { // Susceptibility
955 auto propFun = std::make_shared<CrystalFieldSusceptibilityCalculation>();
956 propFun->setEigensystem(energies, waveFunctions, nre);
957 return propFun;
958 }
959 if (propName == "mh") { // Magnetisation
960 auto propFun = std::make_shared<CrystalFieldMagnetisationCalculation>();
961 propFun->setHamiltonian(hamiltonian, nre);
962 return propFun;
963 }
964 if (propName == "mt") { // MagneticMoment
965 auto propFun = std::make_shared<CrystalFieldMomentCalculation>();
966 propFun->setHamiltonian(hamiltonian, nre);
967 return propFun;
968 }
969
970 throw std::runtime_error("Physical property type not understood: " + propName);
971}
972
980 const ComplexFortranMatrix &waveFunctions,
981 const ComplexFortranMatrix &hamiltonian, API::IFunction &function) const {
982
983 auto propName = function.name();
984
985 if (propName == "cv") { // HeatCapacity
986 auto &propFun = dynamic_cast<CrystalFieldHeatCapacityCalculation &>(function);
987 propFun.setEnergy(energies);
988 } else if (propName == "chi") { // Susceptibility
989 auto &propFun = dynamic_cast<CrystalFieldSusceptibilityCalculation &>(function);
990 propFun.setEigensystem(energies, waveFunctions, nre);
991 } else if (propName == "mh") { // Magnetisation
992 auto &propFun = dynamic_cast<CrystalFieldMagnetisationCalculation &>(function);
993 propFun.setHamiltonian(hamiltonian, nre);
994 } else if (propName == "mt") { // MagneticMoment
995 auto &propFun = dynamic_cast<CrystalFieldMomentCalculation &>(function);
996 propFun.setHamiltonian(hamiltonian, nre);
997 } else {
998 throw std::runtime_error("Physical property type not understood: " + propName);
999 }
1000}
1001
1004 if (!m_target) {
1006 return;
1007 }
1008 m_dirtyTarget = false;
1009 if (isMultiSite()) {
1011 } else {
1013 }
1014 m_target->checkFunction();
1015}
1016
1025
1028 if (isMultiSpectrum()) {
1030 } else {
1032 }
1033}
1034
1037 auto fwhmVariation = m_control.getAttribute("FWHMVariation").asDouble();
1038 auto peakShape = m_control.getAttribute("PeakShape").asString();
1039 bool fixAllPeaks = m_control.getAttribute("FixAllPeaks").asBool();
1040 auto xVec = m_control.getAttribute("FWHMX").asVector();
1041 auto yVec = m_control.getAttribute("FWHMY").asVector();
1042 auto &FWHMs = m_control.FWHMs();
1043 auto defaultFWHM = FWHMs.empty() ? 0.0 : FWHMs[0];
1044 size_t indexShift = hasBackground() ? 1 : 0;
1045
1046 FunctionDomainGeneral domain;
1047 FunctionValues values;
1048 m_source->function(domain, values);
1049 m_target->setAttributeValue("NumDeriv", true);
1050 auto &spectrum = dynamic_cast<CompositeFunction &>(*m_target);
1051 CrystalFieldUtils::updateSpectrumFunction(spectrum, peakShape, values, indexShift, xVec, yVec, fwhmVariation,
1052 defaultFWHM, fixAllPeaks);
1053}
1054
1057 DoubleFortranVector energies;
1058 ComplexFortranMatrix waveFunctions;
1059 ComplexFortranMatrix hamiltonian;
1060 ComplexFortranMatrix hamiltonianZeeman;
1061 int nre = 0;
1062 const auto &peakCalculator = dynamic_cast<CrystalFieldPeaksBase &>(*m_source);
1063 peakCalculator.calculateEigenSystem(energies, waveFunctions, hamiltonian, hamiltonianZeeman, nre);
1064 hamiltonian += hamiltonianZeeman;
1065 size_t iFirst = hasBackground() ? 1 : 0;
1066
1067 const auto &fun = dynamic_cast<MultiDomainFunction &>(*m_target);
1068 const auto &temperatures = m_control.temperatures();
1069 const auto &FWHMs = m_control.FWHMs();
1070 for (size_t iSpec = 0; iSpec < temperatures.size(); ++iSpec) {
1071 auto intensityScaling = m_control.getFunction(iSpec)->getParameter("IntensityScaling");
1072 updateSpectrum(*fun.getFunction(iSpec), nre, energies, waveFunctions, temperatures[iSpec],
1073 FWHMs.size() > iSpec ? FWHMs[iSpec] : 0., iSpec, iFirst, intensityScaling);
1074 }
1075
1076 for (const auto &prop : m_mapPrefixes2PhysProps) {
1077 updatePhysprop(nre, energies, waveFunctions, hamiltonian, *prop.second);
1078 }
1079}
1080
1083 auto fwhmVariation = getAttribute("FWHMVariation").asDouble();
1084 auto peakShape = getAttribute("PeakShape").asString();
1085 bool fixAllPeaks = getAttribute("FixAllPeaks").asBool();
1086 auto xVec = m_control.getAttribute("FWHMX").asVector();
1087 auto yVec = m_control.getAttribute("FWHMY").asVector();
1088 auto &FWHMs = m_control.FWHMs();
1089 auto defaultFWHM = FWHMs.empty() ? 0.0 : FWHMs[0];
1090
1091 size_t spectrumIndexShift = hasBackground() ? 1 : 0;
1092 auto &compSource = compositeSource();
1093 for (size_t ionIndex = 0; ionIndex < compSource.nFunctions(); ++ionIndex) {
1094 FunctionDomainGeneral domain;
1095 FunctionValues values;
1096 compSource.getFunction(ionIndex)->function(domain, values);
1097
1098 auto &ionSpectrum = dynamic_cast<CompositeFunction &>(*m_target->getFunction(ionIndex + spectrumIndexShift));
1099 CrystalFieldUtils::updateSpectrumFunction(ionSpectrum, peakShape, values, 0, xVec, yVec, fwhmVariation, defaultFWHM,
1100 fixAllPeaks);
1101 }
1102}
1103
1106 auto &compSource = compositeSource();
1107 for (size_t ionIndex = 0; ionIndex < compSource.nFunctions(); ++ionIndex) {
1108 DoubleFortranVector energies;
1109 ComplexFortranMatrix waveFunctions;
1110 ComplexFortranMatrix hamiltonian;
1111 ComplexFortranMatrix hamiltonianZeeman;
1112 int nre = 0;
1113 auto &peakCalculator = dynamic_cast<CrystalFieldPeaksBase &>(*compSource.getFunction(ionIndex));
1114 peakCalculator.calculateEigenSystem(energies, waveFunctions, hamiltonian, hamiltonianZeeman, nre);
1115 hamiltonian += hamiltonianZeeman;
1116 size_t iFirst = ionIndex == 0 && hasBackground() ? 1 : 0;
1117
1118 auto &temperatures = m_control.temperatures();
1119 auto &FWHMs = m_control.FWHMs();
1120 auto ionIntensityScaling = compSource.getFunction(ionIndex)->getParameter("IntensityScaling");
1121 for (size_t iSpec = 0; iSpec < temperatures.size(); ++iSpec) {
1122 auto &spectrum = dynamic_cast<CompositeFunction &>(*m_target->getFunction(iSpec));
1123 auto &ionSpectrum = dynamic_cast<CompositeFunction &>(*spectrum.getFunction(ionIndex));
1124 auto spectrumIntensityScaling = m_control.getFunction(iSpec)->getParameter("IntensityScaling");
1125 updateSpectrum(ionSpectrum, nre, energies, waveFunctions, temperatures[iSpec],
1126 FWHMs.size() > iSpec ? FWHMs[iSpec] : 0., iSpec, iFirst,
1127 ionIntensityScaling * spectrumIntensityScaling);
1128 }
1129
1130 std::string prefix("ion");
1131 prefix.append(std::to_string(ionIndex)).append(".");
1132 auto prefixSize = prefix.size();
1133 for (const auto &prop : m_mapPrefixes2PhysProps) {
1134 if (prop.first.substr(0, prefixSize) == prefix) {
1135 updatePhysprop(nre, energies, waveFunctions, hamiltonian, *prop.second);
1136 }
1137 }
1138 }
1139}
1140
1153 const ComplexFortranMatrix &waveFunctions, double temperature, double fwhm,
1154 size_t iSpec, size_t iFirst, double intensityScaling) const {
1155 const auto fwhmVariation = getAttribute("FWHMVariation").asDouble();
1156 const auto peakShape = getAttribute("PeakShape").asString();
1157 const bool fixAllPeaks = getAttribute("FixAllPeaks").asBool();
1158 auto xVec = m_control.getFunction(iSpec)->getAttribute("FWHMX").asVector();
1159 auto yVec = m_control.getFunction(iSpec)->getAttribute("FWHMY").asVector();
1160
1161 FunctionValues values;
1162 calcExcitations(nre, energies, waveFunctions, temperature, values, intensityScaling);
1163 auto &composite = dynamic_cast<API::CompositeFunction &>(spectrum);
1164 CrystalFieldUtils::updateSpectrumFunction(composite, peakShape, values, iFirst, xVec, yVec, fwhmVariation, fwhm,
1165 fixAllPeaks);
1166}
1167
1170 m_mapNames2Indices.clear();
1171 m_mapIndices2Names.resize(nParams());
1172 if (isMultiSite()) {
1173 if (isMultiSpectrum()) {
1175 } else {
1177 }
1178 } else {
1179 if (isMultiSpectrum()) {
1181 } else {
1183 }
1184 }
1185}
1186
1191size_t CrystalFieldFunction::makeMapsForFunction(const IFunction &fun, size_t iFirst, const std::string &prefix) const {
1192 auto n = fun.nParams();
1193 for (size_t i = 0; i < n; ++i) {
1194 size_t j = i + iFirst;
1195 auto paramName(prefix);
1196 paramName.append(fun.parameterName(i));
1197 m_mapNames2Indices[paramName] = j;
1198 m_mapIndices2Names[j] = paramName;
1199 }
1200 return n;
1201}
1202
1205 size_t i = makeMapsForFunction(*m_source, 0, "");
1206
1207 size_t peakIndex = 0;
1208 // If there is a background it's the first function in m_target
1209 if (hasBackground()) {
1210 const auto &background = *m_target->getFunction(0);
1211 i += makeMapsForFunction(background, i, BACKGROUND_PREFIX + ".");
1212 peakIndex = 1;
1213 }
1214 // All other functions are peaks.
1215 for (size_t ip = peakIndex; ip < m_target->nFunctions(); ++ip) {
1216 std::string prefix(PEAK_PREFIX);
1217 prefix.append(std::to_string(ip - peakIndex)).append(".");
1218 i += makeMapsForFunction(*m_target->getFunction(ip), i, prefix);
1219 }
1220}
1221
1224 size_t i = 0;
1225 // Intensity scalings for each spectrum
1226 for (size_t j = 0; j < m_control.nFunctions(); ++j) {
1227 std::string prefix(SPECTRUM_PREFIX);
1228 prefix.append(std::to_string(j)).append(".");
1229 i += makeMapsForFunction(*m_control.getFunction(j), i, prefix);
1230 }
1231 // Crystal field parameters
1232 i += makeMapsForFunction(*m_source, i, "");
1233
1234 size_t peakIndex = 0;
1235 for (size_t iSpec = 0; iSpec < m_target->nFunctions(); ++iSpec) {
1236 if (auto spectrum = dynamic_cast<const CompositeFunction *>(m_target->getFunction(iSpec).get())) {
1237 // This is a normal spectrum
1238 std::string spectrumPrefix(SPECTRUM_PREFIX);
1239 spectrumPrefix.append(std::to_string(iSpec)).append(".");
1240 // If there is a background it's the first function in spectrum
1241 if (hasBackground()) {
1242 const auto &background = *spectrum->getFunction(0);
1243 i += makeMapsForFunction(background, i, spectrumPrefix + BACKGROUND_PREFIX + ".");
1244 peakIndex = 1;
1245 }
1246 // All other functions are peaks.
1247 for (size_t ip = peakIndex; ip < spectrum->nFunctions(); ++ip) {
1248 std::string prefix(spectrumPrefix);
1249 prefix.append(PEAK_PREFIX).append(std::to_string(ip - peakIndex)).append(".");
1250 i += makeMapsForFunction(*spectrum->getFunction(ip), i, prefix);
1251 }
1252 } else {
1253 // This is a physical property function
1254 std::string prefix(m_control.physProps()[iSpec - nSpectra()]);
1255 prefix.append(".");
1256 i += makeMapsForFunction(*m_target->getFunction(iSpec), i, prefix);
1257 }
1258 }
1259}
1260
1263 size_t i = 0;
1264 // Intensity scalings for each ion
1265 const auto &crystalField = compositeSource();
1266 for (size_t ion = 0; ion < crystalField.nFunctions(); ++ion) {
1267 std::string prefix(ION_PREFIX);
1268 prefix.append(std::to_string(ion)).append(".");
1269 i += makeMapsForFunction(*crystalField.getFunction(ion), i, prefix);
1270 }
1271 // Spectrum split into an optional background and groups of peaks for
1272 // each ion
1273 size_t ionIndex = 0;
1274 // If there is a background it's the first function in spectrum
1275 if (hasBackground()) {
1276 const auto &background = *m_target->getFunction(0);
1277 i += makeMapsForFunction(background, i, BACKGROUND_PREFIX + ".");
1278 ionIndex = 1;
1279 }
1280 // All other functions are ion spectra.
1281 for (size_t ion = ionIndex; ion < m_target->nFunctions(); ++ion) {
1282 std::string ionPrefix(ION_PREFIX);
1283 ionPrefix.append(std::to_string(ion - ionIndex)).append(".");
1284 // All other functions are peaks.
1285 auto &spectrum = dynamic_cast<const CompositeFunction &>(*m_target->getFunction(ion));
1286 for (size_t ip = 0; ip < spectrum.nFunctions(); ++ip) {
1287 std::string prefix(ionPrefix);
1288 prefix.append(PEAK_PREFIX).append(std::to_string(ip)).append(".");
1289 i += makeMapsForFunction(*spectrum.getFunction(ip), i, prefix);
1290 }
1291 }
1292}
1293
1296 size_t i = 0;
1297 // Intensity scalings for each spectrum
1298 for (size_t j = 0; j < m_control.nFunctions(); ++j) {
1299 std::string prefix(SPECTRUM_PREFIX);
1300 prefix.append(std::to_string(j)).append(".");
1301 i += makeMapsForFunction(*m_control.getFunction(j), i, prefix);
1302 }
1303 // Intensity scalings for each ion
1304 const auto &crystalField = compositeSource();
1305 for (size_t ion = 0; ion < crystalField.nFunctions(); ++ion) {
1306 std::string prefix(ION_PREFIX);
1307 prefix.append(std::to_string(ion)).append(".");
1308 i += makeMapsForFunction(*crystalField.getFunction(ion), i, prefix);
1309 }
1310
1311 // The spectra (background and peak) parameters
1312 for (size_t iSpec = 0; iSpec < nSpectra(); ++iSpec) {
1313 auto &spectrum = dynamic_cast<const CompositeFunction &>(*m_target->getFunction(iSpec));
1314 std::string spectrumPrefix(SPECTRUM_PREFIX);
1315 spectrumPrefix.append(std::to_string(iSpec)).append(".");
1316
1317 // All other functions are ion spectra.
1318 for (size_t ion = 0; ion < crystalField.nFunctions(); ++ion) {
1319 auto &ionSpectrum = dynamic_cast<const CompositeFunction &>(*spectrum.getFunction(ion));
1320 size_t peakIndex = 0;
1321 if (ion == 0 && hasBackground()) {
1322 peakIndex = 1;
1323 std::string prefix(spectrumPrefix);
1324 prefix.append(BACKGROUND_PREFIX).append(".");
1325 i += makeMapsForFunction(*ionSpectrum.getFunction(0), i, prefix);
1326 }
1327 std::string ionPrefix(ION_PREFIX);
1328 ionPrefix.append(std::to_string(ion)).append(".").append(spectrumPrefix);
1329 // All other functions are peaks.
1330 for (size_t ip = peakIndex; ip < ionSpectrum.nFunctions(); ++ip) {
1331 std::string prefix(ionPrefix);
1332 prefix.append(PEAK_PREFIX).append(std::to_string(ip - peakIndex)).append(".");
1333 i += makeMapsForFunction(*ionSpectrum.getFunction(ip), i, prefix);
1334 }
1335 }
1336 }
1337 // The phys prop parameters
1338 for (size_t iSpec = nSpectra(); iSpec < m_target->nFunctions(); ++iSpec) {
1339 auto &spectrum = dynamic_cast<const CompositeFunction &>(*m_target->getFunction(iSpec));
1340 std::string physPropPrefix(spectrum.getFunction(0)->name());
1341 physPropPrefix.append(".");
1342 for (size_t ion = 0; ion < crystalField.nFunctions(); ++ion) {
1343 std::string prefix(ION_PREFIX);
1344 prefix.append(std::to_string(ion)).append(".").append(physPropPrefix);
1345 i += makeMapsForFunction(*spectrum.getFunction(ion), i, prefix);
1346 }
1347 }
1348}
1349
1353 if (!m_source) {
1354 // No function - nothing to cache
1355 m_parameterResetCache.clear();
1356 return;
1357 }
1358 auto np = m_source->nParams();
1359 m_parameterResetCache.resize(np);
1360 m_fixResetCache.resize(np);
1361 for (size_t i = 0; i < np; ++i) {
1362 m_parameterResetCache[i] = m_source->getParameter(i);
1363 m_fixResetCache[i] = m_source->isFixed(i);
1364 }
1365}
1366
1367} // namespace Mantid::CurveFitting::Functions
std::string name
Definition Run.cpp:60
std::vector< size_t > m_IntensityScalingIdx
std::vector< size_t > m_PPLambdaIdxChild
std::vector< size_t > m_PPLambdaIdxSelf
double value
The value of the point.
Definition FitMW.cpp:51
#define DECLARE_FUNCTION(classname)
Macro for declaring a new type of function to be used with the FunctionFactory.
std::map< DeltaEMode::Type, std::string > index
A composite function is a function containing other functions.
ParameterTie * getTie(size_t i) const override
Get the tie of i-th parameter.
void setParameter(size_t, const double &value, bool explicitlySet=true) override
Set i-th parameter.
size_t getParameterIndex(const ParameterReference &ref) const override
Return parameter index from a parameter reference.
void setParameterDescription(size_t, const std::string &description) override
Set i-th parameter description.
std::size_t nFunctions() const override
Number of functions.
bool isExplicitlySet(size_t i) const override
Checks if a parameter has been set explicitly.
size_t nParams() const override
Total number of parameters.
double getParameter(size_t i) const override
Get i-th parameter.
double getError(size_t i) const override
Get the fitting error for a parameter.
Attribute getAttribute(const std::string &name) const override
Return a value of attribute attName.
std::string parameterDescription(size_t i) const override
Returns the description of parameter i.
IFunction_sptr getFunction(std::size_t i) const override
Returns the pointer to i-th function.
void setError(size_t i, double err) override
Set the fitting error for a parameter.
IConstraint * getConstraint(size_t i) const override
Get constraint of i-th parameter.
ParameterStatus getParameterStatus(size_t i) const override
Get status of parameter.
void checkFunction()
Check the function.
void setParameterStatus(size_t i, ParameterStatus status) override
Change status of parameter.
Represent a domain of a very general type.
Base class that represents the domain of a function.
A class to store values calculated by a function.
size_t size() const
Return the number of values.
void expand(size_t n)
Expand values to a new size, preserve stored values.
void setCalculated(double value)
set all calculated values to same number
An interface to a constraint.
Definition IConstraint.h:26
Attribute is a non-fitting parameter.
Definition IFunction.h:285
std::string asUnquotedString() const
Returns a string value that is guarenteed to be unquoted.
std::vector< double > asVector() const
Returns vector<double> if attribute is vector<double>, throws exception otherwise.
int asInt() const
Returns int value if attribute is a int, throws exception otherwise.
std::string asString() const
Returns string value if attribute is a string, throws exception otherwise.
double asDouble() const
Returns double value if attribute is a double, throws exception otherwise.
bool isEmpty() const
Check if a string attribute is empty.
bool asBool() const
Returns bool value if attribute is a bool, throws exception otherwise.
This is an interface to a fitting function - a semi-abstarct class.
Definition IFunction.h:166
virtual size_t nParams() const =0
Total number of parameters.
virtual Attribute getAttribute(const std::string &name) const
Return a value of attribute attName.
friend class CompositeFunction
Definition IFunction.h:704
ParameterStatus
Describe parameter status in relation to fitting: Active: Fit varies such parameter directly.
Definition IFunction.h:654
virtual void tie(const std::string &parName, const std::string &expr, bool isDefault=false)
Tie a parameter to other parameters (or a constant)
virtual ParameterTie * getTie(size_t i) const
Get the tie of i-th parameter.
virtual void setAttribute(const std::string &name, const Attribute &)
Set a value to attribute attName.
virtual void setUpForFit()
Set up the function for a fit.
virtual std::vector< std::string > getAttributeNames() const
Returns a list of attribute names.
virtual std::string attributeName(size_t index) const
Get name of ith attribute.
virtual std::string parameterName(size_t i) const =0
Returns the name of parameter i.
virtual std::string name() const =0
Returns the function's name.
virtual size_t nAttributes() const
Returns the number of attributes associated with the function.
virtual IConstraint * getConstraint(size_t i) const
Get constraint of i-th parameter.
A composite function defined on a CompositeDomain.
A reference to a parameter in a function.
std::size_t getLocalIndex() const
Return parameter index in the local function.
IFunction * getLocalFunction() const
Return pointer to the local function.
Ties fitting parameters.
double get(const size_t i) const
Get an element.
size_t size() const
Size of the vector.
API::IFunction_sptr buildSource()
Build the source function.
void buildControls()
Build control functions for individual spectra.
const std::vector< std::string > & physProps() const
bool hasPhysProperties() const
Check if there are any phys. properties.
bool isMultiSpectrum() const
Is it a multi-spectrum case?
void updateMultiSite() const
Update the target function in a multi site case.
Attribute getAttribute(const std::string &name) const override
Return a value of attribute attName.
std::unordered_map< std::string, size_t > m_mapNames2Indices
Map parameter names to indices.
void updatePhysprop(int nre, const DoubleFortranVector &en, const ComplexFortranMatrix &wf, const ComplexFortranMatrix &ham, API::IFunction &fun) const
Update a physical property function.
API::IFunction_sptr buildPhysprop(int nre, const DoubleFortranVector &en, const ComplexFortranMatrix &wf, const ComplexFortranMatrix &ham, const std::string &propName) const
Build a physical property function.
void checkTargetFunction() const
Update target function if necessary.
API::IFunction_sptr m_source
Function that calculates parameters of the target function.
bool m_dirtyTarget
Flag indicating that updateTargetFunction() is required.
void calcExcitations(int nre, const DoubleFortranVector &en, const ComplexFortranMatrix &wf, double temperature, API::FunctionValues &values, double intensityScaling) const
Calculate excitations at given temperature.
void updateMultiSiteMultiSpectrum() const
Update the target function in a multi site - multi spectrum case.
void updateMultiSiteSingleSpectrum() const
Update the target function in a multi site - single spectrum case.
void makeMapsSingleSiteMultiSpectrum() const
Parameter-index map for single-site multi-spectrum.
std::pair< API::IFunction *, std::string > getAttributeReference(const std::string &attName) const
Get a reference to an attribute.
void updateSpectrum(API::IFunction &spectrum, int nre, const DoubleFortranVector &en, const ComplexFortranMatrix &wf, double temperature, double fwhm, size_t iSpec, size_t iFirst, double intensityScaling) const
Update a function for a single spectrum.
size_t makeMapsForFunction(const IFunction &fun, size_t iFirst, const std::string &prefix) const
Make parameter names from names of a function and map them to indices.
void buildMultiSiteSingleSpectrum() const
Build the target function in a multi site - single spectrum case.
double getParameter(size_t i) const override
Get i-th parameter.
size_t parameterIndex(const std::string &name) const override
Returns the index of parameter name.
std::vector< std::string > m_attributeNames
Attribute names.
void setSource(API::IFunction_sptr source) const
Set the source function.
void setAttribute(const std::string &name, const Attribute &) override
Set a value to attribute attName.
std::vector< std::string > m_mapIndices2Names
Map parameter indices to names.
void makeMapsMultiSiteMultiSpectrum() const
Parameter-index map for multi-site multi-spectrum.
void declareParameter(const std::string &name, double initValue=0, const std::string &description="") override
Declare a new parameter.
API::ParameterTie * getTie(size_t i) const override
Get the tie for i-th parameter.
API::CompositeFunction & compositeSource() const
Get a reference to the source function if it's composite.
std::vector< std::string > getAttributeNames() const override
Returns a list of attribute names.
std::vector< double > m_parameterResetCache
Temporary cache for parameter values during source function resetting.
bool hasParameter(const std::string &name) const override
Check if function has a parameter with this name.
void buildMultiSite() const
Build the target function in a multi site case.
bool hasBackground() const
Check if the spectra have a background.
API::IFunction_sptr buildSpectrum(int nre, const DoubleFortranVector &en, const ComplexFortranMatrix &wf, double temperature, double fwhm, size_t i, bool addBackground, double intensityScaling) const
Build a function for a single spectrum.
bool hasPhysProperties() const
Check if there are any phys. properties.
size_t nSpectra() const
Get number of the number of spectra (excluding phys prop data).
void makeMapsMultiSiteSingleSpectrum() const
Parameter-index map for multi-site single-spectrum.
double getError(size_t i) const override
Get the fitting error for a parameter.
void buildSingleSiteSingleSpectrum() const
Build the target function in a single site - single spectrum case.
void setParameter(size_t, const double &value, bool explicitlySet=true) override
Set i-th parameter.
bool ignoreTie(const API::ParameterTie &tie) const override
Checks if whether tie should be ignored.
bool hasAttribute(const std::string &name) const override
Check if attribute attName exists.
void setUpForFit() override
Set up the function for a fit.
void buildSingleSiteMultiSpectrum() const
Build the target function in a single site - multi spectrum case.
void setError(size_t i, double err) override
Set the fitting error for a parameter.
void checkSourceFunction() const
Build source function if necessary.
bool isMultiSpectrum() const
Check if the function is set up for a multi-spectrum calculations (Multiple temperatures defined)
void buildMultiSiteMultiSpectrum() const
Build the target function in a multi site - multi spectrum case.
size_t getNumberDomains() const override
Get number of domains required by this function.
std::unordered_map< std::string, API::IFunction_sptr > m_mapPrefixes2PhysProps
Map parameter/attribute prefixes to pointers to phys prop functions.
void buildSourceFunction() const
Build the source function.
void makeMaps() const
Make maps between parameter names and indices.
void buildSingleSite() const
Build the target function in a single site case.
void cacheSourceParameters() const
Temporary cache parameter values of the source function if it's initialised.
std::string parameterName(size_t i) const override
Returns the name of parameter i.
size_t m_nControlParams
Cached number of parameters in m_control.
void updateTargetFunction() const
Update the target function.
bool isExplicitlySet(size_t i) const override
Checks if a parameter has been set explicitly.
CrystalFieldControl m_control
Function that creates the source function.
void buildAttributeNames() const
Build and cache the attribute names.
void setParameterStatus(size_t i, ParameterStatus status) override
Change status of parameter.
void updateSingleSite() const
Update the target function in a single site case.
size_t m_nControlSourceParams
Cached number of parameters in m_control and m_source.
void updateSingleSiteMultiSpectrum() const
Update the target function in a single site - multi spectrum case.
void setParameterDescription(size_t, const std::string &description) override
Set i-th parameter description.
API::CompositeFunction_sptr m_target
Function that actually calculates the output.
API::IConstraint * getConstraint(size_t i) const override
Get the i-th constraint.
bool isMultiSite() const
Check if the function is set up for a multi-site calculations.
std::string name() const override
Returns the function's name.
void makeMapsSingleSiteSingleSpectrum() const
Parameter-index map for single-site single-spectrum.
size_t getParameterIndex(const API::ParameterReference &ref) const override
Return parameter index from a parameter reference.
ParameterStatus getParameterStatus(size_t i) const override
Get status of parameter.
std::string parameterDescription(size_t i) const override
Returns the description of parameter i.
void updateSingleSiteSingleSpectrum() const
Update the target function in a single site - single spectrum case.
bool hasPeaks() const
Check if there are peaks (there is at least one spectrum).
size_t nAttributes() const override
Returns the number of attributes associated with the function.
void function(const API::FunctionDomain &domain, API::FunctionValues &values) const override
Evaluate the function.
std::vector< API::IFunction_sptr > createEquivalentFunctions() const override
Split this function (if needed) into a list of independent functions.
size_t nParams() const override
Total number of parameters.
void setHamiltonian(const ComplexFortranMatrix &ham, const int nre)
CrystalFieldPeaks is a function that calculates crystal field peak positions and intensities.
void calculateEigenSystem(DoubleFortranVector &en, ComplexFortranMatrix &wf, ComplexFortranMatrix &ham, ComplexFortranMatrix &hz, int &nre) const
Calculate the crystal field eigensystem.
void setEigensystem(const DoubleFortranVector &en, const ComplexFortranMatrix &wf, const int nre)
Marks code as not implemented yet.
Definition Exception.h:138
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
Definition IFunction.h:743
size_t updateSpectrumFunction(API::CompositeFunction &spectrum, const std::string &peakShape, const API::FunctionValues &centresAndIntensities, size_t iFirst, const std::vector< double > &xVec, const std::vector< double > &yVec, double fwhmVariation, double defaultFWHM, bool fixAllPeaks)
Update the peaks parameters after recalculationof the crystal field.
size_t buildSpectrumFunction(API::CompositeFunction &spectrum, const std::string &peakShape, const API::FunctionValues &centresAndIntensities, const std::vector< double > &xVec, const std::vector< double > &yVec, double fwhmVariation, double defaultFWHM, size_t nRequiredPeaks, bool fixAllPeaks)
Utility functions to help set up peak functions in a Crystal Field spectrum.
void MANTID_CURVEFITTING_DLL calculateExcitations(const DoubleFortranVector &e_energies, const DoubleFortranMatrix &i_energies, double de, double di, DoubleFortranVector &e_excitations, DoubleFortranVector &i_excitations)
Calculate the excitations (transition energies) and their intensities.
void MANTID_CURVEFITTING_DLL calculateIntensities(int nre, const DoubleFortranVector &energies, const ComplexFortranMatrix &wavefunctions, double temperature, double de, IntFortranVector &degeneration, DoubleFortranVector &e_energies, DoubleFortranMatrix &i_energies)
Calculate the intensities of transitions.
std::string to_string(const wide_integer< Bits, Signed > &n)