BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
InterferenceFunction2DLattice.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Sample/Aggregate/InterferenceFunction2DLattice.cpp
6 //! @brief Implements class InterferenceFunction2DLattice.
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2018
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
16 #include "Base/Math/IntegratorGK.h"
18 #include <algorithm>
19 
20 namespace {
21 // maximum value for qx*Lambdax and qy*lambday
22 const int nmax = 20;
23 // minimum number of neighboring reciprocal lattice points to use
24 const int min_points = 4;
25 } // namespace
26 
28  : IInterferenceFunction(0), m_integrate_xi(false)
29 {
30  setName("Interference2DLattice");
31  m_lattice.reset(lattice.clone());
32  registerChild(m_lattice.get());
34 }
35 
37 
39 {
40  auto* ret = new InterferenceFunction2DLattice(*m_lattice);
41  ret->setPositionVariance(m_position_var);
42  ret->setIntegrationOverXi(integrationOverXi());
43  if (m_decay)
44  ret->setDecayFunction(*m_decay);
45  return ret;
46 }
47 
48 //! Sets two-dimensional decay function.
49 //! @param decay: two-dimensional decay function in reciprocal space
51 {
52  m_decay.reset(decay.clone());
53  registerChild(m_decay.get());
55 }
56 
58 {
59  m_integrate_xi = integrate_xi;
60  m_lattice->setRotationEnabled(!m_integrate_xi); // deregister Xi in the case of integration
61 }
62 
64 {
65  if (!m_lattice)
66  throw std::runtime_error("InterferenceFunction2DLattice::lattice() -> Error. "
67  "No lattice defined.");
68  return *m_lattice;
69 }
70 
72 {
73  double area = m_lattice->unitCellArea();
74  return area == 0.0 ? 0.0 : 1.0 / area;
75 }
76 
77 std::vector<const INode*> InterferenceFunction2DLattice::getChildren() const
78 {
79  return std::vector<const INode*>() << m_decay << m_lattice;
80 }
81 
83 {
86 }
87 
89 {
90  if (!m_decay)
91  throw std::runtime_error("InterferenceFunction2DLattice::evaluate"
92  " -> Error! No decay function defined.");
93  m_qx = q.x();
94  m_qy = q.y();
95  if (!m_integrate_xi)
96  return interferenceForXi(m_lattice->rotationAngle());
97  return RealIntegrator().integrate([&](double xi) -> double { return interferenceForXi(xi); },
98  0.0, M_TWOPI)
99  / M_TWOPI;
100 }
101 
103 {
104  double result = 0.0;
105  auto q_frac = calculateReciprocalVectorFraction(m_qx, m_qy, xi);
106 
107  for (int i = -m_na - 1; i < m_na + 2; ++i) {
108  for (int j = -m_nb - 1; j < m_nb + 2; ++j) {
109  double qx = q_frac.first + i * m_sbase.m_asx + j * m_sbase.m_bsx;
110  double qy = q_frac.second + i * m_sbase.m_asy + j * m_sbase.m_bsy;
111  result += interferenceAtOneRecLatticePoint(qx, qy);
112  }
113  }
114  return getParticleDensity() * result;
115 }
116 
118 {
119  if (!m_decay)
120  throw std::runtime_error("InterferenceFunction2DLattice::interferenceAtOneRecLatticePoint"
121  " -> Error! No decay function defined.");
122  double gamma = m_decay->gamma();
123  auto qXY = rotateOrthonormal(qx, qy, gamma);
124  return m_decay->evaluate(qXY.first, qXY.second);
125 }
126 
127 // Rotate by angle gamma between orthonormal systems
128 std::pair<double, double> InterferenceFunction2DLattice::rotateOrthonormal(double qx, double qy,
129  double gamma) const
130 {
131  double q_X = qx * std::cos(gamma) + qy * std::sin(gamma);
132  double q_Y = -qx * std::sin(gamma) + qy * std::cos(gamma);
133  return {q_X, q_Y};
134 }
135 
136 // (qx, qy) are in the global reciprocal reference frame
137 // the returned values (qx_frac, qy_frac) are in the rotated frame with first lattice basis
138 // vector aligned with the real-space x-axis (same frame as the one stored in m_sbase)
139 std::pair<double, double>
141  double xi) const
142 {
143  double a = m_lattice->length1();
144  double b = m_lattice->length2();
145  double alpha = m_lattice->latticeAngle();
146  // first rotate the input to the system of m_sbase:
147  double qx_rot = qx * std::cos(xi) + qy * std::sin(xi);
148  double qy_rot = -qx * std::sin(xi) + qy * std::cos(xi);
149 
150  // find the reciprocal lattice coordinates of (qx_rot, qy_rot):
151  int qa_int = static_cast<int>(std::lround(a * qx_rot / M_TWOPI));
152  int qb_int = static_cast<int>(
153  std::lround(b * (qx_rot * std::cos(alpha) + qy_rot * std::sin(alpha)) / M_TWOPI));
154  // take the fractional part only (in m_sbase coordinates)
155  double qx_frac = qx_rot - qa_int * m_sbase.m_asx - qb_int * m_sbase.m_bsx;
156  double qy_frac = qy_rot - qa_int * m_sbase.m_asy - qb_int * m_sbase.m_bsy;
157  return {qx_frac, qy_frac};
158 }
159 
160 // Do not store xi in the reciprocal lattice
162 {
163  if (!m_lattice)
164  throw std::runtime_error("InterferenceFunction2DLattice::initialize_rec_vectors() -> "
165  "Error. No lattice defined yet");
166 
167  BasicLattice2D base_lattice(m_lattice->length1(), m_lattice->length2(),
168  m_lattice->latticeAngle(), 0.);
169  m_sbase = base_lattice.reciprocalBases();
170 }
171 
173 {
174  if (!m_decay)
175  throw std::runtime_error("InterferenceFunction2DLattice::initialize_calc_factors"
176  " -> Error! No decay function defined.");
177 
178  // number of reciprocal lattice points to use
179  auto q_bounds = m_decay->boundingReciprocalLatticeCoordinates(
180  nmax / m_decay->decayLengthX(), nmax / m_decay->decayLengthY(), m_lattice->length1(),
181  m_lattice->length2(), m_lattice->latticeAngle());
182  m_na = static_cast<int>(std::lround(q_bounds.first + 0.5));
183  m_nb = static_cast<int>(std::lround(q_bounds.second + 0.5));
184  m_na = std::max(m_na, min_points);
185  m_nb = std::max(m_nb, min_points);
186 }
#define M_TWOPI
Definition: Constants.h:54
Defines classes RealIntegrator, ComplexIntegrator.
Defines class InterferenceFunction2DLattice.
Defines class RealParameter.
A two-dimensional Bravais lattice with no special symmetry.
Definition: Lattice2D.h:53
T y() const
Returns y-component in cartesian coordinate system.
Definition: BasicVector3D.h:65
T x() const
Returns x-component in cartesian coordinate system.
Definition: BasicVector3D.h:63
Interface for two-dimensional decay function in reciprocal space.
Definition: FTDecay2D.h:27
virtual IFTDecayFunction2D * clone() const =0
Abstract base class of interference functions.
void registerChild(INode *node)
Definition: INode.cpp:57
void setName(const std::string &name)
Interference function of a 2D lattice.
void initialize_calc_factors()
Initializes factors needed in each calculation.
std::vector< const INode * > getChildren() const override
Returns a vector of children.
Lattice2D::ReciprocalBases m_sbase
reciprocal lattice is stored without xi
void initialize_rec_vectors()
Initializes the x,y coordinates of the a*,b* reciprocal bases.
std::pair< double, double > calculateReciprocalVectorFraction(double qx, double qy, double xi) const
Returns qx,qy coordinates of q - qint, where qint is a reciprocal lattice vector bounding the recipro...
double getParticleDensity() const override
Returns the particle density associated with this 2d lattice.
~InterferenceFunction2DLattice() override
bool m_integrate_xi
Integrate over the orientation xi.
InterferenceFunction2DLattice(const Lattice2D &lattice)
std::pair< double, double > rotateOrthonormal(double qx, double qy, double gamma) const
Returns reciprocal coordinates in the coordinate system rotated by the angle gamma.
std::unique_ptr< IFTDecayFunction2D > m_decay
InterferenceFunction2DLattice * clone() const override
Returns a clone of this ISampleNode object.
int m_nb
determines the number of reciprocal lattice points to use
double iff_without_dw(const kvector_t q) const override
Calculates the structure factor without Debye-Waller factor.
double interferenceAtOneRecLatticePoint(double qx, double qy) const
Returns interference from a single reciprocal lattice vector.
std::unique_ptr< Lattice2D > m_lattice
void setDecayFunction(const IFTDecayFunction2D &decay)
Sets two-dimensional decay function.
void onChange() override
Action to be taken in inherited class when a parameter has changed.
A two-dimensional Bravais lattice.
Definition: Lattice2D.h:23
ReciprocalBases reciprocalBases() const
Definition: Lattice2D.cpp:35
virtual Lattice2D * clone() const =0
To integrate a real function of a real variable.
Definition: IntegratorGK.h:28
double integrate(const std::function< double(double)> &f, double lmin, double lmax)
double m_asy
x,y coordinates of a*
Definition: Lattice2D.h:31
double m_bsy
x,y coordinates of b*
Definition: Lattice2D.h:32