Skip to content

Commit

Permalink
Refs #10504. SpaceGroupFactory now generates prototypes on demand.
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Wedel committed Dec 1, 2014
1 parent c456cea commit 4c21f89
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 21 deletions.
Expand Up @@ -13,6 +13,29 @@ namespace Mantid
namespace Geometry
{

struct MANTID_GEOMETRY_DLL SpaceGroupSubscriptionHelper
{
enum GenerationMethod {
Tabulated,
Generated
};

SpaceGroupSubscriptionHelper(size_t number,
const std::string &hmSymbol,
const std::string &generationInformation,
GenerationMethod generationMethod) :
number(number),
hmSymbol(hmSymbol),
generationInformation(generationInformation),
generationMethod(generationMethod)
{ }

size_t number;
std::string hmSymbol;
std::string generationInformation;
GenerationMethod generationMethod;
};

/** SpaceGroupFactory
Factory for SpaceGroups. When a space group is subscribed, it
Expand Down Expand Up @@ -52,7 +75,7 @@ class MANTID_GEOMETRY_DLL SpaceGroupFactoryImpl
public:
virtual ~SpaceGroupFactoryImpl() { }

SpaceGroup_const_sptr createSpaceGroup(const std::string &hmSymbol) const;
SpaceGroup_const_sptr createSpaceGroup(const std::string &hmSymbol);

bool isSubscribed(const std::string &hmSymbol) const;
bool isSubscribed(size_t number) const;
Expand All @@ -69,17 +92,26 @@ class MANTID_GEOMETRY_DLL SpaceGroupFactoryImpl
protected:
void throwIfSubscribed(const std::string &hmSymbol);

SpaceGroup_const_sptr generateValidPrototype(const std::string &hmSymbol) const;
Group_const_sptr generateValidGeneratedGroup(const std::string &hmSymbol, const std::string &generators) const;
Group_const_sptr generateValidTabulatedGroup(const std::string &generators) const;

void registerValidPrototype(const SpaceGroup_const_sptr &prototype);

std::string getCenteringString(const std::string &hmSymbol) const;
Group_const_sptr getGeneratedGroup(const std::string &generators, const std::string &centeringSymbol) const;
Group_const_sptr getTabulatedGroup(const std::string &symmetryOperations) const;

SpaceGroup_const_sptr getPrototype(Group_const_sptr generatingGroup, size_t number, const std::string &hmSymbol) const;

void subscribeGeneratorInformation(size_t number, const std::string &hmSymbol, const std::string &generators, SpaceGroupSubscriptionHelper::GenerationMethod method);
bool isValidGeneratorString(const std::string &generatorString) const;
void subscribe(const SpaceGroup_const_sptr &prototype);

SpaceGroup_const_sptr constructFromPrototype(const SpaceGroup_const_sptr prototype) const;

std::multimap<size_t, std::string> m_numberMap;
std::map<std::string, SpaceGroupSubscriptionHelper> m_generatorMap;
std::map<std::string, SpaceGroup_const_sptr> m_prototypes;

SpaceGroupFactoryImpl();
Expand Down
126 changes: 106 additions & 20 deletions Code/Mantid/Framework/Geometry/src/Crystal/SpaceGroupFactory.cpp
@@ -1,26 +1,36 @@
#include "MantidGeometry/Crystal/SpaceGroupFactory.h"
#include "MantidGeometry/Crystal/SymmetryOperationFactory.h"
#include "MantidGeometry/Crystal/SymmetryOperationSymbolParser.h"
#include "MantidKernel/Exception.h"

#include "MantidGeometry/Crystal/ProductOfCyclicGroups.h"
#include "MantidGeometry/Crystal/CenteringGroup.h"

#include "MantidKernel/LibraryManager.h"

#include <boost/make_shared.hpp>
#include <boost/algorithm/string.hpp>

namespace Mantid
{
namespace Geometry
{

/// Creates a space group given the Hermann-Mauguin symbol, throws std::invalid_argument if symbol is not registered.
SpaceGroup_const_sptr SpaceGroupFactoryImpl::createSpaceGroup(const std::string &hmSymbol) const
SpaceGroup_const_sptr SpaceGroupFactoryImpl::createSpaceGroup(const std::string &hmSymbol)
{
if(!isSubscribed(hmSymbol)) {
throw std::invalid_argument("Space group with symbol '" + hmSymbol + "' is not registered.");
}

return constructFromPrototype(m_prototypes.find(hmSymbol)->second);
SpaceGroup_const_sptr prototype = m_prototypes.find(hmSymbol)->second;

if(!prototype) {
prototype = generateValidPrototype(hmSymbol);

registerValidPrototype(prototype);
}

return constructFromPrototype(prototype);
}

/// Returns true if space group with given symbol is subscribed.
Expand Down Expand Up @@ -83,11 +93,15 @@ void SpaceGroupFactoryImpl::unsubscribeSpaceGroup(const std::string &hmSymbol)
}

auto eraseSymbol = m_prototypes.find(hmSymbol);
SpaceGroup_const_sptr spaceGroup = eraseSymbol->second;
m_prototypes.erase(eraseSymbol);

auto eraseGenerator = m_generatorMap.find(hmSymbol);
m_generatorMap.erase(eraseGenerator);

SpaceGroupSubscriptionHelper eraseHelper = eraseGenerator->second;
auto eraseNumber = m_numberMap.find(eraseHelper.number);

auto eraseNumber = m_numberMap.find(spaceGroup->number());
m_numberMap.erase(eraseNumber);
m_prototypes.erase(eraseSymbol);
}

/**
Expand All @@ -111,24 +125,15 @@ void SpaceGroupFactoryImpl::subscribeGeneratedSpaceGroup(size_t number, const st
{
throwIfSubscribed(hmSymbol);

// Generate factor group and centering group
std::string centeringSymbol = getCenteringString(hmSymbol);
Group_const_sptr generatingGroup = getGeneratedGroup(generators, centeringSymbol);

SpaceGroup_const_sptr prototype = getPrototype(generatingGroup, number, hmSymbol);
subscribe(prototype);
subscribeGeneratorInformation(number, hmSymbol, generators, SpaceGroupSubscriptionHelper::GenerationMethod::Generated);
}

/// Subscribes a "tabulated space group" into the factory where all symmetry operations need to be supplied, including centering.
void SpaceGroupFactoryImpl::subscribeTabulatedSpaceGroup(size_t number, const std::string &hmSymbol, const std::string &symmetryOperations)
{
throwIfSubscribed(hmSymbol);

// Generate a group using the supplied symmetry operations
Group_const_sptr generatingGroup = getTabulatedGroup(symmetryOperations);

SpaceGroup_const_sptr prototype = getPrototype(generatingGroup, number, hmSymbol);
subscribe(prototype);
subscribeGeneratorInformation(number, hmSymbol, symmetryOperations, SpaceGroupSubscriptionHelper::GenerationMethod::Tabulated);
}

/// Creatings a prototype instance of SpaceGroup using the supplied parameters.
Expand All @@ -141,6 +146,37 @@ SpaceGroup_const_sptr SpaceGroupFactoryImpl::getPrototype(Group_const_sptr gener
return boost::make_shared<const SpaceGroup>(number, hmSymbol, *generatingGroup);
}

/// Stores a SpaceGroupSubscriptionHelper object which contains all information required for generating a concrete space group.
void SpaceGroupFactoryImpl::subscribeGeneratorInformation(size_t number, const std::string &hmSymbol, const std::string &generators, SpaceGroupSubscriptionHelper::GenerationMethod method)
{
if(!isValidGeneratorString(generators)) {
throw std::invalid_argument("Generator contains elements that can not be parsed as symmetry operations: " + generators);
}

m_numberMap.insert(std::make_pair(number, hmSymbol));

SpaceGroup_const_sptr null;
m_prototypes.insert(std::make_pair(hmSymbol, null));

m_generatorMap.insert(std::make_pair(hmSymbol, SpaceGroupSubscriptionHelper(number, hmSymbol, generators, method)));
}

bool SpaceGroupFactoryImpl::isValidGeneratorString(const std::string &generatorString) const
{
std::vector<std::string> generatorStrings;
boost::split(generatorStrings, generatorString, boost::is_any_of(";"));

for(auto it = generatorStrings.begin(); it != generatorStrings.end(); ++it) {
try {
SymmetryOperationSymbolParser::parseIdentifier(*it);
} catch(Kernel::Exception::ParseError) {
return false;
}
}

return true;
}

/// Returns a copy-constructed instance of the supplied space group prototype object.
SpaceGroup_const_sptr SpaceGroupFactoryImpl::constructFromPrototype(const SpaceGroup_const_sptr prototype) const
{
Expand All @@ -155,10 +191,59 @@ void SpaceGroupFactoryImpl::throwIfSubscribed(const std::string &hmSymbol)
}
}

/// Stores the given prototype in the space group factory.
void SpaceGroupFactoryImpl::subscribe(const SpaceGroup_const_sptr &prototype)
/**
* Generates an actual prototype instance
*
* This method tries to create a space group prototype object from the information
* stored for generating the group. This method is used when a concrete space group
* is constructed for the first time and no prototype is available yet.
*
* @param hmSymbol :: Hermann-Mauguin symbol, has to be registered.
* @return Space group prototype object.
*/
SpaceGroup_const_sptr SpaceGroupFactoryImpl::generateValidPrototype(const std::string &hmSymbol) const
{
auto generationInformation = m_generatorMap.find(hmSymbol);

SpaceGroupSubscriptionHelper helper = generationInformation->second;
Group_const_sptr generatingGroup;

switch(helper.generationMethod) {
case SpaceGroupSubscriptionHelper::GenerationMethod::Generated:
generatingGroup = generateValidGeneratedGroup(hmSymbol, helper.generationInformation);
break;
case SpaceGroupSubscriptionHelper::GenerationMethod::Tabulated:
generatingGroup = generateValidTabulatedGroup(helper.generationInformation);
break;
}

if(!generatingGroup) {
throw std::runtime_error("Could not generate valid prototype. Aborting.");
}

return getPrototype(generatingGroup, helper.number, hmSymbol);
}

/// Generate a valid generated group from the generator and the HM-symbol using SpaceGroupFactory::getGeneratedGroup.
Group_const_sptr SpaceGroupFactoryImpl::generateValidGeneratedGroup(const std::string &hmSymbol, const std::string &generators) const
{
std::string centeringSymbol = getCenteringString(hmSymbol);
return getGeneratedGroup(generators, centeringSymbol);
}

/// Generate a valid tabulated group from the generator string which should be usable by SpaceGroupFactory::getTabulatedGroup.
Group_const_sptr SpaceGroupFactoryImpl::generateValidTabulatedGroup(const std::string &generators) const
{
m_numberMap.insert(std::make_pair(prototype->number(), prototype->hmSymbol()));
return getTabulatedGroup(generators);
}

/// Store prototype in the internal prototype-storage, replace any previously stored prototype with the same HM-symbol.
void SpaceGroupFactoryImpl::registerValidPrototype(const SpaceGroup_const_sptr &prototype)
{
if(!prototype) {
throw std::invalid_argument("Cannot register null-prototype.");
}

m_prototypes.insert(std::make_pair(prototype->hmSymbol(), prototype));
}

Expand Down Expand Up @@ -196,6 +281,7 @@ Group_const_sptr SpaceGroupFactoryImpl::getGeneratedGroup(const std::string &gen
/// Constructor cannot be called, since SingletonHolder is used.
SpaceGroupFactoryImpl::SpaceGroupFactoryImpl() :
m_numberMap(),
m_generatorMap(),
m_prototypes()
{
Kernel::LibraryManager::Instance();
Expand Down

0 comments on commit 4c21f89

Please sign in to comment.