From e2b5b0072ace2bcc008d1bc1bc18996709bd5ddc Mon Sep 17 00:00:00 2001 From: Michael Wedel <michael.wedel@psi.ch> Date: Sun, 14 Jun 2015 17:31:00 +0200 Subject: [PATCH] Refs #12779. SpaceGroupFactory returns space groups for point group. --- .../inc/MantidGeometry/Crystal/SpaceGroup.h | 3 +- .../Crystal/SpaceGroupFactory.h | 14 +++++-- .../Geometry/src/Crystal/SpaceGroup.cpp | 26 +++---------- .../src/Crystal/SpaceGroupFactory.cpp | 39 ++++++++++++++++++- .../Geometry/test/SpaceGroupFactoryTest.h | 19 +++++++++ .../src/Exports/SpaceGroupFactory.cpp | 7 ++++ .../source/concepts/PointAndSpaceGroups.rst | 29 ++++++++++---- 7 files changed, 102 insertions(+), 35 deletions(-) diff --git a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/SpaceGroup.h b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/SpaceGroup.h index 91a9f49d423..bb82c73e0ec 100644 --- a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/SpaceGroup.h +++ b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/SpaceGroup.h @@ -90,13 +90,12 @@ public: bool isAllowedReflection(const Kernel::V3D &hkl) const; - PointGroup_sptr getPointGroup(); + PointGroup_sptr getPointGroup() const; Group_const_sptr getSiteSymmetryGroup(const Kernel::V3D &position) const; protected: size_t m_number; std::string m_hmSymbol; - std::string m_pointGroupSymbol; }; typedef boost::shared_ptr<SpaceGroup> SpaceGroup_sptr; diff --git a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/SpaceGroupFactory.h b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/SpaceGroupFactory.h index df07af3307d..51c2840f897 100644 --- a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/SpaceGroupFactory.h +++ b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/SpaceGroupFactory.h @@ -12,7 +12,7 @@ namespace Mantid { namespace Geometry { bool MANTID_GEOMETRY_DLL - isValidGeneratorString(const std::string &generatorString); +isValidGeneratorString(const std::string &generatorString); /** * @class AbstractSpaceGroupGenerator @@ -58,7 +58,7 @@ private: }; typedef boost::shared_ptr<AbstractSpaceGroupGenerator> - AbstractSpaceGroupGenerator_sptr; +AbstractSpaceGroupGenerator_sptr; /// Concrete space group generator that uses space group generators as given in /// ITA. @@ -142,6 +142,9 @@ public: std::vector<std::string> subscribedSpaceGroupSymbols(size_t number) const; std::vector<size_t> subscribedSpaceGroupNumbers() const; + std::vector<std::string> + subscribedSpaceGroupSymbols(const PointGroup_sptr &pointGroup); + void unsubscribeSpaceGroup(const std::string &hmSymbol); void subscribeGeneratedSpaceGroup(size_t number, const std::string &hmSymbol, @@ -171,8 +174,11 @@ protected: SpaceGroup_const_sptr constructFromPrototype(const SpaceGroup_const_sptr prototype) const; + void fillPointGroupMap(); + std::multimap<size_t, std::string> m_numberMap; std::map<std::string, AbstractSpaceGroupGenerator_sptr> m_generatorMap; + std::multimap<std::string, std::string> m_pointGroupMap; SpaceGroupFactoryImpl(); @@ -183,11 +189,11 @@ private: // This is taken from FuncMinimizerFactory #ifdef _WIN32 template class MANTID_GEOMETRY_DLL - Mantid::Kernel::SingletonHolder<SpaceGroupFactoryImpl>; +Mantid::Kernel::SingletonHolder<SpaceGroupFactoryImpl>; #endif typedef Mantid::Kernel::SingletonHolder<SpaceGroupFactoryImpl> - SpaceGroupFactory; +SpaceGroupFactory; } // namespace Geometry } // namespace Mantid diff --git a/Code/Mantid/Framework/Geometry/src/Crystal/SpaceGroup.cpp b/Code/Mantid/Framework/Geometry/src/Crystal/SpaceGroup.cpp index b2b77586f48..2a8f15ee24e 100644 --- a/Code/Mantid/Framework/Geometry/src/Crystal/SpaceGroup.cpp +++ b/Code/Mantid/Framework/Geometry/src/Crystal/SpaceGroup.cpp @@ -19,13 +19,11 @@ using namespace Kernel; */ SpaceGroup::SpaceGroup(size_t itNumber, const std::string &hmSymbol, const Group &group) - : Group(group), m_number(itNumber), m_hmSymbol(hmSymbol), - m_pointGroupSymbol() {} + : Group(group), m_number(itNumber), m_hmSymbol(hmSymbol) {} /// Copy constructor SpaceGroup::SpaceGroup(const SpaceGroup &other) - : Group(other), m_number(other.m_number), m_hmSymbol(other.m_hmSymbol), - m_pointGroupSymbol(other.m_pointGroupSymbol) {} + : Group(other), m_number(other.m_number), m_hmSymbol(other.m_hmSymbol) {} /// Assignment operator, utilizes Group's assignment operator SpaceGroup &SpaceGroup::operator=(const SpaceGroup &other) { @@ -33,7 +31,6 @@ SpaceGroup &SpaceGroup::operator=(const SpaceGroup &other) { m_number = other.m_number; m_hmSymbol = other.m_hmSymbol; - m_pointGroupSymbol = other.m_pointGroupSymbol; return *this; } @@ -84,24 +81,13 @@ bool SpaceGroup::isAllowedReflection(const Kernel::V3D &hkl) const { * Returns the point group of the space group * * This method uses PointGroupFactory to create the point group of the space- - * group. To avoid parsing the space group symbol over and over again, the - * point group symbol is stored for subsequent calls to this function. Because - * the factory is used for construction, a new object is returned each time - * this method is called. + * group. Becausethe factory is used for construction, a new object is returned + * each time this method is called. * * @return :: PointGroup-object. */ -PointGroup_sptr SpaceGroup::getPointGroup() { - if (m_pointGroupSymbol.empty()) { - PointGroup_sptr pointGroup = - PointGroupFactory::Instance().createPointGroupFromSpaceGroup(*this); - - m_pointGroupSymbol = pointGroup->getSymbol(); - - return pointGroup; - } - - return PointGroupFactory::Instance().createPointGroup(m_pointGroupSymbol); +PointGroup_sptr SpaceGroup::getPointGroup() const { + return PointGroupFactory::Instance().createPointGroupFromSpaceGroup(*this); } /** diff --git a/Code/Mantid/Framework/Geometry/src/Crystal/SpaceGroupFactory.cpp b/Code/Mantid/Framework/Geometry/src/Crystal/SpaceGroupFactory.cpp index 325f8f321f4..cae02496cf1 100644 --- a/Code/Mantid/Framework/Geometry/src/Crystal/SpaceGroupFactory.cpp +++ b/Code/Mantid/Framework/Geometry/src/Crystal/SpaceGroupFactory.cpp @@ -22,7 +22,8 @@ bool isValidGeneratorString(const std::string &generatorString) { for (auto it = generatorStrings.begin(); it != generatorStrings.end(); ++it) { try { SymmetryOperationSymbolParser::parseIdentifier(*it); - } catch (Kernel::Exception::ParseError) { + } + catch (Kernel::Exception::ParseError) { return false; } } @@ -180,6 +181,24 @@ std::vector<size_t> SpaceGroupFactoryImpl::subscribedSpaceGroupNumbers() const { return numbers; } +std::vector<std::string> SpaceGroupFactoryImpl::subscribedSpaceGroupSymbols( + const PointGroup_sptr &pointGroup) { + if (m_pointGroupMap.empty()) { + fillPointGroupMap(); + } + + std::string pointGroupSymbol = pointGroup->getSymbol(); + + std::vector<std::string> symbols; + auto keyPair = m_pointGroupMap.equal_range(pointGroupSymbol); + + for (auto it = keyPair.first; it != keyPair.second; ++it) { + symbols.push_back(it->second); + } + + return symbols; +} + /// Unsubscribes the space group with the given Hermann-Mauguin symbol, but /// throws std::invalid_argument if symbol is not registered. void SpaceGroupFactoryImpl::unsubscribeSpaceGroup(const std::string &hmSymbol) { @@ -237,6 +256,19 @@ SpaceGroup_const_sptr SpaceGroupFactoryImpl::constructFromPrototype( return boost::make_shared<const SpaceGroup>(*prototype); } +/// Fills the internal multimap that maintains the mapping between space and +/// point groups. +void SpaceGroupFactoryImpl::fillPointGroupMap() { + m_pointGroupMap.clear(); + + for (auto it = m_generatorMap.begin(); it != m_generatorMap.end(); ++it) { + SpaceGroup_const_sptr spaceGroup = getPrototype(it->first); + + m_pointGroupMap.insert( + std::make_pair(spaceGroup->getPointGroup()->getSymbol(), it->first)); + } +} + /// Returns a prototype object for the requested space group. SpaceGroup_const_sptr SpaceGroupFactoryImpl::getPrototype(const std::string &hmSymbol) { @@ -260,11 +292,14 @@ void SpaceGroupFactoryImpl::subscribe( m_numberMap.insert( std::make_pair(generator->getNumber(), generator->getHMSymbol())); m_generatorMap.insert(std::make_pair(generator->getHMSymbol(), generator)); + + // Clear the point group map + m_pointGroupMap.clear(); } /// Constructor cannot be called, since SingletonHolder is used. SpaceGroupFactoryImpl::SpaceGroupFactoryImpl() - : m_numberMap(), m_generatorMap() { + : m_numberMap(), m_generatorMap(), m_pointGroupMap() { Kernel::LibraryManager::Instance(); } diff --git a/Code/Mantid/Framework/Geometry/test/SpaceGroupFactoryTest.h b/Code/Mantid/Framework/Geometry/test/SpaceGroupFactoryTest.h index 51d27506702..7ffa884c03d 100644 --- a/Code/Mantid/Framework/Geometry/test/SpaceGroupFactoryTest.h +++ b/Code/Mantid/Framework/Geometry/test/SpaceGroupFactoryTest.h @@ -8,6 +8,7 @@ using ::testing::Return; #include "MantidGeometry/Crystal/SpaceGroupFactory.h" +#include "MantidGeometry/Crystal/PointGroupFactory.h" #include "MantidGeometry/Crystal/CyclicGroup.h" using namespace Mantid::Geometry; @@ -161,6 +162,24 @@ public: TS_ASSERT_EQUALS(symbols.size(), 2); } + void testSubscribedSpaceGroupSymbolsForPointGroup() { + PointGroup_sptr pg = PointGroupFactory::Instance().createPointGroup("-1"); + + TestableSpaceGroupFactory factory; + + TS_ASSERT_EQUALS(factory.subscribedSpaceGroupSymbols(pg).size(), 0); + TS_ASSERT(factory.m_pointGroupMap.empty()); + + factory.subscribeTabulatedSpaceGroup(2, "P-1", "x,y,z; -x,-y,-z"); + TS_ASSERT_EQUALS(factory.subscribedSpaceGroupSymbols(pg).size(), 1); + TS_ASSERT(!factory.m_pointGroupMap.empty()); + + factory.subscribeTabulatedSpaceGroup(2, "F-1", "x,y,z; -x,-y,-z"); + TS_ASSERT(factory.m_pointGroupMap.empty()); + TS_ASSERT_EQUALS(factory.subscribedSpaceGroupSymbols(pg).size(), 2); + TS_ASSERT(!factory.m_pointGroupMap.empty()); + } + void testUnsubscribeSymbol() { TestableSpaceGroupFactory factory; diff --git a/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/SpaceGroupFactory.cpp b/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/SpaceGroupFactory.cpp index 08c42d97b58..365d6e02a78 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/SpaceGroupFactory.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/SpaceGroupFactory.cpp @@ -18,6 +18,12 @@ std::vector<std::string> spaceGroupSymbolsForNumber(SpaceGroupFactoryImpl &self, return self.subscribedSpaceGroupSymbols(number); } +std::vector<std::string> +spaceGroupSymbolsForPointGroup(SpaceGroupFactoryImpl &self, + const PointGroup_sptr &pointGroup) { + return self.subscribedSpaceGroupSymbols(pointGroup); +} + bool isSubscribedSymbol(SpaceGroupFactoryImpl &self, const std::string &symbol) { return self.isSubscribed(symbol); @@ -51,6 +57,7 @@ void export_SpaceGroupFactory() { .def("subscribedSpaceGroupSymbols", &spaceGroupSymbolsForNumber, "Returns all space group symbols that are registered under the " "given number.") + .def("getSpaceGroupsForPointGroup", &spaceGroupSymbolsForPointGroup) .def("Instance", &SpaceGroupFactory::Instance, return_value_policy<reference_existing_object>(), "Returns a reference to the SpaceGroupFactory singleton") diff --git a/Code/Mantid/docs/source/concepts/PointAndSpaceGroups.rst b/Code/Mantid/docs/source/concepts/PointAndSpaceGroups.rst index 72b4342fd07..6867c9b4eda 100644 --- a/Code/Mantid/docs/source/concepts/PointAndSpaceGroups.rst +++ b/Code/Mantid/docs/source/concepts/PointAndSpaceGroups.rst @@ -307,7 +307,23 @@ The script prints the point group of the space group in question: Space group no. 227 has point group: m-3m Space group no. 216 has point group: -43m - + +Sometimes it's useful to reverse the above process - which is not exactly possible, because several space groups may map to the same point group. The space group factory does however provide a way to get all space group symbols that belong to a certain point group: + +.. testcode:: ExSpaceGroupFactoryPointGroup + + from mantid.geometry import PointGroupFactory, SpaceGroupFactory + + pg = PointGroupFactory.createPointGroup("m-3") + + print "Space groups with point group m-3:", SpaceGroupFactory.getSpaceGroupsForPointGroup(pg) + +The example produces the following output: + +.. testoutput:: ExSpaceGroupFactoryPointGroup + + Space groups with point group m-3: ['F d -3','F m -3','I a -3','I m -3','P a -3','P m -3','P n -3'] + While PointGroup offers useful methods to handle reflections, some information can only be obtained from the space group. The presence of translational symmetry causes the contributions from symmetrically equivalent atoms to the structure factor of certain reflections to cancel out completely so that it can not be observed. These systematically absent reflections are characteristic for each space group, a fact that can be used to determine the space group from measured reflection intensities. The following script shows how to check a few reflections: .. testcode:: ExSpaceGroupReflectionIsAllowed @@ -507,7 +523,7 @@ Building on the example above which showed how to check whether a reflection is .. testcode:: ExSpaceGroupCheck - from mantid.geometry import SpaceGroupFactory + from mantid.geometry import SpaceGroupFactory, PointGroupFactory # Small helper function that distinguishes three cases: # 0: The reflection is observed and allowed or not observed and not allowed @@ -550,11 +566,10 @@ Building on the example above which showed how to check whether a reflection is # Check space groups and store results in a list spaceGroupMatchList = [] - # Cubic space groups start at number 195 and go to 230. - # Those that belong to Laue class m-3m start at 221, so 10 space groups need to be checked. - for n in range(221, 231): - # In this example only the first space group is used if more than one are registered for this number. - sgSymbol = SpaceGroupFactory.subscribedSpaceGroupSymbols(n)[0] + # As described above, point group m-3m is assumed + pg = PointGroupFactory.createPointGroup("m-3m") + possibleSpaceGroups = SpaceGroupFactory.getSpaceGroupsForPointGroup(pg) + for sgSymbol in possibleSpaceGroups: sgObject = SpaceGroupFactory.createSpaceGroup(sgSymbol) # For each (hkl, observed) pair obtain whether this matches the space group's conditions -- GitLab