Skip to content

Commit

Permalink
Refs #10280. Cleaned up SymmetryOperation.
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Wedel committed Oct 1, 2014
1 parent 3968263 commit c696488
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 28 deletions.
Expand Up @@ -57,14 +57,17 @@ namespace Geometry
V3D hklPrime = 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, std::vector<int>).
multiplied with and V3R can be added to (for example V3R, V3D).
A special case is the multiplication of several symmetry operations, which can
be used to generate new operations:
SymmetryOperation inversion("-x,-y,-z");
SymmetryOperation identity = inversion * inversion;
Please note that the components of the vector are wrapped to
the interval (0, 1] when two symmetry operations are combined.
Constructing a SymmetryOperation object from a string is heavy, because the string
has to be parsed every time. It's preferable to use the available factory:
Expand Down Expand Up @@ -124,6 +127,7 @@ class MANTID_GEOMETRY_DLL SymmetryOperation
bool isIdentity() const;
bool hasTranslation() const;

/// Returns the transformed vector.
template<typename T>
T operator *(const T &operand) const
{
Expand All @@ -143,7 +147,6 @@ class MANTID_GEOMETRY_DLL SymmetryOperation
SymmetryOperation(const std::pair<Kernel::IntMatrix, V3R> &data);
SymmetryOperation(const Kernel::IntMatrix &matrix, const V3R &vector);

V3R getWrappedVector(const V3R &vector) const;
size_t getOrderFromMatrix(const Kernel::IntMatrix &matrix) const;


Expand All @@ -153,6 +156,9 @@ class MANTID_GEOMETRY_DLL SymmetryOperation
std::string m_identifier;
};

MANTID_GEOMETRY_DLL V3R getWrappedVector(const V3R &vector);
MANTID_GEOMETRY_DLL Kernel::V3D getWrappedVector(const Kernel::V3D &vector);


} // namespace Geometry
} // namespace Mantid
Expand Down
59 changes: 42 additions & 17 deletions Code/Mantid/Framework/Geometry/src/Crystal/SymmetryOperation.cpp
Expand Up @@ -46,7 +46,7 @@ SymmetryOperation::SymmetryOperation(const std::pair<Kernel::IntMatrix, V3R> &da
SymmetryOperation::SymmetryOperation(const Kernel::IntMatrix &matrix, const V3R &vector) :
m_order(0),
m_matrix(matrix),
m_vector(vector),
m_vector(getWrappedVector(vector)),
m_identifier()
{
m_order = getOrderFromMatrix(m_matrix);
Expand Down Expand Up @@ -153,22 +153,7 @@ bool SymmetryOperation::operator !=(const SymmetryOperation &other) const
return !(this->operator ==(other));
}

/// Returns a vector on the interval (0, 1]
V3R SymmetryOperation::getWrappedVector(const V3R &vector) const
{
V3R wrappedVector(vector);
for(size_t i = 0; i < 3; ++i) {
if(wrappedVector[i] < 0) {
wrappedVector[i] += 1;
} else if(wrappedVector[i] >= 1) {
wrappedVector[i] -= 1;
}
}

return wrappedVector;
}

/// Returns the order of the symmetry operation based on the matrix. From Introduction to Crystal Growth and Characterization, Benz and Neumann, Wiley, 2014, p. 51.
/// Returns the order of the symmetry operation based on the matrix. From "Introduction to Crystal Growth and Characterization, Benz and Neumann, Wiley, 2014, p. 51."
size_t SymmetryOperation::getOrderFromMatrix(const Kernel::IntMatrix &matrix) const
{
int trace = matrix.Trace();
Expand Down Expand Up @@ -209,6 +194,46 @@ size_t SymmetryOperation::getOrderFromMatrix(const Kernel::IntMatrix &matrix) co
throw std::runtime_error("There is something wrong with supplied matrix.");
}

/**
* Wraps a V3R to the interval (0, 1]
*
* For certain crystallographic calculations it is necessary to constrain fractional
* coordinates to the unit cell, for example to generate all atomic positions
* in the cell. In this context, the fractional coordinate -0.45 is equal to
* "0.55 of the next cell", so it's transformed to 0.55.
*
* @param vector :: Input vector with arbitrary numbers.
* @return Vector with components on the interval (0, 1]
*/
V3R getWrappedVector(const V3R &vector)
{
V3R wrappedVector(vector);
for(size_t i = 0; i < 3; ++i) {
if(wrappedVector[i] < 0) {
wrappedVector[i] += (abs(vector[i].numerator() / vector[i].denominator()) + 1);
} else if(wrappedVector[i] >= 1) {
wrappedVector[i] -= (vector[i].numerator() / vector[i].denominator());
}
}

return wrappedVector;
}

/// Returns a V3D with components on the interval (0, 1], as the version for V3R.
Kernel::V3D getWrappedVector(const Kernel::V3D &vector)
{
Kernel::V3D wrappedVector(vector);
for(size_t i = 0; i < 3; ++i) {
if(wrappedVector[i] < 0) {
wrappedVector[i] = fmod(vector[i], 1.0) + 1.0;
} else if(wrappedVector[i] >= 1) {
wrappedVector[i] = fmod(vector[i], 1.0);
}
}

return wrappedVector;
}


} // namespace Geometry
} // namespace Mantid
2 changes: 0 additions & 2 deletions Code/Mantid/Framework/Geometry/src/Crystal/V3R.cpp
Expand Up @@ -368,7 +368,5 @@ V3R operator *(const Kernel::IntMatrix &lhs, const V3R &rhs)
return result;
}



} // namespace Geometry
} // namespace Mantid
133 changes: 126 additions & 7 deletions Code/Mantid/Framework/Geometry/test/SymmetryOperationTest.h
Expand Up @@ -47,17 +47,138 @@ class SymmetryOperationTest : public CxxTest::TestSuite
m_allHkl.push_back(m_h00);
}

void testGetWrappedVector()
void testDefaultConstructor()
{
SymmetryOperation symOp;
TS_ASSERT(symOp.isIdentity());
TS_ASSERT(!symOp.hasTranslation())
TS_ASSERT_EQUALS(symOp.order(), 1);
TS_ASSERT_EQUALS(symOp.identifier(), "x,y,z");

V3D hkl(1, 1, 1);
TS_ASSERT_EQUALS(symOp * hkl, hkl);
}

void testStringConstructor()
{
SymmetryOperation inversion("-x,-y,-z");

TS_ASSERT(!inversion.isIdentity());
TS_ASSERT(!inversion.hasTranslation());
TS_ASSERT_EQUALS(inversion.order(), 2);
TS_ASSERT_EQUALS(inversion.identifier(), "-x,-y,-z");

V3D hkl(1, 1, 1);
TS_ASSERT_EQUALS(inversion * hkl, hkl * -1.0);

// translational components are wrapped to the unit cell
SymmetryOperation screw21z("-x,-y,z+3/2");
TS_ASSERT_EQUALS(screw21z.identifier(), "-x,-y,z+1/2");
}

void testCopyConstructor()
{
SymmetryOperation inversion("-x,-y,-z");
SymmetryOperation anotherInversion(inversion);

TS_ASSERT_EQUALS(inversion, anotherInversion);
TS_ASSERT_EQUALS(inversion.order(), anotherInversion.order());
TS_ASSERT_EQUALS(inversion.identifier(), anotherInversion.identifier());
}

void testIsIdentity()
{
SymmetryOperation identity;
TS_ASSERT(identity.isIdentity());

SymmetryOperation inversion("-x,-y,-z");
TS_ASSERT(!inversion.isIdentity());

SymmetryOperation screw21z("-x,-y,z+1/2");
TS_ASSERT(!screw21z.isIdentity());

SymmetryOperation shift("x+1/2,y+1/2,z+1/2");
TS_ASSERT(!shift.isIdentity());
}

void testHasTranslation()
{
SymmetryOperation identity;
TS_ASSERT(!identity.hasTranslation());

SymmetryOperation inversion("-x,-y,-z");
TS_ASSERT(!inversion.hasTranslation());

SymmetryOperation screw21z("-x,-y,z+1/2");
TS_ASSERT(screw21z.hasTranslation());

SymmetryOperation shift("x+1/2,y+1/2,z+1/2");
TS_ASSERT(shift.hasTranslation());
}

void testMultiplicationOperator()
{
SymmetryOperation inversion("-x,-y,-z");

V3D hklDouble(1.0, 1.0, 1.0);
V3D hklDoubleReferenceInversion(-1.0, -1.0, -1.0);
TS_ASSERT_EQUALS(inversion * hklDouble, hklDoubleReferenceInversion);

V3R hklRational(1, 1, 1);
V3R hklRationalReferenceInversion(-1, -1, -1);
TS_ASSERT_EQUALS(inversion * hklRational, hklRationalReferenceInversion);

SymmetryOperation screw21z("-x,-y,z+1/2");

V3D coordinates(0.35, 0.45, 0.75);
V3D coordinatesReference(-0.35, -0.45, 1.25);

TS_ASSERT_EQUALS(screw21z * coordinates, coordinatesReference);
}

void testMultiplicationOperatorSymmetryOperation()
{
SymmetryOperation screw21z("-x,-y,z+1/2");
SymmetryOperation identity;

// should be identity, since 1/2 + 1/2 = 1 => 0
TS_ASSERT_EQUALS(screw21z * screw21z, identity);
}

void testGetWrappedVectorV3R()
{
TestableSymmetryOperation symOp;
V3R one = V3R(1, 1, 1) / 2;
TS_ASSERT_EQUALS(one, symOp.getWrappedVector(one));
TS_ASSERT_EQUALS(one, getWrappedVector(one));

V3R two = one + 1;
TS_ASSERT_EQUALS(one, symOp.getWrappedVector(two));
TS_ASSERT_EQUALS(one, getWrappedVector(two));

V3R three = one - 1;
TS_ASSERT_EQUALS(one, symOp.getWrappedVector(three));
TS_ASSERT_EQUALS(one, getWrappedVector(three));

V3R four = one - 10;
TS_ASSERT_EQUALS(one, getWrappedVector(four));

V3R five = one + 10;
TS_ASSERT_EQUALS(one, getWrappedVector(five));
}

void testGetWrappedVectorV3D()
{
V3D one = V3D(0.5, 0.5, 0.5);
TS_ASSERT_EQUALS(one, getWrappedVector(one));

V3D two = one + V3D(1.0, 1.0, 1.0);
TS_ASSERT_EQUALS(one, getWrappedVector(two));

V3D three = one + V3D(1.0, 1.0, 1.0);
TS_ASSERT_EQUALS(one, getWrappedVector(three));

V3D four = one + V3D(10.0, 10.0, 10.0);
TS_ASSERT_EQUALS(one, getWrappedVector(four));

V3D five = one + V3D(10.0, 10.0, 10.0);
TS_ASSERT_EQUALS(one, getWrappedVector(five));
}

void testGetOrderFromComponents()
Expand All @@ -81,8 +202,6 @@ class SymmetryOperationTest : public CxxTest::TestSuite
TS_ASSERT_EQUALS(symOp.getOrderFromMatrix(param4.first), 4);

// check that random matrices don't work
V3R null;

Mantid::Kernel::IntMatrix randMatrix(3, 3, false);

for(int i = 1; i < 10; ++i) {
Expand Down

0 comments on commit c696488

Please sign in to comment.