BornAgain  1.18.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 scattering at grazing incidence
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/Types/Exceptions.h"
17 #include "Base/Utils/Integrator.h"
19 #include <algorithm>
20 
21 namespace
22 {
23 // maximum value for qx*Lambdax and qy*lambday
24 const int nmax = 20;
25 // minimum number of neighboring reciprocal lattice points to use
26 const int min_points = 4;
27 } // namespace
28 
30  : IInterferenceFunction(0), m_integrate_xi(false)
31 {
32  setName("Interference2DLattice");
34 }
35 
36 //! Constructor of two-dimensional interference function.
37 //! @param length_1: length of the first basis vector in nanometers
38 //! @param length_2: length of the second basis vector in nanometers
39 //! @param alpha: angle between the basis vectors in radians
40 //! @param xi: rotation of the lattice with respect to the x-axis (beam direction) in radians
42  double alpha, double xi)
43  : InterferenceFunction2DLattice(BasicLattice(length_1, length_2, alpha, xi))
44 {
45 }
46 
48 
50 {
51  auto* ret = new InterferenceFunction2DLattice(*m_lattice);
52  ret->setPositionVariance(m_position_var);
53  ret->setIntegrationOverXi(integrationOverXi());
54  if (m_decay)
55  ret->setDecayFunction(*m_decay);
56  return ret;
57 }
58 
59 //! Creates square lattice.
60 //! @param lattice_length: length of the first and second basis vectors in nanometers
61 //! @param xi: rotation of the lattice with respect to the x-axis in radians
63  double xi)
64 {
65  return new InterferenceFunction2DLattice(SquareLattice(lattice_length, xi));
66 }
67 
68 //! Creates hexagonal lattice.
69 //! @param lattice_length: length of the first and second basis vectors in nanometers
70 //! @param xi: rotation of the lattice with respect to the x-axis in radians
72  double xi)
73 {
74  return new InterferenceFunction2DLattice(HexagonalLattice(lattice_length, xi));
75 }
76 
77 //! Sets two-dimensional decay function.
78 //! @param decay: two-dimensional decay function in reciprocal space
80 {
81  m_decay.reset(decay.clone());
82  registerChild(m_decay.get());
84 }
85 
87 {
88  m_integrate_xi = integrate_xi;
89  m_lattice->setRotationEnabled(!m_integrate_xi); // deregister Xi in the case of integration
90 }
91 
93 {
94  if (!m_lattice)
95  throw std::runtime_error("InterferenceFunction2DLattice::lattice() -> Error. "
96  "No lattice defined.");
97  return *m_lattice;
98 }
99 
101 {
102  double area = m_lattice->unitCellArea();
103  return area == 0.0 ? 0.0 : 1.0 / area;
104 }
105 
106 std::vector<const INode*> InterferenceFunction2DLattice::getChildren() const
107 {
108  return std::vector<const INode*>() << m_decay << m_lattice;
109 }
110 
112 {
115 }
116 
118 {
119  if (!m_decay)
120  throw Exceptions::NullPointerException("InterferenceFunction2DLattice::evaluate"
121  " -> Error! No decay function defined.");
122  m_qx = q.x();
123  m_qy = q.y();
124  if (!m_integrate_xi)
125  return interferenceForXi(m_lattice->rotationAngle());
126  return RealIntegrator().integrate([&](double xi) -> double { return interferenceForXi(xi); },
127  0.0, M_TWOPI)
128  / M_TWOPI;
129 }
130 
132 {
133  m_lattice.reset(lattice.clone());
134  registerChild(m_lattice.get());
136 }
137 
139 {
140  double result = 0.0;
141  auto q_frac = calculateReciprocalVectorFraction(m_qx, m_qy, xi);
142 
143  for (int i = -m_na - 1; i < m_na + 2; ++i) {
144  for (int j = -m_nb - 1; j < m_nb + 2; ++j) {
145  double qx = q_frac.first + i * m_sbase.m_asx + j * m_sbase.m_bsx;
146  double qy = q_frac.second + i * m_sbase.m_asy + j * m_sbase.m_bsy;
147  result += interferenceAtOneRecLatticePoint(qx, qy);
148  }
149  }
150  return getParticleDensity() * result;
151 }
152 
154 {
155  if (!m_decay)
157  "InterferenceFunction2DLattice::interferenceAtOneRecLatticePoint"
158  " -> Error! No decay function defined.");
159  double gamma = m_decay->gamma();
160  auto qXY = rotateOrthonormal(qx, qy, gamma);
161  return m_decay->evaluate(qXY.first, qXY.second);
162 }
163 
164 // Rotate by angle gamma between orthonormal systems
165 std::pair<double, double> InterferenceFunction2DLattice::rotateOrthonormal(double qx, double qy,
166  double gamma) const
167 {
168  double q_X = qx * std::cos(gamma) + qy * std::sin(gamma);
169  double q_Y = -qx * std::sin(gamma) + qy * std::cos(gamma);
170  return {q_X, q_Y};
171 }
172 
173 // (qx, qy) are in the global reciprocal reference frame
174 // the returned values (qx_frac, qy_frac) are in the rotated frame with first lattice basis
175 // vector aligned with the real-space x-axis (same frame as the one stored in m_sbase)
176 std::pair<double, double>
178  double xi) const
179 {
180  double a = m_lattice->length1();
181  double b = m_lattice->length2();
182  double alpha = m_lattice->latticeAngle();
183  // first rotate the input to the system of m_sbase:
184  double qx_rot = qx * std::cos(xi) + qy * std::sin(xi);
185  double qy_rot = -qx * std::sin(xi) + qy * std::cos(xi);
186 
187  // find the reciprocal lattice coordinates of (qx_rot, qy_rot):
188  int qa_int = static_cast<int>(std::lround(a * qx_rot / M_TWOPI));
189  int qb_int = static_cast<int>(
190  std::lround(b * (qx_rot * std::cos(alpha) + qy_rot * std::sin(alpha)) / M_TWOPI));
191  // take the fractional part only (in m_sbase coordinates)
192  double qx_frac = qx_rot - qa_int * m_sbase.m_asx - qb_int * m_sbase.m_bsx;
193  double qy_frac = qy_rot - qa_int * m_sbase.m_asy - qb_int * m_sbase.m_bsy;
194  return {qx_frac, qy_frac};
195 }
196 
197 // Do not store xi in the reciprocal lattice
199 {
200  if (!m_lattice)
201  throw std::runtime_error("InterferenceFunction2DLattice::initialize_rec_vectors() -> "
202  "Error. No lattice defined yet");
203 
204  BasicLattice base_lattice(m_lattice->length1(), m_lattice->length2(), m_lattice->latticeAngle(),
205  0.);
206  m_sbase = base_lattice.reciprocalBases();
207 }
208 
210 {
211  if (!m_decay)
213  "InterferenceFunction2DLattice::initialize_calc_factors"
214  " -> Error! No decay function defined.");
215 
216  // number of reciprocal lattice points to use
217  auto q_bounds = m_decay->boundingReciprocalLatticeCoordinates(
218  nmax / m_decay->decayLengthX(), nmax / m_decay->decayLengthY(), m_lattice->length1(),
219  m_lattice->length2(), m_lattice->latticeAngle());
220  m_na = static_cast<int>(std::lround(q_bounds.first + 0.5));
221  m_nb = static_cast<int>(std::lround(q_bounds.second + 0.5));
222  m_na = std::max(m_na, min_points);
223  m_nb = std::max(m_nb, min_points);
224 }
Defines many exception classes in namespace Exceptionss.
Defines classes RealIntegrator, ComplexIntegrator.
Defines class InterferenceFunction2DLattice.
#define M_TWOPI
Definition: MathConstants.h:49
Defines class RealParameter.
T y() const
Returns y-component in cartesian coordinate system.
Definition: BasicVector3D.h:66
T x() const
Returns x-component in cartesian coordinate system.
Definition: BasicVector3D.h:64
Interface for two-dimensional decay function in reciprocal space.
Definition: FTDecay2D.h:26
virtual IFTDecayFunction2D * clone() const =0
Pure virtual base class of interference functions.
void registerChild(INode *node)
Definition: INode.cpp:58
void setName(const std::string &name)
Interference function of a 2D lattice.
void onChange() override final
Action to be taken in inherited class when a parameter has changed.
void initialize_calc_factors()
Initializes factors needed in each calculation.
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.
double iff_without_dw(const kvector_t q) const override final
Calculates the structure factor without Debye-Waller factor.
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...
bool m_integrate_xi
Integrate over the orientation xi.
static InterferenceFunction2DLattice * createSquare(double lattice_length, double xi)
Creates square 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
static InterferenceFunction2DLattice * createHexagonal(double lattice_length, double xi)
Creates hexagonal lattice.
int m_nb
determines the number of reciprocal lattice points to use
std::vector< const INode * > getChildren() const override final
Returns a vector of children (const).
double getParticleDensity() const override final
Returns the particle density associated with this 2d lattice.
double interferenceAtOneRecLatticePoint(double qx, double qy) const
Returns interference from a single reciprocal lattice vector.
std::unique_ptr< Lattice2D > m_lattice
InterferenceFunction2DLattice(double length_1, double length_2, double alpha, double xi)
Constructor of two-dimensional interference function.
void setDecayFunction(const IFTDecayFunction2D &decay)
Sets two-dimensional decay function.
void setLattice(const Lattice2D &lattice)
InterferenceFunction2DLattice * clone() const override final
Returns a clone of this ISample object.
ReciprocalBases reciprocalBases() const
Definition: Lattice2D.cpp:35
virtual Lattice2D * clone() const =0
To integrate a real function of a real variable.
Definition: Integrator.h:24
double integrate(const std::function< double(double)> &f, double lmin, double lmax)
Definition: Integrator.cpp:27
double m_asy
x,y coordinates of a*
Definition: Lattice2D.h:30
double m_bsy
x,y coordinates of b*
Definition: Lattice2D.h:31