BornAgain  1.18.0
Simulate and fit neutron and x-ray scattering at grazing incidence
ILatticeOrientation.cpp
Go to the documentation of this file.
1 // ************************************************************************** //
2 //
3 // BornAgain: simulate and fit scattering at grazing incidence
4 //
5 //! @file Sample/Lattice/ILatticeOrientation.cpp
6 //! @brief Implements subclasses of ILatticeOrientation.
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 
17 namespace
18 {
19 bool ValidMillerIndex(MillerIndex index);
20 bool ParallelMillerIndices(MillerIndex index1, MillerIndex index2);
21 double SignForCrossProduct(MillerIndexOrientation::QComponent q1,
22  MillerIndexOrientation::QComponent q2);
23 MillerIndexOrientation::QComponent ThirdQComponent(MillerIndexOrientation::QComponent q1,
24  MillerIndexOrientation::QComponent q2);
25 void FillVectorInRow(Eigen::Matrix3d& matrix, kvector_t vec,
26  MillerIndexOrientation::QComponent row);
27 } // unnamed namespace
28 
29 ILatticeOrientation::~ILatticeOrientation() = default;
30 
31 MillerIndex::MillerIndex(double h_, double k_, double l_) : h(h_), k(k_), l(l_) {}
32 
33 MillerIndexOrientation::MillerIndexOrientation(MillerIndexOrientation::QComponent q1,
34  MillerIndex index1,
35  MillerIndexOrientation::QComponent q2,
36  MillerIndex index2)
37  : m_prim_lattice(), m_q1(q1), m_q2(q2), m_ind1{index1}, m_ind2{index2}
38 {
39  if (!checkAlignment())
40  throw std::runtime_error("MillerIndexOrientation constructor: "
41  "invalid alignment parameters");
42 }
43 
44 MillerIndexOrientation* MillerIndexOrientation::clone() const
45 {
46  auto* result = new MillerIndexOrientation(m_q1, m_ind1, m_q2, m_ind2);
47  result->usePrimitiveLattice(m_prim_lattice);
48  return result;
49 }
50 
51 MillerIndexOrientation::~MillerIndexOrientation() = default;
52 
53 void MillerIndexOrientation::usePrimitiveLattice(const Lattice& lattice)
54 {
55  m_prim_lattice.resetBasis(lattice.getBasisVectorA(), lattice.getBasisVectorB(),
56  lattice.getBasisVectorC());
57 }
58 
59 Transform3D MillerIndexOrientation::transformationMatrix() const
60 {
61  auto dir_1 = m_prim_lattice.getMillerDirection(m_ind1.h, m_ind1.k, m_ind1.l);
62  auto dir_2 = m_prim_lattice.getMillerDirection(m_ind2.h, m_ind2.k, m_ind2.l);
63  auto dir_2_parallel = dir_2.project(dir_1);
64  dir_2 = (dir_2 - dir_2_parallel).unit();
65  auto dir_3 = SignForCrossProduct(m_q1, m_q2) * dir_1.cross(dir_2);
66  auto q3 = ThirdQComponent(m_q1, m_q2);
67  Eigen::Matrix3d rot_matrix;
68  FillVectorInRow(rot_matrix, dir_1, m_q1);
69  FillVectorInRow(rot_matrix, dir_2, m_q2);
70  FillVectorInRow(rot_matrix, dir_3, q3);
71  return Transform3D(rot_matrix);
72 }
73 
74 bool MillerIndexOrientation::checkAlignment() const
75 {
76  if (m_q1 == m_q2)
77  return false;
78  if (!ValidMillerIndex(m_ind1) || !ValidMillerIndex(m_ind2))
79  return false;
80  if (ParallelMillerIndices(m_ind1, m_ind2))
81  return false;
82  return true;
83 }
84 
85 namespace
86 {
87 bool ValidMillerIndex(MillerIndex index)
88 {
89  return (index.h != 0.0 || index.k != 0.0 || index.l != 0.0);
90 }
91 bool ParallelMillerIndices(MillerIndex index1, MillerIndex index2)
92 {
93  double ratio = 0.0;
94  if (index2.h != 0.0) {
95  ratio = index1.h / index2.h;
96  } else if (index2.k != 0.0) {
97  ratio = index1.k / index2.k;
98  } else if (index2.l != 0.0) {
99  ratio = index1.l / index2.l;
100  }
101  if (ratio == 0.0)
102  return false;
103  return (index1.h == ratio * index2.h && index1.k == ratio * index2.k
104  && index1.l == ratio * index2.l);
105 }
106 double SignForCrossProduct(MillerIndexOrientation::QComponent q1,
107  MillerIndexOrientation::QComponent q2)
108 {
109  if ((q1 == MillerIndexOrientation::QX && q2 == MillerIndexOrientation::QY)
110  || (q1 == MillerIndexOrientation::QY && q2 == MillerIndexOrientation::QZ)
111  || (q1 == MillerIndexOrientation::QZ && q2 == MillerIndexOrientation::QX))
112  return 1.0;
113  return -1.0;
114 }
115 MillerIndexOrientation::QComponent ThirdQComponent(MillerIndexOrientation::QComponent q1,
116  MillerIndexOrientation::QComponent q2)
117 {
118  if (q1 != MillerIndexOrientation::QX && q2 != MillerIndexOrientation::QX)
119  return MillerIndexOrientation::QX;
120  if (q1 != MillerIndexOrientation::QY && q2 != MillerIndexOrientation::QY)
121  return MillerIndexOrientation::QY;
122  return MillerIndexOrientation::QZ;
123 }
124 void FillVectorInRow(Eigen::Matrix3d& mat, kvector_t vec, MillerIndexOrientation::QComponent row)
125 {
126  int i = row == MillerIndexOrientation::QX ? 0 : row == MillerIndexOrientation::QY ? 1 : 2;
127  for (int j = 0; j < 3; ++j)
128  mat(i, j) = vec[j];
129 }
130 } // unnamed namespace
Defines interface ILatticeOrientation and subclasses.
BasicVector3D< T > project(const BasicVector3D< T > &v) const
Returns projection of this onto other vector: (this*v)*v/|v|^2.
auto cross(const BasicVector3D< U > &v) const
Returns cross product of vectors (linear in both arguments).
A lattice with three basis vectors.
Definition: Lattice.h:28
void resetBasis(const kvector_t a1, const kvector_t a2, const kvector_t a3)
Resets the basis vectors.
Definition: Lattice.cpp:72
kvector_t getMillerDirection(double h, double k, double l) const
Returns normalized direction corresponding to the given Miller indices.
Definition: Lattice.cpp:80
kvector_t getBasisVectorB() const
Returns basis vector b.
Definition: Lattice.h:47
kvector_t getBasisVectorC() const
Returns basis vector c.
Definition: Lattice.h:50
kvector_t getBasisVectorA() const
Returns basis vector a.
Definition: Lattice.h:44
Specifies a rotation of a lattice through the Miller indices of two coordinate axes.
MillerIndexOrientation(QComponent q1, MillerIndex index1, QComponent q2, MillerIndex index2)
This constructor is best explained by an example.
Vector transformations in three dimensions.
Definition: Transform3D.h:28
A direction in reciprocal space, specified by double-valued indices hkl.