Skip to content
Snippets Groups Projects
PointGroup.cpp 11.2 KiB
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
 * example in powder diffraction.
 *
 * @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;

/// 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());
/**
 * 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;
    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:
  case PointGroup::CrystalSystem::Tetragonal:
  case PointGroup::CrystalSystem::Hexagonal:
  case PointGroup::CrystalSystem::Trigonal:
  case PointGroup::CrystalSystem::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