24 const double maxkappa = std::log(1.0 / std::numeric_limits<double>::epsilon()) / 2.0;
 
   25 const double maxkappa2 = std::log(std::numeric_limits<double>::max());
 
   27 double FisherDistribution(
double x, 
double kappa)
 
   30         return 1.0 / (4.0 * M_PI);
 
   32     double prefactor = kappa / (4.0 * M_PI);
 
   33     if (kappa > maxkappa) {
 
   34         return 2.0 * prefactor * std::exp(kappa * (x - 1.0));
 
   36     return prefactor * std::exp(kappa * x) / std::sinh(kappa);
 
   39 double FisherPrefactor(
double kappa)
 
   42         return 1.0 / (4.0 * M_PI);
 
   44     if (kappa > maxkappa) {
 
   45         return kappa / 2.0 / M_PI;
 
   47         return kappa * std::exp(kappa) / 4.0 / M_PI / std::sinh(kappa);
 
   51 double MisesPrefactor(
double kappa)
 
   54         return 1.0 / (2.0 * M_PI);
 
   56     if (kappa > maxkappa2) {
 
   57         return std::sqrt(kappa / 2.0 / M_PI) / (1.0 + 1.0 / (8.0 * kappa));
 
   63 double Gauss3D(
double q2, 
double domainsize)
 
   65     double norm_factor = std::pow(domainsize / std::sqrt(M_TWOPI), 3.0);
 
   66     double exponent = -q2 * domainsize * domainsize / 2.0;
 
   67     return norm_factor * std::exp(exponent);
 
   70 double Cauchy3D(
double q2, 
double domainsize)
 
   72     double lorentz1 = domainsize / (1.0 + q2 * domainsize * domainsize) / M_PI;
 
   73     return domainsize * lorentz1 * lorentz1;
 
   82 IPeakShape::IPeakShape(
const NodeMeta& meta, 
const std::vector<double>& PValues)
 
   87 IPeakShape::~IPeakShape() = 
default;
 
   93 IsotropicGaussPeakShape::IsotropicGaussPeakShape(
double max_intensity, 
double domainsize)
 
   94     : m_max_intensity(max_intensity), m_domainsize(domainsize)
 
   98 IsotropicGaussPeakShape::~IsotropicGaussPeakShape() = 
default;
 
  107     double q_norm = q.
mag2();
 
  108     return m_max_intensity * Gauss3D(q_norm, m_domainsize);
 
  113     return evaluate(q - q_lattice_point);
 
  120 IsotropicLorentzPeakShape::IsotropicLorentzPeakShape(
double max_intensity, 
double domainsize)
 
  121     : m_max_intensity(max_intensity), m_domainsize(domainsize)
 
  125 IsotropicLorentzPeakShape::~IsotropicLorentzPeakShape() = 
default;
 
  134     double q_norm = q.
mag2();
 
  135     return m_max_intensity * Cauchy3D(q_norm, m_domainsize);
 
  140     return evaluate(q - q_lattice_point);
 
  147 GaussFisherPeakShape::GaussFisherPeakShape(
double max_intensity, 
double radial_size, 
double kappa)
 
  148     : m_max_intensity(max_intensity), m_radial_size(radial_size), m_kappa(kappa)
 
  152 GaussFisherPeakShape::~GaussFisherPeakShape() = 
default;
 
  161     double q_r = q.
mag();
 
  162     double q_lat_r = q_lattice_point.
mag();
 
  163     double dq2 = (q_r - q_lat_r) * (q_r - q_lat_r);
 
  165         return m_max_intensity * Gauss3D(dq2, m_radial_size);
 
  166     double norm_factor = m_radial_size / std::sqrt(M_TWOPI);
 
  167     double radial_part = norm_factor * std::exp(-dq2 * m_radial_size * m_radial_size / 2.0);
 
  168     double angular_part = 1.0;
 
  169     if (q_r * q_lat_r > 0.0) {
 
  170         double dot_norm = q.
dot(q_lattice_point) / q_r / q_lat_r;
 
  171         angular_part = FisherDistribution(dot_norm, m_kappa) / (q_r * q_r);
 
  173     return m_max_intensity * radial_part * angular_part;
 
  180 LorentzFisherPeakShape::LorentzFisherPeakShape(
double max_intensity, 
double radial_size,
 
  182     : m_max_intensity(max_intensity), m_radial_size(radial_size), m_kappa(kappa)
 
  186 LorentzFisherPeakShape::~LorentzFisherPeakShape() = 
default;
 
  195     double q_r = q.
mag();
 
  196     double q_lat_r = q_lattice_point.
mag();
 
  197     double dq2 = (q_r - q_lat_r) * (q_r - q_lat_r);
 
  199         return m_max_intensity * Cauchy3D(dq2, m_radial_size);
 
  200     double radial_part = m_radial_size / (1.0 + dq2 * m_radial_size * m_radial_size) / M_PI;
 
  201     double angular_part = 1.0;
 
  202     if (q_r * q_lat_r > 0.0) {
 
  203         double dot_norm = q.
dot(q_lattice_point) / q_r / q_lat_r;
 
  204         angular_part = FisherDistribution(dot_norm, m_kappa) / (q_r * q_r);
 
  206     return m_max_intensity * radial_part * angular_part;
 
  213 MisesFisherGaussPeakShape::MisesFisherGaussPeakShape(
double max_intensity, 
double radial_size,
 
  216     : m_max_intensity(max_intensity), m_radial_size(radial_size), m_zenith(zenith.unit()),
 
  217       m_kappa_1(kappa_1), m_kappa_2(kappa_2)
 
  221 MisesFisherGaussPeakShape::~MisesFisherGaussPeakShape() = 
default;
 
  232     double q_r = q.
mag();
 
  233     double q_lat_r = q_lattice_point.
mag();
 
  234     double dq2 = (q_r - q_lat_r) * (q_r - q_lat_r);
 
  235     if (q_lat_r == 0.0 || q_r == 0.0)
 
  236         return m_max_intensity * Gauss3D(dq2, m_radial_size);
 
  237     double norm_factor = m_radial_size / std::sqrt(M_TWOPI);
 
  238     double radial_part = norm_factor * std::exp(-dq2 * m_radial_size * m_radial_size / 2.0);
 
  240     m_uy = m_zenith.
cross(q_lattice_point);
 
  242     m_up = q_lattice_point.
unit();
 
  243     if (m_uy.
mag2() <= 0.0 || zxq.
mag2() <= 0.0) {
 
  245         double angular_part = FisherDistribution(x, m_kappa_1);
 
  246         return m_max_intensity * radial_part * angular_part;
 
  249     m_ux = m_uy.
cross(m_zenith);
 
  251     m_phi = std::acos(q_ortho.
unit().
dot(m_ux));
 
  252     m_theta = std::acos(q.
unit().
dot(m_zenith));
 
  253     double pre_1 = FisherPrefactor(m_kappa_1);
 
  254     double pre_2 = MisesPrefactor(m_kappa_2);
 
  256         [&](
double phi) -> 
double { 
return integrand(phi); }, 0.0, M_TWOPI);
 
  257     return m_max_intensity * radial_part * pre_1 * pre_2 * integral;
 
  260 double MisesFisherGaussPeakShape::integrand(
double phi)
 const 
  262     kvector_t u_q = std::sin(m_theta) * std::cos(phi) * m_ux
 
  263                     + std::sin(m_theta) * std::sin(phi) * m_uy + std::cos(m_theta) * m_zenith;
 
  264     double fisher = std::exp(m_kappa_1 * (u_q.
dot(m_up) - 1.0));
 
  265     double vonmises = std::exp(m_kappa_2 * (std::cos(m_phi - phi) - 1.0));
 
  266     return fisher * vonmises;
 
  273 MisesGaussPeakShape::MisesGaussPeakShape(
double max_intensity, 
double radial_size, 
kvector_t zenith,
 
  275     : m_max_intensity(max_intensity), m_radial_size(radial_size), m_zenith(zenith.unit()),
 
  280 MisesGaussPeakShape::~MisesGaussPeakShape() = 
default;
 
  289     m_uy = m_zenith.
cross(q_lattice_point);
 
  291     if (m_uy.
mag2() <= 0.0 || zxq.
mag2() <= 0.0) {
 
  292         double dq2 = (q - q_lattice_point).mag2();
 
  293         return m_max_intensity * Gauss3D(dq2, m_radial_size);
 
  296     m_p = q_lattice_point;
 
  298     m_ux = m_uy.
cross(m_zenith);
 
  300     m_phi = std::acos(q_ortho.
unit().
dot(m_ux));
 
  301     m_theta = std::acos(q.
unit().
dot(m_zenith));
 
  302     double pre = MisesPrefactor(m_kappa);
 
  304         [&](
double phi) -> 
double { 
return integrand(phi); }, 0.0, M_TWOPI);
 
  305     return m_max_intensity * pre * integral;
 
  308 double MisesGaussPeakShape::integrand(
double phi)
 const 
  311                       * (std::sin(m_theta) * std::cos(phi) * m_ux
 
  312                          + std::sin(m_theta) * std::sin(phi) * m_uy + std::cos(m_theta) * m_zenith);
 
  313     double dq2 = (q_rot - m_p).mag2();
 
  314     double gauss = Gauss3D(dq2, m_radial_size);
 
  315     double vonmises = std::exp(m_kappa * (std::cos(m_phi - phi) - 1.0));
 
  316     return gauss * vonmises;
 
Defines the interface IPeakShape and subclasses.
 
Defines classes RealIntegrator, ComplexIntegrator.
 
Defines M_PI and some more mathematical constants.
 
Defines namespace MathFunctions.
 
double mag2() const
Returns magnitude squared of the vector.
 
auto dot(const BasicVector3D< U > &v) const
Returns dot product of vectors (antilinear in the first [=self] argument).
 
BasicVector3D< T > unit() const
Returns unit vector in direction of this. Throws for null vector.
 
double mag() const
Returns magnitude of the vector.
 
auto cross(const BasicVector3D< U > &v) const
Returns cross product of vectors (linear in both arguments).
 
A peak shape that is Gaussian in the radial direction and uses the Mises-Fisher distribution in the a...
 
double evaluate(const kvector_t q, const kvector_t q_lattice_point) const override
Evaluates the peak shape at q from a reciprocal lattice point at q_lattice_point.
 
GaussFisherPeakShape * clone() const override
Returns a clone of this ISample object.
 
Pure virtual base class for sample components and properties related to scattering.
 
Class that implements an isotropic Gaussian peak shape of a Bragg peak.
 
double evaluate(const kvector_t q, const kvector_t q_lattice_point) const override
Evaluates the peak shape at q from a reciprocal lattice point at q_lattice_point.
 
IsotropicGaussPeakShape * clone() const override
Returns a clone of this ISample object.
 
An isotropic Lorentzian peak shape of a Bragg peak.
 
IsotropicLorentzPeakShape * clone() const override
Returns a clone of this ISample object.
 
double evaluate(const kvector_t q, const kvector_t q_lattice_point) const override
Evaluates the peak shape at q from a reciprocal lattice point at q_lattice_point.
 
A peak shape that is Lorentzian in the radial direction and uses the Mises-Fisher distribution in the...
 
LorentzFisherPeakShape * clone() const override
Returns a clone of this ISample object.
 
double evaluate(const kvector_t q, const kvector_t q_lattice_point) const override
Evaluates the peak shape at q from a reciprocal lattice point at q_lattice_point.
 
A peak shape that is Gaussian in the radial direction and a convolution of a Mises-Fisher distributio...
 
MisesFisherGaussPeakShape * clone() const override
Returns a clone of this ISample object.
 
double evaluate(const kvector_t q, const kvector_t q_lattice_point) const override
Evaluates the peak shape at q from a reciprocal lattice point at q_lattice_point.
 
A peak shape that is a convolution of a Mises-Fisher distribution with a 3d Gaussian.
 
double evaluate(const kvector_t q, const kvector_t q_lattice_point) const override
Evaluates the peak shape at q from a reciprocal lattice point at q_lattice_point.
 
MisesGaussPeakShape * clone() const override
Returns a clone of this ISample object.
 
To integrate a real function of a real variable.
 
double Bessel_I0(double x)
Modified Bessel function of the first kind and order 0.