Mantid
Loading...
Searching...
No Matches
CrystalFieldMagnetisation.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 magnetisation
27void calculate(double *out, const double *xValues, const size_t nData, const ComplexFortranMatrix &ham, const int nre,
28 const DoubleFortranVector &Hmag, const double T, const double convfact, const bool iscgs) {
29 const double beta = 1 / (PhysicalConstants::BoltzmannConstant * T);
30 // x-data is the applied field magnitude. We need to recalculate
31 // the Zeeman term and diagonalise the Hamiltonian at each x-point.
32 int nlevels = ham.len1();
33 for (size_t iH = 0; iH < nData; iH++) {
37 H *= xValues[iH];
38 if (iscgs) {
39 H *= 0.0001; // Converts from Gauss to Tesla.
40 }
41 calculateZeemanEigensystem(en, ev, ham, nre, H);
42 // Calculates the diagonal of the magnetic moment operator <wf|mu|wf>
44 calculateMagneticMoment(ev, Hmag, nre, moment);
45 double Z = 0.;
46 double M = 0.;
47 for (auto iE = 1; iE <= nlevels; iE++) {
48 double expfact = exp(-beta * en(iE));
49 Z += expfact;
50 M += moment(iE) * expfact;
51 }
52 out[iH] = convfact * M / Z;
53 }
54}
55
56// Calculate powder average - Mpowder = (Mx + My + Mz)/3
57void calculate_powder(double *out, const double *xValues, const size_t nData, const ComplexFortranMatrix &ham,
58 const int nre, const double T, const double convfact, const bool cgs) {
59 for (size_t j = 0; j < nData; j++) {
60 out[j] = 0.;
61 }
62 // Loop over the x, y, z directions
63 DoubleFortranVector Hmag(1, 3);
64 std::vector<double> tmp(nData, 0.);
65 for (int i = 1; i <= 3; i++) {
66 Hmag.zero();
67 Hmag(i) = 1.;
68 calculate(&tmp[0], xValues, nData, ham, nre, Hmag, T, convfact, cgs);
69 for (size_t j = 0; j < nData; j++) {
70 out[j] += tmp[j];
71 }
72 }
73 for (size_t j = 0; j < nData; j++) {
74 out[j] /= 3.;
75 }
76}
77} // namespace
78
80 declareAttribute("Hdir", Attribute(std::vector<double>{0., 0., 1.}));
81 declareAttribute("Temperature", Attribute(1.0));
82 declareAttribute("Unit", Attribute("bohr")); // others = "SI", "cgs"
83 declareAttribute("powder", Attribute(false));
84 declareAttribute("ScaleFactor", Attribute(1.0)); // Only for multi-site use
85}
86
87void CrystalFieldMagnetisationBase::function1D(double *out, const double *xValues, const size_t nData) const {
88 // Get the field direction
89 auto Hdir = getAttribute("Hdir").asVector();
90 if (Hdir.size() != 3) {
91 throw std::invalid_argument("Hdir must be a three-element vector.");
92 }
93 auto T = getAttribute("Temperature").asDouble();
94 auto powder = getAttribute("powder").asBool();
95 double Hnorm = sqrt(Hdir[0] * Hdir[0] + Hdir[1] * Hdir[1] + Hdir[2] * Hdir[2]);
96 DoubleFortranVector H(1, 3);
97 if (fabs(Hnorm) > 1.e-6) {
98 for (auto i = 0; i < 3; i++) {
99 H(i + 1) = Hdir[i] / Hnorm;
100 }
101 }
102 auto unit = getAttribute("Unit").asString();
103 const double NAMUB = 5.5849397; // N_A*mu_B - J/T/mol
104 // Converts to different units - SI is in J/T/mol or Am^2/mol.
105 // cgs is in erg/Gauss/mol (emu/mol). The value of uB in erg/G is 1000x in J/T
106 // NB. Atomic ("bohr") units gives magnetisation in uB/ion, but other units
107 // give the molar magnetisation.
108 double convfact = boost::iequals(unit, "SI") ? NAMUB : (boost::iequals(unit, "cgs") ? NAMUB * 1000. : 1.);
109 const bool iscgs = boost::iequals(unit, "cgs");
110 // Use stored values
111 if (powder) {
112 calculate_powder(out, xValues, nData, m_ham, m_nre, T, convfact, iscgs);
113 } else {
114 calculate(out, xValues, nData, m_ham, m_nre, H, T, convfact, iscgs);
115 }
116 auto fact = getAttribute("ScaleFactor").asDouble();
117 if (fact != 1.0) {
118 for (size_t i = 0; i < nData; i++) {
119 out[i] *= fact;
120 }
121 }
122}
123
125
127 : CrystalFieldPeaksBase(), CrystalFieldMagnetisationBase(), m_setDirect(false) {}
128
129// Sets the base crystal field Hamiltonian matrix
131 m_setDirect = true;
132 m_ham = ham;
133 m_nre = nre;
134}
135
136void CrystalFieldMagnetisation::function1D(double *out, const double *xValues, const size_t nData) const {
137 if (!m_setDirect) {
141 calculateEigenSystem(en, wf, m_ham, hz, m_nre);
142 m_ham += hz;
143 }
145}
146
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
CrystalFieldMagnetisation is a function that calculates the induced magnetic moment (in bohr magneton...
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 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.
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.