diff --git a/Code/Mantid/Framework/Geometry/CMakeLists.txt b/Code/Mantid/Framework/Geometry/CMakeLists.txt index 4f6990ac989db80a043e6c03e92bfc2758985d88..f192ebbd483f9d9ff05d6661a9f402e3a982145b 100644 --- a/Code/Mantid/Framework/Geometry/CMakeLists.txt +++ b/Code/Mantid/Framework/Geometry/CMakeLists.txt @@ -6,6 +6,7 @@ set ( SRC_FILES src/Crystal/NiggliCell.cpp src/Crystal/OrientedLattice.cpp src/Crystal/PointGroup.cpp + src/Crystal/PointGroupFactory.cpp src/Crystal/ReducedCell.cpp src/Crystal/ReflectionCondition.cpp src/Crystal/ScalarUtils.cpp @@ -107,6 +108,7 @@ set ( INC_FILES inc/MantidGeometry/Crystal/NiggliCell.h inc/MantidGeometry/Crystal/OrientedLattice.h inc/MantidGeometry/Crystal/PointGroup.h + inc/MantidGeometry/Crystal/PointGroupFactory.h inc/MantidGeometry/Crystal/ReducedCell.h inc/MantidGeometry/Crystal/ReflectionCondition.h inc/MantidGeometry/Crystal/ScalarUtils.h @@ -249,6 +251,7 @@ set ( TEST_FILES ParameterMapTest.h ParametrizedComponentTest.h PlaneTest.h + PointGroupFactoryTest.h PointGroupTest.h PolygonEdgeTest.h QuadrilateralTest.h diff --git a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/PointGroupFactory.h b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/PointGroupFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..c4957d86cb772ccf697cc4349fdf3676fa5ca40c --- /dev/null +++ b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/PointGroupFactory.h @@ -0,0 +1,99 @@ +#ifndef MANTID_GEOMETRY_POINTGROUPFACTORY_H_ +#define MANTID_GEOMETRY_POINTGROUPFACTORY_H_ + +#include "MantidGeometry/DllConfig.h" +#include "MantidKernel/DynamicFactory.h" +#include "MantidKernel/SingletonHolder.h" +#include "MantidGeometry/Crystal/PointGroup.h" + +namespace Mantid +{ +namespace Geometry +{ + /** PointGroupFactory + + A factory for point groups. Point group objects can be constructed by + supplying the Hermann-Mauguin-symbol like this: + + PointGroup_sptr cubic = PointGroupFactory::Instance().createPointgroup("m-3m"); + + Furthermore it's possible to query available point groups + + @author Michael Wedel, Paul Scherrer Institut - SINQ + @date 09/09/2014 + + Copyright © 2014 PSI-MSS + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + File change history is stored at: <https://github.com/mantidproject/mantid> + Code Documentation is available at: <http://doxygen.mantidproject.org> + */ + class MANTID_GEOMETRY_DLL PointGroupFactoryImpl : public Kernel::DynamicFactory<PointGroup> + { + public: + PointGroup_sptr createPointgroup(const std::string &hmSymbol) const; + + std::vector<std::string> getAllPointGroupSymbols() const; + std::vector<std::string> getAllPointGroupSymbols(const PointGroup::CrystalSystem &crystalSystem) const; + + template <class C> + void subscribePointgroup() + { + Kernel::Instantiator<C, PointGroup> *instantiator = new Kernel::Instantiator<C, PointGroup>; + PointGroup_sptr temporaryPointgroup = instantiator->createInstance(); + std::string hmSymbol = temporaryPointgroup->getSymbol(); + + subscribe(hmSymbol, instantiator); + + addToCrystalSystemMap(temporaryPointgroup->crystalSystem(), hmSymbol); + } + + void unsubscribePointgroup(const std::string &hmSymbol) + { + unsubscribe(hmSymbol); + removeFromCrystalSystemMap(hmSymbol); + } + + private: + friend struct Mantid::Kernel::CreateUsingNew<PointGroupFactoryImpl>; + + PointGroupFactoryImpl(); + void addToCrystalSystemMap(const PointGroup::CrystalSystem &crystalSystem, const std::string &hmSymbol); + void removeFromCrystalSystemMap(const std::string &hmSymbol); + + std::map<std::string, PointGroup::CrystalSystem> m_crystalSystemMap; + }; + +// This is taken from FuncMinimizerFactory +#ifdef _WIN32 + template class MANTID_GEOMETRY_DLL Mantid::Kernel::SingletonHolder<PointGroupFactory>; +#endif + +typedef Mantid::Kernel::SingletonHolder<PointGroupFactoryImpl> PointGroupFactory; + + +} // namespace Geometry +} // namespace Mantid + +#define DECLARE_POINTGROUP(classname) \ + namespace { \ + Mantid::Kernel::RegistrationHelper register_pointgroup_##classname( \ + ((Mantid::Geometry::PointGroupFactory::Instance().subscribePointgroup<classname>()) \ + , 0)); \ + } + +#endif /* MANTID_GEOMETRY_POINTGROUPFACTORY_H_ */ diff --git a/Code/Mantid/Framework/Geometry/src/Crystal/PointGroup.cpp b/Code/Mantid/Framework/Geometry/src/Crystal/PointGroup.cpp index debd664c104a4a82d318a46f83f169243d67abd4..98b9d3837de098d0900f3e879a9de2abeb421860 100644 --- a/Code/Mantid/Framework/Geometry/src/Crystal/PointGroup.cpp +++ b/Code/Mantid/Framework/Geometry/src/Crystal/PointGroup.cpp @@ -4,6 +4,8 @@ #include <set> #include <boost/make_shared.hpp> +#include "MantidGeometry/Crystal/PointGroupFactory.h" + namespace Mantid { namespace Geometry @@ -578,20 +580,13 @@ namespace Geometry /** @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; - out.push_back( boost::make_shared<PointGroupLaue1>() ); - out.push_back( boost::make_shared<PointGroupLaue2>() ); - out.push_back( boost::make_shared<PointGroupLaue3>() ); - out.push_back( boost::make_shared<PointGroupLaue4>() ); - out.push_back( boost::make_shared<PointGroupLaue5>() ); - out.push_back( boost::make_shared<PointGroupLaue6>() ); - out.push_back( boost::make_shared<PointGroupLaue7>() ); - out.push_back( boost::make_shared<PointGroupLaue8>() ); - out.push_back( boost::make_shared<PointGroupLaue9>() ); - out.push_back( boost::make_shared<PointGroupLaue10>() ); - out.push_back( boost::make_shared<PointGroupLaue11>() ); - out.push_back( boost::make_shared<PointGroupLaue12>() ); - out.push_back( boost::make_shared<PointGroupLaue13>() ); + for(auto it = allSymbols.begin(); it != allSymbols.end(); ++it) { + out.push_back(PointGroupFactory::Instance().create(*it)); + } + return out; } @@ -607,7 +602,19 @@ namespace Geometry return map; } - + DECLARE_POINTGROUP(PointGroupLaue1) + DECLARE_POINTGROUP(PointGroupLaue2) + DECLARE_POINTGROUP(PointGroupLaue3) + DECLARE_POINTGROUP(PointGroupLaue4) + DECLARE_POINTGROUP(PointGroupLaue5) + DECLARE_POINTGROUP(PointGroupLaue6) + DECLARE_POINTGROUP(PointGroupLaue7) + DECLARE_POINTGROUP(PointGroupLaue8) + DECLARE_POINTGROUP(PointGroupLaue9) + DECLARE_POINTGROUP(PointGroupLaue10) + DECLARE_POINTGROUP(PointGroupLaue11) + DECLARE_POINTGROUP(PointGroupLaue12) + DECLARE_POINTGROUP(PointGroupLaue13) } // namespace Mantid } // namespace Geometry diff --git a/Code/Mantid/Framework/Geometry/src/Crystal/PointGroupFactory.cpp b/Code/Mantid/Framework/Geometry/src/Crystal/PointGroupFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..874123aa7331352743170455a26e3a404239a663 --- /dev/null +++ b/Code/Mantid/Framework/Geometry/src/Crystal/PointGroupFactory.cpp @@ -0,0 +1,58 @@ +#include "MantidGeometry/Crystal/PointGroupFactory.h" + +#include "MantidKernel/LibraryManager.h" + +namespace Mantid +{ +namespace Geometry +{ + +PointGroup_sptr PointGroupFactoryImpl::createPointgroup(const std::string &hmSymbol) const +{ + return create(hmSymbol); +} + +std::vector<std::string> PointGroupFactoryImpl::getAllPointGroupSymbols() const +{ + std::vector<std::string> pointGroups; + + for(auto it = m_crystalSystemMap.begin(); it != m_crystalSystemMap.end(); ++it) { + pointGroups.push_back(it->first); + } + + return pointGroups; +} + +std::vector<std::string> PointGroupFactoryImpl::getAllPointGroupSymbols(const PointGroup::CrystalSystem &crystalSystem) const +{ + std::vector<std::string> pointGroups; + + for(auto it = m_crystalSystemMap.begin(); it != m_crystalSystemMap.end(); ++it) { + if(it->second == crystalSystem) { + pointGroups.push_back(it->first); + } + } + + return pointGroups; +} + +PointGroupFactoryImpl::PointGroupFactoryImpl() : Kernel::DynamicFactory<PointGroup>() +{ + Kernel::LibraryManager::Instance(); +} + +void PointGroupFactoryImpl::addToCrystalSystemMap(const PointGroup::CrystalSystem &crystalSystem, const std::string &hmSymbol) +{ + m_crystalSystemMap.insert(std::make_pair(hmSymbol, crystalSystem)); +} + +void PointGroupFactoryImpl::removeFromCrystalSystemMap(const std::string &hmSymbol) +{ + auto it = m_crystalSystemMap.find(hmSymbol); + m_crystalSystemMap.erase(it); +} + + + +} // namespace Geometry +} // namespace Mantid diff --git a/Code/Mantid/Framework/Geometry/test/PointGroupFactoryTest.h b/Code/Mantid/Framework/Geometry/test/PointGroupFactoryTest.h new file mode 100644 index 0000000000000000000000000000000000000000..ec4414fb80caab2be31c6dc514ee1692fa38b4e6 --- /dev/null +++ b/Code/Mantid/Framework/Geometry/test/PointGroupFactoryTest.h @@ -0,0 +1,146 @@ +#ifndef MANTID_GEOMETRY_POINTGROUPFACTORYTEST_H_ +#define MANTID_GEOMETRY_POINTGROUPFACTORYTEST_H_ + +#include <cxxtest/TestSuite.h> + +#include "MantidGeometry/Crystal/PointGroupFactory.h" +#include "MantidGeometry/Crystal/PointGroup.h" +#include "MantidKernel/Exception.h" + + +using Mantid::Geometry::PointGroupFactoryImpl; +using namespace Mantid::Geometry; + + +/* For testing the factory, three fake point groups are defined + * and registered in the factory (see below). + * + * When the test is destroyed, these are explicitly unregistered, + * so they don't interfere with other tests. + */ +class TestPointGroupCubicA : public PointGroup +{ +public: + TestPointGroupCubicA() : PointGroup("cubicA") + { } + ~TestPointGroupCubicA() { } + + std::string getName() const { return "cubicA (test)"; } + bool isEquivalent(const Mantid::Kernel::V3D &hkl, const Mantid::Kernel::V3D &hkl2) const + { + UNUSED_ARG(hkl); + UNUSED_ARG(hkl2); + + return false; + } + + PointGroup::CrystalSystem crystalSystem() const { return PointGroup::Cubic; } +}; + +class TestPointGroupCubicB : public PointGroup +{ +public: + TestPointGroupCubicB() : PointGroup("cubicB") + { } + ~TestPointGroupCubicB() { } + + std::string getName() const { return "cubicB (test)"; } + bool isEquivalent(const Mantid::Kernel::V3D &hkl, const Mantid::Kernel::V3D &hkl2) const + { + UNUSED_ARG(hkl); + UNUSED_ARG(hkl2); + + return false; + } + + PointGroup::CrystalSystem crystalSystem() const { return PointGroup::Cubic; } +}; + +class TestPointGroupTriclinic : public PointGroup +{ +public: + TestPointGroupTriclinic() : PointGroup("triclinic") + { } + ~TestPointGroupTriclinic() { } + + std::string getName() const { return "triclinic (test)"; } + bool isEquivalent(const Mantid::Kernel::V3D &hkl, const Mantid::Kernel::V3D &hkl2) const + { + UNUSED_ARG(hkl); + UNUSED_ARG(hkl2); + + return false; + } + + PointGroup::CrystalSystem crystalSystem() const { return PointGroup::Triclinic; } +}; + +DECLARE_POINTGROUP(TestPointGroupCubicA); +DECLARE_POINTGROUP(TestPointGroupCubicB); +DECLARE_POINTGROUP(TestPointGroupTriclinic); + + +class PointGroupFactoryTest : public CxxTest::TestSuite +{ +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static PointGroupFactoryTest *createSuite() { return new PointGroupFactoryTest(); } + static void destroySuite( PointGroupFactoryTest *suite ) { delete suite; } + + ~PointGroupFactoryTest() + { + // Unsubscribing the fake point groups + PointGroupFactory::Instance().unsubscribePointgroup("cubicA"); + PointGroupFactory::Instance().unsubscribePointgroup("cubicB"); + PointGroupFactory::Instance().unsubscribePointgroup("triclinic"); + } + + void testCreatePointGroup() + { + TS_ASSERT_THROWS_NOTHING(PointGroupFactory::Instance().createPointgroup("cubicA")); + TS_ASSERT_THROWS_NOTHING(PointGroupFactory::Instance().createPointgroup("cubicB")); + TS_ASSERT_THROWS_NOTHING(PointGroupFactory::Instance().createPointgroup("triclinic")); + + TS_ASSERT_THROWS(PointGroupFactory::Instance().createPointgroup("cubicC"), Mantid::Kernel::Exception::NotFoundError); + } + + void testGetAllPointGroupSymbols() + { + std::vector<std::string> symbols = PointGroupFactory::Instance().getAllPointGroupSymbols(); + + TS_ASSERT_DIFFERS(findString(symbols, "cubicA"), symbols.end()); + TS_ASSERT_DIFFERS(findString(symbols, "cubicB"), symbols.end()); + TS_ASSERT_DIFFERS(findString(symbols, "triclinic"), symbols.end()); + } + + void testGetAllPointGroupSymbolsCrystalSystems() + { + std::vector<std::string> cubic = PointGroupFactory::Instance().getAllPointGroupSymbols(PointGroup::Cubic); + TS_ASSERT_DIFFERS(findString(cubic, "cubicA"), cubic.end()); + TS_ASSERT_DIFFERS(findString(cubic, "cubicB"), cubic.end()); + + std::vector<std::string> triclinic = PointGroupFactory::Instance().getAllPointGroupSymbols(PointGroup::Triclinic); + TS_ASSERT_DIFFERS(findString(triclinic, "triclinic"), triclinic.end()); + } + + void testUnsubscribePointGroup() + { + TS_ASSERT_THROWS_NOTHING(PointGroupFactory::Instance().createPointgroup("cubicA")); + + PointGroupFactory::Instance().unsubscribePointgroup("cubicA"); + TS_ASSERT_THROWS(PointGroupFactory::Instance().create("cubicA"), Mantid::Kernel::Exception::NotFoundError); + + PointGroupFactory::Instance().subscribePointgroup<TestPointGroupCubicA>(); + TS_ASSERT_THROWS_NOTHING(PointGroupFactory::Instance().createPointgroup("cubicA")); + } + +private: + std::vector<std::string>::const_iterator findString(const std::vector<std::string> &vector, const std::string &searchString) + { + return std::find(vector.begin(), vector.end(), searchString); + } +}; + + +#endif /* MANTID_GEOMETRY_POINTGROUPFACTORYTEST_H_ */