25#include <boost/regex.hpp>
29using namespace CurveFitting;
30using namespace Kernel;
37Kernel::Logger
g_log(
"CrystalFieldMultiSpectrum");
40const boost::regex FWHMX_ATTR_REGEX(
"FWHMX([0-9]+)");
41const boost::regex FWHMY_ATTR_REGEX(
"FWHMY([0-9]+)");
45class Peaks :
public CrystalFieldPeaksBase,
public API::IFunctionGeneral {
47 Peaks() : CrystalFieldPeaksBase() {}
48 std::string name()
const override {
return "Peaks"; }
49 size_t getNumberDomainColumns()
const override {
50 throw Exception::NotImplementedError(
"This method is intentionally not implemented.");
52 size_t getNumberValuesPerArgument()
const override {
53 throw Exception::NotImplementedError(
"This method is intentionally not implemented.");
55 void functionGeneral(
const API::FunctionDomainGeneral & , API::FunctionValues & )
const override {
56 throw Exception::NotImplementedError(
"This method is intentionally not implemented.");
64 void declareIntensityScaling(
size_t nSpec) {
70 for (
size_t i = 0; i < nSpec; ++i) {
73 declareParameter(
"IntensityScaling" + si, 1.0,
"Intensity scaling factor for spectrum " + si);
74 }
catch (std::invalid_argument &) {
80 void declarePPLambda(
size_t iSpec) {
89 declareParameter(
"Lambda" + si, 0.0,
"Effective exchange coupling of dataset " + si);
90 }
catch (std::invalid_argument &) {
93 declareParameter(
"Chi0" + si, 0.0,
"Effective exchange coupling of dataset " + si);
94 }
catch (std::invalid_argument &) {
119 }
catch (std::runtime_error
const &ex) {
130 return m_target->getNumberDomains();
132 throw std::runtime_error(
"Failed to build target function.");
138 std::vector<IFunction_sptr> funs;
140 for (
size_t i = 0; i < composite.nFunctions(); ++i) {
141 funs.emplace_back(composite.getFunction(i));
149 if (
name ==
"Temperatures") {
151 const auto nSpec = attr.
asVector().size();
152 dynamic_cast<Peaks &
>(*m_source).declareIntensityScaling(nSpec);
157 const auto nWidths = new_fwhm.size();
158 if (nWidths != nSpec) {
159 new_fwhm.resize(nSpec);
160 if (nWidths > nSpec) {
161 for (
size_t iSpec = nWidths; iSpec < nSpec; ++iSpec) {
162 new_fwhm[iSpec] = new_fwhm[0];
169 for (
size_t iSpec = 0; iSpec < nSpec; ++iSpec) {
174 }
catch (
const std::invalid_argument &) {
180 }
catch (
const std::invalid_argument &) {
184 }
else if (
name ==
"PhysicalProperties") {
185 const auto physpropId = attr.
asVector();
186 const auto nSpec = physpropId.size();
187 auto &source =
dynamic_cast<Peaks &
>(*m_source);
188 for (
size_t iSpec = 0; iSpec < nSpec; ++iSpec) {
190 const auto pptype =
static_cast<int>(physpropId[iSpec]);
205 source.declarePPLambda(iSpec);
209 }
else if (boost::regex_match(
name, match, FWHMX_ATTR_REGEX)) {
210 auto iSpec = std::stoul(match[1]);
214 throw std::invalid_argument(
"Temperatures must be defined before resolution model");
216 }
else if (boost::regex_match(
name, match, FWHMY_ATTR_REGEX)) {
217 auto iSpec = std::stoul(match[1]);
221 throw std::invalid_argument(
"Temperatures must be defined before resolution model");
240 auto &peakCalculator =
dynamic_cast<Peaks &
>(*m_source);
241 peakCalculator.calculateEigenSystem(en, wf, ham, hz, nre);
247 throw std::runtime_error(
"Vector of temperatures cannot be empty.");
252 throw std::runtime_error(
"Vector of FWHMs cannot be empty.");
258 throw std::runtime_error(
"Vector of FWHMs must either have same size as "
266 if (physprops.empty()) {
268 }
else if (physprops.size() != nSpec) {
269 if (physprops.size() == 1) {
270 auto physprop =
static_cast<int>(physprops.front());
273 throw std::runtime_error(
"Vector of PhysicalProperties must have same "
274 "size as Temperatures or size 1.");
279 std::transform(physprops.cbegin(), physprops.cend(), std::back_inserter(
m_physprops),
280 [](
auto elem) { return static_cast<int>(elem); });
288 for (
size_t i = 0; i < nSpec; ++i) {
300 fun->setDomainIndex(i, i);
316 const size_t nSpec =
m_nPeaks.size();
319 auto &source =
dynamic_cast<Peaks &
>(*m_source);
320 double intensityScaling;
321 if (source.m_IntensityScalingIdx.empty()) {
324 intensityScaling =
getParameter(source.m_IntensityScalingIdx[iSpec]);
326 const auto nPeaks = eExcitations.
size();
327 values.
expand(2 * nPeaks);
328 for (
size_t i = 0; i < nPeaks; ++i) {
337 double fwhm,
size_t iSpec)
const {
348 if (!bkgdShape.empty() && bkgdShape.find(
"name=") != 0 && bkgdShape.front() !=
'(') {
349 bkgdShape =
"name=" + bkgdShape;
354 spectrum->addFunction(background);
356 background->fixAll();
360 *spectrum, peakShape, values,
m_fwhmX[iSpec],
m_fwhmY[iSpec], fwhmVariation, fwhm, nRequiredPeaks, fixAllPeaks);
367 size_t iSpec)
const {
380 spectrum.setAttribute(
"Hdir",
getAttribute(
"Hdir" + suffix));
381 spectrum.setAttribute(
"inverse",
getAttribute(
"inverse" + suffix));
382 spectrum.setAttribute(
"powder",
getAttribute(
"powder" + suffix));
383 dynamic_cast<Peaks &
>(*m_source).m_PPLambdaIdxChild[iSpec] = spectrum.parameterIndex(
"Lambda");
384 dynamic_cast<Peaks &
>(*m_source).m_PPChi0IdxChild[iSpec] = spectrum.parameterIndex(
"Chi0");
391 spectrum.setAttributeValue(
"Temperature", temperature);
393 spectrum.setAttribute(
"Unit",
getAttribute(
"Unit" + suffix));
394 spectrum.setAttribute(
"Hdir",
getAttribute(
"Hdir" + suffix));
395 spectrum.setAttribute(
"powder",
getAttribute(
"powder" + suffix));
403 spectrum.setAttribute(
"Unit",
getAttribute(
"Unit" + suffix));
404 spectrum.setAttribute(
"Hdir",
getAttribute(
"Hdir" + suffix));
405 spectrum.setAttribute(
"Hmag",
getAttribute(
"Hmag" + suffix));
406 spectrum.setAttribute(
"inverse",
getAttribute(
"inverse" + suffix));
407 spectrum.setAttribute(
"powder",
getAttribute(
"powder" + suffix));
411 throw std::runtime_error(
"Physical property type not understood");
427 auto &peakCalculator =
dynamic_cast<Peaks &
>(*m_source);
428 peakCalculator.calculateEigenSystem(en, wf, ham, hz, nre);
437 }
catch (std::out_of_range &) {
446 double temperature,
double fwhm,
size_t iSpec)
const {
456 auto &source =
dynamic_cast<Peaks &
>(*m_source);
457 suscept.setParameter(source.m_PPLambdaIdxChild[iSpec],
getParameter(source.m_PPLambdaIdxSelf[iSpec]));
458 suscept.setParameter(source.m_PPChi0IdxChild[iSpec],
getParameter(source.m_PPChi0IdxSelf[iSpec]));
479 m_fwhmY[iSpec], fwhmVariation, fwhm, fixAllPeaks);
std::vector< size_t > m_IntensityScalingIdx
std::vector< size_t > m_PPLambdaIdxChild
std::vector< size_t > m_PPLambdaIdxSelf
std::vector< size_t > m_PPChi0IdxSelf
std::vector< size_t > m_PPChi0IdxChild
#define DECLARE_FUNCTION(classname)
Macro for declaring a new type of function to be used with the FunctionFactory.
A composite function is a function containing other functions.
FunctionGenerator is a partial implementation of IFunction that defines a function consisting of two ...
IFunction_sptr m_source
Function that calculates parameters of the target function.
double getParameter(size_t i) const override
Get i-th parameter.
void setAttribute(const std::string &name, const Attribute &) override
Set a value to attribute attName.
IFunction_sptr m_target
Function that actually calculates the output.
bool m_dirty
Flag indicating that updateTargetFunction() is required.
void checkTargetFunction() const
Update target function if necessary.
Attribute getAttribute(const std::string &name) const override
Return a value of attribute attName.
size_t m_nOwnParams
Cached number of parameters in m_source.
A class to store values calculated by a function.
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
Attribute is a non-fitting parameter.
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.
void setVector(const std::vector< double > &)
Sets new value if attribute is a vector.
double asDouble() const
Returns double value if attribute is a double, throws exception otherwise.
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.
virtual Attribute getAttribute(const std::string &name) const
Return a value of attribute attName.
void declareAttribute(const std::string &name, const API::IFunction::Attribute &defaultValue)
Declare a single attribute.
A composite function defined on a CompositeDomain.
double get(const size_t i) const
Get an element.
size_t size() const
Size of the vector.
void setEnergy(const DoubleFortranVector &en)
void setHamiltonian(const ComplexFortranMatrix &ham, const int nre)
void setHamiltonian(const ComplexFortranMatrix &ham, const int nre)
API::IFunction_sptr buildPhysprop(int nre, const DoubleFortranVector &en, const ComplexFortranMatrix &wf, const ComplexFortranMatrix &ham, double temperature, size_t iSpec) const
std::vector< std::vector< double > > m_fwhmX
Caches of the width functions.
void setAttribute(const std::string &name, const Attribute &) override
Perform custom actions on setting certain attributes.
void updateSpectrum(API::IFunction &spectrum, int nre, const DoubleFortranVector &en, const ComplexFortranMatrix &wf, const ComplexFortranMatrix &ham, double temperature, double fwhm, size_t i) const
Update a function for a single spectrum.
@ Magnetisation
Specify dataset is magnetisation vs field M(H)
@ HeatCapacity
Specify dataset is magnetic heat capacity Cv(T)
@ Susceptibility
Specify dataset is magnetic susceptibility chi(T)
@ MagneticMoment
Specify dataset is magnetisation vs temp M(T)
std::vector< size_t > m_nPeaks
Cache number of fitted peaks.
std::vector< double > m_temperatures
Cache the temperatures.
std::vector< std::vector< double > > m_fwhmY
API::IFunction_sptr buildSpectrum(int nre, const DoubleFortranVector &en, const ComplexFortranMatrix &wf, double temperature, double fwhm, size_t i) const
Build a function for a single spectrum.
std::vector< double > m_FWHMs
Cache the default peak FWHMs.
std::vector< API::IFunction_sptr > createEquivalentFunctions() const override
Split this function (if needed) into a list of independent functions.
size_t getNumberDomains() const override
Get number of domains required by this function.
std::string name() const override
Returns the function's name.
void init() override
overwrite IFunction base class method, which declare function parameters
void buildTargetFunction() const override
Uses source to calculate peak centres and intensities then populates m_spectrum with peaks of type gi...
CrystalFieldMultiSpectrum()
Constructor.
std::vector< int > m_physprops
Cache the list of "spectra" corresponding to physical properties.
void calcExcitations(int nre, const DoubleFortranVector &en, const ComplexFortranMatrix &wf, double temperature, API::FunctionValues &values, size_t iSpec) const
Calculate excitations at given temperature.
void updateTargetFunction() const override
Update m_spectrum function.
void setEigensystem(const DoubleFortranVector &en, const ComplexFortranMatrix &wf, const int nre)
void error(const std::string &msg)
Logs at error level.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
size_t updateSpectrumFunction(API::CompositeFunction &spectrum, const std::string &peakShape, const API::FunctionValues ¢resAndIntensities, 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 calculateNPeaks(const API::FunctionValues ¢resAndIntensities)
Calculate the number of visible peaks.
size_t buildSpectrumFunction(API::CompositeFunction &spectrum, const std::string &peakShape, const API::FunctionValues ¢resAndIntensities, 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 °eneration, DoubleFortranVector &e_energies, DoubleFortranMatrix &i_energies)
Calculate the intensities of transitions.
std::string to_string(const wide_integer< Bits, Signed > &n)