Mantid
Loading...
Searching...
No Matches
VesuvioResolution.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 +
14
15#include <gsl/gsl_poly.h>
16
18
19using namespace Mantid;
20using namespace Mantid::CurveFitting;
22namespace {
24const char *MASS_NAME = "Mass";
25
26const double STDDEV_TO_HWHM = std::sqrt(std::log(4.0));
28} // namespace
29
30// Register into factory
32
33
39 const size_t index) {
40 const auto &spectrumInfo = ws->spectrumInfo();
41 if (!spectrumInfo.hasDetectors(index))
42 throw std::invalid_argument("VesuvioResolution - Workspace has no detector "
43 "attached to histogram at index " +
45
46 ResolutionParams respar;
47 const auto &pmap = ws->constInstrumentParameters();
48 const auto &det = spectrumInfo.detector(index);
49 respar.dl1 = ConvertToYSpace::getComponentParameter(det, pmap, "sigma_l1");
50 respar.dl2 = ConvertToYSpace::getComponentParameter(det, pmap, "sigma_l2");
51 respar.dtof = ConvertToYSpace::getComponentParameter(det, pmap, "sigma_tof");
52 respar.dthe = ConvertToYSpace::getComponentParameter(det, pmap, "sigma_theta"); // radians
53 respar.dEnLorentz = ConvertToYSpace::getComponentParameter(det, pmap, "hwhm_lorentz");
54 respar.dEnGauss = ConvertToYSpace::getComponentParameter(det, pmap, "sigma_gauss");
55 return respar;
56}
57
59 : API::ParamFunction(), API::IFunction1D(), m_log("VesuvioResolution"), m_wsIndex(0), m_mass(0.0), m_voigt(),
60 m_resolutionSigma(0.0), m_lorentzFWHM(0.0) {}
61
65std::string VesuvioResolution::name() const { return "VesuvioResolution"; }
66
67/*
68 * Creates the internal caches
69 */
71 // Voigt
72
73 using namespace Mantid::API;
74 m_voigt = std::dynamic_pointer_cast<IPeakFunction>(FunctionFactory::Instance().createFunction("Voigt"));
75}
76
84void VesuvioResolution::setMatrixWorkspace(std::shared_ptr<const API::MatrixWorkspace> workspace, size_t wsIndex,
85 double startX, double endX) {
86 UNUSED_ARG(startX);
87 UNUSED_ARG(endX);
88
89 m_wsIndex = wsIndex;
92 this->cacheResolutionComponents(detpar, respar);
93}
94
100 const ResolutionParams &respar) {
101 // geometry
102 double theta = detpar.theta; // cache for frequent access
103 double hwhmLorentzE = respar.dEnLorentz;
104 double hwhmGaussE = STDDEV_TO_HWHM * respar.dEnGauss;
105
106 // ------ Fixed coefficients related to resolution & Y-space transforms
107 // ------------------
108 const double mn = PhysicalConstants::NeutronMassAMU;
110
111 const double k1 = std::sqrt(detpar.efixed / mevToK);
112 const double l2l1 = detpar.l2 / detpar.l1;
113
114 // Resolution dependence
115
116 // Find K0/K1 at y=0 by taking the largest root of (M-1)s^2 + 2cos(theta)s -
117 // (M+1) = 0
118 // Quadratic if M != 1 but simple linear if it does
119 double k0k1(0.0);
120 if ((m_mass - 1.0) > DBL_EPSILON) {
121 double x0(0.0), x1(0.0);
122 gsl_poly_solve_quadratic(m_mass - 1.0, 2.0 * std::cos(theta), -(m_mass + 1.0), &x0, &x1);
123 k0k1 = std::max(x0, x1); // K0/K1 at y=0
124 } else {
125 // solution is simply s = 1/cos(theta)
126 k0k1 = 1.0 / std::cos(theta);
127 }
128 double qy0(0.0), wgauss(0.0);
129
130 if (m_mass > 1.0) {
131 qy0 = std::sqrt(k1 * k1 * m_mass * (k0k1 * k0k1 - 1));
132 double k0k1p3 = std::pow(k0k1, 3);
133 double r1 = -(1.0 + l2l1 * k0k1p3);
134 double r2 = 1.0 - l2l1 * k0k1p3 + l2l1 * std::pow(k0k1, 2) * std::cos(theta) - k0k1 * std::cos(theta);
135
136 double factor = (0.2413 / qy0) * ((m_mass / mn) * r1 - r2);
137 m_lorentzFWHM = std::abs(factor * hwhmLorentzE * 2);
138 wgauss = std::abs(factor * hwhmGaussE * 2);
139 } else {
140 qy0 = k1 * std::tan(theta);
141 double factor = (0.2413 * 2.0 / k1) * std::abs((std::cos(theta) + l2l1) / std::sin(theta));
142 m_lorentzFWHM = hwhmLorentzE * factor;
143 wgauss = hwhmGaussE * factor;
144 }
145
146 double k0y0 = k1 * k0k1; // k0_y0 = k0 value at y=0
147 double wtheta = 2.0 * STDDEV_TO_HWHM * std::abs(k0y0 * k1 * std::sin(theta) / qy0) * respar.dthe;
148 double common = (m_mass / mn) - 1 + k1 * std::cos(theta) / k0y0;
149 double wl1 = 2.0 * STDDEV_TO_HWHM * std::abs((std::pow(k0y0, 2) / (qy0 * detpar.l1)) * common) * respar.dl1;
150 double wl2 = 2.0 * STDDEV_TO_HWHM * std::abs((std::pow(k0y0, 3) / (k1 * qy0 * detpar.l1)) * common) * respar.dl2;
151
152 m_resolutionSigma = std::sqrt(std::pow(wgauss, 2) + std::pow(wtheta, 2) + std::pow(wl1, 2) + std::pow(wl2, 2));
153
154 m_log.information() << "--------------------- Mass=" << m_mass << " -----------------------\n";
155 m_log.information() << "w_l1 (FWHM)=" << wl2 << '\n';
156 m_log.information() << "w_l0 (FWHM)=" << wl1 << '\n';
157 m_log.information() << "w_theta (FWHM)=" << wtheta << '\n';
158 m_log.information() << "w_foil_lorentz (FWHM)=" << m_lorentzFWHM << '\n';
159 m_log.information() << "w_foil_gauss (FWHM)=" << wgauss << '\n';
160}
161
162void VesuvioResolution::function1D(double *out, const double *xValues, const size_t nData) const {
163 std::vector<double> outVec(static_cast<int>(nData), 0);
164 const std::vector<double> xValuesVec(xValues, xValues + nData);
165 voigtApprox(outVec, xValuesVec, 0, 1, m_lorentzFWHM, m_resolutionSigma);
166 std::copy(outVec.begin(), outVec.end(), out);
167}
168
170
175void VesuvioResolution::setAttribute(const std::string &name, const Attribute &value) {
176 IFunction::setAttribute(name, value); // Make sure the base-class stores it
177 if (name == MASS_NAME)
178 m_mass = value.asDouble();
179}
180
190void VesuvioResolution::voigtApprox(std::vector<double> &voigt, const std::vector<double> &xValues,
191 const double lorentzPos, const double lorentzAmp) const {
192 voigtApprox(voigt, xValues, lorentzPos, lorentzAmp, m_lorentzFWHM, m_resolutionSigma);
193}
194
206void VesuvioResolution::voigtApprox(std::vector<double> &voigt, const std::vector<double> &xValues,
207 const double lorentzPos, const double lorentzAmp, const double lorentzWidth,
208 const double gaussWidth) const {
209 m_voigt->setParameter(0, lorentzAmp);
210 m_voigt->setParameter(1, lorentzPos);
211 m_voigt->setParameter(2, lorentzWidth);
212 m_voigt->setParameter(3, gaussWidth);
213 assert(voigt.size() == xValues.size());
214 m_voigt->functionLocal(voigt.data(), xValues.data(), xValues.size());
215
216 // Normalize so that integral of V=lorentzAmp
217 const double norm = 1.0 / (0.5 * M_PI * lorentzWidth);
218 using std::placeholders::_1;
219 std::transform(voigt.begin(), voigt.end(), voigt.begin(), std::bind(std::multiplies<double>(), _1, norm));
220}
221
222} // namespace Mantid::CurveFitting::Functions
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.
IPeaksWorkspace_sptr workspace
Definition: IndexPeaks.cpp:114
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition: System.h:64
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
void declareAttribute(const std::string &name, const API::IFunction::Attribute &defaultValue)
Declare a single attribute.
Definition: IFunction.cpp:1418
virtual void setAttribute(const std::string &name, const Attribute &)
Set a value to attribute attName.
Definition: IFunction.cpp:1409
Implements the part of IFunction interface dealing with parameters.
Definition: ParamFunction.h:33
static DetectorParams getDetectorParameters(const API::MatrixWorkspace_const_sptr &ws, const size_t index)
Creates a POD struct containing the required detector parameters for this spectrum.
static double getComponentParameter(const Geometry::IComponent &det, const Geometry::ParameterMap &pmap, const std::string &name)
Retrieve a component parameter.
Calculate the resolution from a workspace of Vesuvio data using the mass & instrument definition.
static ResolutionParams getResolutionParameters(const API::MatrixWorkspace_const_sptr &ws, const size_t index)
Creates a POD struct containing the required resolution parameters for this spectrum.
size_t m_wsIndex
Current workspace index, required to access instrument parameters.
void declareAttributes() override
Declare parameters that will never participate in the fit.
void setUpForFit() override
Ensure the object is ready to be fitted.
void voigtApprox(std::vector< double > &voigt, const std::vector< double > &xValues, const double lorentzPos, const double lorentzAmp, const double lorentzWidth, const double gaussWidth) const
Compute Voigt function.
VesuvioResolution()
Default constructor required for factory.
void cacheResolutionComponents(const Algorithms::DetectorParams &detpar, const ResolutionParams &respar)
Pre-calculate the resolution components values.
void function1D(double *out, const double *xValues, const size_t nData) const override
Calculate the function.
std::shared_ptr< API::IPeakFunction > m_voigt
Voigt function.
void setMatrixWorkspace(std::shared_ptr< const API::MatrixWorkspace > workspace, size_t wsIndex, double startX, double endX) override
Cache a copy of the workspace pointer and pull out the parameters.
void setAttribute(const std::string &name, const Attribute &value) override
Set an attribute value (and possibly cache its value)
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
static constexpr double E_mev_toNeutronWavenumberSq
Transformation coefficient to transform neutron energy into neutron wavevector: K-neutron[m^-10] = sq...
static constexpr double NeutronMassAMU
Mass of the neutron in AMU.
Helper class which provides the Collimation Length for SANS instruments.
Generate a tableworkspace to store the calibration results.
std::string to_string(const wide_integer< Bits, Signed > &n)
Simple data structure to store nominal detector values It avoids some functions taking a huge number ...
double theta
scattering angle in radians
double l1
source-sample distance in metres
double l2
sample-detector distance in metres
Simple data structure to store resolution parameter values It avoids some functions taking a huge num...
double dl2
spread in sample-detector distance (m)
double dthe
spread in scattering angle (radians)
double dtof
spread in tof measurement (us)
double dl1
spread in source-sample distance (m)
double dEnLorentz
lorentz width in energy (meV)
double dEnGauss
gaussian width in energy (meV