Newer
Older
#include "MantidGeometry/Crystal/PointGroup.h"
#include "MantidKernel/System.h"
#include <set>
#include <boost/make_shared.hpp>
#include <boost/algorithm/string.hpp>
#include "MantidGeometry/Crystal/PointGroupFactory.h"
#include "MantidGeometry/Crystal/SymmetryOperationFactory.h"
#include "MantidGeometry/Crystal/SymmetryElementFactory.h"
namespace Mantid {
namespace Geometry {
using Kernel::V3D;
using Kernel::IntMatrix;
/**
* Returns all equivalent reflections for the supplied hkl.
*
* This method returns a vector containing all equivalent hkls for the supplied
* one. It depends on the internal state of the pointgroup object (e.g. which
* symmetry operations and therefore, which transformation matrices are
* present). This internal state is unique for each concrete point group and
* is set in the constructor.
*
* The returned vector always contains a set of unique hkls, so for special hkls
* like (100), it has fewer entries than for a general hkl. See also
* PointGroup::getEquivalentSet.
*
* @param hkl :: Arbitrary hkl
* @return :: std::vector containing all equivalent hkls.
*/
std::vector<V3D> PointGroup::getEquivalents(const V3D &hkl) const {
return getEquivalentSet(hkl);
}
/**
* Returns the same V3D for all equivalent hkls.
*
* This method is closely related to PointGroup::getEquivalents. It returns the
* same V3D for all hkls of one "family". For example in a cubic point group
* it will return (100) for (001), (010), (0-10), etc.
*
* It can be used to generate a set of symmetry independent hkls, useful for
*
* @param hkl :: Arbitrary hkl
* @return :: hkl specific to a family of index-triplets
*/
V3D PointGroup::getReflectionFamily(const Kernel::V3D &hkl) const {
return *getEquivalentSet(hkl).begin();
}
/// Protected constructor - can not be used directly.
PointGroup::PointGroup(const std::string &symbolHM, const Group &group,
const std::string &description)
: Group(group), m_symbolHM(symbolHM),
m_name(symbolHM + " (" + description + ")") {
m_crystalSystem = getCrystalSystemFromGroup();
m_latticeSystem = getLatticeSystemFromCrystalSystemAndGroup(m_crystalSystem);
PointGroup::PointGroup(const PointGroup &other)
: Group(other), m_symbolHM(other.m_symbolHM), m_name(other.m_name),
m_crystalSystem(other.m_crystalSystem),
m_latticeSystem(other.m_latticeSystem) {}
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_latticeSystem = other.m_latticeSystem;
return *this;
}
/// Hermann-Mauguin symbol
std::string PointGroup::getSymbol() const { return m_symbolHM; }
bool PointGroup::isEquivalent(const Kernel::V3D &hkl,
const Kernel::V3D &hkl2) const {
std::vector<V3D> hklEquivalents = getEquivalentSet(hkl);
return (std::find(hklEquivalents.begin(), hklEquivalents.end(), hkl2) !=
hklEquivalents.end());
/**
* Generates a set of hkls
*
* This method applies all transformation matrices to the supplied hkl and puts
* it into a set, which is returned in the end. Using a set ensures that each
* hkl occurs once and only once. This set is the set of equivalent hkls,
* specific to a concrete point group.
*
* The symmetry operations need to be set prior to calling this method by a call
* to PointGroup::setTransformationMatrices.
*
* @param hkl :: Arbitrary hkl
* @return :: set of hkls.
*/
std::vector<V3D> PointGroup::getEquivalentSet(const Kernel::V3D &hkl) const {
std::vector<V3D> equivalents;
equivalents.reserve(m_allOperations.size());
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>());
equivalents.erase(std::unique(equivalents.begin(), equivalents.end()),
equivalents.end());
return equivalents;
/**
* Returns the CrystalSystem determined from symmetry elements
*
* This method determines the crystal system of the point group. It makes
* use of the fact that each crystal system has a characteristic set of
* symmetry elements. The requirement for the cubic system is for example
* that four 3-fold axes are present, whereas one 3-fold axis indicates
* that the group belongs to the trigonal system.
*
* @return Crystal system that the point group belongs to.
*/
PointGroup::CrystalSystem PointGroup::getCrystalSystemFromGroup() const {
std::map<std::string, std::set<V3D>> symbolMap;
for (auto op = m_allOperations.begin(); op != m_allOperations.end(); ++op) {
SymmetryElementWithAxis_sptr element =
boost::dynamic_pointer_cast<SymmetryElementWithAxis>(
SymmetryElementFactory::Instance().createSymElement(*op));
if (element) {
std::string symbol = element->hmSymbol();
V3D axis = element->getAxis();
symbolMap[symbol].insert(axis);
}
}
if (symbolMap["3"].size() == 4) {
return CrystalSystem::Cubic;
}
if (symbolMap["6"].size() == 1 || symbolMap["-6"].size() == 1) {
return CrystalSystem::Hexagonal;
}
if (symbolMap["3"].size() == 1) {
return CrystalSystem::Trigonal;
}
if (symbolMap["4"].size() == 1 || symbolMap["-4"].size() == 1) {
return CrystalSystem::Tetragonal;
}
if (symbolMap["2"].size() == 3 ||
(symbolMap["2"].size() == 1 && symbolMap["m"].size() == 2)) {
return CrystalSystem::Orthorhombic;
}
if (symbolMap["2"].size() == 1 || symbolMap["m"].size() == 1) {
return CrystalSystem::Monoclinic;
}
return CrystalSystem::Triclinic;
}
/**
* Returns the LatticeSystem of the point group, using the crystal system
*
* This function uses the crystal system argument and the coordinate system
* stored in Group to determine the lattice system. For all crystal systems
* except trigonal there is a 1:1 correspondence, but for trigonal groups
* the lattice system can be either rhombohedral or hexagonal.
*
* @param crystalSystem :: CrystalSystem of the point group.
* @return LatticeSystem the point group belongs to.
*/
PointGroup::LatticeSystem PointGroup::getLatticeSystemFromCrystalSystemAndGroup(
const CrystalSystem &crystalSystem) const {
switch (crystalSystem) {
case CrystalSystem::Cubic:
return LatticeSystem::Cubic;
case CrystalSystem::Hexagonal:
return LatticeSystem::Hexagonal;
case CrystalSystem::Tetragonal:
return LatticeSystem::Tetragonal;
case CrystalSystem::Orthorhombic:
return LatticeSystem::Orthorhombic;
case CrystalSystem::Monoclinic:
return LatticeSystem::Monoclinic;
case CrystalSystem::Triclinic:
return LatticeSystem::Triclinic;
default: {
if (getCoordinateSystem() == Group::Hexagonal) {
return LatticeSystem::Hexagonal;
}
return LatticeSystem::Rhombohedral;
}
}
}
/** @return a vector with all possible PointGroup objects */
std::vector<PointGroup_sptr> getAllPointGroups() {
std::vector<std::string> allSymbols =
PointGroupFactory::Instance().getAllPointGroupSymbols();
std::vector<PointGroup_sptr> out;
for (auto it = allSymbols.begin(); it != allSymbols.end(); ++it) {
out.push_back(PointGroupFactory::Instance().createPointGroup(*it));
}
return out;
}
/// Returns a multimap with crystal system as key and point groups as values.
PointGroupCrystalSystemMap getPointGroupsByCrystalSystem() {
PointGroupCrystalSystemMap map;
std::vector<PointGroup_sptr> pointGroups = getAllPointGroups();
for (size_t i = 0; i < pointGroups.size(); ++i) {
map.insert(std::make_pair(pointGroups[i]->crystalSystem(), pointGroups[i]));
}
return map;
}
/// Return a human-readable string for the given crystal system
std::string
getCrystalSystemAsString(const PointGroup::CrystalSystem &crystalSystem) {
switch (crystalSystem) {
case PointGroup::CrystalSystem::Cubic:
return "Cubic";
case PointGroup::CrystalSystem::Tetragonal:
return "Tetragonal";
case PointGroup::CrystalSystem::Hexagonal:
return "Hexagonal";
case PointGroup::CrystalSystem::Trigonal:
return "Trigonal";
case PointGroup::CrystalSystem::Orthorhombic:
return "Orthorhombic";
case PointGroup::CrystalSystem::Monoclinic:
return "Monoclinic";
default:
return "Triclinic";
}
}
/// Returns the crystal system enum that corresponds to the supplied string or
/// throws an invalid_argument exception.
PointGroup::CrystalSystem
getCrystalSystemFromString(const std::string &crystalSystem) {
std::string crystalSystemLC = boost::algorithm::to_lower_copy(crystalSystem);
if (crystalSystemLC == "cubic") {
return PointGroup::CrystalSystem::Cubic;
} else if (crystalSystemLC == "tetragonal") {
return PointGroup::CrystalSystem::Tetragonal;
} else if (crystalSystemLC == "hexagonal") {
return PointGroup::CrystalSystem::Hexagonal;
} else if (crystalSystemLC == "trigonal") {
return PointGroup::CrystalSystem::Trigonal;
} else if (crystalSystemLC == "orthorhombic") {
return PointGroup::CrystalSystem::Orthorhombic;
} else if (crystalSystemLC == "monoclinic") {
return PointGroup::CrystalSystem::Monoclinic;
} else if (crystalSystemLC == "triclinic") {
return PointGroup::CrystalSystem::Triclinic;
} else {
throw std::invalid_argument("Not a valid crystal system: '" +
crystalSystem + "'.");
}
}
/// Returns the supplied LatticeSystem as a string.
std::string
getLatticeSystemAsString(const PointGroup::LatticeSystem &latticeSystem) {
switch (latticeSystem) {
case PointGroup::LatticeSystem::Cubic:
return "Cubic";
case PointGroup::LatticeSystem::Tetragonal:
return "Tetragonal";
case PointGroup::LatticeSystem::Hexagonal:
return "Hexagonal";
case PointGroup::LatticeSystem::Rhombohedral:
return "Rhombohedral";
case PointGroup::LatticeSystem::Orthorhombic:
return "Orthorhombic";
case PointGroup::LatticeSystem::Monoclinic:
return "Monoclinic";
default:
return "Triclinic";
}
}
/// Returns the lattice system enum that corresponds to the supplied string or
/// throws an invalid_argument exception.PointGroup::LatticeSystem
PointGroup::LatticeSystem
getLatticeSystemFromString(const std::string &latticeSystem) {
std::string latticeSystemLC = boost::algorithm::to_lower_copy(latticeSystem);
if (latticeSystemLC == "cubic") {
return PointGroup::LatticeSystem::Cubic;
} else if (latticeSystemLC == "tetragonal") {
return PointGroup::LatticeSystem::Tetragonal;
} else if (latticeSystemLC == "hexagonal") {
return PointGroup::LatticeSystem::Hexagonal;
} else if (latticeSystemLC == "rhombohedral") {
return PointGroup::LatticeSystem::Rhombohedral;
} else if (latticeSystemLC == "orthorhombic") {
return PointGroup::LatticeSystem::Orthorhombic;
} else if (latticeSystemLC == "monoclinic") {
return PointGroup::LatticeSystem::Monoclinic;
} else if (latticeSystemLC == "triclinic") {
return PointGroup::LatticeSystem::Triclinic;
} else {
throw std::invalid_argument("Not a valid lattice system: '" +
latticeSystem + "'.");
}
}
bool CrystalSystemComparator::
operator()(const PointGroup::CrystalSystem &lhs,
const PointGroup::CrystalSystem &rhs) const {
return static_cast<int>(lhs) < static_cast<int>(rhs);
}
} // namespace Mantid
} // namespace Geometry