Skip to content

Commit

Permalink
Refs #11006. Making matrix transpose for hkl clearer in code and docs.
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Wedel committed Mar 4, 2015
1 parent cc692e6 commit 69c089d
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 42 deletions.
Expand Up @@ -60,13 +60,10 @@ class MANTID_GEOMETRY_DLL PointGroup : public Group {
std::vector<Kernel::V3D> getEquivalentSet(const Kernel::V3D &hkl) const;

CrystalSystem getCrystalSystemFromGroup() const;
std::vector<Kernel::IntMatrix> getHKLTranformationMatrices() const;

std::string m_symbolHM;
std::string m_name;
CrystalSystem m_crystalSystem;

std::vector<Kernel::IntMatrix> m_hklTransformationMatrices;
};

/// Shared pointer to a PointGroup
Expand Down
Expand Up @@ -55,10 +55,18 @@ namespace Geometry {
is overloaded:
SymmetryOperation inversion("-x,-y,-z");
V3D hklPrime = inversion * V3D(1, 1, -1); // results in -1, -1, 1
V3D transformed = inversion * V3D(1, 1, -1); // results in -1, -1, 1
The operator is templated and works for any object Kernel::IntMatrix can be
multiplied with and V3R can be added to (for example V3R, V3D).
multiplied with and V3R can be added to (for example V3R, V3D). Note that
for the transformation of HKLs, the matrix needs to be transposed. In some
cases, such as the example above, it does not matter, because the matrix is
identical to its transposed. In general however, transposing is necessary,
so there is a dedicated method for that:
SymmetryOperation sixFold("x-y,x,z");
V3D hklPrime = sixFold.transformHKL(V3D(1,0,0)); //
A special case is the multiplication of several symmetry operations, which
can be used to generate new operations:
Expand Down Expand Up @@ -137,6 +145,8 @@ class MANTID_GEOMETRY_DLL SymmetryOperation {
return (m_matrix * operand) + m_vector;
}

Kernel::V3D transformHKL(const Kernel::V3D &hkl) const;

SymmetryOperation operator*(const SymmetryOperation &operand) const;
SymmetryOperation inverse() const;

Expand All @@ -161,6 +171,8 @@ class MANTID_GEOMETRY_DLL SymmetryOperation {

MANTID_GEOMETRY_DLL V3R getWrappedVector(const V3R &vector);
MANTID_GEOMETRY_DLL Kernel::V3D getWrappedVector(const Kernel::V3D &vector);
MANTID_GEOMETRY_DLL Kernel::V3D
multiplyTransposed(const Kernel::IntMatrix &matrix, const Kernel::V3D &vector);

} // namespace Geometry
} // namespace Mantid
Expand Down
32 changes: 4 additions & 28 deletions Code/Mantid/Framework/Geometry/src/Crystal/PointGroup.cpp
Expand Up @@ -57,21 +57,18 @@ PointGroup::PointGroup(const std::string &symbolHM, const Group &group,
: Group(group), m_symbolHM(symbolHM),
m_name(symbolHM + " (" + description + ")") {
m_crystalSystem = getCrystalSystemFromGroup();
m_hklTransformationMatrices = getHKLTranformationMatrices();
}

PointGroup::PointGroup(const PointGroup &other)
: Group(other), m_symbolHM(other.m_symbolHM), m_name(other.m_name),
m_crystalSystem(other.m_crystalSystem),
m_hklTransformationMatrices(other.m_hklTransformationMatrices) {}
m_crystalSystem(other.m_crystalSystem) {}

PointGroup &PointGroup::operator=(const PointGroup &other) {
Group::operator=(other);

m_symbolHM = other.m_symbolHM;
m_name = other.m_name;
m_crystalSystem = other.m_crystalSystem;
m_hklTransformationMatrices = other.m_hklTransformationMatrices;

return *this;
}
Expand Down Expand Up @@ -103,10 +100,10 @@ bool PointGroup::isEquivalent(const Kernel::V3D &hkl,
*/
std::vector<V3D> PointGroup::getEquivalentSet(const Kernel::V3D &hkl) const {
std::vector<V3D> equivalents;
equivalents.reserve(m_hklTransformationMatrices.size());
equivalents.reserve(m_allOperations.size());

for (auto op = m_hklTransformationMatrices.begin(); op != m_hklTransformationMatrices.end(); ++op) {
equivalents.push_back((*op) * hkl);
for (auto op = m_allOperations.begin(); op != m_allOperations.end(); ++op) {
equivalents.push_back((*op).transformHKL(hkl));
}

std::sort(equivalents.begin(), equivalents.end(), std::greater<V3D>());
Expand Down Expand Up @@ -161,27 +158,6 @@ PointGroup::CrystalSystem PointGroup::getCrystalSystemFromGroup() const {
return Triclinic;
}

/**
* Returns transformation matrices for HKLs
*
* The transformation matrices for points must be transposed in order to get
* correct results for transformation of miller indices. This is important
* in case of hexagonal transformation matrices.
*
* @return :: Transformation matrices for hkls.
*/
std::vector<Kernel::IntMatrix> PointGroup::getHKLTranformationMatrices() const {
std::vector<Kernel::IntMatrix> matrices;
matrices.reserve(m_allOperations.size());

for (auto op = m_allOperations.begin(); op != m_allOperations.end(); ++op) {
Kernel::IntMatrix matrix = (*op).matrix();
matrices.push_back(matrix.Transpose());
}

return matrices;
}

/** @return a vector with all possible PointGroup objects */
std::vector<PointGroup_sptr> getAllPointGroups() {
std::vector<std::string> allSymbols =
Expand Down
24 changes: 24 additions & 0 deletions Code/Mantid/Framework/Geometry/src/Crystal/SymmetryOperation.cpp
Expand Up @@ -94,6 +94,19 @@ bool SymmetryOperation::isIdentity() const {
/// Returns true if the operation has a translational component.
bool SymmetryOperation::hasTranslation() const { return m_vector != 0; }

/**
* Transforms an index triplet hkl
*
* Unlike points, vectors are transformed using the transposed transformation
* matrix. This method performs the multiplication with the transposed matrix.
*
* @param hkl :: HKL index triplet to transform
* @return :: Transformed index triplet.
*/
Kernel::V3D SymmetryOperation::transformHKL(const Kernel::V3D &hkl) const {
return multiplyTransposed(m_matrix, hkl);
}

/**
* Multiplication operator for combining symmetry operations
*
Expand Down Expand Up @@ -248,5 +261,16 @@ Kernel::V3D getWrappedVector(const Kernel::V3D &vector) {
return wrappedVector;
}

/// Multiplies the transposed 3x3-matrix with the vector.
Kernel::V3D multiplyTransposed(const Kernel::IntMatrix &matrix,
const Kernel::V3D &vector) {
return Kernel::V3D(matrix[0][0] * vector.X() + matrix[1][0] * vector.Y() +
matrix[2][0] * vector.Z(),
matrix[0][1] * vector.X() + matrix[1][1] * vector.Y() +
matrix[2][1] * vector.Z(),
matrix[0][2] * vector.X() + matrix[1][2] * vector.Y() +
matrix[2][2] * vector.Z());
}

} // namespace Geometry
} // namespace Mantid
31 changes: 26 additions & 5 deletions Code/Mantid/Framework/Geometry/test/SymmetryOperationTest.h
Expand Up @@ -252,10 +252,11 @@ class SymmetryOperationTest : public CxxTest::TestSuite
testSymmetryOperation(twoFoldXOp,
2, V3D(m_h, -m_k, -m_l), "x,-y,-z");

// 2-fold rotation around [210] in hexagonal system
SymmetryOperation twoFold210Op("x, x-y, -z");
testSymmetryOperation(twoFold210Op,
2, V3D(m_h, m_h-m_k, -m_l), "x,x-y,-z");
// 6-fold rotation around [001] in hexagonal
SymmetryOperation sixFoldZOp("x-y , x, z");
testSymmetryOperation(sixFoldZOp,
6, V3D((m_h+m_k), -m_h, m_l), "x-y,x,z");

}

void testPower()
Expand All @@ -275,6 +276,26 @@ class SymmetryOperationTest : public CxxTest::TestSuite
TS_ASSERT_EQUALS(fourFoldZ^4, identity);
}

void checkTransposedMatrixMultiply()
{
IntMatrix matrix(3, 3, true);
matrix[1][2] = 3;
matrix[2][0] = -2;
matrix[1][0] = 5;

IntMatrix transposed = matrix.Transpose();

TS_ASSERT_DIFFERS(transposed, matrix);

V3D vector(2, 3, 7);

V3D transposedProduct = transposed * vector;
V3D testProduct = multiplyTransposed(matrix, vector);

TS_ASSERT_EQUALS(transposedProduct, testProduct);

}

private:
V3D applyOrderTimes(const SymmetryOperation &symOp, const V3D &vector)
{
Expand Down Expand Up @@ -317,7 +338,7 @@ class SymmetryOperationTest : public CxxTest::TestSuite

void checkCorrectTransformationGeneralHKL(const SymmetryOperation &symOp, const V3D &expected)
{
V3D transformed = symOp * m_hkl;
V3D transformed = symOp.transformHKL(m_hkl);

TSM_ASSERT_EQUALS(symOp.identifier() + ": Transformed hkl is " + transformed.toString() + ", expected " + expected.toString(),
transformed, expected);
Expand Down
Expand Up @@ -19,7 +19,12 @@ namespace //<unnamed>

Mantid::Kernel::V3D applyToVector(SymmetryOperation & self, const object& hkl)
{
return self.operator *<Mantid::Kernel::V3D>(Converters::PyObjectToV3D(hkl)());
return self.transformHKL(Converters::PyObjectToV3D(hkl)());
}

Mantid::Kernel::V3D applyToCoordinates(SymmetryOperation & self, const object& coordinates)
{
return self.operator *<Mantid::Kernel::V3D>(Converters::PyObjectToV3D(coordinates)());
}
}

Expand All @@ -30,6 +35,8 @@ void export_SymmetryOperation()
class_<SymmetryOperation>("SymmetryOperation")
.def("order", &SymmetryOperation::order)
.def("identifier", &SymmetryOperation::identifier)
.def("transformCoordinates", &applyToCoordinates)
.def("transformHKL", &applyToVector)
.def("apply", &applyToVector);
}

30 changes: 27 additions & 3 deletions Code/Mantid/docs/source/concepts/Point_groups.rst
Expand Up @@ -39,10 +39,15 @@ As mentioned before, point groups can describe the symmetry of a lattice, includ
.. math::
\mathbf{h}' = \mathbf{S}_i \cdot \mathbf{h}
To describe the rotational and translational components of the symmetry operation, a matrix :math:`M_i` and a vector :math:`v_i` are used. In three dimensions :math:`\mathbf{h}` has three elements, so :math:`\mathbf{M_i}` is a :math:`3\times3`-matrix and the symmetry operation is applied like this:
To describe the rotational and translational components of the symmetry operation, a matrix :math:`\mathbf{W}_i` and a vector :math:`\mathbf{w}_i` are used. In three dimensions :math:`\mathbf{h}` has three elements, so :math:`\mathbf{W}_i` is a :math:`3\times3`-matrix and the symmetry operation is applied like this:

.. math::
\mathbf{h}' = \mathbf{M}_i \cdot \mathbf{h} + \mathbf{v_i}
\mathbf{h}' = \mathbf{W}_i^T \cdot \mathbf{h}
Note that the translational component is not used for transforming HKLs and :math:`\mathbf{W}_i` is transposed. Coordinates :math:`\mathbf{x}` are transformed differently, they are affected by the translational component:

.. math::
\mathbf{x}' = \mathbf{W}_i \cdot \mathbf{h} + \mathbf{w}_i
A point group is an ensemble of symmetry operations. The number of operations present in this collection is the so called order :math:`N` of the corresponding point group. Applying all symmetry operations of a point group to a given vector :math:`\mathbf{h}` results in :math:`N` new vectors :math:`\mathbf{h}'`, some of which may be identical (this depends on the symmetry and also on the vectors, e.g. if one or more index is 0). This means that the symmetry operations of a point group generate a set of :math:`N'` (where :math:`N' < N`) non-identical vectors :math:`\mathbf{h}'` for a given vector :math:`\mathbf{h}` - these vectors are called symmetry equivalents.

Expand Down Expand Up @@ -75,7 +80,7 @@ Using these identifiers, ``SymmetryOperation``-objects can be created through a
symOp = SymmetryOperationFactory.createSymOp("x,y,-z")
hkl = [1, -1, 3]
hklPrime = symOp.apply(hkl)
hklPrime = symOp.transformHKL(hkl)
print "Mirrored hkl:", hklPrime
Expand All @@ -84,7 +89,26 @@ The above code will print the mirrored index:
.. testoutput :: ExSymmetryOperation
Mirrored hkl: [1,-1,-3]
Point groups can also be used to transform coordinates, which are handled a bit differently than vectors (as described above), so there the symmetry operation class has a dedicated method for performing this operation:

.. testcode :: ExSymmetryOperationPoint
from mantid.geometry import SymmetryOperation, SymmetryOperationFactory
symOp = SymmetryOperationFactory.createSymOp("x-y,x,z")
coordinates = [0.3, 0.4, 0.5]
coordinatesPrime = symOp.transformCoordinates(coordinates)
print "Transformed coordinates:", coordinatesPrime
The script prints the transformed coordinates:

.. testoutput :: ExSymmetryOperationPoint
Transformed coordinates: [-0.1,0.3,0.5]
Sometimes it is easier to think about symmetry in terms of the elements that cause certain symmetry. These are commonly described with Herrman-Mauguin symbols. A symmetry element can be derived from the matrix/vector pair that described the symmetry operation, according to the International Tables for Crystallography A, section 11.2. Expanding a bit on the above example, it's possible to get information about the symmetry element associated to the operation ``x,y,-z``:

.. testcode :: ExSymmetryElement
Expand Down

0 comments on commit 69c089d

Please sign in to comment.