Mantid
Loading...
Searching...
No Matches
SymmetryElementFactory.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 +
8#include <boost/math/special_functions/round.hpp>
9#include <gsl/gsl_complex_math.h>
10#include <gsl/gsl_eigen.h>
11#include <stdexcept>
12
13namespace Mantid::Geometry {
14
17 UNUSED_ARG(operation);
18
19 return std::make_shared<SymmetryElementIdentity>();
20}
21
25
26 return !operation.hasTranslation() && operation.order() == 1;
27}
28
32 return std::make_shared<SymmetryElementTranslation>(operation.vector());
33}
34
38 return operation.order() == 1 && operation.hasTranslation();
39}
40
44
45 return std::make_shared<SymmetryElementInversion>(operation.vector() / 2);
46}
47
50 Kernel::IntMatrix inversionMatrix(3, 3, true);
51 inversionMatrix *= -1;
52
53 return operation.matrix() == inversionMatrix;
54}
55
58 return operation.reducedVector();
59}
60
71gsl_matrix *getGSLMatrix(const Kernel::IntMatrix &matrix) {
72 gsl_matrix *gslMatrix = gsl_matrix_alloc(matrix.numRows(), matrix.numCols());
73
74 for (size_t r = 0; r < matrix.numRows(); ++r) {
75 for (size_t c = 0; c < matrix.numCols(); ++c) {
76 gsl_matrix_set(gslMatrix, r, c, static_cast<double>(matrix[r][c]));
77 }
78 }
79
80 return gslMatrix;
81}
82
94gsl_matrix *getGSLIdentityMatrix(size_t rows, size_t cols) {
95 gsl_matrix *gslMatrix = gsl_matrix_alloc(rows, cols);
96
97 gsl_matrix_set_identity(gslMatrix);
98
99 return gslMatrix;
100}
101
114 gsl_matrix *eigenMatrix = getGSLMatrix(matrix);
115 gsl_matrix *identityMatrix = getGSLIdentityMatrix(matrix.numRows(), matrix.numCols());
116
117 gsl_eigen_genv_workspace *eigenWs = gsl_eigen_genv_alloc(matrix.numRows());
118
119 gsl_vector_complex *alpha = gsl_vector_complex_alloc(3);
120 gsl_vector *beta = gsl_vector_alloc(3);
121 gsl_matrix_complex *eigenVectors = gsl_matrix_complex_alloc(3, 3);
122
123 gsl_eigen_genv(eigenMatrix, identityMatrix, alpha, beta, eigenVectors, eigenWs);
124 gsl_eigen_genv_sort(alpha, beta, eigenVectors, GSL_EIGEN_SORT_ABS_DESC);
125
126 double determinant = matrix.determinant();
127
128 Kernel::V3D eigenVector;
129
130 for (size_t i = 0; i < matrix.numCols(); ++i) {
131 double eigenValue = GSL_REAL(gsl_complex_div_real(gsl_vector_complex_get(alpha, i), gsl_vector_get(beta, i)));
132
133 if (fabs(eigenValue - determinant) < 1e-9) {
134 for (size_t j = 0; j < matrix.numRows(); ++j) {
135 double element = GSL_REAL(gsl_matrix_complex_get(eigenVectors, j, i));
136
137 eigenVector[j] = element;
138 }
139 }
140 }
141
142 eigenVector *= determinant;
143
144 double sumOfElements = eigenVector.X() + eigenVector.Y() + eigenVector.Z();
145
146 if (sumOfElements < 0) {
147 eigenVector *= -1.0;
148 }
149
150 gsl_matrix_free(eigenMatrix);
151 gsl_matrix_free(identityMatrix);
152 gsl_eigen_genv_free(eigenWs);
153 gsl_vector_complex_free(alpha);
154 gsl_vector_free(beta);
155 gsl_matrix_complex_free(eigenVectors);
156
157 double min = 1.0;
158 for (size_t i = 0; i < 3; ++i) {
159 double absoluteValue = fabs(eigenVector[i]);
160 if (absoluteValue != 0.0 && (eigenVector[i] < min && (absoluteValue - fabs(min)) < 1e-9)) {
161 min = eigenVector[i];
162 }
163 }
164
165 V3R axis;
166 for (size_t i = 0; i < 3; ++i) {
167 axis[i] = static_cast<int>(boost::math::round(eigenVector[i] / min));
168 }
169
170 return axis;
171}
172
176 const Kernel::IntMatrix &matrix = operation.matrix();
177
178 V3R axis = determineAxis(matrix);
179 V3R translation = determineTranslation(operation);
180 SymmetryElementRotation::RotationSense rotationSense = determineRotationSense(operation, axis);
181 std::string symbol = determineSymbol(operation);
182
183 return std::make_shared<SymmetryElementRotation>(symbol, axis, translation, rotationSense);
184}
185
189 const Kernel::IntMatrix &matrix = operation.matrix();
190 int determinant = matrix.determinant();
191 int trace = matrix.Trace();
192
193 return (abs(trace) != 3) && !(trace == 1 && determinant == -1);
194}
195
199 const V3R &rotationAxis) const {
200 Kernel::V3D pointOnAxis1 = rotationAxis;
201 Kernel::V3D pointOnAxis2 = rotationAxis * 2;
202 Kernel::V3D pointOffAxis = rotationAxis + Kernel::V3D(2.1, 5.05, -1.1);
203 Kernel::V3D generatedPoint = operation * pointOffAxis;
204
205 Kernel::DblMatrix matrix(3, 3, false);
206 matrix.setColumn(0, pointOnAxis2 - pointOnAxis1);
207 matrix.setColumn(1, pointOffAxis - pointOnAxis1);
208 matrix.setColumn(2, generatedPoint - pointOnAxis1);
209
210 double determinant = matrix.determinant() * operation.matrix().determinant();
211
212 if (determinant < 0) {
214 } else {
216 }
217}
218
222 const Kernel::IntMatrix &matrix = operation.matrix();
223
224 int trace = matrix.Trace();
225 int determinant = matrix.determinant();
226
227 if (trace == 0 && determinant == -1) {
228 return "-3";
229 }
230
231 std::string symbol;
232
233 if (determinant < 0) {
234 symbol += "-";
235 }
236
237 symbol += std::to_string(operation.order());
238
239 int translation =
240 static_cast<int>(static_cast<double>(operation.order()) * Kernel::V3D(determineTranslation(operation)).norm());
241
242 if (translation != 0) {
243 symbol += std::to_string(translation);
244 }
245
246 return symbol;
247}
248
249std::map<V3R, std::string> SymmetryElementMirrorGenerator::g_glideSymbolMap = {
250 {V3R(0, 0, 0), "m"}, {V3R(1, 0, 0) / 2, "a"}, {V3R(0, 1, 0) / 2, "b"}, {V3R(0, 0, 1) / 2, "c"},
251 {V3R(1, 1, 0) / 2, "n"}, {V3R(1, 0, 1) / 2, "n"}, {V3R(0, 1, 1) / 2, "n"}, {V3R(1, 1, 1) / 2, "n"},
252 {V3R(1, 1, 0) / 4, "d"}, {V3R(1, 0, 1) / 4, "d"}, {V3R(0, 1, 1) / 4, "d"}, {V3R(1, 1, 1) / 4, "d"}};
253
257 const Kernel::IntMatrix &matrix = operation.matrix();
258
259 V3R axis = determineAxis(matrix);
260 V3R translation = determineTranslation(operation);
261 std::string symbol = determineSymbol(operation);
262
263 return std::make_shared<SymmetryElementMirror>(symbol, axis, translation);
264}
265
268 const Kernel::IntMatrix &matrix = operation.matrix();
269
270 return matrix.Trace() == 1 && matrix.determinant() == -1;
271}
272
275 V3R rawTranslation = determineTranslation(operation);
276
277 V3R translation;
278 for (size_t i = 0; i < 3; ++i) {
279 translation[i] = rawTranslation[i] > RationalNumber(1, 2) ? rawTranslation[i] - 1 : rawTranslation[i];
280 }
281
282 std::string symbol = g_glideSymbolMap[translation.getPositiveVector()];
283
284 /* Some space groups have "unconventional glides" for which there is no
285 * proper symbol, so the general symbol "g" is used for these cases.
286 * Examples can be found in No. 227 (Fd-3m).
287 */
288 if (symbol.empty()) {
289 return "g";
290 }
291
292 return symbol;
293}
294
307 std::string operationIdentifier = operation.identifier();
308
309 SymmetryElement_sptr element = createFromPrototype(operationIdentifier);
310
311 if (element) {
312 return element;
313 }
314
316
317 if (!generator) {
318 throw std::runtime_error("Could not process symmetry operation '" + operationIdentifier + "'.");
319 }
320
321 insertPrototype(operationIdentifier, generator->generateElement(operation));
322
323 return createFromPrototype(operationIdentifier);
324}
325
327bool SymmetryElementFactoryImpl::isSubscribed(const std::string &generatorClassName) const {
328 return (std::find(m_generatorNames.begin(), m_generatorNames.end(), generatorClassName) != m_generatorNames.end());
329}
330
333 const std::string &generatorClassName) {
334 m_generators.emplace_back(generator);
335 m_generatorNames.insert(generatorClassName);
336}
337
340 auto prototypeIterator = m_prototypes.find(identifier);
341
342 if (prototypeIterator != m_prototypes.end()) {
343 return (prototypeIterator->second)->clone();
344 }
345
346 return SymmetryElement_sptr();
347}
348
353 const auto found = std::find_if(m_generators.cbegin(), m_generators.cend(),
354 [&operation](const auto &generator) { return generator->canProcess(operation); });
355 return found != m_generators.end() ? *found : nullptr;
356}
357
359void SymmetryElementFactoryImpl::insertPrototype(const std::string &identifier, const SymmetryElement_sptr &prototype) {
360 m_prototypes.emplace(identifier, prototype);
361}
362
368
369} // namespace Mantid::Geometry
#define fabs(x)
Definition: Matrix.cpp:22
#define DECLARE_SYMMETRY_ELEMENT_GENERATOR(classname)
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition: System.h:64
std::unordered_set< std::string > m_generatorNames
void subscribe(const AbstractSymmetryElementGenerator_sptr &generator, const std::string &generatorClassName)
Subscribes a generator and stores its class name for later checks.
AbstractSymmetryElementGenerator_sptr getGenerator(const SymmetryOperation &operation) const
Returns a generator that can process the supplied symmetry operation or an invalid pointer if no appr...
std::map< std::string, SymmetryElement_sptr > m_prototypes
std::vector< AbstractSymmetryElementGenerator_sptr > m_generators
SymmetryElement_sptr createFromPrototype(const std::string &identifier) const
Creates a SymmetryElement from an internally stored prototype.
bool isSubscribed(const std::string &generatorClassName) const
Checks whether a generator with that class name is already subscribed.
void insertPrototype(const std::string &identifier, const SymmetryElement_sptr &prototype)
Inserts the provided prototype into the factory.
SymmetryElement_sptr createSymElement(const SymmetryOperation &operation)
Creates a SymmetryElement from a SymmetryOperation.
This implementation of AbstractSymmetryElementGenerator produces only identity elements.
SymmetryElement_sptr generateElement(const SymmetryOperation &operation) const override
Generates an instance of SymmetryElementIdentity.
bool canProcess(const SymmetryOperation &operation) const override
Checks that the SymmetryOperation has no translation and the matrix is of order 1.
This implementation of AbstractSymmetryElementGenerator produces only inversion elements.
bool canProcess(const SymmetryOperation &operation) const override
Checks that the matrix is identity matrix multiplied with -1.
SymmetryElement_sptr generateElement(const SymmetryOperation &operation) const override
Generates an instance of SymmetryElementInversion with the inversion point equal to the vector of the...
SymmetryElementMirrorGenerator also inherits from SymmetryElementWithAxisGenerator.
SymmetryElement_sptr generateElement(const SymmetryOperation &operation) const override
Generates an instance of SymmetryElementMirror with the corresponding symbol, axis and translation ve...
std::string determineSymbol(const SymmetryOperation &operation) const override
Determines the symbol from the translation vector using a map.
bool canProcess(const SymmetryOperation &operation) const override
Checks that the trace of the matrix is 1 and the determinant is -1.
static std::map< V3R, std::string > g_glideSymbolMap
SymmetryElementRotationGenerator inherits from SymmetryElementWithAxisGenerator, using its methods fo...
SymmetryElement_sptr generateElement(const SymmetryOperation &operation) const override
Generates an instance of SymmetryElementRotation with the corresponding symbol, axis,...
bool canProcess(const SymmetryOperation &operation) const override
Checks the trace and determinat of the matrix to determine if the matrix belongs to a rotation.
std::string determineSymbol(const SymmetryOperation &operation) const override
Determines the Hermann-Mauguin symbol of the rotation-, rotoinversion- or screw-axis.
SymmetryElementRotation::RotationSense determineRotationSense(const SymmetryOperation &operation, const V3R &rotationAxis) const
Determines the rotation sense according to the description in ITA 11.2.
This implementation of AbstractSymmetryElementGenerator produces only translation elements.
SymmetryElement_sptr generateElement(const SymmetryOperation &operation) const override
Generates an instance of SymmetryElementTranslation with the vector of the operation as translation v...
bool canProcess(const SymmetryOperation &operation) const override
Checks that the order of the matrix is 1 and the operation has a translation.
V3R determineAxis(const Kernel::IntMatrix &matrix) const
Returns the symmetry axis for the given matrix.
V3R determineTranslation(const SymmetryOperation &operation) const
Returns the reduced vector of the operation.
Crystallographic symmetry operations are composed of a rotational component, which is represented by ...
std::string identifier() const
Returns the string-identifier for this symmetry operation.
const Kernel::IntMatrix & matrix() const
Returns a const reference to the internally stored matrix.
const V3R & reducedVector() const
SymmetryOperation::reducedVector.
bool hasTranslation() const
Returns true if the operation has a translational component.
size_t order() const
Returns the order of the symmetry operation.
const V3R & vector() const
Returns a const reference to the internall stored vector.
V3R getPositiveVector() const
Returns a V3R with absolute components.
Definition: V3R.cpp:293
T determinant() const
Calculate the determinant.
Definition: Matrix.cpp:1048
T Trace() const
Trace of the matrix.
Definition: Matrix.cpp:1280
size_t numRows() const
Return the number of rows in the matrix.
Definition: Matrix.h:144
void setColumn(const size_t nCol, const std::vector< T > &newCol)
Definition: Matrix.cpp:675
size_t numCols() const
Return the number of columns in the matrix.
Definition: Matrix.h:147
Class for 3D vectors.
Definition: V3D.h:34
constexpr double X() const noexcept
Get x.
Definition: V3D.h:232
constexpr double Y() const noexcept
Get y.
Definition: V3D.h:233
constexpr double Z() const noexcept
Get z.
Definition: V3D.h:234
boost::rational< int > RationalNumber
V3R :
Definition: V3R.h:35
MANTID_GEOMETRY_DLL gsl_matrix * getGSLIdentityMatrix(size_t rows, size_t cols)
Returns a GSL-indentity matrix.
std::shared_ptr< AbstractSymmetryElementGenerator > AbstractSymmetryElementGenerator_sptr
MANTID_GEOMETRY_DLL gsl_matrix * getGSLMatrix(const Kernel::IntMatrix &matrix)
Returns a GSL-matrix for the given IntMatrix.
std::shared_ptr< SymmetryElement > SymmetryElement_sptr
std::string to_string(const wide_integer< Bits, Signed > &n)