Mantid
Loading...
Searching...
No Matches
CrystalFieldMoment.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 +
13#include "MantidAPI/Jacobian.h"
19#include <boost/algorithm/string/predicate.hpp>
20#include <cmath>
21
23
24namespace {
25
26// Does the actual calculation of the magnetic moment
27void calculate(double *out, const double *xValues, const size_t nData, const ComplexFortranMatrix &ham, const int nre,
28 const DoubleFortranVector &Hdir, const double Hmag, const double convfact) {
29 const double k_B = PhysicalConstants::BoltzmannConstant;
33 H *= Hmag;
34 calculateZeemanEigensystem(en, ev, ham, nre, H);
35 // Calculates the diagonal of the magnetic moment operator <wf|mu|wf>
37 calculateMagneticMoment(ev, Hdir, nre, moment);
38 int nlevels = ham.len1();
39 // x-data is the temperature.
40 for (size_t iT = 0; iT < nData; iT++) {
41 double Z = 0.;
42 double M = 0.;
43 const double beta = 1 / (k_B * xValues[iT]);
44 for (auto iE = 1; iE <= nlevels; iE++) {
45 double expfact = exp(-beta * en(iE));
46 Z += expfact;
47 M += moment(iE) * expfact;
48 }
49 out[iT] = convfact * M / Z;
50 }
51}
52
53// Powder averaging - sum over calculations along x, y, z
54void calculate_powder(double *out, const double *xValues, const size_t nData, const ComplexFortranMatrix &ham,
55 const int nre, const double Hmag, const double convfact) {
56 for (size_t j = 0; j < nData; j++) {
57 out[j] = 0.;
58 }
59 DoubleFortranVector Hd(1, 3);
60 std::vector<double> tmp(nData, 0.);
61 for (int i = 1; i <= 3; i++) {
62 Hd.zero();
63 Hd(i) = 1.;
64 calculate(&tmp[0], xValues, nData, ham, nre, Hd, Hmag, convfact);
65 for (size_t j = 0; j < nData; j++) {
66 out[j] += tmp[j];
67 }
68 }
69 for (size_t j = 0; j < nData; j++) {
70 out[j] /= 3.;
71 }
72}
73} // namespace
74
76 declareAttribute("Hdir", Attribute(std::vector<double>{0., 0., 1.}));
77 declareAttribute("Hmag", Attribute(1.0));
78 declareAttribute("Unit", Attribute("bohr")); // others = "SI", "cgs"
79 declareAttribute("inverse", Attribute(false));
80 declareAttribute("powder", Attribute(false));
81 declareAttribute("ScaleFactor", Attribute(1.0)); // Only for multi-site use
82}
83
84void CrystalFieldMomentBase::function1D(double *out, const double *xValues, const size_t nData) const {
85 // Get the field direction
86 auto Hdir = getAttribute("Hdir").asVector();
87 if (Hdir.size() != 3) {
88 throw std::invalid_argument("Hdir must be a three-element vector.");
89 }
90 auto Hmag = getAttribute("Hmag").asDouble();
91 auto powder = getAttribute("powder").asBool();
92 double Hnorm = sqrt(Hdir[0] * Hdir[0] + Hdir[1] * Hdir[1] + Hdir[2] * Hdir[2]);
93 DoubleFortranVector H(1, 3);
94 if (fabs(Hnorm) > 1.e-6) {
95 for (auto i = 0; i < 3; i++) {
96 H(i + 1) = Hdir[i] / Hnorm;
97 }
98 }
99 auto unit = getAttribute("Unit").asString();
100 const double NAMUB = 5.5849397; // N_A*mu_B - J/T/mol
101 // Converts to different units - SI is in J/T/mol or Am^2/mol. cgs in emu/mol.
102 // NB. Atomic ("bohr") units gives magnetisation in bohr magneton/ion, but
103 // other units give the molar magnetisation.
104 double convfact = boost::iequals(unit, "SI") ? NAMUB : (boost::iequals(unit, "cgs") ? NAMUB * 1000. : 1.);
105 if (boost::iequals(unit, "cgs")) {
106 Hmag *= 0.0001; // Converts field from Gauss to Tesla (calcs in SI).
107 }
108 if (powder) {
109 calculate_powder(out, xValues, nData, m_ham, m_nre, Hmag, convfact);
110 } else {
111 calculate(out, xValues, nData, m_ham, m_nre, H, Hmag, convfact);
112 }
113 if (getAttribute("inverse").asBool()) {
114 for (size_t i = 0; i < nData; i++) {
115 out[i] = 1. / out[i];
116 }
117 }
118 auto fact = getAttribute("ScaleFactor").asDouble();
119 if (fact != 1.0) {
120 for (size_t i = 0; i < nData; i++) {
121 out[i] *= fact;
122 }
123 }
124}
125
127
129
130// Sets the base crystal field Hamiltonian matrix
132 m_setDirect = true;
133 m_ham = ham;
134 m_nre = nre;
135}
136
137void CrystalFieldMoment::function1D(double *out, const double *xValues, const size_t nData) const {
138 if (!m_setDirect) {
142 calculateEigenSystem(en, wf, m_ham, hz, m_nre);
143 m_ham += hz;
144 }
145 CrystalFieldMomentBase::function1D(out, xValues, nData);
146}
147
149
150// Sets the base crystal field Hamiltonian matrix
152 m_ham = ham;
153 m_nre = nre;
154}
155
156} // namespace Mantid::CurveFitting::Functions
gsl_vector * tmp
#define DECLARE_FUNCTION(classname)
Macro for declaring a new type of function to be used with the FunctionFactory.
#define fabs(x)
Definition: Matrix.cpp:22
This is a specialization of IFunction for functions of one real argument.
Definition: IFunction1D.h:43
Attribute is a non-fitting parameter.
Definition: IFunction.h:282
std::vector< double > asVector() const
Returns vector<double> if attribute is vector<double>, throws exception otherwise.
Definition: IFunction.cpp:765
std::string asString() const
Returns string value if attribute is a string, throws exception otherwise.
Definition: IFunction.cpp:660
double asDouble() const
Returns double value if attribute is a double, throws exception otherwise.
Definition: IFunction.cpp:739
bool asBool() const
Returns bool value if attribute is a bool, throws exception otherwise.
Definition: IFunction.cpp:752
virtual Attribute getAttribute(const std::string &name) const
Return a value of attribute attName.
Definition: IFunction.cpp:1394
void declareAttribute(const std::string &name, const API::IFunction::Attribute &defaultValue)
Declare a single attribute.
Definition: IFunction.cpp:1418
Implements the part of IFunction interface dealing with parameters.
Definition: ParamFunction.h:33
CrystalFieldMoment is a function that calculates the induced magnetic moment (in bohr magnetons per i...
void function1D(double *out, const double *xValues, const size_t nData) const override
Function you want to fit to.
void setHamiltonian(const ComplexFortranMatrix &ham, const int nre)
void function1D(double *out, const double *xValues, const size_t nData) const override
Function you want to fit to.
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 MANTID_CURVEFITTING_DLL calculateMagneticMoment(const ComplexFortranMatrix &ev, const DoubleFortranVector &Hmag, const int nre, DoubleFortranVector &moment)
Calculate the diagonal matrix elements of the magnetic moment operator in a particular eigenvector ba...
void MANTID_CURVEFITTING_DLL calculateZeemanEigensystem(DoubleFortranVector &eigenvalues, ComplexFortranMatrix &eigenvectors, const ComplexFortranMatrix &hamiltonian, int nre, const DoubleFortranVector &bext)
Calculates the eigenvalues/vectors of a crystal field Hamiltonian in a specified external magnetic fi...
FortranMatrix< ComplexMatrix > ComplexFortranMatrix
FortranVector< EigenVector > DoubleFortranVector
MANTID_GEOMETRY_DLL Raster calculate(const Kernel::V3D &beamDirection, const IObject &shape, const double cubeSizeInMetre)
Definition: Rasterize.cpp:181
static constexpr double BoltzmannConstant
Boltzmann Constant in meV/K Taken from http://physics.nist.gov/cuu/Constants on 10/07/2012.