diff --git a/Core/Computation/ParticleLayoutComputation.cpp b/Core/Computation/ParticleLayoutComputation.cpp
index 26db9d2a9f0fe84cd815412c77d0a396d3a66afa..1397aed4a96508b06e3bd03ea0c211ef9a119261 100644
--- a/Core/Computation/ParticleLayoutComputation.cpp
+++ b/Core/Computation/ParticleLayoutComputation.cpp
@@ -40,15 +40,11 @@ processedInterferenceFunction(const ProcessedLayout& layout, const SimulationOpt
 
     if (p_radial_para && p_radial_para->kappa() > 0.0) {
         double kappa = p_radial_para->kappa();
-        result = std::make_unique<SSCApproximationStrategy>(weighted_formfactors, p_iff, sim_params,
-                                                            polarized, kappa);
-    } else {
-        result = std::make_unique<DecouplingApproximationStrategy>(weighted_formfactors, p_iff,
-                                                                   sim_params, polarized);
+        return std::make_unique<SSCApproximationStrategy>(weighted_formfactors, p_iff, sim_params,
+                                                          polarized, kappa);
     }
-    if (!result)
-        throw Exceptions::ClassInitializationException("Could not create appropriate result");
-    return result;
+    return std::make_unique<DecouplingApproximationStrategy>(weighted_formfactors, p_iff,
+                                                             sim_params, polarized);
 }
 
 } // namespace
diff --git a/Core/Computation/ProcessedLayout.cpp b/Core/Computation/ProcessedLayout.cpp
index 045e881448c39562c0501a8ec5a8bd28548fc9ab..1c11512269566b5259b2cd24d6753df7e97a41c5 100644
--- a/Core/Computation/ProcessedLayout.cpp
+++ b/Core/Computation/ProcessedLayout.cpp
@@ -14,7 +14,7 @@
 
 #include "Core/Computation/ProcessedLayout.h"
 #include "Sample/Aggregate/IInterferenceFunction.h"
-#include "Sample/Correlations/ILayout.h"
+#include "Sample/Aggregate/ParticleLayout.h"
 #include "Sample/Fresnel/FormFactorCoherentSum.h"
 #include "Sample/Particle/IParticle.h"
 #include "Sample/Scattering/FormFactorBAPol.h"
@@ -28,7 +28,7 @@ namespace
 void ScaleRegionMap(std::map<size_t, std::vector<HomogeneousRegion>>& region_map, double factor);
 }
 
-ProcessedLayout::ProcessedLayout(const ILayout& layout, const std::vector<Slice>& slices,
+ProcessedLayout::ProcessedLayout(const ParticleLayout& layout, const std::vector<Slice>& slices,
                                  double z_ref, const IFresnelMap* p_fresnel_map, bool polarized)
     : m_fresnel_map(p_fresnel_map), m_polarized(polarized)
 {
@@ -76,8 +76,8 @@ std::map<size_t, std::vector<HomogeneousRegion>> ProcessedLayout::regionMap() co
 
 ProcessedLayout::~ProcessedLayout() = default;
 
-void ProcessedLayout::collectFormFactors(const ILayout& layout, const std::vector<Slice>& slices,
-                                         double z_ref)
+void ProcessedLayout::collectFormFactors(const ParticleLayout& layout,
+                                         const std::vector<Slice>& slices, double z_ref)
 {
     double layout_abundance = layout.getTotalAbundance();
     for (auto p_particle : layout.particles()) {
diff --git a/Core/Computation/ProcessedLayout.h b/Core/Computation/ProcessedLayout.h
index 54c01e3aa1f0619aa16b8e4c3f6542fb4543bd08..1cf8012537a4f1c181a307a2df762efee33454cf 100644
--- a/Core/Computation/ProcessedLayout.h
+++ b/Core/Computation/ProcessedLayout.h
@@ -23,7 +23,7 @@ class FormFactorCoherentSum;
 struct HomogeneousRegion;
 class IFresnelMap;
 class IInterferenceFunction;
-class ILayout;
+class ParticleLayout;
 class IParticle;
 class Slice;
 
@@ -37,7 +37,7 @@ class Slice;
 class ProcessedLayout
 {
 public:
-    ProcessedLayout(const ILayout& layout, const std::vector<Slice>& slices, double z_ref,
+    ProcessedLayout(const ParticleLayout& layout, const std::vector<Slice>& slices, double z_ref,
                     const IFresnelMap* p_fresnel_map, bool polarized);
     ProcessedLayout(ProcessedLayout&& other);
     ~ProcessedLayout();
@@ -49,7 +49,8 @@ public:
     std::map<size_t, std::vector<HomogeneousRegion>> regionMap() const;
 
 private:
-    void collectFormFactors(const ILayout& layout, const std::vector<Slice>& slices, double z_ref);
+    void collectFormFactors(const ParticleLayout& layout, const std::vector<Slice>& slices,
+                            double z_ref);
     FormFactorCoherentSum processParticle(const IParticle& particle,
                                           const std::vector<Slice>& slices, double z_ref);
     void mergeRegionMap(const std::map<size_t, std::vector<HomogeneousRegion>>& region_map);
diff --git a/Core/Export/OrderedMap.h b/Core/Export/OrderedMap.h
index 0fc22197462f39398ce8a456bd1cff5554be947e..c96b225103da76c30bbf4591c94f3bffea351596 100644
--- a/Core/Export/OrderedMap.h
+++ b/Core/Export/OrderedMap.h
@@ -65,20 +65,16 @@ public:
 
     iterator find(const Key& key)
     {
-        iterator result = m_list.end();
-        if (m_map.find(key) != m_map.end()) {
-            result = m_map[key];
-        }
-        return result;
+        if (m_map.find(key) != m_map.end())
+            return m_map[key];
+        return m_list.end();
     }
 
     const_iterator find(const Key& key) const
     {
-        const_iterator result = m_list.end();
-        if (m_map.find(key) != m_map.end()) {
-            result = m_map[key];
-        }
-        return result;
+        if (m_map.find(key) != m_map.end())
+            return m_map[key];
+        return m_list.end();
     }
 
     size_t erase(const Key& key)
@@ -95,9 +91,8 @@ public:
     const Object& value(const Key& key) const
     {
         typename map_t::const_iterator mit = m_map.find(key);
-        if (mit == m_map.end()) {
+        if (mit == m_map.end())
             throw std::runtime_error("OrderedMap::value() -> No such key");
-        }
         const_iterator it = mit->second;
         return (*it).second;
     }
diff --git a/Core/Export/SampleLabelHandler.cpp b/Core/Export/SampleLabelHandler.cpp
index e117c58ece483c247cc53e208fd3c2adf6fd16dc..05a58d3d80eb6d2356016bcbe1a4aa0b182565fb 100644
--- a/Core/Export/SampleLabelHandler.cpp
+++ b/Core/Export/SampleLabelHandler.cpp
@@ -43,9 +43,9 @@ std::string SampleLabelHandler::labelLayer(const Layer* layer)
     return m_LayerLabel[layer];
 }
 
-std::string SampleLabelHandler::labelLayout(const ILayout* layout)
+std::string SampleLabelHandler::labelLayout(const ParticleLayout* layout)
 {
-    return m_ILayoutLabel[layout];
+    return m_ParticleLayoutLabel[layout];
 }
 
 std::string SampleLabelHandler::labelMaterial(const Material* mat)
@@ -53,9 +53,14 @@ std::string SampleLabelHandler::labelMaterial(const Material* mat)
     return m_MaterialLabel[mat];
 }
 
-std::string SampleLabelHandler::labelLattice(const Lattice* lat)
+std::string SampleLabelHandler::labelLattice2D(const Lattice2D* lat)
 {
-    return m_LatticeLabel[lat];
+    return m_Lattice2DLabel[lat];
+}
+
+std::string SampleLabelHandler::labelLattice3D(const Lattice3D* lat)
+{
+    return m_Lattice3DLabel[lat];
 }
 
 std::string SampleLabelHandler::labelMultiLayer(const MultiLayer* ml)
@@ -107,16 +112,28 @@ void SampleLabelHandler::insertInterferenceFunction(const IInterferenceFunction*
     m_InterferenceFunctionLabel.insert(sample, label);
 }
 
+void SampleLabelHandler::insertLattice2D(const Lattice2D* sample)
+{
+    std::string label = "lattice2D_" + std::to_string(m_Lattice2DLabel.size() + 1);
+    m_Lattice2DLabel.insert(sample, label);
+}
+
+void SampleLabelHandler::insertLattice3D(const Lattice3D* sample)
+{
+    std::string label = "lattice3D_" + std::to_string(m_Lattice3DLabel.size() + 1);
+    m_Lattice3DLabel.insert(sample, label);
+}
+
 void SampleLabelHandler::insertLayer(const Layer* sample)
 {
     std::string label = "layer_" + std::to_string(m_LayerLabel.size() + 1);
     m_LayerLabel.insert(sample, label);
 }
 
-void SampleLabelHandler::insertLayout(const ILayout* sample)
+void SampleLabelHandler::insertLayout(const ParticleLayout* sample)
 {
-    std::string label = "layout_" + std::to_string(m_ILayoutLabel.size() + 1);
-    m_ILayoutLabel.insert(sample, label);
+    std::string label = "layout_" + std::to_string(m_ParticleLayoutLabel.size() + 1);
+    m_ParticleLayoutLabel.insert(sample, label);
 }
 
 void SampleLabelHandler::insertMaterial(const Material* mat)
@@ -136,12 +153,6 @@ void SampleLabelHandler::insertMaterial(const Material* mat)
     m_MaterialLabel.insert(mat, label);
 }
 
-void SampleLabelHandler::insertLattice(const Lattice* sample)
-{
-    std::string label = "lattice_" + std::to_string(m_LatticeLabel.size() + 1);
-    m_LatticeLabel.insert(sample, label);
-}
-
 void SampleLabelHandler::insertMesoCrystal(const MesoCrystal* sample)
 {
     std::string label = "mesocrystal_" + std::to_string(m_MesoCrystalLabel.size() + 1);
diff --git a/Core/Export/SampleLabelHandler.h b/Core/Export/SampleLabelHandler.h
index e93b0a8f65391e02f0fe729851823207569440ab..108708f7585db40dd86863253484b2a24b9480d9 100644
--- a/Core/Export/SampleLabelHandler.h
+++ b/Core/Export/SampleLabelHandler.h
@@ -22,10 +22,11 @@ class Crystal;
 class IAbstractParticle;
 class IFormFactor;
 class IInterferenceFunction;
-class ILayout;
+class ParticleLayout;
 class Material;
 class IRotation;
-class Lattice;
+class Lattice2D;
+class Lattice3D;
 class Layer;
 class LayerRoughness;
 class MultiLayer;
@@ -49,9 +50,10 @@ public:
     typedef LabelMap<const IFormFactor*> formfactors_t;
     typedef LabelMap<const IInterferenceFunction*> interferences_t;
     typedef LabelMap<const Layer*> layers_t;
-    typedef LabelMap<const ILayout*> layouts_t;
+    typedef LabelMap<const ParticleLayout*> layouts_t;
     typedef LabelMap<const Material*> materials_t;
-    typedef LabelMap<const Lattice*> lattices_t;
+    typedef LabelMap<const Lattice2D*> lattices2D_t;
+    typedef LabelMap<const Lattice3D*> lattices3D_t;
     typedef LabelMap<const MesoCrystal*> mesocrystals_t;
     typedef LabelMap<const MultiLayer*> multilayers_t;
     typedef LabelMap<const ParticleComposition*> particlecompositions_t;
@@ -66,9 +68,10 @@ public:
     formfactors_t* formFactorMap() { return &m_FormFactorLabel; }
     interferences_t* interferenceFunctionMap() { return &m_InterferenceFunctionLabel; }
     layers_t* layerMap() { return &m_LayerLabel; }
-    layouts_t* particleLayoutMap() { return &m_ILayoutLabel; }
+    layouts_t* particleLayoutMap() { return &m_ParticleLayoutLabel; }
     materials_t* materialMap() { return &m_MaterialLabel; }
-    lattices_t* latticeMap() { return &m_LatticeLabel; }
+    lattices2D_t* lattice2DMap() { return &m_Lattice2DLabel; }
+    lattices3D_t* lattice3DMap() { return &m_Lattice3DLabel; }
     mesocrystals_t* mesocrystalMap() { return &m_MesoCrystalLabel; }
     multilayers_t* multiLayerMap() { return &m_MultiLayerLabel; }
     particlecompositions_t* particleCompositionMap() { return &m_ParticleCompositionLabel; }
@@ -82,9 +85,10 @@ public:
     std::string labelFormFactor(const IFormFactor* sample);
     std::string labelInterferenceFunction(const IInterferenceFunction* sample);
     std::string labelLayer(const Layer* sample);
-    std::string labelLayout(const ILayout* sample);
+    std::string labelLayout(const ParticleLayout* sample);
     std::string labelMaterial(const Material* sample);
-    std::string labelLattice(const Lattice* sample);
+    std::string labelLattice2D(const Lattice2D* sample);
+    std::string labelLattice3D(const Lattice3D* sample);
     std::string labelMultiLayer(const MultiLayer* sample);
     std::string labelParticle(const IAbstractParticle* sample);
     std::string labelRotation(const IRotation* sample);
@@ -94,9 +98,10 @@ public:
     void insertFormFactor(const IFormFactor* sample);
     void insertInterferenceFunction(const IInterferenceFunction* sample);
     void insertLayer(const Layer* sample);
-    void insertLayout(const ILayout* sample);
+    void insertLayout(const ParticleLayout* sample);
     void insertMaterial(const Material* sample);
-    void insertLattice(const Lattice* sample);
+    void insertLattice2D(const Lattice2D* sample);
+    void insertLattice3D(const Lattice3D* sample);
     void insertMesoCrystal(const MesoCrystal* sample);
     void insertMultiLayer(const MultiLayer* sample);
     void insertParticleComposition(const ParticleComposition* sample);
@@ -111,9 +116,10 @@ private:
     formfactors_t m_FormFactorLabel;
     interferences_t m_InterferenceFunctionLabel;
     layers_t m_LayerLabel;
-    layouts_t m_ILayoutLabel;
+    layouts_t m_ParticleLayoutLabel;
     materials_t m_MaterialLabel;
-    lattices_t m_LatticeLabel;
+    lattices2D_t m_Lattice2DLabel;
+    lattices3D_t m_Lattice3DLabel;
     mesocrystals_t m_MesoCrystalLabel;
     multilayers_t m_MultiLayerLabel;
     particlecompositions_t m_ParticleCompositionLabel;
diff --git a/Core/Export/SampleToPython.cpp b/Core/Export/SampleToPython.cpp
index 4426a7dcaf9b2897ddbeb7264862785a484c9c75..11d9ef1d0632680cbcd0e74f0e5e64929c3d875c 100644
--- a/Core/Export/SampleToPython.cpp
+++ b/Core/Export/SampleToPython.cpp
@@ -54,7 +54,7 @@ void SampleToPython::initLabels(const MultiLayer& multilayer)
         m_label->insertRoughness(x);
     for (auto x : INodeUtils::AllDescendantsOfType<IFormFactor>(multilayer))
         m_label->insertFormFactor(x);
-    for (auto x : INodeUtils::AllDescendantsOfType<ILayout>(multilayer))
+    for (auto x : INodeUtils::AllDescendantsOfType<ParticleLayout>(multilayer))
         m_label->insertLayout(x);
     for (auto x : INodeUtils::AllDescendantsOfType<IInterferenceFunction>(multilayer))
         m_label->insertInterferenceFunction(x);
@@ -66,8 +66,10 @@ void SampleToPython::initLabels(const MultiLayer& multilayer)
         m_label->insertParticleComposition(x);
     for (auto x : INodeUtils::AllDescendantsOfType<ParticleDistribution>(multilayer))
         m_label->insertParticleDistribution(x);
-    for (auto x : INodeUtils::AllDescendantsOfType<Lattice>(multilayer))
-        m_label->insertLattice(x);
+    for (auto x : INodeUtils::AllDescendantsOfType<Lattice2D>(multilayer))
+        m_label->insertLattice2D(x);
+    for (auto x : INodeUtils::AllDescendantsOfType<Lattice3D>(multilayer))
+        m_label->insertLattice3D(x);
     for (auto x : INodeUtils::AllDescendantsOfType<Crystal>(multilayer))
         m_label->insertCrystal(x);
     for (auto x : INodeUtils::AllDescendantsOfType<MesoCrystal>(multilayer))
@@ -84,7 +86,8 @@ std::string SampleToPython::defineGetSample() const
 {
     return "def " + pyfmt::getSampleFunctionName() + "():\n" + defineMaterials() + defineLayers()
            + defineFormFactors() + defineParticles() + defineCoreShellParticles()
-           + defineParticleCompositions() + defineLattices() + defineCrystals()
+           + defineParticleCompositions() + defineLattices2D() + defineLattices3D()
+           + defineCrystals()
            + defineMesoCrystals() + defineParticleDistributions() + defineInterferenceFunctions()
            + defineParticleLayouts() + defineRoughnesses() + addLayoutsToLayers()
            + defineMultiLayers() + "\n\n";
@@ -101,29 +104,29 @@ std::string SampleToPython::defineMaterials() const
         return "# No Materials.\n\n";
     std::ostringstream result;
     result << std::setprecision(12);
-    result << indent() << "# Defining Materials\n";
+    result << indent() << "# Define Materials\n";
     std::set<std::string> visitedMaterials;
     for (auto it = themap->begin(); it != themap->end(); ++it) {
         if (visitedMaterials.find(it->second) != visitedMaterials.end())
             continue;
         visitedMaterials.insert(it->second);
-        const Material* p_material = it->first;
-        const auto factory_name = factory_names.find(p_material->typeID());
+        const Material* material = it->first;
+        const auto factory_name = factory_names.find(material->typeID());
         if (factory_name == factory_names.cend())
             throw std::runtime_error(
                 "Error in ExportToPython::defineMaterials(): unknown material type");
-        const complex_t& material_data = p_material->materialData();
-        if (p_material->isScalarMaterial()) {
-            result << indent() << m_label->labelMaterial(p_material) << " = ba."
-                   << factory_name->second << "(\"" << p_material->getName() << "\", "
+        const complex_t& material_data = material->materialData();
+        if (material->isScalarMaterial()) {
+            result << indent() << m_label->labelMaterial(material) << " = ba."
+                   << factory_name->second << "(\"" << material->getName() << "\", "
                    << pyfmt::printDouble(material_data.real()) << ", "
                    << pyfmt::printDouble(material_data.imag()) << ")\n";
         } else {
-            kvector_t magnetic_field = p_material->magnetization();
+            kvector_t magnetic_field = material->magnetization();
             result << indent() << "magnetic_field = kvector_t(" << magnetic_field.x() << ", "
                    << magnetic_field.y() << ", " << magnetic_field.z() << ")\n";
-            result << indent() << m_label->labelMaterial(p_material) << " = ba."
-                   << factory_name->second << "(\"" << p_material->getName();
+            result << indent() << m_label->labelMaterial(material) << " = ba."
+                   << factory_name->second << "(\"" << material->getName();
             result << "\", " << pyfmt::printDouble(material_data.real()) << ", "
                    << pyfmt::printDouble(material_data.imag()) << ", "
                    << "magnetic_field)\n";
@@ -139,7 +142,7 @@ std::string SampleToPython::defineLayers() const
         return "# No Layers.\n\n";
     std::ostringstream result;
     result << std::setprecision(12);
-    result << "\n" << indent() << "# Defining Layers\n";
+    result << "\n" << indent() << "# Define Layers\n";
     for (auto it = themap->begin(); it != themap->end(); ++it) {
         const Layer* layer = it->first;
         result << indent() << it->second << " = ba.Layer("
@@ -161,11 +164,11 @@ std::string SampleToPython::defineFormFactors() const
         return "";
     std::ostringstream result;
     result << std::setprecision(12);
-    result << "\n" << indent() << "# Defining Form Factors\n";
+    result << "\n" << indent() << "# Define Form Factors\n";
     for (auto it = themap->begin(); it != themap->end(); ++it) {
-        const IFormFactor* p_ff = it->first;
-        result << indent() << it->second << " = ba.FormFactor" << p_ff->getName() << "("
-               << pyfmt2::argumentList(p_ff) << ")\n";
+        const IFormFactor* ff = it->first;
+        result << indent() << it->second << " = ba.FormFactor" << ff->getName() << "("
+               << pyfmt2::argumentList(ff) << ")\n";
     }
     return result.str();
 }
@@ -177,18 +180,18 @@ std::string SampleToPython::defineParticles() const
         return "";
     std::ostringstream result;
     result << std::setprecision(12);
-    result << "\n" << indent() << "# Defining Particles\n";
+    result << "\n" << indent() << "# Define Particles\n";
     for (auto it = themap->begin(); it != themap->end(); ++it) {
-        const Particle* p_particle = it->first;
+        const Particle* particle = it->first;
         std::string particle_name = it->second;
-        auto p_ff = INodeUtils::OnlyChildOfType<IFormFactor>(*p_particle);
-        if (!p_ff)
+        auto ff = INodeUtils::OnlyChildOfType<IFormFactor>(*particle);
+        if (!ff)
             continue;
         result << indent() << particle_name << " = ba.Particle("
-               << m_label->labelMaterial(p_particle->material()) << ", "
-               << m_label->labelFormFactor(p_ff) << ")\n";
-        setRotationInformation(p_particle, particle_name, result);
-        setPositionInformation(p_particle, particle_name, result);
+               << m_label->labelMaterial(particle->material()) << ", "
+               << m_label->labelFormFactor(ff) << ")\n";
+        setRotationInformation(particle, particle_name, result);
+        setPositionInformation(particle, particle_name, result);
     }
     return result.str();
 }
@@ -200,16 +203,16 @@ std::string SampleToPython::defineCoreShellParticles() const
         return "";
     std::ostringstream result;
     result << std::setprecision(12);
-    result << "\n" << indent() << "# Defining Core Shell Particles\n";
+    result << "\n" << indent() << "# Define Core Shell Particles\n";
     for (auto it = themap->begin(); it != themap->end(); ++it) {
-        const ParticleCoreShell* p_coreshell = it->first;
+        const ParticleCoreShell* coreshell = it->first;
         result << "\n"
                << indent() << it->second << " = ba.ParticleCoreShell("
-               << m_label->labelParticle(p_coreshell->shellParticle()) << ", "
-               << m_label->labelParticle(p_coreshell->coreParticle()) << ")\n";
+               << m_label->labelParticle(coreshell->shellParticle()) << ", "
+               << m_label->labelParticle(coreshell->coreParticle()) << ")\n";
         std::string core_shell_name = it->second;
-        setRotationInformation(p_coreshell, core_shell_name, result);
-        setPositionInformation(p_coreshell, core_shell_name, result);
+        setRotationInformation(coreshell, core_shell_name, result);
+        setPositionInformation(coreshell, core_shell_name, result);
     }
     return result.str();
 }
@@ -222,15 +225,15 @@ std::string SampleToPython::defineParticleDistributions() const
 
     std::ostringstream result;
     result << std::setprecision(12);
-    result << "\n" << indent() << "# Defining particles with parameter following a distribution\n";
+    result << "\n" << indent() << "# Define particles with parameter following a distribution\n";
 
     int index(1);
     for (auto it = themap->begin(); it != themap->end(); ++it) {
-        const ParticleDistribution* p_particle_distr = it->first;
+        const ParticleDistribution* particle_distr = it->first;
 
-        const std::string units = p_particle_distr->mainUnits();
+        const std::string units = particle_distr->mainUnits();
 
-        ParameterDistribution par_distr = p_particle_distr->parameterDistribution();
+        ParameterDistribution par_distr = particle_distr->parameterDistribution();
 
         // building distribution functions
         std::string s_distr = "distr_" + std::to_string(index);
@@ -252,11 +255,11 @@ std::string SampleToPython::defineParticleDistributions() const
             result << "\n";
         }
 
-        auto p_particle = INodeUtils::OnlyChildOfType<IParticle>(*p_particle_distr);
-        if (!p_particle)
+        auto particle = INodeUtils::OnlyChildOfType<IParticle>(*particle_distr);
+        if (!particle)
             continue;
         result << indent() << it->second << " = ba.ParticleDistribution("
-               << m_label->labelParticle(p_particle) << ", " << s_par_distr << ")\n";
+               << m_label->labelParticle(particle) << ", " << s_par_distr << ")\n";
         index++;
     }
     return result.str();
@@ -269,37 +272,58 @@ std::string SampleToPython::defineParticleCompositions() const
         return "";
     std::ostringstream result;
     result << std::setprecision(12);
-    result << "\n" << indent() << "# Defining composition of particles at specific positions\n";
+    result << "\n" << indent() << "# Define composition of particles at specific positions\n";
     for (auto it = themap->begin(); it != themap->end(); ++it) {
-        const ParticleComposition* p_particle_composition = it->first;
+        const ParticleComposition* particle_composition = it->first;
         std::string particle_composition_name = it->second;
         result << indent() << particle_composition_name << " = ba.ParticleComposition()\n";
-        auto particle_list = INodeUtils::ChildNodesOfType<IParticle>(*p_particle_composition);
-        for (auto p_particle : particle_list) {
+        auto particle_list = INodeUtils::ChildNodesOfType<IParticle>(*particle_composition);
+        for (auto particle : particle_list) {
             result << indent() << particle_composition_name << ".addParticle("
-                   << m_label->labelParticle(p_particle) << ")\n";
+                   << m_label->labelParticle(particle) << ")\n";
         }
-        setRotationInformation(p_particle_composition, particle_composition_name, result);
-        setPositionInformation(p_particle_composition, particle_composition_name, result);
+        setRotationInformation(particle_composition, particle_composition_name, result);
+        setPositionInformation(particle_composition, particle_composition_name, result);
     }
     return result.str();
 }
 
-std::string SampleToPython::defineLattices() const
+std::string SampleToPython::defineLattices2D() const
 {
-    const auto themap = m_label->latticeMap();
+    const auto themap = m_label->lattice2DMap();
     if (themap->empty())
         return "";
     std::ostringstream result;
     result << std::setprecision(12);
-    result << "\n" << indent() << "# Defining 3D lattices\n";
+    result << "\n" << indent() << "# Define 2D lattices\n";
     for (auto it = themap->begin(); it != themap->end(); ++it) {
-        const Lattice* p_lattice = it->first;
+        const Lattice2D* lattice = it->first;
         std::string lattice_name = it->second;
-        kvector_t bas_a = p_lattice->getBasisVectorA();
-        kvector_t bas_b = p_lattice->getBasisVectorB();
-        kvector_t bas_c = p_lattice->getBasisVectorC();
-        result << indent() << lattice_name << " = ba.Lattice(\n";
+        result << indent() << lattice_name << " = ba.BasicLattice(\n";
+        result << indent() << indent()
+               << pyfmt::printNm(lattice->length1()) << ", "
+               << pyfmt::printNm(lattice->length2()) << ", "
+               << pyfmt::printDegrees(lattice->latticeAngle()) << ", "
+               << pyfmt::printDegrees(lattice->rotationAngle()) << "),\n";
+    }
+    return result.str();
+}
+
+std::string SampleToPython::defineLattices3D() const
+{
+    const auto themap = m_label->lattice3DMap();
+    if (themap->empty())
+        return "";
+    std::ostringstream result;
+    result << std::setprecision(12);
+    result << "\n" << indent() << "# Define 3D lattices\n";
+    for (auto it = themap->begin(); it != themap->end(); ++it) {
+        const Lattice3D* lattice = it->first;
+        std::string lattice_name = it->second;
+        kvector_t bas_a = lattice->getBasisVectorA();
+        kvector_t bas_b = lattice->getBasisVectorB();
+        kvector_t bas_c = lattice->getBasisVectorC();
+        result << indent() << lattice_name << " = ba.Lattice3D(\n";
         result << indent() << indent() << "ba.kvector_t(" << pyfmt::printNm(bas_a.x()) << ", "
                << pyfmt::printNm(bas_a.y()) << ", " << pyfmt::printNm(bas_a.z()) << "),\n";
         result << indent() << indent() << "ba.kvector_t(" << pyfmt::printNm(bas_b.x()) << ", "
@@ -317,17 +341,17 @@ std::string SampleToPython::defineCrystals() const
         return "";
     std::ostringstream result;
     result << std::setprecision(12);
-    result << "\n" << indent() << "# Defining crystals: basis particle + lattice\n";
+    result << "\n" << indent() << "# Define crystals: basis particle + lattice\n";
     for (auto it = themap->begin(); it != themap->end(); ++it) {
-        const Crystal* p_crystal = it->first;
+        const Crystal* crystal = it->first;
         std::string crystal_name = it->second;
-        auto p_lattice = INodeUtils::OnlyChildOfType<Lattice>(*p_crystal);
-        auto p_basis = INodeUtils::OnlyChildOfType<IParticle>(*p_crystal);
-        if (!p_lattice || !p_basis)
+        auto lattice = INodeUtils::OnlyChildOfType<Lattice3D>(*crystal);
+        auto basis = INodeUtils::OnlyChildOfType<IParticle>(*crystal);
+        if (!lattice || !basis)
             continue;
         result << indent() << crystal_name << " = ba.Crystal(";
-        result << m_label->labelParticle(p_basis) << ", ";
-        result << m_label->labelLattice(p_lattice) << ")\n";
+        result << m_label->labelParticle(basis) << ", ";
+        result << m_label->labelLattice3D(lattice) << ")\n";
     }
     return result.str();
 }
@@ -339,19 +363,19 @@ std::string SampleToPython::defineMesoCrystals() const
         return "";
     std::ostringstream result;
     result << std::setprecision(12);
-    result << "\n" << indent() << "# Defining mesocrystals\n";
+    result << "\n" << indent() << "# Define mesocrystals\n";
     for (auto it = themap->begin(); it != themap->end(); ++it) {
-        const MesoCrystal* p_mesocrystal = it->first;
+        const MesoCrystal* mesocrystal = it->first;
         std::string mesocrystal_name = it->second;
-        auto p_crystal = INodeUtils::OnlyChildOfType<Crystal>(*p_mesocrystal);
-        auto p_outer_shape = INodeUtils::OnlyChildOfType<IFormFactor>(*p_mesocrystal);
-        if (!p_crystal || !p_outer_shape)
+        auto crystal = INodeUtils::OnlyChildOfType<Crystal>(*mesocrystal);
+        auto outer_shape = INodeUtils::OnlyChildOfType<IFormFactor>(*mesocrystal);
+        if (!crystal || !outer_shape)
             continue;
         result << indent() << mesocrystal_name << " = ba.MesoCrystal(";
-        result << m_label->labelCrystal(p_crystal) << ", ";
-        result << m_label->labelFormFactor(p_outer_shape) << ")\n";
-        setRotationInformation(p_mesocrystal, mesocrystal_name, result);
-        setPositionInformation(p_mesocrystal, mesocrystal_name, result);
+        result << m_label->labelCrystal(crystal) << ", ";
+        result << m_label->labelFormFactor(outer_shape) << ")\n";
+        setRotationInformation(mesocrystal, mesocrystal_name, result);
+        setPositionInformation(mesocrystal, mesocrystal_name, result);
     }
     return result.str();
 }
@@ -363,91 +387,91 @@ std::string SampleToPython::defineInterferenceFunctions() const
         return "";
     std::ostringstream result;
     result << std::setprecision(12);
-    result << "\n" << indent() << "# Defining Interference Functions\n";
+    result << "\n" << indent() << "# Define Interference Functions\n";
     for (auto it = themap->begin(); it != themap->end(); ++it) {
         const IInterferenceFunction* interference = it->first;
 
         if (dynamic_cast<const InterferenceFunctionNone*>(interference))
             result << indent() << it->second << " = ba.InterferenceFunctionNone()\n";
-        else if (auto p_lattice_1d =
+        else if (auto lattice_1d =
                      dynamic_cast<const InterferenceFunction1DLattice*>(interference)) {
             result << indent() << it->second << " = ba.InterferenceFunction1DLattice("
-                   << pyfmt::printNm(p_lattice_1d->getLength()) << ", "
-                   << pyfmt::printDegrees(p_lattice_1d->getXi()) << ")\n";
+                   << pyfmt::printNm(lattice_1d->getLength()) << ", "
+                   << pyfmt::printDegrees(lattice_1d->getXi()) << ")\n";
 
-            auto pdf = INodeUtils::OnlyChildOfType<IFTDecayFunction1D>(*p_lattice_1d);
+            auto pdf = INodeUtils::OnlyChildOfType<IFTDecayFunction1D>(*lattice_1d);
 
             if (pdf->decayLength() != 0.0)
                 result << indent() << it->second << "_pdf  = ba." << pdf->getName() << "("
                        << pyfmt2::argumentList(pdf) << ")\n"
                        << indent() << it->second << ".setDecayFunction(" << it->second << "_pdf)\n";
-        } else if (auto p_para_radial =
+        } else if (auto para_radial =
                        dynamic_cast<const InterferenceFunctionRadialParaCrystal*>(interference)) {
             result << indent() << it->second << " = ba.InterferenceFunctionRadialParaCrystal("
-                   << pyfmt::printNm(p_para_radial->peakDistance()) << ", "
-                   << pyfmt::printNm(p_para_radial->dampingLength()) << ")\n";
+                   << pyfmt::printNm(para_radial->peakDistance()) << ", "
+                   << pyfmt::printNm(para_radial->dampingLength()) << ")\n";
 
-            if (p_para_radial->kappa() != 0.0)
+            if (para_radial->kappa() != 0.0)
                 result << indent() << it->second << ".setKappa("
-                       << pyfmt::printDouble(p_para_radial->kappa()) << ")\n";
+                       << pyfmt::printDouble(para_radial->kappa()) << ")\n";
 
-            if (p_para_radial->domainSize() != 0.0)
+            if (para_radial->domainSize() != 0.0)
                 result << indent() << it->second << ".setDomainSize("
-                       << pyfmt::printDouble(p_para_radial->domainSize()) << ")\n";
+                       << pyfmt::printDouble(para_radial->domainSize()) << ")\n";
 
-            auto pdf = INodeUtils::OnlyChildOfType<IFTDistribution1D>(*p_para_radial);
+            auto pdf = INodeUtils::OnlyChildOfType<IFTDistribution1D>(*para_radial);
 
             if (pdf->omega() != 0.0)
                 result << indent() << it->second << "_pdf  = ba." << pdf->getName() << "("
                        << pyfmt2::argumentList(pdf) << ")\n"
                        << indent() << it->second << ".setProbabilityDistribution(" << it->second
                        << "_pdf)\n";
-        } else if (auto p_lattice_2d =
+        } else if (auto lattice_2d =
                        dynamic_cast<const InterferenceFunction2DLattice*>(interference)) {
-            const Lattice2D& lattice = p_lattice_2d->lattice();
+            const Lattice2D& lattice = lattice_2d->lattice();
             result << indent() << it->second << " = ba.InterferenceFunction2DLattice("
                    << pyfmt::printNm(lattice.length1()) << ", " << pyfmt::printNm(lattice.length2())
                    << ", " << pyfmt::printDegrees(lattice.latticeAngle()) << ", "
                    << pyfmt::printDegrees(lattice.rotationAngle()) << ")\n";
 
-            auto pdf = INodeUtils::OnlyChildOfType<IFTDecayFunction2D>(*p_lattice_2d);
+            auto pdf = INodeUtils::OnlyChildOfType<IFTDecayFunction2D>(*lattice_2d);
 
             result << indent() << it->second << "_pdf  = ba." << pdf->getName() << "("
                    << pyfmt2::argumentList(pdf) << ")\n"
                    << indent() << it->second << ".setDecayFunction(" << it->second << "_pdf)\n";
 
-            if (p_lattice_2d->integrationOverXi() == true)
+            if (lattice_2d->integrationOverXi() == true)
                 result << indent() << it->second << ".setIntegrationOverXi(True)\n";
-        } else if (auto p_lattice_2d =
+        } else if (auto lattice_2d =
                        dynamic_cast<const InterferenceFunctionFinite2DLattice*>(interference)) {
-            const Lattice2D& lattice = p_lattice_2d->lattice();
+            const Lattice2D& lattice = lattice_2d->lattice();
             result << indent() << it->second << " = ba.InterferenceFunctionFinite2DLattice("
                    << pyfmt::printNm(lattice.length1()) << ", " << pyfmt::printNm(lattice.length2())
                    << ", " << pyfmt::printDegrees(lattice.latticeAngle()) << ", "
                    << pyfmt::printDegrees(lattice.rotationAngle()) << ", "
-                   << p_lattice_2d->numberUnitCells1() << ", " << p_lattice_2d->numberUnitCells2()
+                   << lattice_2d->numberUnitCells1() << ", " << lattice_2d->numberUnitCells2()
                    << ")\n";
 
-            if (p_lattice_2d->integrationOverXi() == true)
+            if (lattice_2d->integrationOverXi() == true)
                 result << indent() << it->second << ".setIntegrationOverXi(True)\n";
-        } else if (auto p_para_2d =
+        } else if (auto para_2d =
                        dynamic_cast<const InterferenceFunction2DParaCrystal*>(interference)) {
-            std::vector<double> domainSize = p_para_2d->domainSizes();
-            const Lattice2D& lattice = p_para_2d->lattice();
+            std::vector<double> domainSize = para_2d->domainSizes();
+            const Lattice2D& lattice = para_2d->lattice();
             result << indent() << it->second << " = ba.InterferenceFunction2DParaCrystal("
                    << pyfmt::printNm(lattice.length1()) << ", " << pyfmt::printNm(lattice.length2())
                    << ", " << pyfmt::printDegrees(lattice.latticeAngle()) << ", "
                    << pyfmt::printDegrees(lattice.rotationAngle()) << ", "
-                   << pyfmt::printNm(p_para_2d->dampingLength()) << ")\n";
+                   << pyfmt::printNm(para_2d->dampingLength()) << ")\n";
 
             if (domainSize[0] != 0.0 || domainSize[1] != 0.0)
                 result << indent() << it->second << ".setDomainSizes("
                        << pyfmt::printNm(domainSize[0]) << ", " << pyfmt::printNm(domainSize[1])
                        << ")\n";
-            if (p_para_2d->integrationOverXi() == true)
+            if (para_2d->integrationOverXi() == true)
                 result << indent() << it->second << ".setIntegrationOverXi(True)\n";
 
-            auto pdf_vector = INodeUtils::ChildNodesOfType<IFTDistribution2D>(*p_para_2d);
+            auto pdf_vector = INodeUtils::ChildNodesOfType<IFTDistribution2D>(*para_2d);
             if (pdf_vector.size() != 2)
                 continue;
             const IFTDistribution2D* pdf = pdf_vector[0];
@@ -461,11 +485,11 @@ std::string SampleToPython::defineInterferenceFunctions() const
                    << pyfmt2::argumentList(pdf) << ")\n";
             result << indent() << it->second << ".setProbabilityDistributions(" << it->second
                    << "_pdf_1, " << it->second << "_pdf_2)\n";
-        } else if (auto p_lattice_hd =
+        } else if (auto lattice_hd =
                        dynamic_cast<const InterferenceFunctionHardDisk*>(interference)) {
             result << indent() << it->second << " = ba.InterferenceFunctionHardDisk("
-                   << pyfmt::printNm(p_lattice_hd->radius()) << ", "
-                   << pyfmt::printDouble(p_lattice_hd->density()) << ")\n";
+                   << pyfmt::printNm(lattice_hd->radius()) << ", "
+                   << pyfmt::printDouble(lattice_hd->density()) << ")\n";
         } else
             throw Exceptions::NotImplementedException(
                 "Bug: ExportToPython::defineInterferenceFunctions() called with unexpected "
@@ -486,22 +510,22 @@ std::string SampleToPython::defineParticleLayouts() const
         return "";
     std::ostringstream result;
     result << std::setprecision(12);
-    result << "\n" << indent() << "# Defining Particle Layouts and adding Particles\n";
+    result << "\n" << indent() << "# Define Particle Layouts and adding Particles\n";
     for (auto it = themap->begin(); it != themap->end(); ++it) {
-        const ILayout* iLayout = it->first;
+        const ParticleLayout* iLayout = it->first;
         if (const ParticleLayout* particleLayout = dynamic_cast<const ParticleLayout*>(iLayout)) {
             result << indent() << it->second << " = ba.ParticleLayout()\n";
             auto particles = INodeUtils::ChildNodesOfType<IAbstractParticle>(*particleLayout);
 
-            for (auto p_particle : particles) {
-                double abundance = p_particle->abundance();
+            for (auto particle : particles) {
+                double abundance = particle->abundance();
                 result << indent() << it->second << ".addParticle("
-                       << m_label->labelParticle(p_particle) << ", "
+                       << m_label->labelParticle(particle) << ", "
                        << pyfmt::printDouble(abundance) << ")\n";
             }
-            if (auto p_iff = INodeUtils::OnlyChildOfType<IInterferenceFunction>(*particleLayout))
+            if (auto iff = INodeUtils::OnlyChildOfType<IInterferenceFunction>(*particleLayout))
                 result << indent() << it->second << ".setInterferenceFunction("
-                       << m_label->labelInterferenceFunction(p_iff) << ")\n";
+                       << m_label->labelInterferenceFunction(iff) << ")\n";
             result << indent() << it->second << ".setWeight(" << particleLayout->weight() << ")\n";
             result << indent() << it->second << ".setTotalParticleSurfaceDensity("
                    << particleLayout->totalParticleSurfaceDensity() << ")\n";
@@ -517,7 +541,7 @@ std::string SampleToPython::defineRoughnesses() const
         return "";
     std::ostringstream result;
     result << std::setprecision(12);
-    result << "\n" << indent() << "# Defining Roughness Parameters\n";
+    result << "\n" << indent() << "# Define Roughness Parameters\n";
     for (auto it = themap->begin(); it != themap->end(); ++it)
         result << indent() << it->second << " = ba.LayerRoughness("
                << pyfmt2::argumentList(it->first) << ")\n";
@@ -530,13 +554,13 @@ std::string SampleToPython::addLayoutsToLayers() const
         return "";
     std::ostringstream result;
     result << std::setprecision(12);
-    result << "\n" << indent() << "# Adding layouts to layers";
+    result << "\n" << indent() << "# Add layouts to layers";
     const auto layermap = m_label->layerMap();
     for (auto it = layermap->begin(); it != layermap->end(); ++it) {
         const Layer* layer = it->first;
-        for (auto p_layout : layer->layouts())
+        for (auto layout : layer->layouts())
             result << "\n"
-                   << indent() << it->second << ".addLayout(" << m_label->labelLayout(p_layout)
+                   << indent() << it->second << ".addLayout(" << m_label->labelLayout(layout)
                    << ")\n";
     }
     return result.str();
@@ -549,7 +573,7 @@ std::string SampleToPython::defineMultiLayers() const
         return "# No MultiLayers.\n\n";
     std::ostringstream result;
     result << std::setprecision(12);
-    result << "\n" << indent() << "# Defining Multilayers\n";
+    result << "\n" << indent() << "# Define Multilayers\n";
     for (auto it = themap->begin(); it != themap->end(); ++it) {
         result << indent() << it->second << " = ba.MultiLayer()\n";
         double ccl = it->first->crossCorrLength();
@@ -593,33 +617,33 @@ std::string SampleToPython::indent() const
     return "    ";
 }
 
-void SampleToPython::setRotationInformation(const IParticle* p_particle, std::string name,
+void SampleToPython::setRotationInformation(const IParticle* particle, std::string name,
                                             std::ostringstream& result) const
 {
-    if (p_particle->rotation()) {
-        switch (p_particle->rotation()->getTransform3D().getRotationType()) {
+    if (particle->rotation()) {
+        switch (particle->rotation()->getTransform3D().getRotationType()) {
         case Transform3D::EULER: {
             double alpha, beta, gamma;
-            p_particle->rotation()->getTransform3D().calculateEulerAngles(&alpha, &beta, &gamma);
+            particle->rotation()->getTransform3D().calculateEulerAngles(&alpha, &beta, &gamma);
             result << indent() << name << "_rotation = ba.RotationEuler("
                    << pyfmt::printDegrees(alpha) << ", " << pyfmt::printDegrees(beta) << ", "
                    << pyfmt::printDegrees(gamma) << ")\n";
             break;
         }
         case Transform3D::XAXIS: {
-            double alpha = p_particle->rotation()->getTransform3D().calculateRotateXAngle();
+            double alpha = particle->rotation()->getTransform3D().calculateRotateXAngle();
             result << indent() << name << "_rotation = ba.RotationX(" << pyfmt::printDegrees(alpha)
                    << ")\n";
             break;
         }
         case Transform3D::YAXIS: {
-            double alpha = p_particle->rotation()->getTransform3D().calculateRotateYAngle();
+            double alpha = particle->rotation()->getTransform3D().calculateRotateYAngle();
             result << indent() << name << "_rotation = ba.RotationY(" << pyfmt::printDegrees(alpha)
                    << ")\n";
             break;
         }
         case Transform3D::ZAXIS: {
-            double alpha = p_particle->rotation()->getTransform3D().calculateRotateZAngle();
+            double alpha = particle->rotation()->getTransform3D().calculateRotateZAngle();
             result << indent() << name << "_rotation = ba.RotationZ(" << pyfmt::printDegrees(alpha)
                    << ")\n";
             break;
@@ -629,16 +653,14 @@ void SampleToPython::setRotationInformation(const IParticle* p_particle, std::st
     }
 }
 
-void SampleToPython::setPositionInformation(const IParticle* p_particle, std::string name,
+void SampleToPython::setPositionInformation(const IParticle* particle, std::string name,
                                             std::ostringstream& result) const
 {
-    kvector_t pos = p_particle->position();
-    bool has_position_info = (pos != kvector_t());
-
-    if (has_position_info) {
-        result << indent() << name << "_position = kvector_t(" << pyfmt::printNm(pos.x()) << ", "
-               << pyfmt::printNm(pos.y()) << ", " << pyfmt::printNm(pos.z()) << ")\n";
+    kvector_t pos = particle->position();
+    if (pos == kvector_t())
+        return;
 
-        result << indent() << name << ".setPosition(" << name << "_position)\n";
-    }
+    result << indent() << name << "_position = kvector_t(" << pyfmt::printNm(pos.x()) << ", "
+           << pyfmt::printNm(pos.y()) << ", " << pyfmt::printNm(pos.z()) << ")\n";
+    result << indent() << name << ".setPosition(" << name << "_position)\n";
 }
diff --git a/Core/Export/SampleToPython.h b/Core/Export/SampleToPython.h
index 4f9caa5b3b39aa7e9f250df3573492aae7148b54..f60aaeaa742a80d1b108f59835826dbaadae4105 100644
--- a/Core/Export/SampleToPython.h
+++ b/Core/Export/SampleToPython.h
@@ -43,7 +43,8 @@ private:
     std::string defineCoreShellParticles() const;
     std::string defineParticleDistributions() const;
     std::string defineParticleCompositions() const;
-    std::string defineLattices() const;
+    std::string defineLattices2D() const;
+    std::string defineLattices3D() const;
     std::string defineCrystals() const;
     std::string defineMesoCrystals() const;
     std::string defineInterferenceFunctions() const;
diff --git a/Core/Simulation/StandardSimulations.cpp b/Core/Simulation/StandardSimulations.cpp
index 39aadc5f64ac94efcfc49034ad90a8f4e5153fab..e516720542e768f85f8a0df37504b07c5e9ecc9d 100644
--- a/Core/Simulation/StandardSimulations.cpp
+++ b/Core/Simulation/StandardSimulations.cpp
@@ -49,9 +49,9 @@ const double rdet_width(20.0), rdet_height(18.0), rdet_distance(1000.0);
 GISASSimulation* StandardSimulations::BasicGISAS()
 {
     GISASSimulation* result = new GISASSimulation();
-    result->setDetectorParameters(100, 0.0 * Units::degree, 2.0 * Units::degree, 100,
-                                  0.0 * Units::degree, 2.0 * Units::degree);
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setDetectorParameters(100, 0.0 * Units::deg, 2.0 * Units::deg, 100, 0.0 * Units::deg,
+                                  2.0 * Units::deg);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
     return result;
 }
 
@@ -82,9 +82,9 @@ GISASSimulation* StandardSimulations::BasicPolarizedGISAS()
 GISASSimulation* StandardSimulations::MiniGISAS()
 {
     GISASSimulation* result = new GISASSimulation();
-    result->setDetectorParameters(25, -2.0 * Units::degree, 2.0 * Units::degree, 25,
-                                  0.0 * Units::degree, 2.0 * Units::degree);
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setDetectorParameters(25, -2.0 * Units::deg, 2.0 * Units::deg, 25, 0.0 * Units::deg,
+                                  2.0 * Units::deg);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
     return result;
 }
 
@@ -93,9 +93,9 @@ GISASSimulation* StandardSimulations::MiniGISAS()
 GISASSimulation* StandardSimulations::MiniGISAS_v2()
 {
     GISASSimulation* result = new GISASSimulation();
-    result->setDetectorParameters(25, -1.0 * Units::degree, 1.0 * Units::degree, 25,
-                                  0.0 * Units::degree, 1.0 * Units::degree);
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setDetectorParameters(25, -1.0 * Units::deg, 1.0 * Units::deg, 25, 0.0 * Units::deg,
+                                  1.0 * Units::deg);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
     return result;
 }
 
@@ -106,8 +106,8 @@ GISASSimulation* StandardSimulations::MiniGISASBeamDivergence()
     GISASSimulation* result = MiniGISAS();
 
     DistributionLogNormal wavelength_distr(1.0 * Units::angstrom, 0.1);
-    DistributionGaussian alpha_distr(0.2 * Units::degree, 0.02 * Units::degree);
-    DistributionGate phi_distr(-0.1 * Units::degree, 0.02 * Units::degree);
+    DistributionGaussian alpha_distr(0.2 * Units::deg, 0.02 * Units::deg);
+    DistributionGate phi_distr(-0.1 * Units::deg, 0.02 * Units::deg);
 
     ParameterPattern pattern1;
     pattern1.beginsWith("*").add("Beam").add("Wavelength");
@@ -127,14 +127,14 @@ GISASSimulation* StandardSimulations::MiniGISASBeamDivergence()
 GISASSimulation* StandardSimulations::GISASWithMasks()
 {
     GISASSimulation* result = new GISASSimulation();
-    result->setDetectorParameters(50, -1.0 * Units::degree, 1.0 * Units::degree, 50,
-                                  0.0 * Units::degree, 2.0 * Units::degree);
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setDetectorParameters(50, -1.0 * Units::deg, 1.0 * Units::deg, 50, 0.0 * Units::deg,
+                                  2.0 * Units::deg);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
     result->setBeamIntensity(1e+7);
 
     result->maskAll();
     // pacman
-    const double deg = Units::degree;
+    const double deg = Units::deg;
     result->addMask(Ellipse(0.0 * deg, 1.0 * deg, 0.5 * deg, 0.5 * deg), false);
     result->addMask(Ellipse(0.11 * deg, 1.25 * deg, 0.05 * deg, 0.05 * deg), true);
 
@@ -219,9 +219,9 @@ GISASSimulation* StandardSimulations::MiniGISASPolarizationMM()
 GISASSimulation* StandardSimulations::MiniGISASSpecularPeak()
 {
     GISASSimulation* result = new GISASSimulation();
-    result->setDetectorParameters(25, -2.0 * Units::degree, 2.0 * Units::degree, 25,
-                                  0.0 * Units::degree, 2.0 * Units::degree);
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setDetectorParameters(25, -2.0 * Units::deg, 2.0 * Units::deg, 25, 0.0 * Units::deg,
+                                  2.0 * Units::deg);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
     result->getOptions().setIncludeSpecular(true);
     return result;
 }
@@ -231,9 +231,9 @@ GISASSimulation* StandardSimulations::MiniGISASSpecularPeak()
 GISASSimulation* StandardSimulations::MaxiGISAS()
 {
     GISASSimulation* result = new GISASSimulation();
-    result->setDetectorParameters(256, -2.0 * Units::degree, 2.0 * Units::degree, 256,
-                                  0.0 * Units::degree, 2.0 * Units::degree);
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setDetectorParameters(256, -2.0 * Units::deg, 2.0 * Units::deg, 256, 0.0 * Units::deg,
+                                  2.0 * Units::deg);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
     return result;
 }
 
@@ -254,10 +254,10 @@ GISASSimulation* StandardSimulations::IsGISAXSSimulation1()
 {
     GISASSimulation* result = new GISASSimulation();
     IsGISAXSDetector detector;
-    detector.setDetectorParameters(100, -1.0 * Units::degree, 1.0 * Units::degree, 100,
-                                   0.0 * Units::degree, 2.0 * Units::degree);
+    detector.setDetectorParameters(100, -1.0 * Units::deg, 1.0 * Units::deg, 100, 0.0 * Units::deg,
+                                   2.0 * Units::deg);
     result->setDetector(detector);
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
     return result;
 }
 
@@ -267,10 +267,10 @@ GISASSimulation* StandardSimulations::IsGISAXSSimulation2()
 {
     GISASSimulation* result = new GISASSimulation();
     IsGISAXSDetector detector;
-    detector.setDetectorParameters(100, 0.0 * Units::degree, 2.0 * Units::degree, 100,
-                                   0.0 * Units::degree, 2.0 * Units::degree);
+    detector.setDetectorParameters(100, 0.0 * Units::deg, 2.0 * Units::deg, 100, 0.0 * Units::deg,
+                                   2.0 * Units::deg);
     result->setDetector(detector);
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
     return result;
 }
 
@@ -279,7 +279,7 @@ GISASSimulation* StandardSimulations::IsGISAXSSimulation2()
 GISASSimulation* StandardSimulations::RectDetectorGeneric()
 {
     GISASSimulation* result = new GISASSimulation();
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
 
     RectangularDetector detector(rdet_nbinsx, rdet_width, rdet_nbinsy, rdet_height);
     detector.setPosition(kvector_t(rdet_distance, 10.0, 5.0), rdet_width / 2., 1.0,
@@ -294,7 +294,7 @@ GISASSimulation* StandardSimulations::RectDetectorGeneric()
 GISASSimulation* StandardSimulations::RectDetectorPerpToSample()
 {
     GISASSimulation* result = new GISASSimulation();
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
 
     RectangularDetector detector(rdet_nbinsx, rdet_width, rdet_nbinsy, rdet_height);
     detector.setPerpendicularToSampleX(rdet_distance, rdet_width / 2., 1.0);
@@ -308,7 +308,7 @@ GISASSimulation* StandardSimulations::RectDetectorPerpToSample()
 GISASSimulation* StandardSimulations::RectDetectorPerpToDirectBeam()
 {
     GISASSimulation* result = new GISASSimulation();
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
 
     RectangularDetector detector(rdet_nbinsx, rdet_width, rdet_nbinsy, rdet_height);
     detector.setPerpendicularToDirectBeam(rdet_distance, rdet_width / 2., 1.0);
@@ -322,7 +322,7 @@ GISASSimulation* StandardSimulations::RectDetectorPerpToDirectBeam()
 GISASSimulation* StandardSimulations::RectDetectorPerpToReflectedBeam()
 {
     GISASSimulation* result = new GISASSimulation();
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
 
     RectangularDetector detector(rdet_nbinsx, rdet_width, rdet_nbinsy, rdet_height);
     detector.setPerpendicularToReflectedBeam(rdet_distance, rdet_width / 2., 1.0);
@@ -337,7 +337,7 @@ GISASSimulation* StandardSimulations::RectDetectorPerpToReflectedBeam()
 GISASSimulation* StandardSimulations::RectDetectorPerpToReflectedBeamDpos()
 {
     GISASSimulation* result = new GISASSimulation();
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
 
     RectangularDetector detector(rdet_nbinsx, rdet_width, rdet_nbinsy, rdet_height);
     detector.setPerpendicularToReflectedBeam(rdet_distance);
@@ -361,13 +361,13 @@ GISASSimulation* StandardSimulations::MiniGISASMonteCarlo()
 GISASSimulation* StandardSimulations::SphericalDetWithRoi()
 {
     GISASSimulation* result = new GISASSimulation();
-    result->setDetectorParameters(40, -2.0 * Units::degree, 2.0 * Units::degree, 30,
-                                  0.0 * Units::degree, 3.0 * Units::degree);
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
-    result->addMask(Rectangle(-0.5 * Units::degree, 0.3 * Units::degree, -0.2 * Units::degree,
-                              0.6 * Units::degree));
-    result->setRegionOfInterest(-1.5 * Units::degree, 0.25 * Units::degree, 1.5 * Units::degree,
-                                1.75 * Units::degree);
+    result->setDetectorParameters(40, -2.0 * Units::deg, 2.0 * Units::deg, 30, 0.0 * Units::deg,
+                                  3.0 * Units::deg);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
+    result->addMask(
+        Rectangle(-0.5 * Units::deg, 0.3 * Units::deg, -0.2 * Units::deg, 0.6 * Units::deg));
+    result->setRegionOfInterest(-1.5 * Units::deg, 0.25 * Units::deg, 1.5 * Units::deg,
+                                1.75 * Units::deg);
     return result;
 }
 
@@ -478,7 +478,7 @@ SpecularSimulation* StandardSimulations::SpecularDivergentBeam()
     const double min_angle = 0 * Units::deg;
     const double max_angle = 5 * Units::deg;
     const double wl_stddev = 0.1 * Units::angstrom;
-    const double ang_stddev = 0.1 * Units::degree;
+    const double ang_stddev = 0.1 * Units::deg;
     AngularSpecScan scan(wavelength, FixedBinAxis("axis", number_of_bins, min_angle, max_angle));
 
     RangedDistributionGaussian wl_distr(n_integration_points, /*sigma_factor = */ 2.0);
@@ -644,9 +644,9 @@ DepthProbeSimulation* StandardSimulations::BasicDepthProbe()
 GISASSimulation* StandardSimulations::MiniGISASFit()
 {
     auto* result = new GISASSimulation;
-    result->setDetectorParameters(25, -2.0 * Units::degree, 2.0 * Units::degree, 25,
-                                  0.0 * Units::degree, 2.0 * Units::degree);
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setDetectorParameters(25, -2.0 * Units::deg, 2.0 * Units::deg, 25, 0.0 * Units::deg,
+                                  2.0 * Units::deg);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
     result->setBeamIntensity(1e6);
     return result;
 }
diff --git a/Examples/Demos/FitCylindersPrisms_movie.py b/Examples/Demos/FitCylindersPrisms_movie.py
index c099201bb87acf3cfbbe49d6d0934630ce7182bb..acd255944a14c87d47c1da59b92ebf5fff7945c7 100644
--- a/Examples/Demos/FitCylindersPrisms_movie.py
+++ b/Examples/Demos/FitCylindersPrisms_movie.py
@@ -154,9 +154,9 @@ class DrawObserver(IFitObserver):
         ax.set_xlim(0, 10)
         ax.set_ylim(0, 10)
         # # plotting difference map
-        # diff_map = (real_data - simulated_data)/numpy.sqrt(real_data + 1)
+        # diff = (real_data - simulated_data)/numpy.sqrt(real_data + 1)
         # pylab.subplot(2, 2, 3)
-        # im = pylab.imshow(diff_map, norm=matplotlib.colors.LogNorm(), extent=[-1.0, 1.0, 0, 2.0], vmin = 0.001, vmax = 1.0)
+        # im = pylab.imshow(diff, norm=matplotlib.colors.LogNorm(), extent=[-1.0, 1.0, 0, 2.0], vmin = 0.001, vmax = 1.0)
         # pylab.colorbar(im)
         # pylab.title('Difference map')
         # # plotting parameters info
diff --git a/Examples/Demos/simul_demo_lattice1.py b/Examples/Demos/simul_demo_lattice1.py
index 7b433807041b314e360380f93b8df4bfa4b63c35..e83b8afef7e69777be7d09d0ac3e525b00bdb750 100644
--- a/Examples/Demos/simul_demo_lattice1.py
+++ b/Examples/Demos/simul_demo_lattice1.py
@@ -27,7 +27,7 @@ def RunSimulation():
     particle_layout.addParticle(cylinder, 1.0)
 
     # interference function
-    interference = InterferenceFunction2DLattice.createSquare(10.0*nanometer)
+    interference = InterferenceFunction2DLattice(ba.SquareLattice(10.0*nanometer))
     pdf = FTDecayFunction2DCauchy(300.0*nanometer/2.0/M_PI, 100.0*nanometer/2.0/M_PI, 0)
     interference.setDecayFunction(pdf)
     particle_layout.setInterferenceFunction(interference)
@@ -67,9 +67,3 @@ if __name__ == '__main__':
     plt.xlabel(r'$\phi_f$', fontsize=20)
     plt.ylabel(r'$\alpha_f$', fontsize=20)
     plt.show()
-
-
-
-
-
-
diff --git a/Examples/Demos/simul_demo_lattice2.py b/Examples/Demos/simul_demo_lattice2.py
index 67b89d1f7ce838f39800bcc9fbe467e62c5bf34c..2e99c5e192c867b9a3c769272db7c7053f90b2ae 100644
--- a/Examples/Demos/simul_demo_lattice2.py
+++ b/Examples/Demos/simul_demo_lattice2.py
@@ -32,7 +32,7 @@ def RunSimulation():
     particle_layout2.addParticle(cylinder, 1.0)
 
     # interference function
-    interference = InterferenceFunction2DLattice.createSquare(10.0*nanometer)
+    interference = InterferenceFunction2DLattice(ba.SquareLattice(10.0*nanometer))
     pdf = FTDecayFunction2DCauchy(300.0*nanometer/2.0/M_PI, 100.0*nanometer/2.0/M_PI, 0)
     interference.setDecayFunction(pdf)
     particle_layout1.setInterferenceFunction(interference)
@@ -74,7 +74,3 @@ if __name__ == '__main__':
     plt.xlabel(r'$\phi_f$', fontsize=20)
     plt.ylabel(r'$\alpha_f$', fontsize=20)
     plt.show()
-
-
-
-
diff --git a/Examples/cpp/CylindersAndPrisms/CylindersAndPrisms.cpp b/Examples/cpp/CylindersAndPrisms/CylindersAndPrisms.cpp
index 3eddfff5367f2efc0cace41ebc17c24792530df5..dfaa81373c26f3d83a6a558ff14c9c1ce3d6f229 100644
--- a/Examples/cpp/CylindersAndPrisms/CylindersAndPrisms.cpp
+++ b/Examples/cpp/CylindersAndPrisms/CylindersAndPrisms.cpp
@@ -37,12 +37,10 @@ int main()
     ParticleLayout particle_layout;
     Material particle_material = HomogeneousMaterial("Particle", 6e-4, 2e-8);
 
-    Particle cylinder(particle_material,
-                      FormFactorCylinder(5 * Units::nanometer, 5 * Units::nanometer));
+    Particle cylinder(particle_material, FormFactorCylinder(5 * Units::nm, 5 * Units::nm));
     particle_layout.addParticle(cylinder, 0.5);
 
-    Particle prism(particle_material,
-                   FormFactorPrism3(10 * Units::nanometer, 5 * Units::nanometer));
+    Particle prism(particle_material, FormFactorPrism3(10 * Units::nm, 5 * Units::nm));
     particle_layout.addParticle(prism, 0.5);
 
     vacuum_layer.addLayout(particle_layout);
@@ -53,9 +51,9 @@ int main()
 
     // Define the simulation
     GISASSimulation simulation;
-    simulation.setDetectorParameters(400, -1.0 * Units::degree, 1.0 * Units::degree, 400,
-                                     0.0 * Units::degree, 2.0 * Units::degree);
-    simulation.setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    simulation.setDetectorParameters(400, -1.0 * Units::deg, 1.0 * Units::deg, 400,
+                                     0.0 * Units::deg, 2.0 * Units::deg);
+    simulation.setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
     simulation.setSample(sample);
 
     // Run the simulation, and store the result
diff --git a/Examples/python/fitting/ex03_ExtendedExamples/custom_objective_function/custom_objective_function.py b/Examples/python/fitting/ex03_ExtendedExamples/custom_objective_function/custom_objective_function.py
index 7bf6b538dfd93597db8c1809b3a54b4f84b9540f..26c5727efef3fead00d813052204d4cdd8b88b1d 100644
--- a/Examples/python/fitting/ex03_ExtendedExamples/custom_objective_function/custom_objective_function.py
+++ b/Examples/python/fitting/ex03_ExtendedExamples/custom_objective_function/custom_objective_function.py
@@ -51,7 +51,8 @@ def get_sample(params):
     particle_layout = ba.ParticleLayout()
     particle_layout.addParticle(sphere)
 
-    interference = ba.InterferenceFunction2DLattice.createHexagonal(lattice_length)
+    interference = ba.InterferenceFunction2DLattice(
+        ba.HexagonalLattice(lattice_length))
     pdf = ba.FTDecayFunction2DCauchy(10*nm, 10*nm, 0)
     interference.setDecayFunction(pdf)
 
diff --git a/Examples/python/fitting/ex03_ExtendedExamples/external_minimizer/lmfit_basics.py b/Examples/python/fitting/ex03_ExtendedExamples/external_minimizer/lmfit_basics.py
index 04b310c0d98a205aba5bcf5ed01be42ccaa009a6..2f8f4618085a191a825f8ea6546b9e8eb4755244 100644
--- a/Examples/python/fitting/ex03_ExtendedExamples/external_minimizer/lmfit_basics.py
+++ b/Examples/python/fitting/ex03_ExtendedExamples/external_minimizer/lmfit_basics.py
@@ -25,7 +25,8 @@ def get_sample(params):
     particle_layout = ba.ParticleLayout()
     particle_layout.addParticle(sphere)
 
-    interference = ba.InterferenceFunction2DLattice.createHexagonal(lattice_length)
+    interference = ba.InterferenceFunction2DLattice(
+        ba.HexagonalLattice(lattice_length))
     pdf = ba.FTDecayFunction2DCauchy(10*nm, 10*nm, 0)
     interference.setDecayFunction(pdf)
 
diff --git a/Examples/python/fitting/ex03_ExtendedExamples/external_minimizer/lmfit_with_plotting.py b/Examples/python/fitting/ex03_ExtendedExamples/external_minimizer/lmfit_with_plotting.py
index fa9b864483a937b49603c02f4f3650b8e6e0427b..c05ac002ba332a89782b778b231535054c375844 100644
--- a/Examples/python/fitting/ex03_ExtendedExamples/external_minimizer/lmfit_with_plotting.py
+++ b/Examples/python/fitting/ex03_ExtendedExamples/external_minimizer/lmfit_with_plotting.py
@@ -26,7 +26,8 @@ def get_sample(params):
     particle_layout = ba.ParticleLayout()
     particle_layout.addParticle(sphere)
 
-    interference = ba.InterferenceFunction2DLattice.createHexagonal(lattice_length)
+    interference = ba.InterferenceFunction2DLattice(
+        ba.HexagonalLattice(lattice_length))
     pdf = ba.FTDecayFunction2DCauchy(10*nm, 10*nm, 0)
     interference.setDecayFunction(pdf)
 
diff --git a/Examples/python/simulation/ex02_LayeredStructures/BuriedParticles.py b/Examples/python/simulation/ex02_LayeredStructures/BuriedParticles.py
index ed7959d2779a532ab02e8e8926799157e52cfc56..64a9e3c72b5d035020ee3f7985a579930cc16073 100644
--- a/Examples/python/simulation/ex02_LayeredStructures/BuriedParticles.py
+++ b/Examples/python/simulation/ex02_LayeredStructures/BuriedParticles.py
@@ -17,8 +17,8 @@ def get_sample():
     m_particle = ba.HomogeneousMaterial("Particle", 0.0, 0.0)
 
     # collection of particles
-    ff_sphere = ba.FormFactorFullSphere(10.2*nm)
-    sphere = ba.Particle(m_particle, ff_sphere)
+    ff = ba.FormFactorFullSphere(10.2*nm)
+    sphere = ba.Particle(m_particle, ff)
     sphere.setPosition(0.0, 0.0, -25.2)
     particle_layout = ba.ParticleLayout()
     particle_layout.addParticle(sphere, 1.0)
diff --git a/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DCenteredSquareLattice.py b/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DCenteredSquareLattice.py
index a5ac25677f000b57fafcacedca799a594baad653..ea4363117a2f6e6ea119785898b44c18c9f15482 100644
--- a/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DCenteredSquareLattice.py
+++ b/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DCenteredSquareLattice.py
@@ -17,7 +17,7 @@ def get_sample():
     m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8)
 
     # collection of particles
-    interference = ba.InterferenceFunction2DLattice.createSquare(25.0*nm, 0)
+    interference = ba.InterferenceFunction2DLattice(ba.SquareLattice(25.0*nm, 0))
     pdf = ba.FTDecayFunction2DCauchy(300.0*nm/2.0/numpy.pi,
                                      100.0*nm/2.0/numpy.pi, 0)
     interference.setDecayFunction(pdf)
diff --git a/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DLatticeSumOfRotated.py b/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DLatticeSumOfRotated.py
index 2e987129e11c1d4140063d1e837be6dc75dd0921..125a213decaa034781ef6d72ddd3fd9d99eba2dd 100644
--- a/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DLatticeSumOfRotated.py
+++ b/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DLatticeSumOfRotated.py
@@ -17,15 +17,15 @@ def get_sample():
     substrate_layer = ba.Layer(m_substrate)
 
     p_interference_function = \
-        ba.InterferenceFunction2DLattice.createSquare(25.0*nm, 0)
+        ba.InterferenceFunction2DLattice(ba.SquareLattice(25.0*nm, 0))
     pdf = ba.FTDecayFunction2DCauchy(300.0*nm/2.0/numpy.pi,
                                      100.0*nm/2.0/numpy.pi, 0)
     p_interference_function.setDecayFunction(pdf)
 
     particle_layout = ba.ParticleLayout()
-    ff_cyl = ba.FormFactorCylinder(3.0*nm, 3.0*nm)
+    ff = ba.FormFactorCylinder(3.0*nm, 3.0*nm)
     position = ba.kvector_t(0.0, 0.0, 0.0)
-    cylinder = ba.Particle(m_particle, ff_cyl.clone())
+    cylinder = ba.Particle(m_particle, ff.clone())
     cylinder.setPosition(position)
     particle_layout.addParticle(cylinder, 1.0)
     particle_layout.setInterferenceFunction(p_interference_function)
diff --git a/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DParaCrystal.py b/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DParaCrystal.py
index ad7b5e226ad0ee880a85dc94c686f5fd8bd78a35..af0500ab3f5e4df91699ee618719297af832d5e7 100644
--- a/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DParaCrystal.py
+++ b/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DParaCrystal.py
@@ -17,8 +17,9 @@ def get_sample():
     cylinder_ff = ba.FormFactorCylinder(4*nm, 5*nm)
     cylinder = ba.Particle(m_particle, cylinder_ff)
 
-    interference = ba.InterferenceFunction2DParaCrystal.createSquare(
-        10.0*nm, 0.0, 20.0*micrometer, 20.0*micrometer)
+    interference = ba.InterferenceFunction2DParaCrystal(
+        ba.SquareLattice(10.0*nm), 0.0, 20.0*micrometer, 20.0*micrometer)
+    interference.setIntegrationOverXi(True)
     pdf = ba.FTDistribution2DCauchy(1.0*nm, 1.0*nm, 0)
     interference.setProbabilityDistributions(pdf, pdf)
 
diff --git a/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DRotatedSquareLattice.py b/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DRotatedSquareLattice.py
index daed2dea6785d0323c5613487e0cd3b5fabbc090..99993c2f2978a2c576526da58dc4098d0c0245e6 100644
--- a/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DRotatedSquareLattice.py
+++ b/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DRotatedSquareLattice.py
@@ -16,8 +16,8 @@ def get_sample():
     m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8)
 
     # collection of particles
-    interference = ba.InterferenceFunction2DLattice.createSquare(
-        25.0*nm, 30.0*deg)
+    interference = ba.InterferenceFunction2DLattice(
+        ba.SquareLattice(25.0*nm, 30.0*deg))
     pdf = ba.FTDecayFunction2DCauchy(300.0*nm/2.0/numpy.pi, 100.0*nm/2.0/numpy.pi, 0)
     pdf.setParameterValue("Gamma", 30.0*deg)
     interference.setDecayFunction(pdf)
diff --git a/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DSquareFiniteLattice.py b/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DSquareFiniteLattice.py
index ad783998dc36098c433f69b13ea73e0cd261d929..0319d13ca30d07f23ceb311c37baf3f28e6755da 100644
--- a/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DSquareFiniteLattice.py
+++ b/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DSquareFiniteLattice.py
@@ -16,8 +16,8 @@ def get_sample():
     m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8)
 
     # collection of particles
-    interference = ba.InterferenceFunctionFinite2DLattice.createSquare(
-        25.0*nm, 0.0, 40, 40)
+    interference = ba.InterferenceFunctionFinite2DLattice(
+        ba.SquareLattice(25.0*nm, 0.0), 40, 40)
     interference.setPositionVariance(1.0)
 
     cylinder_ff = ba.FormFactorCylinder(3.*nm, 3.*nm)
diff --git a/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DSquareLattice.py b/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DSquareLattice.py
index de7eb3b86dd42c98c9a17d345c3af87555c14950..b44049343179d999936e7dadd45de028a15004bf 100644
--- a/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DSquareLattice.py
+++ b/Examples/python/simulation/ex03_InterferenceFunctions/Interference2DSquareLattice.py
@@ -16,7 +16,7 @@ def get_sample():
     m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8)
 
     # collection of particles
-    interference = ba.InterferenceFunction2DLattice.createSquare(25.0*nm, 0*deg)
+    interference = ba.InterferenceFunction2DLattice(ba.SquareLattice(25.0*nm, 0*deg))
     pdf = ba.FTDecayFunction2DCauchy(300.0*nm/2.0/numpy.pi,
                                      100.0*nm/2.0/numpy.pi, 0)
     interference.setDecayFunction(pdf)
diff --git a/Examples/python/simulation/ex03_InterferenceFunctions/SpheresAtHexLattice.py b/Examples/python/simulation/ex03_InterferenceFunctions/SpheresAtHexLattice.py
index 3acb9d9be9ab9e33878aeec6cddb1647db8ff724..5813247a2a430c59651a7b5e953703c97893c598 100644
--- a/Examples/python/simulation/ex03_InterferenceFunctions/SpheresAtHexLattice.py
+++ b/Examples/python/simulation/ex03_InterferenceFunctions/SpheresAtHexLattice.py
@@ -19,7 +19,8 @@ def get_sample():
     particle_layout = ba.ParticleLayout()
     particle_layout.addParticle(sphere)
 
-    interference = ba.InterferenceFunction2DLattice.createHexagonal(20.0*nm, 0*deg)
+    interference = ba.InterferenceFunction2DLattice(
+        ba.HexagonalLattice(20.0*nm, 0*deg))
     pdf = ba.FTDecayFunction2DCauchy(10*nm, 10*nm, 0)
     interference.setDecayFunction(pdf)
 
diff --git a/Examples/python/simulation/ex04_ComplexShapes/HexagonalLatticesWithBasis.py b/Examples/python/simulation/ex04_ComplexShapes/HexagonalLatticesWithBasis.py
index 94a8a4b03e977352de6eece0d7b9cf08a96d3b0b..e798c1b411fa0243ceee8c3a7d84281eead55670 100644
--- a/Examples/python/simulation/ex04_ComplexShapes/HexagonalLatticesWithBasis.py
+++ b/Examples/python/simulation/ex04_ComplexShapes/HexagonalLatticesWithBasis.py
@@ -26,8 +26,8 @@ def get_sample():
     basis.addParticles(sphere, [pos0, pos1])
     particle_layout.addParticle(basis)
 
-    interference = ba.InterferenceFunction2DLattice.createHexagonal(
-        radius*2.0, 0*deg)
+    interference = ba.InterferenceFunction2DLattice(
+        ba.HexagonalLattice(radius*2.0, 0*deg))
     pdf = ba.FTDecayFunction2DCauchy(10*nm, 10*nm, 0)
     interference.setDecayFunction(pdf)
 
diff --git a/Examples/python/simulation/ex04_ComplexShapes/MesoCrystal.py b/Examples/python/simulation/ex04_ComplexShapes/MesoCrystal.py
index cb7550db810db48da2074c0a484d01fd03111dbc..857aa322b49142ee77059a220f40cc26790a6617 100644
--- a/Examples/python/simulation/ex04_ComplexShapes/MesoCrystal.py
+++ b/Examples/python/simulation/ex04_ComplexShapes/MesoCrystal.py
@@ -18,7 +18,7 @@ def get_sample():
     lattice_basis_1 = ba.kvector_t(5.0, 0.0, 0.0)
     lattice_basis_2 = ba.kvector_t(0.0, 5.0, 0.0)
     lattice_basis_3 = ba.kvector_t(0.0, 0.0, 5.0)
-    lattice = ba.Lattice(lattice_basis_1, lattice_basis_2, lattice_basis_3)
+    lattice = ba.Lattice3D(lattice_basis_1, lattice_basis_2, lattice_basis_3)
 
     # spherical particle that forms the base of the mesocrystal
     sphere_ff = ba.FormFactorFullSphere(2*nm)
diff --git a/Examples/python/simulation/ex06_Reflectometry/MaterialProfileWithParticles.py b/Examples/python/simulation/ex06_Reflectometry/MaterialProfileWithParticles.py
index cb941cb2474b69206cb2eec36003d70a8fd9029a..2fd471de8348f318110d6e6784a0220f57820a9d 100644
--- a/Examples/python/simulation/ex06_Reflectometry/MaterialProfileWithParticles.py
+++ b/Examples/python/simulation/ex06_Reflectometry/MaterialProfileWithParticles.py
@@ -35,7 +35,7 @@ def get_sample():
     particle = ba.Particle(m_particle, ff)
     layout = ba.ParticleLayout()
     layout.addParticle(particle)
-    iff = ba.InterferenceFunction2DLattice.createSquare(10 * nm, 0)
+    iff = ba.InterferenceFunction2DLattice(ba.SquareLattice(10 * nm, 0))
     layout.setInterferenceFunction(iff)
     ambient_layer.addLayout(layout)
     ambient_layer.setNumberOfSlices(20)
diff --git a/Examples/python/simulation/ex07_Miscellaneous/AccessingSimulationResults.py b/Examples/python/simulation/ex07_Miscellaneous/AccessingSimulationResults.py
index b04ba49cdcd5bc769e3795aac0148e08641df87f..3f923e86ee0a35726522912458fbe5e36e9d9291 100644
--- a/Examples/python/simulation/ex07_Miscellaneous/AccessingSimulationResults.py
+++ b/Examples/python/simulation/ex07_Miscellaneous/AccessingSimulationResults.py
@@ -125,8 +125,8 @@ def plot(hist):
     plt.title("Cropping")
 
     plt.subplot(2, 2, 3)
-    reldiff_hist = get_relative_difference(hist)
-    plot_histogram(reldiff_hist, zmin=1e-03, zmax=10)
+    reldiff = get_relative_difference(hist)
+    plot_histogram(reldiff, zmin=1e-03, zmax=10)
     plt.title("Relative difference")
 
     plt.subplot(2, 2, 4)
diff --git a/Examples/python/simulation/ex07_Miscellaneous/BoxesWithSpecularPeak.py b/Examples/python/simulation/ex07_Miscellaneous/BoxesWithSpecularPeak.py
index 9f87fcc2ae2e303f8723bf4b10d8a42385c68f46..aa060d9272ed258b121c3a730a86a5444bfa1a67 100644
--- a/Examples/python/simulation/ex07_Miscellaneous/BoxesWithSpecularPeak.py
+++ b/Examples/python/simulation/ex07_Miscellaneous/BoxesWithSpecularPeak.py
@@ -21,7 +21,7 @@ def get_sample():
     particle_layout.addParticle(box)
 
     # interference function
-    interference = ba.InterferenceFunction2DLattice.createSquare(8*nm, 0*deg)
+    interference = ba.InterferenceFunction2DLattice(ba.SquareLattice(8*nm, 0*deg))
     pdf = ba.FTDecayFunction2DCauchy(100*nm, 100*nm, 0)
     interference.setDecayFunction(pdf)
     particle_layout.setInterferenceFunction(interference)
diff --git a/Examples/python/simulation/ex07_Miscellaneous/CylindersInAverageLayer.py b/Examples/python/simulation/ex07_Miscellaneous/CylindersInAverageLayer.py
index 917a65dd8667cb07079cf3e3f3e9adc1eb3cc4e9..96af9bfa2090d173f6058ab64ba8416234e6fc9d 100644
--- a/Examples/python/simulation/ex07_Miscellaneous/CylindersInAverageLayer.py
+++ b/Examples/python/simulation/ex07_Miscellaneous/CylindersInAverageLayer.py
@@ -23,7 +23,7 @@ def get_sample(cyl_height=5*nm):
     particle_layout.addParticle(cylinder, 1.0, position)
 
     # interference function
-    interference = ba.InterferenceFunction2DLattice.createSquare(15*nm, 0*deg)
+    interference = ba.InterferenceFunction2DLattice(ba.SquareLattice(15*nm, 0*deg))
     pdf = ba.FTDecayFunction2DCauchy(300*nm, 300*nm, 0)
     interference.setDecayFunction(pdf)
     particle_layout.setInterferenceFunction(interference)
diff --git a/Examples/python/simulation/ex07_Miscellaneous/HalfSpheresInAverageTopLayer.py b/Examples/python/simulation/ex07_Miscellaneous/HalfSpheresInAverageTopLayer.py
index b486ffdd191d87b87812ecf767526f4c4f4319d4..2ecf336360fd1dcef066a0d666dd9c4a2d04afd2 100644
--- a/Examples/python/simulation/ex07_Miscellaneous/HalfSpheresInAverageTopLayer.py
+++ b/Examples/python/simulation/ex07_Miscellaneous/HalfSpheresInAverageTopLayer.py
@@ -26,7 +26,7 @@ def get_sample():
     particle_layout.addParticle(half_sphere)
 
     # interference function
-    interference = ba.InterferenceFunction2DLattice.createSquare(10*nm, 0*deg)
+    interference = ba.InterferenceFunction2DLattice(ba.SquareLattice(10*nm, 0*deg))
     pdf = ba.FTDecayFunction2DCauchy(100*nm, 100*nm, 0)
     interference.setDecayFunction(pdf)
     particle_layout.setInterferenceFunction(interference)
diff --git a/GUI/coregui/Models/BeamAngleItems.cpp b/GUI/coregui/Models/BeamAngleItems.cpp
index 8363dc378928b967b371ef279ef9a4a96b4beb45..ea37c5a988db8cc11d2c42790e86cd698c3855fd 100644
--- a/GUI/coregui/Models/BeamAngleItems.cpp
+++ b/GUI/coregui/Models/BeamAngleItems.cpp
@@ -37,7 +37,7 @@ double BeamAzimuthalAngleItem::azimuthalAngle() const
 
 double BeamAzimuthalAngleItem::scaleFactor() const
 {
-    return Units::degree;
+    return Units::deg;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -64,5 +64,5 @@ double BeamInclinationAngleItem::inclinationAngle() const
 
 double BeamInclinationAngleItem::scaleFactor() const
 {
-    return Units::degree;
+    return Units::deg;
 }
diff --git a/GUI/coregui/Models/DepthProbeInstrumentItem.cpp b/GUI/coregui/Models/DepthProbeInstrumentItem.cpp
index f496ea63a10d0fb48e13dd632cf6ba54effa1527..643af11980dd45f8c95ea865408ae83625c375ba 100644
--- a/GUI/coregui/Models/DepthProbeInstrumentItem.cpp
+++ b/GUI/coregui/Models/DepthProbeInstrumentItem.cpp
@@ -72,7 +72,7 @@ std::unique_ptr<DepthProbeSimulation> DepthProbeInstrumentItem::createSimulation
 
     const auto axis_item = beamItem()->currentInclinationAxisItem();
 
-    auto axis = axis_item->createAxis(Units::degree);
+    auto axis = axis_item->createAxis(Units::deg);
 
     simulation->setBeamParameters(beamItem()->getWavelength(), static_cast<int>(axis->size()),
                                   axis->lowerBound(), axis->upperBound());
diff --git a/GUI/coregui/Models/DomainObjectBuilder.cpp b/GUI/coregui/Models/DomainObjectBuilder.cpp
index f6c283fb7bf850a5ba68039baa7e7ae2d563f418..a5ea1b1ddd96ebab0e0403f8df116e98cd17128e 100644
--- a/GUI/coregui/Models/DomainObjectBuilder.cpp
+++ b/GUI/coregui/Models/DomainObjectBuilder.cpp
@@ -149,7 +149,7 @@ DomainObjectBuilder::createUnitConverter(const InstrumentItem* instrumentItem)
             instrumentItem->getItem(OffSpecInstrumentItem::P_ALPHA_AXIS));
         const auto detector2d = dynamic_cast<const IDetector2D*>(instrument->getDetector());
         return std::make_unique<OffSpecularConverter>(*detector2d, instrument->beam(),
-                                                      *axis_item->createAxis(Units::degree));
+                                                      *axis_item->createAxis(Units::deg));
     }
 
     throw GUIHelpers::Error(
diff --git a/GUI/coregui/Models/DomainSimulationBuilder.cpp b/GUI/coregui/Models/DomainSimulationBuilder.cpp
index 8cb0b55e80cafba8f25a241ad1a095d532018f7d..236b2ff9fc950445a5d6a89fc45916d1a06a7494 100644
--- a/GUI/coregui/Models/DomainSimulationBuilder.cpp
+++ b/GUI/coregui/Models/DomainSimulationBuilder.cpp
@@ -124,7 +124,7 @@ std::unique_ptr<OffSpecSimulation> createOffSpecSimulation(std::unique_ptr<Multi
     auto beamItem = instrument->beamItem();
     auto axisItem =
         dynamic_cast<BasicAxisItem*>(instrument->getItem(OffSpecInstrumentItem::P_ALPHA_AXIS));
-    ret->setBeamParameters(beamItem->getWavelength(), *axisItem->createAxis(Units::degree),
+    ret->setBeamParameters(beamItem->getWavelength(), *axisItem->createAxis(Units::deg),
                            beamItem->getAzimuthalAngle());
 
     // TODO Take care about distributions
@@ -152,7 +152,7 @@ createSpecularSimulation(std::unique_ptr<MultiLayer> P_multilayer,
     const auto axis_item = beam_item->currentInclinationAxisItem();
     const auto footprint = beam_item->currentFootprintItem();
 
-    AngularSpecScan scan(beam_item->getWavelength(), *axis_item->createAxis(Units::degree));
+    AngularSpecScan scan(beam_item->getWavelength(), *axis_item->createAxis(Units::deg));
     scan.setFootprintFactor(footprint->createFootprint().get());
 
     TransformToDomain::addBeamDivergencesToScan(*beam_item, scan);
diff --git a/GUI/coregui/Models/FormFactorItems.cpp b/GUI/coregui/Models/FormFactorItems.cpp
index 946d00a210b8e1b812861b11c8d8be9433f669cb..e3ddafe56dc21b69dd2474113020482286e294ee 100644
--- a/GUI/coregui/Models/FormFactorItems.cpp
+++ b/GUI/coregui/Models/FormFactorItems.cpp
@@ -37,7 +37,7 @@ std::unique_ptr<IFormFactor> AnisoPyramidItem::createFormFactor() const
 {
     return std::make_unique<FormFactorAnisoPyramid>(
         getItemValue(P_LENGTH).toDouble(), getItemValue(P_WIDTH).toDouble(),
-        getItemValue(P_HEIGHT).toDouble(), getItemValue(P_ALPHA).toDouble() * Units::degree);
+        getItemValue(P_HEIGHT).toDouble(), getItemValue(P_ALPHA).toDouble() * Units::deg);
 }
 
 /* ------------------------------------------------ */
@@ -122,7 +122,7 @@ std::unique_ptr<IFormFactor> ConeItem::createFormFactor() const
 {
     return std::make_unique<FormFactorCone>(getItemValue(P_RADIUS).toDouble(),
                                             getItemValue(P_HEIGHT).toDouble(),
-                                            getItemValue(P_ALPHA).toDouble() * Units::degree);
+                                            getItemValue(P_ALPHA).toDouble() * Units::deg);
 }
 
 /* ------------------------------------------------ */
@@ -143,7 +143,7 @@ std::unique_ptr<IFormFactor> Cone6Item::createFormFactor() const
 {
     return std::make_unique<FormFactorCone6>(getItemValue(P_BASEEDGE).toDouble(),
                                              getItemValue(P_HEIGHT).toDouble(),
-                                             getItemValue(P_ALPHA).toDouble() * Units::degree);
+                                             getItemValue(P_ALPHA).toDouble() * Units::deg);
 }
 
 /* ------------------------------------------------ */
@@ -169,7 +169,7 @@ std::unique_ptr<IFormFactor> CuboctahedronItem::createFormFactor() const
 {
     return std::make_unique<FormFactorCuboctahedron>(
         getItemValue(P_LENGTH).toDouble(), getItemValue(P_HEIGHT).toDouble(),
-        getItemValue(P_HEIGHT_RATIO).toDouble(), getItemValue(P_ALPHA).toDouble() * Units::degree);
+        getItemValue(P_HEIGHT_RATIO).toDouble(), getItemValue(P_ALPHA).toDouble() * Units::deg);
 }
 
 /* ------------------------------------------------ */
@@ -369,7 +369,7 @@ std::unique_ptr<IFormFactor> PyramidItem::createFormFactor() const
 {
     return std::make_unique<FormFactorPyramid>(getItemValue(P_BASEEDGE).toDouble(),
                                                getItemValue(P_HEIGHT).toDouble(),
-                                               getItemValue(P_ALPHA).toDouble() * Units::degree);
+                                               getItemValue(P_ALPHA).toDouble() * Units::deg);
 }
 
 /* ------------------------------------------------ */
@@ -524,9 +524,9 @@ TetrahedronItem::TetrahedronItem() : FormFactorItem("Tetrahedron")
 
 std::unique_ptr<IFormFactor> TetrahedronItem::createFormFactor() const
 {
-    return std::make_unique<FormFactorTetrahedron>(
-        getItemValue(P_BASEEDGE).toDouble(), getItemValue(P_HEIGHT).toDouble(),
-        getItemValue(P_ALPHA).toDouble() * Units::degree);
+    return std::make_unique<FormFactorTetrahedron>(getItemValue(P_BASEEDGE).toDouble(),
+                                                   getItemValue(P_HEIGHT).toDouble(),
+                                                   getItemValue(P_ALPHA).toDouble() * Units::deg);
 }
 
 /* ------------------------------------------------ */
diff --git a/GUI/coregui/Models/InterferenceFunctionItems.cpp b/GUI/coregui/Models/InterferenceFunctionItems.cpp
index 987c37d34b4d8572ba184998a81c89d422b2ef36..c98855a803e5b4b99bf77eb751813a689b357d47 100644
--- a/GUI/coregui/Models/InterferenceFunctionItems.cpp
+++ b/GUI/coregui/Models/InterferenceFunctionItems.cpp
@@ -57,7 +57,7 @@ InterferenceFunction1DLatticeItem::InterferenceFunction1DLatticeItem()
     : InterferenceFunctionItem("Interference1DLattice")
 {
     setToolTip("Interference function of a 1D lattice");
-    addProperty(P_LENGTH, 20.0 * Units::nanometer)->setToolTip("Lattice length in nanometers");
+    addProperty(P_LENGTH, 20.0 * Units::nm)->setToolTip("Lattice length in nanometers");
     addProperty(P_ROTATION_ANGLE, 0.0)
         ->setToolTip("Rotation of lattice with respect to x-axis of reference \n"
                      "frame (beam direction) in degrees ");
@@ -306,7 +306,7 @@ InterferenceFunctionHardDiskItem::InterferenceFunctionHardDiskItem()
     : InterferenceFunctionItem("InterferenceHardDisk")
 {
     setToolTip("Interference function for hard disk Percus-Yevick");
-    addProperty(P_RADIUS, 5.0 * Units::nanometer)->setToolTip("Hard disk radius in nanometers");
+    addProperty(P_RADIUS, 5.0 * Units::nm)->setToolTip("Hard disk radius in nanometers");
     addProperty(P_DENSITY, 0.002)->setToolTip("Particle density in particles per square nanometer");
 }
 
@@ -335,9 +335,9 @@ InterferenceFunctionRadialParaCrystalItem::InterferenceFunctionRadialParaCrystal
     : InterferenceFunctionItem("InterferenceRadialParaCrystal")
 {
     setToolTip("Interference function of a radial paracrystal");
-    addProperty(P_PEAK_DISTANCE, 20.0 * Units::nanometer)
+    addProperty(P_PEAK_DISTANCE, 20.0 * Units::nm)
         ->setToolTip("Average distance to the next neighbor in nanometers");
-    addProperty(P_DAMPING_LENGTH, 1000.0 * Units::nanometer)
+    addProperty(P_DAMPING_LENGTH, 1000.0 * Units::nm)
         ->setToolTip("The damping (coherence) length of the paracrystal "
                      "in nanometers");
     addProperty(P_DOMAIN_SIZE, 0.0)
diff --git a/GUI/coregui/Models/MesoCrystalItem.cpp b/GUI/coregui/Models/MesoCrystalItem.cpp
index 86ed0425acb4a205446e1624bc4cb97ed2b7c9a0..c2e9eada6484a00623e4bfb0cbb3b9a16885a877 100644
--- a/GUI/coregui/Models/MesoCrystalItem.cpp
+++ b/GUI/coregui/Models/MesoCrystalItem.cpp
@@ -48,7 +48,11 @@ const QString density_tooltip =
     "Number of mesocrystals per square nanometer (particle surface density).\n "
     "Should be defined for disordered and 1d-ordered particle collections.";
 
-bool IsIParticleName(QString name);
+bool IsIParticleName(QString name)
+{
+    return (name.startsWith("Particle") || name.startsWith("ParticleComposition")
+            || name.startsWith("ParticleCoreShell") || name.startsWith("MesoCrystal"));
+}
 
 } // namespace
 
@@ -105,47 +109,43 @@ MesoCrystalItem::MesoCrystalItem() : SessionGraphicsItem("MesoCrystal")
 
 std::unique_ptr<MesoCrystal> MesoCrystalItem::createMesoCrystal() const
 {
-    auto lattice = getLattice();
-    if (!(lattice.volume() > 0.0)) {
+    const Lattice3D& lattice = getLattice();
+    if (!(lattice.unitCellVolume() > 0.0))
         throw GUIHelpers::Error("MesoCrystalItem::createMesoCrystal(): "
                                 "Lattice volume not strictly positive");
-    }
-    auto P_basis = getBasis();
-    if (!P_basis) {
+    std::unique_ptr<IParticle> basis = getBasis();
+    if (!basis)
         throw GUIHelpers::Error("MesoCrystalItem::createMesoCrystal(): "
                                 "No basis particle defined");
-    }
-    Crystal crystal(*P_basis, lattice);
+    Crystal crystal(*basis, lattice);
 
-    auto P_ff = getOuterShape();
-    if (!P_ff) {
+    std::unique_ptr<IFormFactor> ff = getOuterShape();
+    if (!ff)
         throw GUIHelpers::Error("MesoCrystalItem::createMesoCrystal(): "
                                 "No outer shape defined");
-    }
 
-    auto P_result = std::make_unique<MesoCrystal>(crystal, *P_ff);
-    TransformToDomain::setTransformationInfo(P_result.get(), *this);
+    auto result = std::make_unique<MesoCrystal>(crystal, *ff);
+    TransformToDomain::setTransformationInfo(result.get(), *this);
 
-    return P_result;
+    return result;
 }
 
 QStringList MesoCrystalItem::translateList(const QStringList& list) const
 {
     QStringList result = list;
     // Add CrystalType to path name of basis particle
-    if (IsIParticleName(list.back())) {
+    if (IsIParticleName(list.back()))
         result << QString::fromStdString("Crystal");
-    }
     result = SessionItem::translateList(result);
     return result;
 }
 
-Lattice MesoCrystalItem::getLattice() const
+Lattice3D MesoCrystalItem::getLattice() const
 {
-    kvector_t a1 = GetVectorItem(*this, P_VECTOR_A);
-    kvector_t a2 = GetVectorItem(*this, P_VECTOR_B);
-    kvector_t a3 = GetVectorItem(*this, P_VECTOR_C);
-    return Lattice(a1, a2, a3);
+    const kvector_t a1 = GetVectorItem(*this, P_VECTOR_A);
+    const kvector_t a2 = GetVectorItem(*this, P_VECTOR_B);
+    const kvector_t a3 = GetVectorItem(*this, P_VECTOR_C);
+    return Lattice3D(a1, a2, a3);
 }
 
 std::unique_ptr<IParticle> MesoCrystalItem::getBasis() const
@@ -174,12 +174,3 @@ std::unique_ptr<IFormFactor> MesoCrystalItem::getOuterShape() const
     auto& ff_item = groupItem<FormFactorItem>(MesoCrystalItem::P_OUTER_SHAPE);
     return ff_item.createFormFactor();
 }
-
-namespace
-{
-bool IsIParticleName(QString name)
-{
-    return (name.startsWith("Particle") || name.startsWith("ParticleComposition")
-            || name.startsWith("ParticleCoreShell") || name.startsWith("MesoCrystal"));
-}
-} // namespace
diff --git a/GUI/coregui/Models/MesoCrystalItem.h b/GUI/coregui/Models/MesoCrystalItem.h
index 615e811b000f0a8268f3b74cb3ebd28e25ed9ba4..edfd9e2799a9eea00c57b2e437836e894568dfb8 100644
--- a/GUI/coregui/Models/MesoCrystalItem.h
+++ b/GUI/coregui/Models/MesoCrystalItem.h
@@ -16,7 +16,7 @@
 #define BORNAGAIN_GUI_COREGUI_MODELS_MESOCRYSTALITEM_H
 
 #include "GUI/coregui/Models/SessionGraphicsItem.h"
-#include "Sample/Lattice/Lattice.h"
+#include "Sample/Lattice/Lattice3D.h"
 
 class IFormFactor;
 class IParticle;
@@ -37,7 +37,7 @@ public:
 
     QStringList translateList(const QStringList& list) const override;
 
-    Lattice getLattice() const;
+    Lattice3D getLattice() const;
     std::unique_ptr<IParticle> getBasis() const;
     std::unique_ptr<IFormFactor> getOuterShape() const;
 };
diff --git a/GUI/coregui/Models/ParticleDistributionItem.cpp b/GUI/coregui/Models/ParticleDistributionItem.cpp
index f6ba211decec3fb972bb28f2f1ff3339c1b158ad..d1a477122a9da3d197dc99cc35809fa3f1e1702c 100644
--- a/GUI/coregui/Models/ParticleDistributionItem.cpp
+++ b/GUI/coregui/Models/ParticleDistributionItem.cpp
@@ -90,7 +90,7 @@ std::unique_ptr<ParticleDistribution> ParticleDistributionItem::createParticleDi
 
     std::string domain_par = domainMainParameter();
 
-    double scale = ParameterUtils::isAngleRelated(domain_par) ? Units::degree : 1.0;
+    double scale = ParameterUtils::isAngleRelated(domain_par) ? Units::deg : 1.0;
     auto P_distribution = distr_item.createDistribution(scale);
 
     RealLimits limits = RealLimits::limitless();
diff --git a/GUI/coregui/Models/SpecularBeamInclinationItem.cpp b/GUI/coregui/Models/SpecularBeamInclinationItem.cpp
index a1ad3dacf70845a6cbff55288b45bd42a942c600..a10df3f19074f720b6138d180e532ef02804e791 100644
--- a/GUI/coregui/Models/SpecularBeamInclinationItem.cpp
+++ b/GUI/coregui/Models/SpecularBeamInclinationItem.cpp
@@ -39,7 +39,7 @@ SpecularBeamInclinationItem::~SpecularBeamInclinationItem() = default;
 
 double SpecularBeamInclinationItem::scaleFactor() const
 {
-    return Units::degree;
+    return Units::deg;
 }
 
 void SpecularBeamInclinationItem::updateFileName(const QString& filename)
diff --git a/GUI/coregui/Models/SphericalDetectorItem.cpp b/GUI/coregui/Models/SphericalDetectorItem.cpp
index 3cae51adedaa9b096c0b2006df7ead5285bda12d..3b2b71c352749ccc95fe8f1375f59450ef955daa 100644
--- a/GUI/coregui/Models/SphericalDetectorItem.cpp
+++ b/GUI/coregui/Models/SphericalDetectorItem.cpp
@@ -88,5 +88,5 @@ void SphericalDetectorItem::setYSize(int ny)
 
 double SphericalDetectorItem::axesToDomainUnitsFactor() const
 {
-    return Units::degree;
+    return Units::deg;
 }
diff --git a/GUI/coregui/Models/TransformFromDomain.cpp b/GUI/coregui/Models/TransformFromDomain.cpp
index 91d4ffb934dada9b680dc503ba9115fbbdc3f1e4..d75c35f6c09b0bb0b522f7757d8787abbc663ec9 100644
--- a/GUI/coregui/Models/TransformFromDomain.cpp
+++ b/GUI/coregui/Models/TransformFromDomain.cpp
@@ -220,7 +220,7 @@ void TransformFromDomain::setParticleDistributionItem(SessionItem* item,
 
     double unit_factor(1.0);
     if (sample.mainUnits() == "rad")
-        unit_factor = 1. / Units::degree;
+        unit_factor = 1. / Units::deg;
 
     QString group_name = ParticleDistributionItem::P_DISTRIBUTION;
     setDistribution(distItem, par_distr, group_name, unit_factor);
@@ -355,7 +355,7 @@ void TransformFromDomain::setDetectorResolution(DetectorItem* detector_item,
                                                                 "ResolutionFunction2DGaussian");
             double scale(1.0);
             if (detector_item->modelType() == "SphericalDetector")
-                scale = 1. / Units::degree;
+                scale = 1. / Units::deg;
             item->setItemValue(ResolutionFunction2DGaussianItem::P_SIGMA_X,
                                scale * resfunc->getSigmaX());
             item->setItemValue(ResolutionFunction2DGaussianItem::P_SIGMA_Y,
@@ -481,7 +481,7 @@ void TransformFromDomain::setDetectorMasks(DetectorItem* detector_item,
 
         double scale(1.0);
         if (detector_item->modelType() == "SphericalDetector")
-            scale = 1. / Units::degree;
+            scale = 1. / Units::deg;
 
         setMaskContainer(detector_item->maskContainerItem(), *detector, scale);
     }
diff --git a/Param/Node/INodeVisitor.h b/Param/Node/INodeVisitor.h
index ea14ac42d3788c08a3555da5befbf19f6b04952e..e513d4cc5ec3724c4ce69a2d5f08d315b04726da 100644
--- a/Param/Node/INodeVisitor.h
+++ b/Param/Node/INodeVisitor.h
@@ -98,7 +98,7 @@ class IFormFactor;
 class IFormFactorBorn;
 class IFormFactorDecorator;
 class IInterferenceFunction;
-class ILayout;
+class ParticleLayout;
 class INode;
 class Instrument;
 class InterferenceFunction1DLattice;
@@ -127,7 +127,6 @@ class Particle;
 class ParticleComposition;
 class ParticleCoreShell;
 class ParticleDistribution;
-class ParticleLayout;
 class PoissonNoiseBackground;
 class RectangularDetector;
 class ResolutionFunction2DGaussian;
@@ -234,7 +233,7 @@ public:
     virtual void visit(const IFormFactorBorn*) {}
     virtual void visit(const IFormFactorDecorator*) {}
     virtual void visit(const IInterferenceFunction*) {}
-    virtual void visit(const ILayout*) {}
+    virtual void visit(const ParticleLayout*) {}
     virtual void visit(const INode*) {}
     virtual void visit(const Instrument*) {}
     virtual void visit(const InterferenceFunction1DLattice*) {}
@@ -263,7 +262,6 @@ public:
     virtual void visit(const ParticleComposition*) {}
     virtual void visit(const ParticleCoreShell*) {}
     virtual void visit(const ParticleDistribution*) {}
-    virtual void visit(const ParticleLayout*) {}
     virtual void visit(const PoissonNoiseBackground*) {}
     virtual void visit(const RectangularDetector*) {}
     virtual void visit(const ResolutionFunction2DGaussian*) {}
diff --git a/Sample/Aggregate/InterferenceFunction2DLattice.cpp b/Sample/Aggregate/InterferenceFunction2DLattice.cpp
index b103698ae81f09a1c11e01b5dbe928caf49fff6d..afcb51ec7efd9ff71960ec18eddb107b81fea335 100644
--- a/Sample/Aggregate/InterferenceFunction2DLattice.cpp
+++ b/Sample/Aggregate/InterferenceFunction2DLattice.cpp
@@ -30,7 +30,9 @@ InterferenceFunction2DLattice::InterferenceFunction2DLattice(const Lattice2D& la
     : IInterferenceFunction(0), m_integrate_xi(false)
 {
     setName("Interference2DLattice");
-    setLattice(lattice);
+    m_lattice.reset(lattice.clone());
+    registerChild(m_lattice.get());
+    initialize_rec_vectors();
 }
 
 //! Constructor of two-dimensional interference function.
@@ -56,24 +58,6 @@ InterferenceFunction2DLattice* InterferenceFunction2DLattice::clone() const
     return ret;
 }
 
-//! Creates square lattice.
-//! @param lattice_length: length of the first and second basis vectors in nanometers
-//! @param xi: rotation of the lattice with respect to the x-axis in radians
-InterferenceFunction2DLattice* InterferenceFunction2DLattice::createSquare(double lattice_length,
-                                                                           double xi)
-{
-    return new InterferenceFunction2DLattice(SquareLattice(lattice_length, xi));
-}
-
-//! Creates hexagonal lattice.
-//! @param lattice_length: length of the first and second basis vectors in nanometers
-//! @param xi: rotation of the lattice with respect to the x-axis in radians
-InterferenceFunction2DLattice* InterferenceFunction2DLattice::createHexagonal(double lattice_length,
-                                                                              double xi)
-{
-    return new InterferenceFunction2DLattice(HexagonalLattice(lattice_length, xi));
-}
-
 //! Sets two-dimensional decay function.
 //! @param decay: two-dimensional decay function in reciprocal space
 void InterferenceFunction2DLattice::setDecayFunction(const IFTDecayFunction2D& decay)
@@ -128,13 +112,6 @@ double InterferenceFunction2DLattice::iff_without_dw(const kvector_t q) const
            / M_TWOPI;
 }
 
-void InterferenceFunction2DLattice::setLattice(const Lattice2D& lattice)
-{
-    m_lattice.reset(lattice.clone());
-    registerChild(m_lattice.get());
-    initialize_rec_vectors();
-}
-
 double InterferenceFunction2DLattice::interferenceForXi(double xi) const
 {
     double result = 0.0;
diff --git a/Sample/Aggregate/InterferenceFunction2DLattice.h b/Sample/Aggregate/InterferenceFunction2DLattice.h
index 173d061d261d00995f7bbdbcd7eaa0beaf357c08..de7c89eab928158bd4bf45efc83c78347dd4f3f4 100644
--- a/Sample/Aggregate/InterferenceFunction2DLattice.h
+++ b/Sample/Aggregate/InterferenceFunction2DLattice.h
@@ -34,9 +34,6 @@ public:
 
     void accept(INodeVisitor* visitor) const override final { visitor->visit(this); }
 
-    static InterferenceFunction2DLattice* createSquare(double lattice_length, double xi);
-    static InterferenceFunction2DLattice* createHexagonal(double lattice_length, double xi);
-
     void setDecayFunction(const IFTDecayFunction2D& decay);
 
     void setIntegrationOverXi(bool integrate_xi);
@@ -53,7 +50,6 @@ public:
 
 private:
     double iff_without_dw(const kvector_t q) const override final;
-    void setLattice(const Lattice2D& lattice);
 
     double interferenceForXi(double xi) const;
 
diff --git a/Sample/Aggregate/InterferenceFunction2DParaCrystal.cpp b/Sample/Aggregate/InterferenceFunction2DParaCrystal.cpp
index 5546d50fdc840b95f1f757a617c4842113111625..4f3e8b6148351100fbeeeb53aa7f350559018b31 100644
--- a/Sample/Aggregate/InterferenceFunction2DParaCrystal.cpp
+++ b/Sample/Aggregate/InterferenceFunction2DParaCrystal.cpp
@@ -26,7 +26,8 @@ InterferenceFunction2DParaCrystal::InterferenceFunction2DParaCrystal(const Latti
     : IInterferenceFunction(0), m_integrate_xi(false), m_damping_length(damping_length)
 {
     setName("Interference2DParaCrystal");
-    setLattice(lattice);
+    m_lattice.reset(lattice.clone());
+    registerChild(m_lattice.get());
     setDomainSizes(domain_size_1, domain_size_2);
     registerParameter("DampingLength", &m_damping_length).setUnit("nm").setNonnegative();
     registerParameter("DomainSize1", &m_domain_sizes[0]).setUnit("nm").setNonnegative();
@@ -105,44 +106,6 @@ double InterferenceFunction2DParaCrystal::iff_without_dw(const kvector_t q) cons
            / M_TWOPI;
 }
 
-void InterferenceFunction2DParaCrystal::setLattice(const Lattice2D& lattice)
-{
-    m_lattice.reset(lattice.clone());
-    registerChild(m_lattice.get());
-}
-
-//! Creates square lattice.
-//! @param lattice_length: length of first and second lattice vectors in nanometers
-//! @param damping_length: the damping (coherence) length of the paracrystal in nanometers
-//! @param domain_size_1: size of the coherent domain along the first basis vector in nanometers
-//! @param domain_size_2: size of the coherent domain along the second basis vector in nanometers
-
-InterferenceFunction2DParaCrystal*
-InterferenceFunction2DParaCrystal::createSquare(double lattice_length, double damping_length,
-                                                double domain_size_1, double domain_size_2)
-{
-    auto result = new InterferenceFunction2DParaCrystal(
-        SquareLattice(lattice_length), damping_length, domain_size_1, domain_size_2);
-    result->setIntegrationOverXi(true);
-    return result;
-}
-
-//! Creates hexagonal lattice.
-//! @param lattice_length: length of first and second lattice vectors in nanometers
-//! @param damping_length: the damping (coherence) length of the paracrystal in nanometers
-//! @param domain_size_1: size of the coherent domain along the first basis vector in nanometers
-//! @param domain_size_2: size of the coherent domain along the second basis vector in nanometers
-
-InterferenceFunction2DParaCrystal*
-InterferenceFunction2DParaCrystal::createHexagonal(double lattice_length, double damping_length,
-                                                   double domain_size_1, double domain_size_2)
-{
-    auto result = new InterferenceFunction2DParaCrystal(
-        HexagonalLattice(lattice_length, 0.), damping_length, domain_size_1, domain_size_2);
-    result->setIntegrationOverXi(true);
-    return result;
-}
-
 //! Sets the sizes of coherence domains.
 //! @param size_1: coherence domain size along the first basis vector in nanometers
 //! @param size_2: coherence domain size along the second basis vector in nanometers
diff --git a/Sample/Aggregate/InterferenceFunction2DParaCrystal.h b/Sample/Aggregate/InterferenceFunction2DParaCrystal.h
index b333d35cec2339b9435545f96b2a3aed1815ec86..7f61d639436540ac0c006b3b7970387323d02c34 100644
--- a/Sample/Aggregate/InterferenceFunction2DParaCrystal.h
+++ b/Sample/Aggregate/InterferenceFunction2DParaCrystal.h
@@ -41,15 +41,6 @@ public:
 
     void accept(INodeVisitor* visitor) const override final { visitor->visit(this); }
 
-    static InterferenceFunction2DParaCrystal* createSquare(double lattice_length,
-                                                           double damping_length,
-                                                           double domain_size_1,
-                                                           double domain_size_2);
-    static InterferenceFunction2DParaCrystal* createHexagonal(double lattice_length,
-                                                              double damping_length,
-                                                              double domain_size_1,
-                                                              double domain_size_2);
-
     void setDomainSizes(double size_1, double size_2);
 
     void setProbabilityDistributions(const IFTDistribution2D& pdf_1,
@@ -75,7 +66,6 @@ public:
 
 private:
     double iff_without_dw(const kvector_t q) const override final;
-    void setLattice(const Lattice2D& lattice);
 
     double interferenceForXi(double xi) const;
     double interference1D(double qx, double qy, double xi, size_t index) const;
diff --git a/Sample/Aggregate/InterferenceFunction2DSuperLattice.cpp b/Sample/Aggregate/InterferenceFunction2DSuperLattice.cpp
index 8d7b58ecd57f84e042b800e75939dd9c05db1bc5..e58c11ba3c431b2dfae2f0177af333e28ab79d52 100644
--- a/Sample/Aggregate/InterferenceFunction2DSuperLattice.cpp
+++ b/Sample/Aggregate/InterferenceFunction2DSuperLattice.cpp
@@ -32,7 +32,8 @@ InterferenceFunction2DSuperLattice::InterferenceFunction2DSuperLattice(const Lat
     , m_size_2(size_2)
 {
     setName("Interference2DSuperLattice");
-    setLattice(lattice);
+    m_lattice.reset(lattice.clone());
+    registerChild(m_lattice.get());
     setSubstructureIFF(InterferenceFunctionNone());
 }
 
@@ -72,28 +73,6 @@ const IInterferenceFunction& InterferenceFunction2DSuperLattice::substructureIFF
     return *m_substructure;
 }
 
-//! Creates square lattice.
-// @param lattice_length: length of first and second lattice vectors in nanometers
-// @param xi: rotation of lattice with respect to x-axis in radians
-InterferenceFunction2DSuperLattice*
-InterferenceFunction2DSuperLattice::createSquare(double lattice_length, double xi, unsigned size_1,
-                                                 unsigned size_2)
-{
-    return new InterferenceFunction2DSuperLattice(SquareLattice(lattice_length, xi), size_1,
-                                                  size_2);
-}
-
-//! Creates hexagonal lattice.
-// @param lattice_length: length of first and second lattice vectors in nanometers
-// @param xi: rotation of lattice with respect to x-axis in radians
-InterferenceFunction2DSuperLattice*
-InterferenceFunction2DSuperLattice::createHexagonal(double lattice_length, double xi,
-                                                    unsigned size_1, unsigned size_2)
-{
-    return new InterferenceFunction2DSuperLattice(HexagonalLattice(lattice_length, xi), size_1,
-                                                  size_2);
-}
-
 double InterferenceFunction2DSuperLattice::evaluate(const kvector_t q, double outer_iff) const
 {
     m_outer_iff = outer_iff;
@@ -139,12 +118,6 @@ double InterferenceFunction2DSuperLattice::iff_without_dw(const kvector_t q) con
     return ampl * ampl / (m_size_1 * m_size_2);
 }
 
-void InterferenceFunction2DSuperLattice::setLattice(const Lattice2D& lattice)
-{
-    m_lattice.reset(lattice.clone());
-    registerChild(m_lattice.get());
-}
-
 double InterferenceFunction2DSuperLattice::interferenceForXi(double xi) const
 {
     m_xi = xi; // TODO ASAP don't set as collateratel effect; rm mutable
diff --git a/Sample/Aggregate/InterferenceFunction2DSuperLattice.h b/Sample/Aggregate/InterferenceFunction2DSuperLattice.h
index 9f6cff8f562b476c9aff757d3215a4190f6401cb..babd1e177df4201355765da9bc521cc0845842d1 100644
--- a/Sample/Aggregate/InterferenceFunction2DSuperLattice.h
+++ b/Sample/Aggregate/InterferenceFunction2DSuperLattice.h
@@ -37,11 +37,6 @@ public:
     void setSubstructureIFF(const IInterferenceFunction& sub_iff);
     const IInterferenceFunction& substructureIFF() const;
 
-    static InterferenceFunction2DSuperLattice* createSquare(double lattice_length, double xi,
-                                                            unsigned size_1, unsigned size_2);
-    static InterferenceFunction2DSuperLattice* createHexagonal(double lattice_length, double xi,
-                                                               unsigned size_1, unsigned size_2);
-
     double evaluate(const kvector_t q, double outer_iff = 1.0) const override final;
     unsigned domainSize1() const { return m_size_1; }
     unsigned domainSize2() const { return m_size_2; }
@@ -55,7 +50,6 @@ public:
 
 private:
     double iff_without_dw(const kvector_t q) const override final;
-    void setLattice(const Lattice2D& lattice);
 
     double interferenceForXi(double xi) const;
 
diff --git a/Sample/Aggregate/InterferenceFunction3DLattice.cpp b/Sample/Aggregate/InterferenceFunction3DLattice.cpp
index 73188ec40c4b33dd124915de7cf730466a248890..e30ba9256660c822cc0968936e0b42e659d17769 100644
--- a/Sample/Aggregate/InterferenceFunction3DLattice.cpp
+++ b/Sample/Aggregate/InterferenceFunction3DLattice.cpp
@@ -17,7 +17,7 @@
 #include "Sample/Correlations/IPeakShape.h"
 #include <algorithm>
 
-InterferenceFunction3DLattice::InterferenceFunction3DLattice(const Lattice& lattice)
+InterferenceFunction3DLattice::InterferenceFunction3DLattice(const Lattice3D& lattice)
     : IInterferenceFunction(0), m_lattice(lattice), m_peak_shape(nullptr), m_rec_radius(0.0)
 {
     setName("Interference3DLattice");
@@ -40,7 +40,7 @@ void InterferenceFunction3DLattice::setPeakShape(const IPeakShape& peak_shape)
     m_peak_shape.reset(peak_shape.clone());
 }
 
-const Lattice& InterferenceFunction3DLattice::lattice() const
+const Lattice3D& InterferenceFunction3DLattice::lattice() const
 {
     return m_lattice;
 }
diff --git a/Sample/Aggregate/InterferenceFunction3DLattice.h b/Sample/Aggregate/InterferenceFunction3DLattice.h
index 848ed23399c590c18fc8cdf8da00c8b759449de4..b87a9a5224384c13a8c7ae714395b363181d2220 100644
--- a/Sample/Aggregate/InterferenceFunction3DLattice.h
+++ b/Sample/Aggregate/InterferenceFunction3DLattice.h
@@ -16,7 +16,7 @@
 #define BORNAGAIN_SAMPLE_AGGREGATE_INTERFERENCEFUNCTION3DLATTICE_H
 
 #include "Sample/Aggregate/IInterferenceFunction.h"
-#include "Sample/Lattice/Lattice.h"
+#include "Sample/Lattice/Lattice3D.h"
 
 class IPeakShape;
 
@@ -26,7 +26,7 @@ class IPeakShape;
 class InterferenceFunction3DLattice : public IInterferenceFunction
 {
 public:
-    InterferenceFunction3DLattice(const Lattice& lattice);
+    InterferenceFunction3DLattice(const Lattice3D& lattice);
     ~InterferenceFunction3DLattice() final;
 
     InterferenceFunction3DLattice* clone() const override final;
@@ -35,7 +35,7 @@ public:
 
     void setPeakShape(const IPeakShape& peak_shape);
 
-    const Lattice& lattice() const;
+    const Lattice3D& lattice() const;
 
     bool supportsMultilayer() const override final { return false; }
 
@@ -47,7 +47,7 @@ private:
     double iff_without_dw(const kvector_t q) const override final;
     void initRecRadius();
 
-    Lattice m_lattice; // TODO ASAP unique_ptr as in otehr InterferenceFunction%s
+    Lattice3D m_lattice; // TODO ASAP unique_ptr as in otehr InterferenceFunction%s
     std::unique_ptr<IPeakShape> m_peak_shape;
     double m_rec_radius; //!< radius in reciprocal space defining the nearest q vectors to use
 };
diff --git a/Sample/Aggregate/InterferenceFunctionFinite2DLattice.cpp b/Sample/Aggregate/InterferenceFunctionFinite2DLattice.cpp
index ef2f13ab6be1094db9e7a6942d1a6949373e0a1b..f53a35ef17af12e3549b6f187bf285e6d11ec889 100644
--- a/Sample/Aggregate/InterferenceFunctionFinite2DLattice.cpp
+++ b/Sample/Aggregate/InterferenceFunctionFinite2DLattice.cpp
@@ -32,7 +32,8 @@ InterferenceFunctionFinite2DLattice::InterferenceFunctionFinite2DLattice(const L
     : IInterferenceFunction(0), m_integrate_xi(false), m_N_1(N_1), m_N_2(N_2)
 {
     setName("InterferenceFinite2DLattice");
-    setLattice(lattice);
+    m_lattice.reset(lattice.clone());
+    registerChild(m_lattice.get());
 }
 
 //! Constructor of two-dimensional finite lattice interference function.
@@ -60,30 +61,6 @@ InterferenceFunctionFinite2DLattice* InterferenceFunctionFinite2DLattice::clone(
     return ret;
 }
 
-//! Creates square lattice.
-//! @param lattice_length: length of first and second lattice vectors in nanometers
-//! @param xi: rotation of lattice with respect to x-axis in radians
-//! @param N_1: number of lattice cells in the first lattice direction
-//! @param N_2: number of lattice cells in the second lattice direction
-InterferenceFunctionFinite2DLattice*
-InterferenceFunctionFinite2DLattice::createSquare(double lattice_length, double xi, unsigned N_1,
-                                                  unsigned N_2)
-{
-    return new InterferenceFunctionFinite2DLattice(SquareLattice(lattice_length, xi), N_1, N_2);
-}
-
-//! Creates hexagonal lattice.
-//! @param lattice_length: length of first and second lattice vectors in nanometers
-//! @param xi: rotation of lattice with respect to x-axis in radians
-//! @param N_1: number of lattice cells in the first lattice direction
-//! @param N_2: number of lattice cells in the second lattice direction
-InterferenceFunctionFinite2DLattice*
-InterferenceFunctionFinite2DLattice::createHexagonal(double lattice_length, double xi, unsigned N_1,
-                                                     unsigned N_2)
-{
-    return new InterferenceFunctionFinite2DLattice(HexagonalLattice(lattice_length, xi), N_1, N_2);
-}
-
 void InterferenceFunctionFinite2DLattice::setIntegrationOverXi(bool integrate_xi)
 {
     m_integrate_xi = integrate_xi;
@@ -120,12 +97,6 @@ double InterferenceFunctionFinite2DLattice::iff_without_dw(const kvector_t q) co
            / M_TWOPI;
 }
 
-void InterferenceFunctionFinite2DLattice::setLattice(const Lattice2D& lattice)
-{
-    m_lattice.reset(lattice.clone());
-    registerChild(m_lattice.get());
-}
-
 double InterferenceFunctionFinite2DLattice::interferenceForXi(double xi) const
 {
     double a = m_lattice->length1();
diff --git a/Sample/Aggregate/InterferenceFunctionFinite2DLattice.h b/Sample/Aggregate/InterferenceFunctionFinite2DLattice.h
index 1cd85527e6bfb8a06bce9822739ff9ffd6545ae4..6f90b1fac3e1b11e5b0ad3a930d6bb051cf3bf59 100644
--- a/Sample/Aggregate/InterferenceFunctionFinite2DLattice.h
+++ b/Sample/Aggregate/InterferenceFunctionFinite2DLattice.h
@@ -33,11 +33,6 @@ public:
 
     void accept(INodeVisitor* visitor) const override final { visitor->visit(this); }
 
-    static InterferenceFunctionFinite2DLattice* createSquare(double lattice_length, double xi,
-                                                             unsigned N_1, unsigned N_2);
-    static InterferenceFunctionFinite2DLattice* createHexagonal(double lattice_length, double xi,
-                                                                unsigned N_1, unsigned N_2);
-
     unsigned numberUnitCells1() const { return m_N_1; }
     unsigned numberUnitCells2() const { return m_N_2; }
 
@@ -53,7 +48,6 @@ public:
 
 private:
     double iff_without_dw(const kvector_t q) const override final;
-    void setLattice(const Lattice2D& lattice);
 
     double interferenceForXi(double xi) const;
 
diff --git a/Sample/Aggregate/InterferenceFunctionFinite3DLattice.cpp b/Sample/Aggregate/InterferenceFunctionFinite3DLattice.cpp
index 569eeecb300e353403403d73a5c3456c840a17c1..7bcc39315df9e2cfbd75aeeb30ab91105b795438 100644
--- a/Sample/Aggregate/InterferenceFunctionFinite3DLattice.cpp
+++ b/Sample/Aggregate/InterferenceFunctionFinite3DLattice.cpp
@@ -20,7 +20,7 @@
 
 #include <limits>
 
-InterferenceFunctionFinite3DLattice::InterferenceFunctionFinite3DLattice(const Lattice& lattice,
+InterferenceFunctionFinite3DLattice::InterferenceFunctionFinite3DLattice(const Lattice3D& lattice,
                                                                          unsigned N_1, unsigned N_2,
                                                                          unsigned N_3)
     : IInterferenceFunction(0), m_N_1(N_1), m_N_2(N_2), m_N_3(N_3)
@@ -38,7 +38,7 @@ InterferenceFunctionFinite3DLattice* InterferenceFunctionFinite3DLattice::clone(
     return ret;
 }
 
-const Lattice& InterferenceFunctionFinite3DLattice::lattice() const
+const Lattice3D& InterferenceFunctionFinite3DLattice::lattice() const
 {
     if (!m_lattice)
         throw std::runtime_error("InterferenceFunctionFinite3DLattice::lattice() -> Error. "
@@ -61,8 +61,8 @@ double InterferenceFunctionFinite3DLattice::iff_without_dw(const kvector_t q) co
     return ampl * ampl / (m_N_1 * m_N_2 * m_N_3);
 }
 
-void InterferenceFunctionFinite3DLattice::setLattice(const Lattice& lattice)
+void InterferenceFunctionFinite3DLattice::setLattice(const Lattice3D& lattice)
 {
-    m_lattice = std::make_unique<Lattice>(lattice);
+    m_lattice = std::make_unique<Lattice3D>(lattice);
     registerChild(m_lattice.get());
 }
diff --git a/Sample/Aggregate/InterferenceFunctionFinite3DLattice.h b/Sample/Aggregate/InterferenceFunctionFinite3DLattice.h
index a393780d95f8732fce64e3453892c87e24227f1f..c89c1b4c3993c829da3e1c6532cdf9262361a336 100644
--- a/Sample/Aggregate/InterferenceFunctionFinite3DLattice.h
+++ b/Sample/Aggregate/InterferenceFunctionFinite3DLattice.h
@@ -16,7 +16,7 @@
 #define BORNAGAIN_SAMPLE_AGGREGATE_INTERFERENCEFUNCTIONFINITE3DLATTICE_H
 
 #include "Sample/Aggregate/IInterferenceFunction.h"
-#include "Sample/Lattice/Lattice.h"
+#include "Sample/Lattice/Lattice3D.h"
 
 //! Interference function of a finite 3D lattice.
 //! @ingroup interference
@@ -24,7 +24,7 @@
 class InterferenceFunctionFinite3DLattice : public IInterferenceFunction
 {
 public:
-    InterferenceFunctionFinite3DLattice(const Lattice& lattice, unsigned N_1, unsigned N_2,
+    InterferenceFunctionFinite3DLattice(const Lattice3D& lattice, unsigned N_1, unsigned N_2,
                                         unsigned N_3);
     ~InterferenceFunctionFinite3DLattice() final;
 
@@ -36,7 +36,7 @@ public:
     unsigned numberUnitCells2() const { return m_N_2; }
     unsigned numberUnitCells3() const { return m_N_3; }
 
-    const Lattice& lattice() const;
+    const Lattice3D& lattice() const;
 
     bool supportsMultilayer() const override final { return false; }
 
@@ -44,9 +44,9 @@ public:
 
 private:
     double iff_without_dw(const kvector_t q) const override final;
-    void setLattice(const Lattice& lattice);
+    void setLattice(const Lattice3D& lattice);
 
-    std::unique_ptr<Lattice> m_lattice;
+    std::unique_ptr<Lattice3D> m_lattice;
     unsigned m_N_1, m_N_2, m_N_3; //!< Size of the finite lattice in lattice units
 };
 
diff --git a/Sample/Aggregate/ParticleLayout.cpp b/Sample/Aggregate/ParticleLayout.cpp
index 1ff12ba89a6473dc33f89844d46965d6bc083dc8..8881eddede6e3d28ba86d28d49027bbd57a69af5 100644
--- a/Sample/Aggregate/ParticleLayout.cpp
+++ b/Sample/Aggregate/ParticleLayout.cpp
@@ -34,7 +34,8 @@ bool particleDensityIsProvidedByInterference(const IInterferenceFunction& iff)
 }
 } // namespace
 
-ParticleLayout::ParticleLayout() : m_interference_function{nullptr}, m_total_particle_density{0.01}
+ParticleLayout::ParticleLayout()
+    : m_weight(1.0), m_total_particle_density(0.01), m_interference_function(nullptr)
 {
     setName("ParticleLayout");
     registerParticleDensity();
@@ -42,7 +43,7 @@ ParticleLayout::ParticleLayout() : m_interference_function{nullptr}, m_total_par
 }
 
 ParticleLayout::ParticleLayout(const IAbstractParticle& particle, double abundance)
-    : m_interference_function{nullptr}, m_total_particle_density{0.01}
+    : m_weight(1.0), m_total_particle_density(0.01), m_interference_function(nullptr)
 {
     setName("ParticleLayout");
     addParticle(particle, abundance);
diff --git a/Sample/Aggregate/ParticleLayout.h b/Sample/Aggregate/ParticleLayout.h
index ddb434c3a2843351fd6c2cc865b5e9e39c88a2ce..3876818acc3cc30e71e0b650c777260d12ff2637 100644
--- a/Sample/Aggregate/ParticleLayout.h
+++ b/Sample/Aggregate/ParticleLayout.h
@@ -15,7 +15,8 @@
 #ifndef BORNAGAIN_SAMPLE_AGGREGATE_PARTICLELAYOUT_H
 #define BORNAGAIN_SAMPLE_AGGREGATE_PARTICLELAYOUT_H
 
-#include "Sample/Correlations/ILayout.h"
+#include "Base/Types/SafePointerVector.h"
+#include "Sample/Scattering/ISample.h"
 #include "Sample/Scattering/Rotations.h"
 #include <memory>
 
@@ -26,32 +27,38 @@ class IParticle;
 //! Decorator class that adds particles to ISample objects.
 //! @ingroup samples
 
-class ParticleLayout : public ILayout
+class ParticleLayout : public ISample
 {
 public:
     ParticleLayout();
     ParticleLayout(const IAbstractParticle& particle, double abundance = -1.0);
     ~ParticleLayout() override;
 
-    ParticleLayout* clone() const final override;
+    ParticleLayout* clone() const override;
 
-    void accept(INodeVisitor* visitor) const final override { visitor->visit(this); }
+    void accept(INodeVisitor* visitor) const override { visitor->visit(this); }
 
     void addParticle(const IAbstractParticle& particle, double abundance = -1.0,
                      const kvector_t position = {}, const IRotation& rotation = IdentityRotation());
 
-    SafePointerVector<IParticle> particles() const final override;
+    SafePointerVector<IParticle> particles() const;
 
-    const IInterferenceFunction* interferenceFunction() const final override;
+    const IInterferenceFunction* interferenceFunction() const;
 
-    double getTotalAbundance() const final override;
+    double getTotalAbundance() const;
 
     void setInterferenceFunction(const IInterferenceFunction& interference_function);
 
-    double totalParticleSurfaceDensity() const final override;
-    void setTotalParticleSurfaceDensity(double particle_density) final override;
+    double totalParticleSurfaceDensity() const;
+    void setTotalParticleSurfaceDensity(double particle_density);
 
-    std::vector<const INode*> getChildren() const final override;
+    std::vector<const INode*> getChildren() const override;
+
+    //! Returns the relative weight of this layout
+    double weight() const { return m_weight; }
+
+    //! Sets the relative weight of this layout
+    void setWeight(double weight) { m_weight = weight; }
 
 private:
     void addAndRegisterAbstractParticle(IAbstractParticle* child);
@@ -60,9 +67,10 @@ private:
     void registerParticleDensity(bool make_registered = true);
     void registerWeight();
 
+    double m_weight;
+    double m_total_particle_density;
     SafePointerVector<IAbstractParticle> m_particles; //!< Vector of particle types
     std::unique_ptr<IInterferenceFunction> m_interference_function;
-    double m_total_particle_density;
 };
 
 #endif // BORNAGAIN_SAMPLE_AGGREGATE_PARTICLELAYOUT_H
diff --git a/Sample/Correlations/ILayout.cpp b/Sample/Correlations/ILayout.cpp
deleted file mode 100644
index 7c6009c964278d985c9149e95730ac17d09f97e0..0000000000000000000000000000000000000000
--- a/Sample/Correlations/ILayout.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-// ************************************************************************** //
-//
-//  BornAgain: simulate and fit scattering at grazing incidence
-//
-//! @file      Sample/Correlations/ILayout.cpp
-//! @brief     Implements interface class ILayout.
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-// ************************************************************************** //
-
-#include "Sample/Correlations/ILayout.h"
-
-ILayout::ILayout() : m_weight(1.0) {}
-
-ILayout::~ILayout() = default;
diff --git a/Sample/Correlations/ILayout.h b/Sample/Correlations/ILayout.h
deleted file mode 100644
index 8ec537dc5a5b7bbf82bc25783e572cefe35a4d42..0000000000000000000000000000000000000000
--- a/Sample/Correlations/ILayout.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// ************************************************************************** //
-//
-//  BornAgain: simulate and fit scattering at grazing incidence
-//
-//! @file      Sample/Correlations/ILayout.h
-//! @brief     Defines and implements interface class ILayout.
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-// ************************************************************************** //
-
-#ifndef BORNAGAIN_SAMPLE_CORRELATIONS_ILAYOUT_H
-#define BORNAGAIN_SAMPLE_CORRELATIONS_ILAYOUT_H
-
-#include "Base/Types/SafePointerVector.h"
-#include "Sample/Scattering/ISample.h"
-
-class IAbstractParticle;
-class IInterferenceFunction;
-
-//! Pure virtual interface class to equip a sample layer with scattering properties.
-//! Currently only inherited by ParticleLayout; in the future also by domain structure.
-//!
-//! @ingroup samples_internal
-
-// NOTE: When domain structures are implemented, this interface would probably undergo
-// major changes, because a domain layout would not contain particles
-class ILayout : public ISample
-{
-public:
-    ILayout();
-    virtual ~ILayout();
-
-    virtual ILayout* clone() const = 0;
-    virtual void accept(INodeVisitor* visitor) const = 0;
-
-    //! Returns information on all particles (type and abundance)
-    //! and generates new particles if an IAbstractParticle denotes a collection
-    virtual SafePointerVector<IParticle> particles() const = 0;
-
-    //! Returns the interference function
-    virtual const IInterferenceFunction* interferenceFunction() const = 0;
-
-    /// Get total abundance of all particles
-    virtual double getTotalAbundance() const = 0;
-
-    //! Returns surface density of all particles
-    virtual double totalParticleSurfaceDensity() const = 0;
-
-    //! Sets surface density of all particles
-    virtual void setTotalParticleSurfaceDensity(double particle_density) = 0;
-
-    //! Returns the relative weight of this layout
-    double weight() const { return m_weight; }
-
-    //! Sets the relative weight of this layout
-    void setWeight(double weight) { m_weight = weight; }
-
-protected:
-    double m_weight;
-};
-
-#endif // BORNAGAIN_SAMPLE_CORRELATIONS_ILAYOUT_H
diff --git a/Sample/Lattice/BakeLattice.cpp b/Sample/Lattice/BakeLattice.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f9979f0da7cb6a2f0e3b4e72d012f65ad92662ee
--- /dev/null
+++ b/Sample/Lattice/BakeLattice.cpp
@@ -0,0 +1,65 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      Sample/Lattice/BakeLattice.cpp
+//! @brief     Implements class Lattice.
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2018
+//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
+//
+// ************************************************************************** //
+
+#include "Sample/Lattice/BakeLattice.h"
+#include "Sample/Lattice/Lattice3D.h"
+
+Lattice3D bake::createCubicLattice(double a)
+{
+    kvector_t a1(a, 0.0, 0.0);
+    kvector_t a2(0.0, a, 0.0);
+    kvector_t a3(0.0, 0.0, a);
+    return Lattice3D(a1, a2, a3);
+}
+
+Lattice3D bake::createFCCLattice(double a)
+{
+    double b = a / 2.0;
+    kvector_t a1(0.0, b, b);
+    kvector_t a2(b, 0.0, b);
+    kvector_t a3(b, b, 0.0);
+    return Lattice3D(a1, a2, a3);
+}
+
+Lattice3D bake::createHexagonalLattice(double a, double c)
+{
+    kvector_t a1(a, 0.0, 0.0);
+    kvector_t a2(-a / 2.0, std::sqrt(3.0) * a / 2.0, 0.0);
+    kvector_t a3(0.0, 0.0, c);
+    return Lattice3D(a1, a2, a3);
+}
+
+Lattice3D bake::createHCPLattice(double a, double c)
+{
+    kvector_t a1(a, 0.0, 0.0);
+    kvector_t a2(-a / 2.0, std::sqrt(3.0) * a / 2.0, 0);
+    kvector_t a3(a / 2.0, a / std::sqrt(3.0) / 2.0, c / 2.0);
+    return Lattice3D(a1, a2, a3);
+}
+
+Lattice3D bake::createTetragonalLattice(double a, double c)
+{
+    kvector_t a1(a, 0.0, 0.0);
+    kvector_t a2(0.0, a, 0.0);
+    kvector_t a3(0.0, 0.0, c);
+    return Lattice3D(a1, a2, a3);
+}
+
+Lattice3D bake::createBCTLattice(double a, double c)
+{
+    kvector_t a1(a, 0.0, 0.0);
+    kvector_t a2(0.0, a, 0.0);
+    kvector_t a3(a / 2.0, a / 2.0, c / 2.0);
+    return Lattice3D(a1, a2, a3);
+}
diff --git a/Sample/Lattice/BakeLattice.h b/Sample/Lattice/BakeLattice.h
new file mode 100644
index 0000000000000000000000000000000000000000..4f0373f36a61a2c881c3402888abd8bdbf08a3e6
--- /dev/null
+++ b/Sample/Lattice/BakeLattice.h
@@ -0,0 +1,44 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      Sample/Lattice/BakeLattice.h
+//! @brief     Defines class Lattice.
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2018
+//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
+//
+// ************************************************************************** //
+
+#ifndef BORNAGAIN_SAMPLE_LATTICE_BAKELATTICE_H
+#define BORNAGAIN_SAMPLE_LATTICE_BAKELATTICE_H
+
+class Lattice3D;
+
+namespace bake
+{
+
+//! Returns a primitive cubic (cP) lattice with edge length a.
+Lattice3D createCubicLattice(double a);
+
+//! Returns a face-centered cubic (cF) lattice with edge length a.
+Lattice3D createFCCLattice(double a);
+
+//! Returns a primitive hexagonal (hP) lattice with hexagonal edge a and height c.
+Lattice3D createHexagonalLattice(double a, double c);
+
+//! TODO: Clarify how this is meant: HCP is not a Bravais lattice.
+Lattice3D createHCPLattice(double a, double c);
+
+//! Returns a primitive tetragonal (tP) lattice with square base edge a and height c.
+Lattice3D createTetragonalLattice(double a, double c);
+
+//! Returns a body-centered cubic (cI) lattice with edge length a.
+//! TODO: Clarify meaning of c
+Lattice3D createBCTLattice(double a, double c);
+
+} // namespace bake
+
+#endif // BORNAGAIN_SAMPLE_LATTICE_BAKELATTICE_H
diff --git a/Sample/Lattice/ILatticeOrientation.cpp b/Sample/Lattice/ILatticeOrientation.cpp
deleted file mode 100644
index 212d83c6eb839f9c61a8c968b8107f7358b85126..0000000000000000000000000000000000000000
--- a/Sample/Lattice/ILatticeOrientation.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-// ************************************************************************** //
-//
-//  BornAgain: simulate and fit scattering at grazing incidence
-//
-//! @file      Sample/Lattice/ILatticeOrientation.cpp
-//! @brief     Implements subclasses of ILatticeOrientation.
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-// ************************************************************************** //
-
-#include "Sample/Lattice/ILatticeOrientation.h"
-
-namespace
-{
-bool ValidMillerIndex(MillerIndex index);
-bool ParallelMillerIndices(MillerIndex index1, MillerIndex index2);
-double SignForCrossProduct(MillerIndexOrientation::QComponent q1,
-                           MillerIndexOrientation::QComponent q2);
-MillerIndexOrientation::QComponent ThirdQComponent(MillerIndexOrientation::QComponent q1,
-                                                   MillerIndexOrientation::QComponent q2);
-void FillVectorInRow(Eigen::Matrix3d& matrix, kvector_t vec,
-                     MillerIndexOrientation::QComponent row);
-} // unnamed namespace
-
-ILatticeOrientation::~ILatticeOrientation() = default;
-
-MillerIndex::MillerIndex(double h_, double k_, double l_) : h(h_), k(k_), l(l_) {}
-
-MillerIndexOrientation::MillerIndexOrientation(MillerIndexOrientation::QComponent q1,
-                                               MillerIndex index1,
-                                               MillerIndexOrientation::QComponent q2,
-                                               MillerIndex index2)
-    : m_prim_lattice(), m_q1(q1), m_q2(q2), m_ind1{index1}, m_ind2{index2}
-{
-    if (!checkAlignment())
-        throw std::runtime_error("MillerIndexOrientation constructor: "
-                                 "invalid alignment parameters");
-}
-
-MillerIndexOrientation* MillerIndexOrientation::clone() const
-{
-    auto* result = new MillerIndexOrientation(m_q1, m_ind1, m_q2, m_ind2);
-    result->usePrimitiveLattice(m_prim_lattice);
-    return result;
-}
-
-MillerIndexOrientation::~MillerIndexOrientation() = default;
-
-void MillerIndexOrientation::usePrimitiveLattice(const Lattice& lattice)
-{
-    m_prim_lattice.resetBasis(lattice.getBasisVectorA(), lattice.getBasisVectorB(),
-                              lattice.getBasisVectorC());
-}
-
-Transform3D MillerIndexOrientation::transformation() const
-{
-    auto dir_1 = m_prim_lattice.getMillerDirection(m_ind1.h, m_ind1.k, m_ind1.l);
-    auto dir_2 = m_prim_lattice.getMillerDirection(m_ind2.h, m_ind2.k, m_ind2.l);
-    auto dir_2_parallel = dir_2.project(dir_1);
-    dir_2 = (dir_2 - dir_2_parallel).unit();
-    auto dir_3 = SignForCrossProduct(m_q1, m_q2) * dir_1.cross(dir_2);
-    auto q3 = ThirdQComponent(m_q1, m_q2);
-    Eigen::Matrix3d rot_matrix;
-    FillVectorInRow(rot_matrix, dir_1, m_q1);
-    FillVectorInRow(rot_matrix, dir_2, m_q2);
-    FillVectorInRow(rot_matrix, dir_3, q3);
-    return Transform3D(rot_matrix);
-}
-
-bool MillerIndexOrientation::checkAlignment() const
-{
-    if (m_q1 == m_q2)
-        return false;
-    if (!ValidMillerIndex(m_ind1) || !ValidMillerIndex(m_ind2))
-        return false;
-    if (ParallelMillerIndices(m_ind1, m_ind2))
-        return false;
-    return true;
-}
-
-namespace
-{
-bool ValidMillerIndex(MillerIndex index)
-{
-    return (index.h != 0.0 || index.k != 0.0 || index.l != 0.0);
-}
-bool ParallelMillerIndices(MillerIndex index1, MillerIndex index2)
-{
-    double ratio = 0.0;
-    if (index2.h != 0.0) {
-        ratio = index1.h / index2.h;
-    } else if (index2.k != 0.0) {
-        ratio = index1.k / index2.k;
-    } else if (index2.l != 0.0) {
-        ratio = index1.l / index2.l;
-    }
-    if (ratio == 0.0)
-        return false;
-    return (index1.h == ratio * index2.h && index1.k == ratio * index2.k
-            && index1.l == ratio * index2.l);
-}
-double SignForCrossProduct(MillerIndexOrientation::QComponent q1,
-                           MillerIndexOrientation::QComponent q2)
-{
-    if ((q1 == MillerIndexOrientation::QX && q2 == MillerIndexOrientation::QY)
-        || (q1 == MillerIndexOrientation::QY && q2 == MillerIndexOrientation::QZ)
-        || (q1 == MillerIndexOrientation::QZ && q2 == MillerIndexOrientation::QX))
-        return 1.0;
-    return -1.0;
-}
-MillerIndexOrientation::QComponent ThirdQComponent(MillerIndexOrientation::QComponent q1,
-                                                   MillerIndexOrientation::QComponent q2)
-{
-    if (q1 != MillerIndexOrientation::QX && q2 != MillerIndexOrientation::QX)
-        return MillerIndexOrientation::QX;
-    if (q1 != MillerIndexOrientation::QY && q2 != MillerIndexOrientation::QY)
-        return MillerIndexOrientation::QY;
-    return MillerIndexOrientation::QZ;
-}
-void FillVectorInRow(Eigen::Matrix3d& mat, kvector_t vec, MillerIndexOrientation::QComponent row)
-{
-    int i = row == MillerIndexOrientation::QX ? 0 : row == MillerIndexOrientation::QY ? 1 : 2;
-    for (int j = 0; j < 3; ++j)
-        mat(i, j) = vec[j];
-}
-} // unnamed namespace
diff --git a/Sample/Lattice/ILatticeOrientation.h b/Sample/Lattice/ILatticeOrientation.h
deleted file mode 100644
index 9b6c519627265a018bf809a760d2a14bc4d1a823..0000000000000000000000000000000000000000
--- a/Sample/Lattice/ILatticeOrientation.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// ************************************************************************** //
-//
-//  BornAgain: simulate and fit scattering at grazing incidence
-//
-//! @file      Sample/Lattice/ILatticeOrientation.h
-//! @brief     Defines interface ILatticeOrientation and subclasses.
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-// ************************************************************************** //
-
-#ifndef BORNAGAIN_SAMPLE_LATTICE_ILATTICEORIENTATION_H
-#define BORNAGAIN_SAMPLE_LATTICE_ILATTICEORIENTATION_H
-
-#include "Base/Vector/Transform3D.h"
-#include "Sample/Lattice/Lattice.h"
-
-//! Pure virtual base of classes that specify a lattice orientation.
-//! Currently only inherited by MillerIndexOrientation.
-
-class ILatticeOrientation
-{
-public:
-    virtual ~ILatticeOrientation();
-
-    virtual ILatticeOrientation* clone() const = 0;
-
-    virtual void usePrimitiveLattice(const Lattice& lattice) = 0;
-
-    virtual Transform3D transformation() const = 0;
-};
-
-//! A direction in reciprocal space, specified by double-valued indices hkl.
-struct MillerIndex {
-    MillerIndex(double h_, double k_, double l_);
-    double h, k, l;
-};
-
-//! Specifies a rotation of a lattice through the Miller indices of two coordinate axes.
-
-class MillerIndexOrientation : public ILatticeOrientation
-{
-public:
-    enum QComponent { QX, QY, QZ };
-
-    //! This constructor is best explained by an example.
-    //! Arguments QX, (1,1,0), QY, (0,2,1) mean:
-    //! Rotate the lattice such that the axis [110] points into x direction,
-    //! and the axis [021], projected into the yz plane, points into z direction.
-    MillerIndexOrientation(QComponent q1, MillerIndex index1, QComponent q2, MillerIndex index2);
-    ~MillerIndexOrientation() override;
-
-    MillerIndexOrientation* clone() const override;
-
-    void usePrimitiveLattice(const Lattice& lattice) override;
-
-    Transform3D transformation() const override;
-
-private:
-    bool checkAlignment() const;
-    Lattice m_prim_lattice;
-    QComponent m_q1, m_q2;
-    MillerIndex m_ind1, m_ind2;
-};
-
-#endif // BORNAGAIN_SAMPLE_LATTICE_ILATTICEORIENTATION_H
diff --git a/Sample/Lattice/Lattice.cpp b/Sample/Lattice/Lattice.cpp
deleted file mode 100644
index 3192afb274ba08673803bfe0ade556f8bd235cd6..0000000000000000000000000000000000000000
--- a/Sample/Lattice/Lattice.cpp
+++ /dev/null
@@ -1,288 +0,0 @@
-// ************************************************************************** //
-//
-//  BornAgain: simulate and fit scattering at grazing incidence
-//
-//! @file      Sample/Lattice/Lattice.cpp
-//! @brief     Implements class Lattice.
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-// ************************************************************************** //
-
-#include "Sample/Lattice/Lattice.h"
-#include "Base/Const/MathConstants.h"
-#include "Base/Vector/Transform3D.h"
-#include "Param/Base/RealParameter.h"
-#include "Sample/Lattice/ISelectionRule.h"
-#include <gsl/gsl_linalg.h>
-
-Lattice::Lattice()
-    : m_selection_rule(nullptr)
-    , m_a({1.0, 0.0, 0.0})
-    , m_b({0.0, 1.0, 0.0})
-    , m_c({0.0, 0.0, 1.0})
-    , m_cache_ok(false)
-{
-    setName("Lattice");
-    initialize();
-    registerBasisVectors();
-}
-
-Lattice::Lattice(const kvector_t a1, const kvector_t a2, const kvector_t a3)
-    : m_selection_rule(nullptr), m_a(a1), m_b(a2), m_c(a3), m_cache_ok(false)
-{
-    setName("Lattice");
-    initialize();
-    registerBasisVectors();
-}
-
-Lattice::Lattice(const Lattice& lattice)
-    : INode()
-    , m_selection_rule(nullptr)
-    , m_a(lattice.m_a)
-    , m_b(lattice.m_b)
-    , m_c(lattice.m_c)
-    , m_cache_ok(false)
-{
-    setName("Lattice");
-    initialize();
-    if (lattice.m_selection_rule)
-        setSelectionRule(*lattice.m_selection_rule);
-    registerBasisVectors();
-}
-
-Lattice::~Lattice()
-{
-    delete m_selection_rule;
-}
-
-Lattice Lattice::transformed(const Transform3D& transform) const
-{
-    kvector_t a1 = transform.transformed(m_a);
-    kvector_t a2 = transform.transformed(m_b);
-    kvector_t a3 = transform.transformed(m_c);
-    Lattice result = {a1, a2, a3};
-    if (m_selection_rule)
-        result.setSelectionRule(*m_selection_rule);
-    return result;
-}
-
-void Lattice::initialize() const
-{
-    computeReciprocalVectors();
-    m_cache_ok = true;
-}
-
-void Lattice::resetBasis(const kvector_t a1, const kvector_t a2, const kvector_t a3)
-{
-    m_a = a1;
-    m_b = a2;
-    m_c = a3;
-    onChange();
-}
-
-kvector_t Lattice::getMillerDirection(double h, double k, double l) const
-{
-    kvector_t b1, b2, b3;
-    getReciprocalLatticeBasis(b1, b2, b3);
-    kvector_t direction = h * b1 + k * b2 + l * b3;
-    return direction.unit();
-}
-
-double Lattice::volume() const
-{
-    return std::abs(m_a.dot(m_b.cross(m_c)));
-}
-
-void Lattice::getReciprocalLatticeBasis(kvector_t& b1, kvector_t& b2, kvector_t& b3) const
-{
-    if (!m_cache_ok) {
-        initialize();
-    }
-    b1 = m_ra;
-    b2 = m_rb;
-    b3 = m_rc;
-    return;
-}
-
-ivector_t Lattice::getNearestLatticeVectorCoordinates(const kvector_t vector_in) const
-{
-    double a1_coord = vector_in.dot(m_ra) / M_TWOPI;
-    double a2_coord = vector_in.dot(m_rb) / M_TWOPI;
-    double a3_coord = vector_in.dot(m_rc) / M_TWOPI;
-    int c1 = static_cast<int>(std::floor(a1_coord + 0.5));
-    int c2 = static_cast<int>(std::floor(a2_coord + 0.5));
-    int c3 = static_cast<int>(std::floor(a3_coord + 0.5));
-    return ivector_t(c1, c2, c3);
-}
-
-ivector_t Lattice::getNearestReciprocalLatticeVectorCoordinates(const kvector_t vector_in) const
-{
-    double b1_coord = vector_in.dot(m_a) / M_TWOPI;
-    double b2_coord = vector_in.dot(m_b) / M_TWOPI;
-    double b3_coord = vector_in.dot(m_c) / M_TWOPI;
-    int c1 = static_cast<int>(std::floor(b1_coord + 0.5));
-    int c2 = static_cast<int>(std::floor(b2_coord + 0.5));
-    int c3 = static_cast<int>(std::floor(b3_coord + 0.5));
-    return ivector_t(c1, c2, c3);
-}
-
-std::vector<kvector_t> Lattice::reciprocalLatticeVectorsWithinRadius(const kvector_t input_vector,
-                                                                     double radius) const
-{
-    if (!m_cache_ok)
-        initialize();
-    ivector_t nearest_coords = getNearestReciprocalLatticeVectorCoordinates(input_vector);
-    return vectorsWithinRadius(input_vector, nearest_coords, radius, m_ra, m_rb, m_rc, m_a, m_b,
-                               m_c);
-}
-
-Lattice Lattice::createCubicLattice(double a)
-{
-    kvector_t a1(a, 0.0, 0.0);
-    kvector_t a2(0.0, a, 0.0);
-    kvector_t a3(0.0, 0.0, a);
-    return Lattice(a1, a2, a3);
-}
-
-Lattice Lattice::createFCCLattice(double a)
-{
-    double b = a / 2.0;
-    kvector_t a1(0.0, b, b);
-    kvector_t a2(b, 0.0, b);
-    kvector_t a3(b, b, 0.0);
-    return Lattice(a1, a2, a3);
-}
-
-Lattice Lattice::createHexagonalLattice(double a, double c)
-{
-    kvector_t a1(a, 0.0, 0.0);
-    kvector_t a2(-a / 2.0, std::sqrt(3.0) * a / 2.0, 0.0);
-    kvector_t a3(0.0, 0.0, c);
-    return Lattice(a1, a2, a3);
-}
-
-Lattice Lattice::createHCPLattice(double a, double c)
-{
-    kvector_t a1(a, 0.0, 0.0);
-    kvector_t a2(-a / 2.0, std::sqrt(3.0) * a / 2.0, 0);
-    kvector_t a3(a / 2.0, a / std::sqrt(3.0) / 2.0, c / 2.0);
-    return Lattice(a1, a2, a3);
-}
-
-Lattice Lattice::createTetragonalLattice(double a, double c)
-{
-    kvector_t a1(a, 0.0, 0.0);
-    kvector_t a2(0.0, a, 0.0);
-    kvector_t a3(0.0, 0.0, c);
-    return Lattice(a1, a2, a3);
-}
-
-Lattice Lattice::createBCTLattice(double a, double c)
-{
-    kvector_t a1(a, 0.0, 0.0);
-    kvector_t a2(0.0, a, 0.0);
-    kvector_t a3(a / 2.0, a / 2.0, c / 2.0);
-    return Lattice(a1, a2, a3);
-}
-
-void Lattice::onChange()
-{
-    m_cache_ok = false;
-}
-
-void Lattice::registerBasisVectors()
-{
-    if (!parameter(XComponentName("BasisA"))) {
-        registerVector("BasisA", &m_a, "nm");
-        registerVector("BasisB", &m_b, "nm");
-        registerVector("BasisC", &m_c, "nm");
-    }
-}
-
-void Lattice::computeReciprocalVectors() const
-{
-    kvector_t a23 = m_b.cross(m_c);
-    kvector_t a31 = m_c.cross(m_a);
-    kvector_t a12 = m_a.cross(m_b);
-    m_ra = M_TWOPI / m_a.dot(a23) * a23;
-    m_rb = M_TWOPI / m_b.dot(a31) * a31;
-    m_rc = M_TWOPI / m_c.dot(a12) * a12;
-}
-
-std::vector<kvector_t> Lattice::vectorsWithinRadius(const kvector_t input_vector,
-                                                    const ivector_t& nearest_coords, double radius,
-                                                    const kvector_t v1, const kvector_t v2,
-                                                    const kvector_t v3, const kvector_t rec1,
-                                                    const kvector_t rec2,
-                                                    const kvector_t rec3) const
-{
-    int max_X = static_cast<int>(std::floor(rec1.mag() * radius / M_TWOPI + 0.5));
-    int max_Y = static_cast<int>(std::floor(rec2.mag() * radius / M_TWOPI + 0.5));
-    int max_Z = static_cast<int>(std::floor(rec3.mag() * radius / M_TWOPI + 0.5));
-
-    std::vector<kvector_t> ret;
-    for (int index_X = -max_X; index_X <= max_X; ++index_X) {
-        for (int index_Y = -max_Y; index_Y <= max_Y; ++index_Y) {
-            for (int index_Z = -max_Z; index_Z <= max_Z; ++index_Z) {
-                ivector_t coords(index_X + nearest_coords[0], index_Y + nearest_coords[1],
-                                 index_Z + nearest_coords[2]);
-                if (m_selection_rule && !m_selection_rule->coordinateSelected(coords))
-                    continue;
-                kvector_t latticePoint = coords[0] * v1 + coords[1] * v2 + coords[2] * v3;
-                if ((latticePoint - input_vector).mag() <= radius)
-                    ret.push_back(latticePoint);
-            }
-        }
-    }
-    return ret;
-}
-
-void Lattice::computeInverseVectors(const kvector_t v1, const kvector_t v2, const kvector_t v3,
-                                    kvector_t o1, kvector_t o2, kvector_t o3)
-{
-    gsl_matrix* p_basisMatrix = gsl_matrix_alloc(3, 3);
-    gsl_matrix* p_inverseMatrix = gsl_matrix_alloc(3, 3);
-    gsl_permutation* p_perm = gsl_permutation_alloc(3);
-    int s;
-
-    gsl_matrix_set(p_basisMatrix, 0, 0, v1.x());
-    gsl_matrix_set(p_basisMatrix, 0, 1, v2.x());
-    gsl_matrix_set(p_basisMatrix, 0, 2, v3.x());
-
-    gsl_matrix_set(p_basisMatrix, 1, 0, v1.y());
-    gsl_matrix_set(p_basisMatrix, 1, 1, v2.y());
-    gsl_matrix_set(p_basisMatrix, 1, 2, v3.y());
-
-    gsl_matrix_set(p_basisMatrix, 2, 0, v1.z());
-    gsl_matrix_set(p_basisMatrix, 2, 1, v2.z());
-    gsl_matrix_set(p_basisMatrix, 2, 2, v3.z());
-
-    gsl_linalg_LU_decomp(p_basisMatrix, p_perm, &s);
-    gsl_linalg_LU_invert(p_basisMatrix, p_perm, p_inverseMatrix);
-
-    o1.setX(gsl_matrix_get(p_inverseMatrix, 0, 0));
-    o1.setY(gsl_matrix_get(p_inverseMatrix, 1, 0));
-    o1.setZ(gsl_matrix_get(p_inverseMatrix, 2, 0));
-
-    o2.setX(gsl_matrix_get(p_inverseMatrix, 0, 1));
-    o2.setY(gsl_matrix_get(p_inverseMatrix, 1, 1));
-    o2.setZ(gsl_matrix_get(p_inverseMatrix, 2, 1));
-
-    o3.setX(gsl_matrix_get(p_inverseMatrix, 0, 2));
-    o3.setY(gsl_matrix_get(p_inverseMatrix, 1, 2));
-    o3.setZ(gsl_matrix_get(p_inverseMatrix, 2, 2));
-
-    gsl_permutation_free(p_perm);
-    gsl_matrix_free(p_basisMatrix);
-    gsl_matrix_free(p_inverseMatrix);
-}
-
-void Lattice::setSelectionRule(const ISelectionRule& p_selection_rule)
-{
-    delete m_selection_rule;
-    m_selection_rule = p_selection_rule.clone();
-}
diff --git a/Sample/Lattice/Lattice.h b/Sample/Lattice/Lattice.h
deleted file mode 100644
index ab640a2a1959228f266d784c3c25eb19b544e1d7..0000000000000000000000000000000000000000
--- a/Sample/Lattice/Lattice.h
+++ /dev/null
@@ -1,119 +0,0 @@
-// ************************************************************************** //
-//
-//  BornAgain: simulate and fit scattering at grazing incidence
-//
-//! @file      Sample/Lattice/Lattice.h
-//! @brief     Defines class Lattice.
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-// ************************************************************************** //
-
-#ifndef BORNAGAIN_SAMPLE_LATTICE_LATTICE_H
-#define BORNAGAIN_SAMPLE_LATTICE_LATTICE_H
-
-#include "Param/Node/INode.h"
-#include <vector>
-
-class ISelectionRule;
-class Transform3D;
-
-//! A lattice with three basis vectors.
-//! @ingroup samples
-
-class Lattice : public INode
-{
-public:
-    Lattice();
-    Lattice(const kvector_t a1, const kvector_t a2, const kvector_t a3);
-    Lattice(const Lattice& lattice);
-    ~Lattice() override;
-
-    void accept(INodeVisitor* visitor) const override { visitor->visit(this); }
-
-    //! Creates transformed lattice
-    Lattice transformed(const Transform3D& transform) const;
-
-    //! Initializes cached data
-    void initialize() const;
-
-    //! Returns basis vector a
-    kvector_t getBasisVectorA() const { return m_a; }
-
-    //! Returns basis vector b
-    kvector_t getBasisVectorB() const { return m_b; }
-
-    //! Returns basis vector c
-    kvector_t getBasisVectorC() const { return m_c; }
-
-    //! Resets the basis vectors
-    void resetBasis(const kvector_t a1, const kvector_t a2, const kvector_t a3);
-
-    //! Returns normalized direction corresponding to the given Miller indices
-    kvector_t getMillerDirection(double h, double k, double l) const;
-
-    //! Returns the volume of the unit cell
-    double volume() const;
-
-    //! Returns the reciprocal basis vectors
-    void getReciprocalLatticeBasis(kvector_t& b1, kvector_t& b2, kvector_t& b3) const;
-
-    //! Returns the nearest lattice point from a given vector
-    ivector_t getNearestLatticeVectorCoordinates(const kvector_t vector_in) const;
-
-    //! Returns the nearest reciprocal lattice point from a given vector
-    ivector_t getNearestReciprocalLatticeVectorCoordinates(const kvector_t vector_in) const;
-
-    //! Computes a list of reciprocal lattice vectors within a specified distance of a given vector
-    std::vector<kvector_t> reciprocalLatticeVectorsWithinRadius(const kvector_t input_vector,
-                                                                double radius) const;
-
-    //! Sets a selection rule for the reciprocal vectors
-    void setSelectionRule(const ISelectionRule& p_selection_rule);
-
-    //! Returns a primitive cubic (cP) lattice with edge length a.
-    static Lattice createCubicLattice(double a);
-
-    //! Returns a face-centered cubic (cF) lattice with edge length a.
-    static Lattice createFCCLattice(double a);
-
-    //! Returns a primitive hexagonal (hP) lattice with hexagonal edge a and height c.
-    static Lattice createHexagonalLattice(double a, double c);
-
-    //! TODO: Clarify how this is meant: HCP is not a Bravais lattice.
-    static Lattice createHCPLattice(double a, double c);
-
-    //! Returns a primitive tetragonal (tP) lattice with square base edge a and height c.
-    static Lattice createTetragonalLattice(double a, double c);
-
-    //! Returns a body-centered cubic (cI) lattice with edge length a.
-    //! TODO: Clarify meaning of c
-    static Lattice createBCTLattice(double a, double c);
-
-    void onChange() override;
-
-private:
-    Lattice& operator=(const Lattice& lattice);
-
-    void registerBasisVectors();
-
-    std::vector<kvector_t> vectorsWithinRadius(const kvector_t input_vector,
-                                               const ivector_t& nearest_coords, double radius,
-                                               const kvector_t v1, const kvector_t v2,
-                                               const kvector_t v3, const kvector_t rec1,
-                                               const kvector_t rec2, const kvector_t rec3) const;
-
-    void computeReciprocalVectors() const;
-    static void computeInverseVectors(const kvector_t v1, const kvector_t v2, const kvector_t v3,
-                                      kvector_t o1, kvector_t o2, kvector_t o3);
-    ISelectionRule* m_selection_rule;
-    kvector_t m_a, m_b, m_c;            //!< Basis vectors in real space
-    mutable kvector_t m_ra, m_rb, m_rc; //!< Cache of basis vectors in reciprocal space
-    //! Boolean indicating if the reciprocal vectors are already initialized in the cache
-    mutable bool m_cache_ok;
-};
-
-#endif // BORNAGAIN_SAMPLE_LATTICE_LATTICE_H
diff --git a/Sample/Lattice/Lattice3D.cpp b/Sample/Lattice/Lattice3D.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1d6bb2bef82b536f5ac1ce6a9f8e25f55cc12ac5
--- /dev/null
+++ b/Sample/Lattice/Lattice3D.cpp
@@ -0,0 +1,131 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      Sample/Lattice/Lattice3D.cpp
+//! @brief     Implements class Lattice.
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2018
+//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
+//
+// ************************************************************************** //
+
+#include "Sample/Lattice/Lattice3D.h"
+#include "Base/Const/MathConstants.h"
+#include "Base/Vector/Transform3D.h"
+#include "Param/Base/RealParameter.h"
+#include "Sample/Lattice/ISelectionRule.h"
+#include <gsl/gsl_linalg.h>
+
+Lattice3D::Lattice3D(const kvector_t a, const kvector_t b, const kvector_t c)
+    : m_a(a), m_b(b), m_c(c)
+{
+    setName("Lattice");
+    initialize();
+}
+
+Lattice3D::Lattice3D(const Lattice3D& lattice)
+    : INode(), m_a(lattice.m_a), m_b(lattice.m_b), m_c(lattice.m_c)
+{
+    setName("Lattice");
+    initialize();
+    if (lattice.m_selection_rule)
+        setSelectionRule(*lattice.m_selection_rule);
+}
+
+Lattice3D::~Lattice3D() = default;
+
+void Lattice3D::initialize()
+{
+    computeReciprocalVectors();
+    if (!parameter(XComponentName("BasisA"))) {
+        registerVector("BasisA", &m_a, "nm");
+        registerVector("BasisB", &m_b, "nm");
+        registerVector("BasisC", &m_c, "nm");
+    }
+}
+
+void Lattice3D::onChange()
+{
+    computeReciprocalVectors();
+}
+
+Lattice3D Lattice3D::transformed(const Transform3D& transform) const
+{
+    kvector_t q1 = transform.transformed(m_a);
+    kvector_t q2 = transform.transformed(m_b);
+    kvector_t q3 = transform.transformed(m_c);
+    Lattice3D result = {q1, q2, q3};
+    if (m_selection_rule)
+        result.setSelectionRule(*m_selection_rule);
+    return result;
+}
+
+//! Currently unused but may be useful for checks
+kvector_t Lattice3D::getMillerDirection(double h, double k, double l) const
+{
+    kvector_t direction = h * m_ra + k * m_rb + l * m_rc;
+    return direction.unit();
+}
+
+double Lattice3D::unitCellVolume() const
+{
+    return std::abs(m_a.dot(m_b.cross(m_c)));
+}
+
+//! Currently only used in tests
+void Lattice3D::getReciprocalLatticeBasis(kvector_t& ra, kvector_t& rb, kvector_t& rc) const
+{
+    ra = m_ra;
+    rb = m_rb;
+    rc = m_rc;
+}
+
+ivector_t Lattice3D::getNearestReciprocalLatticeVectorCoordinates(const kvector_t q) const
+{
+    return {(int)std::lround(q.dot(m_a) / M_TWOPI), (int)std::lround(q.dot(m_b) / M_TWOPI),
+            (int)std::lround(q.dot(m_c) / M_TWOPI)};
+}
+
+std::vector<kvector_t> Lattice3D::reciprocalLatticeVectorsWithinRadius(const kvector_t q,
+                                                                       double dq) const
+{
+    ivector_t nearest_coords = getNearestReciprocalLatticeVectorCoordinates(q);
+
+    int max_X = std::lround(m_a.mag() * dq / M_TWOPI);
+    int max_Y = std::lround(m_b.mag() * dq / M_TWOPI);
+    int max_Z = std::lround(m_c.mag() * dq / M_TWOPI);
+
+    std::vector<kvector_t> ret;
+    for (int index_X = -max_X; index_X <= max_X; ++index_X) {
+        for (int index_Y = -max_Y; index_Y <= max_Y; ++index_Y) {
+            for (int index_Z = -max_Z; index_Z <= max_Z; ++index_Z) {
+                ivector_t coords(index_X + nearest_coords[0], index_Y + nearest_coords[1],
+                                 index_Z + nearest_coords[2]);
+                if (m_selection_rule && !m_selection_rule->coordinateSelected(coords))
+                    continue;
+                kvector_t latticePoint = coords[0] * m_ra + coords[1] * m_rb + coords[2] * m_rc;
+                if ((latticePoint - q).mag() <= dq)
+                    ret.push_back(latticePoint);
+            }
+        }
+    }
+    return ret;
+}
+
+void Lattice3D::computeReciprocalVectors() const
+{
+    kvector_t q23 = m_b.cross(m_c);
+    kvector_t q31 = m_c.cross(m_a);
+    kvector_t q12 = m_a.cross(m_b);
+    m_ra = M_TWOPI / m_a.dot(q23) * q23;
+    m_rb = M_TWOPI / m_b.dot(q31) * q31;
+    m_rc = M_TWOPI / m_c.dot(q12) * q12;
+}
+
+void Lattice3D::setSelectionRule(const ISelectionRule& selection_rule)
+{
+    m_selection_rule.reset(selection_rule.clone());
+}
diff --git a/Sample/Lattice/Lattice3D.h b/Sample/Lattice/Lattice3D.h
new file mode 100644
index 0000000000000000000000000000000000000000..b4ae819e5279dbe695bf53bdf43b7c679ae0e8eb
--- /dev/null
+++ b/Sample/Lattice/Lattice3D.h
@@ -0,0 +1,84 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      Sample/Lattice/Lattice3D.h
+//! @brief     Defines class Lattice.
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2018
+//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
+//
+// ************************************************************************** //
+
+#ifndef BORNAGAIN_SAMPLE_LATTICE_LATTICE_H
+#define BORNAGAIN_SAMPLE_LATTICE_LATTICE_H
+
+#include "Param/Node/INode.h"
+#include <memory>
+#include <vector>
+
+class ISelectionRule;
+class Transform3D;
+
+//! A Bravais lattice, characterized by three basis vectors, and optionally an ISelectionRule.
+
+//! @ingroup samples
+
+class Lattice3D : public INode
+{
+public:
+    Lattice3D() = delete;
+    Lattice3D(const kvector_t a, const kvector_t b, const kvector_t c);
+    Lattice3D(const Lattice3D& lattice);
+    ~Lattice3D() override;
+    Lattice3D& operator=(const Lattice3D&) = delete;
+
+    void accept(INodeVisitor* visitor) const override { visitor->visit(this); }
+
+    //! Creates transformed lattice
+    Lattice3D transformed(const Transform3D& transform) const;
+
+    //! Initializes cached data
+    void initialize();
+
+    //! Returns basis vector a
+    kvector_t getBasisVectorA() const { return m_a; }
+
+    //! Returns basis vector b
+    kvector_t getBasisVectorB() const { return m_b; }
+
+    //! Returns basis vector c
+    kvector_t getBasisVectorC() const { return m_c; }
+
+    //! Returns normalized direction corresponding to the given Miller indices
+    kvector_t getMillerDirection(double h, double k, double l) const;
+
+    //! Returns the volume of the unit cell
+    double unitCellVolume() const;
+
+    //! Returns the reciprocal basis vectors
+    void getReciprocalLatticeBasis(kvector_t& ra, kvector_t& rb, kvector_t& rc) const;
+
+    //! Returns the nearest reciprocal lattice point from a given vector
+    ivector_t getNearestReciprocalLatticeVectorCoordinates(const kvector_t q) const;
+
+    //! Returns a list of reciprocal lattice vectors within distance dq of a vector q
+    std::vector<kvector_t> reciprocalLatticeVectorsWithinRadius(const kvector_t q, double dq) const;
+
+    //! Sets a selection rule for the reciprocal vectors
+    void setSelectionRule(const ISelectionRule& selection_rule);
+
+private:
+    void onChange() override;
+
+    void computeReciprocalVectors() const;
+
+    kvector_t m_a, m_b, m_c; //!< Basis vectors in real space
+    std::unique_ptr<ISelectionRule> m_selection_rule;
+
+    mutable kvector_t m_ra, m_rb, m_rc; //!< Cache of basis vectors in reciprocal space
+};
+
+#endif // BORNAGAIN_SAMPLE_LATTICE_LATTICE_H
diff --git a/Sample/Lattice/LatticeUtils.cpp b/Sample/Lattice/LatticeUtils.cpp
deleted file mode 100644
index d1fd9a8b02d1b4eb98b2b3cb946e8c0046234e38..0000000000000000000000000000000000000000
--- a/Sample/Lattice/LatticeUtils.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-// ************************************************************************** //
-//
-//  BornAgain: simulate and fit scattering at grazing incidence
-//
-//! @file      Sample/Lattice/LatticeUtils.cpp
-//! @brief     Implements factory functions for different types of lattices and orientations.
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-// ************************************************************************** //
-
-#include "Sample/Lattice/LatticeUtils.h"
-#include "Sample/Lattice/ILatticeOrientation.h"
-
-Lattice LatticeUtils::createFCCLattice(double lattice_constant,
-                                       const ILatticeOrientation& orientation)
-{
-    const Lattice prim_cubic = Lattice::createCubicLattice(1.0);
-    std::unique_ptr<ILatticeOrientation> P_orientation(orientation.clone());
-    P_orientation->usePrimitiveLattice(prim_cubic);
-    const Transform3D trafo = P_orientation->transformation();
-    const Lattice fcc = Lattice::createFCCLattice(lattice_constant);
-    return fcc.transformed(trafo);
-}
-
-Lattice LatticeUtils::createHCPLattice(double a, double c, const ILatticeOrientation& orientation)
-{
-    const Lattice prim_hexagonal = Lattice::createHexagonalLattice(1.0, c / a);
-    std::unique_ptr<ILatticeOrientation> P_orientation(orientation.clone());
-    P_orientation->usePrimitiveLattice(prim_hexagonal);
-    const Transform3D trafo = P_orientation->transformation();
-    const Lattice hcp = Lattice::createHCPLattice(a, c);
-    return hcp.transformed(trafo);
-}
-
-Lattice LatticeUtils::createBCTLattice(double a, double c, const ILatticeOrientation& orientation)
-{
-    const Lattice prim_tetragonal = Lattice::createTetragonalLattice(1.0, c / a);
-    std::unique_ptr<ILatticeOrientation> P_orientation(orientation.clone());
-    P_orientation->usePrimitiveLattice(prim_tetragonal);
-    const Transform3D trafo = P_orientation->transformation();
-    const Lattice hcp = Lattice::createBCTLattice(a, c);
-    return hcp.transformed(trafo);
-}
diff --git a/Sample/Lattice/LatticeUtils.h b/Sample/Lattice/LatticeUtils.h
deleted file mode 100644
index aa1b418938adbff49338a0faa6bc5bacbb3c31e1..0000000000000000000000000000000000000000
--- a/Sample/Lattice/LatticeUtils.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// ************************************************************************** //
-//
-//  BornAgain: simulate and fit scattering at grazing incidence
-//
-//! @file      Sample/Lattice/LatticeUtils.h
-//! @brief     Defines factory functions for different types of lattices and orientations.
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-// ************************************************************************** //
-
-#ifndef BORNAGAIN_SAMPLE_LATTICE_LATTICEUTILS_H
-#define BORNAGAIN_SAMPLE_LATTICE_LATTICEUTILS_H
-
-#include "Sample/Lattice/Lattice.h"
-
-class ILatticeOrientation;
-
-namespace LatticeUtils
-{
-Lattice createFCCLattice(double lattice_constant, const ILatticeOrientation& orientation);
-Lattice createHCPLattice(double a, double c, const ILatticeOrientation& orientation);
-Lattice createBCTLattice(double a, double c, const ILatticeOrientation& orientation);
-} // namespace LatticeUtils
-
-#endif // BORNAGAIN_SAMPLE_LATTICE_LATTICEUTILS_H
diff --git a/Sample/Multilayer/Layer.cpp b/Sample/Multilayer/Layer.cpp
index f33917ce14f6d9337aa9a4bb66264aaffa35c665..ec7a8265243dabf5f4d4c0b342c788a2d467f836 100644
--- a/Sample/Multilayer/Layer.cpp
+++ b/Sample/Multilayer/Layer.cpp
@@ -16,7 +16,7 @@
 #include "Base/Types/Exceptions.h"
 #include "Param/Base/ParameterPool.h"
 #include "Param/Base/RealParameter.h"
-#include "Sample/Correlations/ILayout.h"
+#include "Sample/Aggregate/ParticleLayout.h"
 
 //! Constructor of a layer with thickness and material
 //! @param material: material the layer is made of
@@ -54,16 +54,16 @@ void Layer::setMaterial(Material material)
     m_material = std::move(material);
 }
 
-void Layer::addLayout(const ILayout& layout)
+void Layer::addLayout(const ParticleLayout& layout)
 {
-    ILayout* clone = layout.clone();
+    ParticleLayout* clone = layout.clone();
     m_layouts.push_back(clone);
     registerChild(clone);
 }
 
-std::vector<const ILayout*> Layer::layouts() const
+std::vector<const ParticleLayout*> Layer::layouts() const
 {
-    std::vector<const ILayout*> result;
+    std::vector<const ParticleLayout*> result;
     for (auto p_layout : m_layouts)
         result.push_back(p_layout);
     return result;
diff --git a/Sample/Multilayer/Layer.h b/Sample/Multilayer/Layer.h
index 5d2b7fe382367c6261d2e895a95821b29dbb7a8e..1cf7bfaa182e3e800170c4f2847ec6ee596db2be 100644
--- a/Sample/Multilayer/Layer.h
+++ b/Sample/Multilayer/Layer.h
@@ -19,7 +19,7 @@
 #include "Sample/Material/Material.h"
 #include "Sample/Scattering/ISample.h"
 
-class ILayout;
+class ParticleLayout;
 
 //! A layer, with thickness (in nanometer) and material.
 //! @ingroup samples
@@ -41,9 +41,9 @@ public:
     const Material* material() const override final { return &m_material; }
     void setMaterial(Material material);
 
-    void addLayout(const ILayout& decoration);
+    void addLayout(const ParticleLayout& decoration);
     size_t numberOfLayouts() const { return m_layouts.size(); }
-    std::vector<const ILayout*> layouts() const;
+    std::vector<const ParticleLayout*> layouts() const;
 
     std::vector<const INode*> getChildren() const override final;
 
@@ -53,11 +53,11 @@ public:
     unsigned int numberOfSlices() const { return m_n_slices; }
 
 private:
-    Material m_material;                  //!< material
-    kvector_t m_B_field;                  //!< cached value of magnetic induction
-    double m_thickness;                   //!< layer thickness in nanometers
-    SafePointerVector<ILayout> m_layouts; //!< independent layouts in this layer
-    unsigned int m_n_slices = 1;          //!< number of slices to create for graded layer approach
+    Material m_material;                         //!< material
+    kvector_t m_B_field;                         //!< cached value of magnetic induction
+    double m_thickness;                          //!< layer thickness in nanometers
+    SafePointerVector<ParticleLayout> m_layouts; //!< independent layouts in this layer
+    unsigned int m_n_slices = 1; //!< number of slices to create for graded layer approach
 };
 
 #endif // BORNAGAIN_SAMPLE_MULTILAYER_LAYER_H
diff --git a/Sample/Multilayer/MultiLayer.cpp b/Sample/Multilayer/MultiLayer.cpp
index 1a9228ab7bc95209fb4b7130aee2df0d50179ff5..5106f703f460b544aba21b332c234a6a4c521657 100644
--- a/Sample/Multilayer/MultiLayer.cpp
+++ b/Sample/Multilayer/MultiLayer.cpp
@@ -16,7 +16,7 @@
 #include "Base/Types/Exceptions.h"
 #include "Param/Base/ParameterPool.h"
 #include "Param/Base/RealParameter.h"
-#include "Sample/Correlations/ILayout.h"
+#include "Sample/Aggregate/ParticleLayout.h"
 #include "Sample/Material/MaterialUtils.h"
 #include "Sample/Multilayer/Layer.h"
 #include "Sample/Multilayer/MultiLayerUtils.h"
diff --git a/Sample/Multilayer/MultiLayer.h b/Sample/Multilayer/MultiLayer.h
index da2325fad302e76ea4eedc56add90ec28b3b62d6..0a647a489ad492f4bd85f968b0c74610a4c31e36 100644
--- a/Sample/Multilayer/MultiLayer.h
+++ b/Sample/Multilayer/MultiLayer.h
@@ -20,7 +20,7 @@
 #include "Sample/Scattering/ISample.h"
 #include <functional>
 
-class ILayout;
+class ParticleLayout;
 class Layer;
 class LayerInterface;
 class LayerRoughness;
diff --git a/Sample/Multilayer/MultiLayerUtils.cpp b/Sample/Multilayer/MultiLayerUtils.cpp
index befbd7a17c2ac8781bf9a17a2eb6973cae180cc7..f95b6e14dc00609b13332b7b3fc99bd49829e958 100644
--- a/Sample/Multilayer/MultiLayerUtils.cpp
+++ b/Sample/Multilayer/MultiLayerUtils.cpp
@@ -13,7 +13,7 @@
 // ************************************************************************** //
 
 #include "Sample/Multilayer/MultiLayerUtils.h"
-#include "Sample/Correlations/ILayout.h"
+#include "Sample/Aggregate/ParticleLayout.h"
 #include "Sample/Material/MaterialUtils.h"
 #include "Sample/Multilayer/Layer.h"
 #include "Sample/Multilayer/MultiLayer.h"
@@ -23,7 +23,20 @@
 
 namespace
 {
-std::vector<double> BottomLayerCoordinates(const MultiLayer& multilayer);
+
+std::vector<double> BottomLayerCoordinates(const MultiLayer& multilayer)
+{
+    auto n_layers = multilayer.numberOfLayers();
+    if (n_layers < 2)
+        return {};
+    std::vector<double> result(n_layers - 1);
+    result[0] = 0.0;
+    for (size_t i = 1; i < n_layers - 1; ++i) {
+        result[i] = result[i - 1] - MultiLayerUtils::LayerThickness(multilayer, i);
+    }
+    return result;
+}
+
 } // namespace
 
 double MultiLayerUtils::LayerThickness(const MultiLayer& multilayer, size_t i)
@@ -92,19 +105,3 @@ bool MultiLayerUtils::hasRoughness(const MultiLayer& sample)
     }
     return false;
 }
-
-namespace
-{
-std::vector<double> BottomLayerCoordinates(const MultiLayer& multilayer)
-{
-    auto n_layers = multilayer.numberOfLayers();
-    if (n_layers < 2)
-        return {};
-    std::vector<double> result(n_layers - 1);
-    result[0] = 0.0;
-    for (size_t i = 1; i < n_layers - 1; ++i) {
-        result[i] = result[i - 1] - MultiLayerUtils::LayerThickness(multilayer, i);
-    }
-    return result;
-}
-} // unnamed namespace
diff --git a/Sample/Particle/Crystal.cpp b/Sample/Particle/Crystal.cpp
index 5d68e28fbbd837d514a4b55368086b22b864d701..55c15b47154defb3f6c49107c11aa1ca6328172b 100644
--- a/Sample/Particle/Crystal.cpp
+++ b/Sample/Particle/Crystal.cpp
@@ -18,13 +18,22 @@
 #include "Sample/Particle/ParticleComposition.h"
 #include "Sample/Particle/SlicedParticle.h"
 
-Crystal::Crystal(const IParticle& lattice_basis, const Lattice& lattice)
-    : m_lattice(lattice), m_position_variance(0.0)
+Crystal::Crystal(const IParticle& basis, const Lattice3D& lattice, double position_variance)
+    : m_lattice(lattice), m_position_variance(position_variance)
 {
     setName("Crystal");
-    m_lattice_basis.reset(lattice_basis.clone());
-    m_lattice_basis->registerAbundance(false);
-    registerChild(m_lattice_basis.get());
+    m_basis.reset(basis.clone());
+    m_basis->registerAbundance(false);
+    registerChild(m_basis.get());
+    registerChild(&m_lattice);
+}
+
+Crystal::Crystal(IParticle* p_basis, const Lattice3D& lattice, double position_variance)
+    : m_lattice(lattice), m_position_variance(position_variance)
+{
+    setName("Crystal");
+    m_basis.reset(p_basis);
+    registerChild(m_basis.get());
     registerChild(&m_lattice);
 }
 
@@ -32,17 +41,15 @@ Crystal::~Crystal() = default;
 
 Crystal* Crystal::clone() const
 {
-    Crystal* p_new = new Crystal(*m_lattice_basis, m_lattice);
-    p_new->setPositionVariance(m_position_variance);
-    return p_new;
+    return new Crystal(*m_basis, m_lattice, m_position_variance);
 }
 
 IFormFactor* Crystal::createTotalFormFactor(const IFormFactor& meso_crystal_form_factor,
                                             const IRotation* p_rotation,
                                             const kvector_t& translation) const
 {
-    Lattice transformed_lattice = transformedLattice(p_rotation);
-    std::unique_ptr<IParticle> P_basis_clone{m_lattice_basis->clone()};
+    Lattice3D transformed_lattice = transformedLattice(p_rotation);
+    std::unique_ptr<IParticle> P_basis_clone{m_basis->clone()};
     if (p_rotation)
         P_basis_clone->rotate(*p_rotation);
     P_basis_clone->translate(translation);
@@ -54,10 +61,10 @@ IFormFactor* Crystal::createTotalFormFactor(const IFormFactor& meso_crystal_form
 std::vector<HomogeneousRegion> Crystal::homogeneousRegions() const
 {
     std::vector<HomogeneousRegion> result;
-    double unit_cell_volume = m_lattice.volume();
+    double unit_cell_volume = m_lattice.unitCellVolume();
     if (unit_cell_volume <= 0)
         return {};
-    auto particles = m_lattice_basis->decompose();
+    auto particles = m_basis->decompose();
     ZLimits limits;
     for (auto p_particle : particles) {
         auto sliced_particle = p_particle->createSlicedParticle(limits);
@@ -69,24 +76,14 @@ std::vector<HomogeneousRegion> Crystal::homogeneousRegions() const
     return result;
 }
 
-Lattice Crystal::transformedLattice(const IRotation* p_rotation) const
+Lattice3D Crystal::transformedLattice(const IRotation* p_rotation) const
 {
-    if (p_rotation)
-        return m_lattice.transformed(p_rotation->getTransform3D());
-    else
+    if (!p_rotation)
         return m_lattice;
+    return m_lattice.transformed(p_rotation->getTransform3D());
 }
 
 std::vector<const INode*> Crystal::getChildren() const
 {
-    return std::vector<const INode*>() << m_lattice_basis << &m_lattice;
-}
-
-Crystal::Crystal(IParticle* p_lattice_basis, const Lattice& lattice)
-    : m_lattice(lattice), m_position_variance(0.0)
-{
-    setName("Crystal");
-    m_lattice_basis.reset(p_lattice_basis);
-    registerChild(m_lattice_basis.get());
-    registerChild(&m_lattice);
+    return std::vector<const INode*>() << m_basis << &m_lattice;
 }
diff --git a/Sample/Particle/Crystal.h b/Sample/Particle/Crystal.h
index b60de86420421deb8ea305ae46968c655fb62572..c9a247a38e373a7051fdfcadd71d118bb1b2d7a0 100644
--- a/Sample/Particle/Crystal.h
+++ b/Sample/Particle/Crystal.h
@@ -15,17 +15,27 @@
 #ifndef BORNAGAIN_SAMPLE_PARTICLE_CRYSTAL_H
 #define BORNAGAIN_SAMPLE_PARTICLE_CRYSTAL_H
 
-#include "Sample/Lattice/Lattice.h"
-#include "Sample/Particle/IClusteredParticles.h"
+#include "Sample/Lattice/Lattice3D.h"
+#include "Sample/Scattering/ISample.h"
 
-//! A crystal structure with a ParticleComposition as a basis.
+class IFormFactor;
+class IRotation;
+struct HomogeneousRegion;
+
+//! A crystal structure, defined by a Bravais lattice, a basis, and a position variance.
+//!
+//! The basis is either a Particle or a ParticleComposition.
+//!
+//! Computations are delegated to class FormFactorCrystal.
+//!
 //! Used in MesoCrystal, where it is given an outer shape.
+//!
 //! @ingroup samples
 
-class Crystal : public IClusteredParticles
+class Crystal : public ISample
 {
 public:
-    Crystal(const IParticle& lattice_basis, const Lattice& lattice);
+    Crystal(const IParticle& basis, const Lattice3D& lattice, double position_variance = 0);
     ~Crystal();
 
     Crystal* clone() const override final;
@@ -34,22 +44,20 @@ public:
 
     IFormFactor* createTotalFormFactor(const IFormFactor& meso_crystal_form_factor,
                                        const IRotation* p_rotation,
-                                       const kvector_t& translation) const override final;
-
-    std::vector<HomogeneousRegion> homogeneousRegions() const override final;
+                                       const kvector_t& translation) const;
 
-    Lattice transformedLattice(const IRotation* p_rotation = nullptr) const;
+    std::vector<HomogeneousRegion> homogeneousRegions() const;
 
-    void setPositionVariance(double position_variance) { m_position_variance = position_variance; }
+    Lattice3D transformedLattice(const IRotation* p_rotation = nullptr) const;
 
     std::vector<const INode*> getChildren() const override final;
 
 private:
-    Crystal(IParticle* p_lattice_basis, const Lattice& lattice);
+    Crystal(IParticle* p_basis, const Lattice3D& lattice, double position_variance = 0);
 
-    Lattice m_lattice;
-    std::unique_ptr<IParticle> m_lattice_basis;
-    double m_position_variance;
+    Lattice3D m_lattice;
+    std::unique_ptr<IParticle> m_basis;
+    const double m_position_variance;
 };
 
 #endif // BORNAGAIN_SAMPLE_PARTICLE_CRYSTAL_H
diff --git a/Sample/Particle/FormFactorCrystal.cpp b/Sample/Particle/FormFactorCrystal.cpp
index e3a5c9663e9bb79f1ee199b3806ffecd2079950a..28cab893db9fd09c8c5c22b64d865b7ff04f39ea 100644
--- a/Sample/Particle/FormFactorCrystal.cpp
+++ b/Sample/Particle/FormFactorCrystal.cpp
@@ -17,7 +17,7 @@
 #include "Base/Types/Exceptions.h"
 #include "Sample/Material/WavevectorInfo.h"
 
-FormFactorCrystal::FormFactorCrystal(const Lattice& lattice, const IFormFactor& basis_form_factor,
+FormFactorCrystal::FormFactorCrystal(const Lattice3D& lattice, const IFormFactor& basis_form_factor,
                                      const IFormFactor& meso_form_factor, double position_variance)
     : m_lattice(lattice)
     , m_basis_form_factor(basis_form_factor.clone())
@@ -65,8 +65,7 @@ complex_t FormFactorCrystal::evaluate(const WavevectorInfo& wavevectors) const
     }
     // the transformed delta train gets a factor of (2pi)^3/V, but the (2pi)^3
     // is canceled by the convolution of Fourier transforms :
-    double volume = m_lattice.volume();
-    return result / volume;
+    return result / m_lattice.unitCellVolume();
 }
 
 Eigen::Matrix2cd FormFactorCrystal::evaluatePol(const WavevectorInfo& wavevectors) const
@@ -90,8 +89,7 @@ Eigen::Matrix2cd FormFactorCrystal::evaluatePol(const WavevectorInfo& wavevector
     }
     // the transformed delta train gets a factor of (2pi)^3/V, but the (2pi)^3
     // is canceled by the convolution of Fourier transforms :
-    double volume = m_lattice.volume();
-    return result / volume;
+    return result / m_lattice.unitCellVolume();
 }
 
 void FormFactorCrystal::calculateLargestReciprocalDistance()
diff --git a/Sample/Particle/FormFactorCrystal.h b/Sample/Particle/FormFactorCrystal.h
index ea098a254b0fc30819a50188d646bbbce2f80326..22acd8a096ea826a43c463813725af89694d6724 100644
--- a/Sample/Particle/FormFactorCrystal.h
+++ b/Sample/Particle/FormFactorCrystal.h
@@ -15,7 +15,7 @@
 #ifndef BORNAGAIN_SAMPLE_PARTICLE_FORMFACTORCRYSTAL_H
 #define BORNAGAIN_SAMPLE_PARTICLE_FORMFACTORCRYSTAL_H
 
-#include "Sample/Lattice/Lattice.h"
+#include "Sample/Lattice/Lattice3D.h"
 #include "Sample/Scattering/IFormFactorBorn.h"
 
 //! The form factor of a MesoCrystal.
@@ -24,7 +24,7 @@
 class FormFactorCrystal : public IFormFactor
 {
 public:
-    FormFactorCrystal(const Lattice& lattice, const IFormFactor& basis_form_factor,
+    FormFactorCrystal(const Lattice3D& lattice, const IFormFactor& basis_form_factor,
                       const IFormFactor& meso_form_factor, double position_variance = 0.0);
     ~FormFactorCrystal() override final;
 
@@ -57,7 +57,7 @@ private:
     void calculateLargestReciprocalDistance();
     complex_t debyeWallerFactor(const kvector_t& q_i) const;
 
-    Lattice m_lattice;
+    Lattice3D m_lattice;
     IFormFactor* m_basis_form_factor;
     IFormFactor* m_meso_form_factor; //!< The outer shape of this mesocrystal
     double m_position_variance;
diff --git a/Sample/Particle/IClusteredParticles.h b/Sample/Particle/IClusteredParticles.h
deleted file mode 100644
index 0b9ed83f9c521405235ec05c0b1fa5522315ea58..0000000000000000000000000000000000000000
--- a/Sample/Particle/IClusteredParticles.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// ************************************************************************** //
-//
-//  BornAgain: simulate and fit scattering at grazing incidence
-//
-//! @file      Sample/Particle/IClusteredParticles.h
-//! @brief     Defines class IClusteredParticles.
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-// ************************************************************************** //
-
-#ifndef BORNAGAIN_SAMPLE_PARTICLE_ICLUSTEREDPARTICLES_H
-#define BORNAGAIN_SAMPLE_PARTICLE_ICLUSTEREDPARTICLES_H
-
-#include "Sample/Particle/HomogeneousRegion.h"
-#include "Sample/Scattering/ISample.h"
-
-class IFormFactor;
-class IRotation;
-
-//! An ordered assembly of particles. Currently, the only child class is Crystal.
-//! @ingroup samples_internal
-
-class IClusteredParticles : public ISample
-{
-public:
-    IClusteredParticles* clone() const override = 0;
-
-    //! Creates a total form factor for the mesocrystal with a specific shape and content
-    //! The bulk content of the mesocrystal is encapsulated by the IClusteredParticles object itself
-    virtual IFormFactor* createTotalFormFactor(const IFormFactor&, const IRotation*,
-                                               const kvector_t& /*translation*/) const = 0;
-
-    //! Creates region information with volumetric densities instead of absolute volume
-    //! These densities need to be multiplied by the total mesocrystal volume
-    virtual std::vector<HomogeneousRegion> homogeneousRegions() const = 0;
-};
-
-#endif // BORNAGAIN_SAMPLE_PARTICLE_ICLUSTEREDPARTICLES_H
diff --git a/Sample/Particle/MesoCrystal.cpp b/Sample/Particle/MesoCrystal.cpp
index ead55e97686eab54757ddfc15bf6f62702b9b8c0..652ac6de5b320148aba38b1b2b345b4ae51beec2 100644
--- a/Sample/Particle/MesoCrystal.cpp
+++ b/Sample/Particle/MesoCrystal.cpp
@@ -13,13 +13,12 @@
 // ************************************************************************** //
 
 #include "Sample/Particle/MesoCrystal.h"
-#include "Sample/Particle/IClusteredParticles.h"
+#include "Sample/Particle/Crystal.h"
 #include "Sample/Particle/SlicedParticle.h"
 #include "Sample/Scattering/FormFactorDecoratorPositionFactor.h"
 #include "Sample/Scattering/FormFactorDecoratorRotation.h"
 
-MesoCrystal::MesoCrystal(const IClusteredParticles& particle_structure,
-                         const IFormFactor& form_factor)
+MesoCrystal::MesoCrystal(const Crystal& particle_structure, const IFormFactor& form_factor)
     : m_particle_structure(particle_structure.clone()), m_meso_form_factor(form_factor.clone())
 {
     initialize();
@@ -47,19 +46,19 @@ SlicedParticle MesoCrystal::createSlicedParticle(ZLimits limits) const
 {
     if (!m_particle_structure || !m_meso_form_factor)
         return {};
-    std::unique_ptr<IRotation> P_rotation(new IdentityRotation);
+    std::unique_ptr<IRotation> rotation(new IdentityRotation);
     if (m_rotation)
-        P_rotation.reset(m_rotation->clone());
-    std::unique_ptr<IFormFactor> P_tem_ff(
-        m_meso_form_factor->createSlicedFormFactor(limits, *P_rotation, m_position));
-    std::unique_ptr<IFormFactor> P_total_ff(
-        m_particle_structure->createTotalFormFactor(*P_tem_ff, P_rotation.get(), m_position));
+        rotation.reset(m_rotation->clone());
+    std::unique_ptr<IFormFactor> tem_ff(
+        m_meso_form_factor->createSlicedFormFactor(limits, *rotation, m_position));
+    std::unique_ptr<IFormFactor> total_ff(
+        m_particle_structure->createTotalFormFactor(*tem_ff, rotation.get(), m_position));
     double meso_volume = m_meso_form_factor->volume();
     auto regions = m_particle_structure->homogeneousRegions();
     for (auto& region : regions)
         region.m_volume *= meso_volume;
     SlicedParticle result;
-    result.m_slicedff = std::move(P_total_ff);
+    result.m_slicedff = std::move(total_ff);
     result.m_regions = regions;
     return result;
 }
@@ -70,8 +69,8 @@ std::vector<const INode*> MesoCrystal::getChildren() const
            << IParticle::getChildren() << m_particle_structure << m_meso_form_factor;
 }
 
-MesoCrystal::MesoCrystal(IClusteredParticles* p_particle_structure, IFormFactor* p_form_factor)
-    : m_particle_structure(p_particle_structure), m_meso_form_factor(p_form_factor)
+MesoCrystal::MesoCrystal(Crystal* particle_structure, IFormFactor* form_factor)
+    : m_particle_structure(particle_structure), m_meso_form_factor(form_factor)
 {
     initialize();
 }
diff --git a/Sample/Particle/MesoCrystal.h b/Sample/Particle/MesoCrystal.h
index 401e9ac4ff79661040046ccb317e99d67a46c836..b2a5f1d87f58bd5a150b28d6dc5a0c1648547b4e 100644
--- a/Sample/Particle/MesoCrystal.h
+++ b/Sample/Particle/MesoCrystal.h
@@ -17,7 +17,7 @@
 
 #include "Sample/Particle/IParticle.h"
 
-class IClusteredParticles;
+class Crystal;
 
 //! A particle with an internal structure of smaller particles.
 //! @ingroup samples
@@ -25,7 +25,7 @@ class IClusteredParticles;
 class MesoCrystal : public IParticle
 {
 public:
-    MesoCrystal(const IClusteredParticles& particle_structure, const IFormFactor& form_factor);
+    MesoCrystal(const Crystal& particle_structure, const IFormFactor& form_factor);
 
     ~MesoCrystal();
     MesoCrystal* clone() const override final;
@@ -37,11 +37,11 @@ public:
     std::vector<const INode*> getChildren() const override final;
 
 private:
-    MesoCrystal(IClusteredParticles* p_particle_structure, IFormFactor* p_form_factor);
+    MesoCrystal(Crystal* p_particle_structure, IFormFactor* p_form_factor);
     void initialize();
 
-    std::unique_ptr<IClusteredParticles> m_particle_structure; //!< Crystal  structure
-    std::unique_ptr<IFormFactor> m_meso_form_factor;           //!< Outer shape of this mesocrystal
+    std::unique_ptr<Crystal> m_particle_structure;   //!< Crystal  structure
+    std::unique_ptr<IFormFactor> m_meso_form_factor; //!< Outer shape of this mesocrystal
 };
 
 #endif // BORNAGAIN_SAMPLE_PARTICLE_MESOCRYSTAL_H
diff --git a/Sample/StandardSamples/BoxCompositionBuilder.cpp b/Sample/StandardSamples/BoxCompositionBuilder.cpp
index 11ee1968dddf72133af04a8cb68bd1f9e5440aff..60114f6cd24fd603325bdfc47e51977e2f5b5b4d 100644
--- a/Sample/StandardSamples/BoxCompositionBuilder.cpp
+++ b/Sample/StandardSamples/BoxCompositionBuilder.cpp
@@ -26,10 +26,10 @@ namespace
 {
 
 const Material particleMaterial = HomogeneousMaterial("Ag", 1.245e-5, 5.419e-7);
-const double layer_thickness = 100.0 * Units::nanometer;
-const double length = 50.0 * Units::nanometer;
-const double width = 20.0 * Units::nanometer;
-const double height = 10.0 * Units::nanometer;
+const double layer_thickness = 100.0 * Units::nm;
+const double length = 50.0 * Units::nm;
+const double width = 20.0 * Units::nm;
+const double height = 10.0 * Units::nm;
 
 MultiLayer* finalizeMultiLayer(const ParticleComposition& composition)
 {
@@ -58,7 +58,7 @@ MultiLayer* BoxCompositionRotateXBuilder::buildSample() const
     ParticleComposition composition;
     composition.addParticle(box, kvector_t(0.0, 0.0, 0.0));
     composition.addParticle(box, kvector_t(length / 2.0, 0.0, 0.0));
-    composition.setRotation(RotationX(90.0 * Units::degree));
+    composition.setRotation(RotationX(90.0 * Units::deg));
     composition.setPosition(kvector_t(0.0, 0.0, -layer_thickness / 2.0));
     return finalizeMultiLayer(composition);
 }
@@ -71,7 +71,7 @@ MultiLayer* BoxCompositionRotateYBuilder::buildSample() const
     ParticleComposition composition;
     composition.addParticle(box, kvector_t(0.0, 0.0, 0.0));
     composition.addParticle(box, kvector_t(length / 2.0, 0.0, 0.0));
-    composition.setRotation(RotationY(90.0 * Units::degree));
+    composition.setRotation(RotationY(90.0 * Units::deg));
     composition.setPosition(kvector_t(0.0, 0.0, -layer_thickness / 2.0 + length / 4.0));
     return finalizeMultiLayer(composition);
 }
@@ -84,7 +84,7 @@ MultiLayer* BoxCompositionRotateZBuilder::buildSample() const
     ParticleComposition composition;
     composition.addParticle(box, kvector_t(0.0, 0.0, 0.0));
     composition.addParticle(box, kvector_t(length / 2.0, 0.0, 0.0));
-    composition.setRotation(RotationZ(90.0 * Units::degree));
+    composition.setRotation(RotationZ(90.0 * Units::deg));
     composition.setPosition(kvector_t(0.0, 0.0, -layer_thickness / 2.0 - height / 2.0));
     return finalizeMultiLayer(composition);
 }
@@ -97,8 +97,8 @@ MultiLayer* BoxCompositionRotateZandYBuilder::buildSample() const
     ParticleComposition composition;
     composition.addParticle(box, kvector_t(0.0, 0.0, 0.0));
     composition.addParticle(box, kvector_t(length / 2.0, 0.0, 0.0));
-    composition.setRotation(RotationZ(90.0 * Units::degree));
-    composition.rotate(RotationY(90.0 * Units::degree));
+    composition.setRotation(RotationZ(90.0 * Units::deg));
+    composition.rotate(RotationY(90.0 * Units::deg));
     composition.setPosition(kvector_t(0.0, 0.0, -layer_thickness / 2.0));
     return finalizeMultiLayer(composition);
 }
@@ -115,19 +115,19 @@ MultiLayer* BoxStackCompositionBuilder::buildSample() const
     const double box1_width = 50;
     const double box1_height = 5;
     Particle box1(particleMaterial, FormFactorBox(box1_length, box1_width, box1_height));
-    box1.setRotation(RotationZ(90. * Units::degree));
+    box1.setRotation(RotationZ(90. * Units::deg));
 
     // box2 (5,20,50), rotatedY
     const double box2_length = 5.0;
     const double box2_width = 20.0;
     const double box2_height = 50.0;
     Particle box2(particleMaterial, FormFactorBox(box2_length, box2_width, box2_height));
-    box2.setRotation(RotationY(90. * Units::degree));
+    box2.setRotation(RotationY(90. * Units::deg));
     box2.setPosition(kvector_t(-box2_height / 2.0, 0.0, box2_length / 2.0));
 
     composition.addParticle(box1, kvector_t(0.0, 0.0, 0.0));
     composition.addParticle(box2, kvector_t(0.0, 0.0, box1_height));
-    composition.setRotation(RotationY(90.0 * Units::degree));
+    composition.setRotation(RotationY(90.0 * Units::deg));
     composition.setPosition(kvector_t(0.0, 0.0, -layer_thickness / 2.));
 
     return finalizeMultiLayer(composition);
diff --git a/Sample/StandardSamples/BoxesSquareLatticeBuilder.cpp b/Sample/StandardSamples/BoxesSquareLatticeBuilder.cpp
index 8934b4b4bf4e64d3dddf38c08dcef84e59823fca..10331c867b06ef015a4824ca2679f0f95f10c6cf 100644
--- a/Sample/StandardSamples/BoxesSquareLatticeBuilder.cpp
+++ b/Sample/StandardSamples/BoxesSquareLatticeBuilder.cpp
@@ -24,17 +24,16 @@
 
 MultiLayer* BoxesSquareLatticeBuilder::buildSample() const
 {
-    const double length = 5 * Units::nanometer;
-    const double height = 10 * Units::nanometer;
+    const double length = 5 * Units::nm;
+    const double height = 10 * Units::nm;
 
     Layer vacuum_layer(refMat::Vacuum);
     Layer substrate_layer(refMat::Substrate);
 
-    std::unique_ptr<InterferenceFunction2DLattice> P_interference_function(
-        InterferenceFunction2DLattice::createSquare(8 * Units::nanometer, 0));
+    InterferenceFunction2DLattice iff(SquareLattice(8 * Units::nm, 0));
 
-    FTDecayFunction2DCauchy pdf(100.0 * Units::nanometer, 100.0 * Units::nanometer, 0);
-    P_interference_function->setDecayFunction(pdf);
+    FTDecayFunction2DCauchy pdf(100.0 * Units::nm, 100.0 * Units::nm, 0);
+    iff.setDecayFunction(pdf);
 
     // particles
     ParticleLayout particle_layout;
@@ -42,7 +41,7 @@ MultiLayer* BoxesSquareLatticeBuilder::buildSample() const
     Particle particle(refMat::Particle, ff_box);
     particle_layout.addParticle(particle, 1.0);
 
-    particle_layout.setInterferenceFunction(*P_interference_function);
+    particle_layout.setInterferenceFunction(iff);
 
     vacuum_layer.addLayout(particle_layout);
 
diff --git a/Sample/StandardSamples/CoreShellParticleBuilder.cpp b/Sample/StandardSamples/CoreShellParticleBuilder.cpp
index 14c19efc13c05c2ab5eec68f1fa9abb49fb8f688..caf4a6e744d152a87ed977067c3f0d8b195c0165 100644
--- a/Sample/StandardSamples/CoreShellParticleBuilder.cpp
+++ b/Sample/StandardSamples/CoreShellParticleBuilder.cpp
@@ -34,10 +34,10 @@ MultiLayer* CoreShellParticleBuilder::buildSample() const
 
     Layer vacuum_layer(refMat::Vacuum);
 
-    FormFactorBox ff_box1(16 * Units::nanometer, 16 * Units::nanometer, 8 * Units::nanometer);
+    FormFactorBox ff_box1(16 * Units::nm, 16 * Units::nm, 8 * Units::nm);
     Particle shell_particle(shell_material, ff_box1);
 
-    FormFactorBox ff_box2(12 * Units::nanometer, 12 * Units::nanometer, 7 * Units::nanometer);
+    FormFactorBox ff_box2(12 * Units::nm, 12 * Units::nm, 7 * Units::nm);
     Particle core_particle(core_material, ff_box2);
 
     kvector_t core_position(0.0, 0.0, 0.0);
@@ -55,12 +55,12 @@ MultiLayer* CoreShellParticleBuilder::buildSample() const
 
 MultiLayer* CoreShellBoxRotateZandYBuilder::buildSample() const
 {
-    const double layer_thickness(100.0 * Units::nanometer);
+    const double layer_thickness(100.0 * Units::nm);
 
     // core shell particle
-    const double shell_length(50.0 * Units::nanometer);
-    const double shell_width(20.0 * Units::nanometer);
-    const double shell_height(10.0 * Units::nanometer);
+    const double shell_length(50.0 * Units::nm);
+    const double shell_width(20.0 * Units::nm);
+    const double shell_height(10.0 * Units::nm);
     double core_length = shell_length / 2.0;
     double core_width = shell_width / 2.0;
     double core_height = shell_height / 2.0;
@@ -69,8 +69,8 @@ MultiLayer* CoreShellBoxRotateZandYBuilder::buildSample() const
     Particle shell(refMat::AgO2, FormFactorBox(shell_length, shell_width, shell_height));
     ParticleCoreShell coreshell(shell, core,
                                 kvector_t(0.0, 0.0, (shell_height - core_height) / 2.0));
-    coreshell.setRotation(RotationZ(90.0 * Units::degree));
-    coreshell.rotate(RotationY(90.0 * Units::degree));
+    coreshell.setRotation(RotationZ(90.0 * Units::deg));
+    coreshell.rotate(RotationY(90.0 * Units::deg));
     coreshell.setPosition(kvector_t(0.0, 0.0, -layer_thickness / 2.0));
 
     ParticleLayout layout;
diff --git a/Sample/StandardSamples/CustomMorphologyBuilder.cpp b/Sample/StandardSamples/CustomMorphologyBuilder.cpp
index 87a9a09eb9d400db41f1c3b4afca9799117ab352..155f1365fc0ae2bbd2c4b9ca59a4277a33f0b505 100644
--- a/Sample/StandardSamples/CustomMorphologyBuilder.cpp
+++ b/Sample/StandardSamples/CustomMorphologyBuilder.cpp
@@ -28,71 +28,71 @@ MultiLayer* CustomMorphologyBuilder::buildSample() const
     ParticleLayout particle_layout;
 
     // add particle number 1:
-    FormFactorBox ff1(2.0 * Units::nanometer, 2.0 * Units::nanometer, 1.0 * Units::nanometer);
-    kvector_t pos1(0.0 * Units::nanometer, 0.0 * Units::nanometer, 0.0);
+    FormFactorBox ff1(2.0 * Units::nm, 2.0 * Units::nm, 1.0 * Units::nm);
+    kvector_t pos1(0.0 * Units::nm, 0.0 * Units::nm, 0.0);
     Particle p1(refMat::Particle, ff1);
     p1.setPosition(pos1);
     particle_layout.addParticle(p1, 0.5);
     // add particle number 2:
-    FormFactorBox ff2(2.0 * Units::nanometer, 4.0 * Units::nanometer, 1.0 * Units::nanometer);
-    kvector_t pos2(5.0 * Units::nanometer, 5.0 * Units::nanometer, 0.0);
-    RotationZ m2(10 * Units::degree);
+    FormFactorBox ff2(2.0 * Units::nm, 4.0 * Units::nm, 1.0 * Units::nm);
+    kvector_t pos2(5.0 * Units::nm, 5.0 * Units::nm, 0.0);
+    RotationZ m2(10 * Units::deg);
     Particle p2(refMat::Particle, ff2, m2);
     p2.setPosition(pos2);
     particle_layout.addParticle(p2, 0.5);
     // add particle number 3:
-    FormFactorBox ff3(2.0 * Units::nanometer, 6.0 * Units::nanometer, 1.0 * Units::nanometer);
-    kvector_t pos3(-5.0 * Units::nanometer, -5.0 * Units::nanometer, 0.0);
-    RotationZ m3(20 * Units::degree);
+    FormFactorBox ff3(2.0 * Units::nm, 6.0 * Units::nm, 1.0 * Units::nm);
+    kvector_t pos3(-5.0 * Units::nm, -5.0 * Units::nm, 0.0);
+    RotationZ m3(20 * Units::deg);
     Particle p3(refMat::Particle, ff3, m3);
     p3.setPosition(pos3);
     particle_layout.addParticle(p3, 0.5);
     // add particle number 4:
-    FormFactorBox ff4(2.0 * Units::nanometer, 8.0 * Units::nanometer, 1.0 * Units::nanometer);
-    kvector_t pos4(5.0 * Units::nanometer, -5.0 * Units::nanometer, 0.0);
-    RotationZ m4(30 * Units::degree);
+    FormFactorBox ff4(2.0 * Units::nm, 8.0 * Units::nm, 1.0 * Units::nm);
+    kvector_t pos4(5.0 * Units::nm, -5.0 * Units::nm, 0.0);
+    RotationZ m4(30 * Units::deg);
     Particle p4(refMat::Particle, ff4, m4);
     p4.setPosition(pos4);
     particle_layout.addParticle(p4, 0.5);
     // add particle number 5:
-    FormFactorBox ff5(2.0 * Units::nanometer, 10.0 * Units::nanometer, 1.0 * Units::nanometer);
-    kvector_t pos5(-5.0 * Units::nanometer, 5.0 * Units::nanometer, 0.0);
-    RotationZ m5(40 * Units::degree);
+    FormFactorBox ff5(2.0 * Units::nm, 10.0 * Units::nm, 1.0 * Units::nm);
+    kvector_t pos5(-5.0 * Units::nm, 5.0 * Units::nm, 0.0);
+    RotationZ m5(40 * Units::deg);
     Particle p5(refMat::Particle, ff5, m5);
     p5.setPosition(pos5);
     particle_layout.addParticle(p5, 0.5);
     // add particle number 6:
-    FormFactorBox ff6(2.0 * Units::nanometer, 2.0 * Units::nanometer, 1.0 * Units::nanometer);
-    kvector_t pos6(0.0 * Units::nanometer, 0.0 * Units::nanometer, 0.0);
-    RotationZ m6(50 * Units::degree);
+    FormFactorBox ff6(2.0 * Units::nm, 2.0 * Units::nm, 1.0 * Units::nm);
+    kvector_t pos6(0.0 * Units::nm, 0.0 * Units::nm, 0.0);
+    RotationZ m6(50 * Units::deg);
     Particle p6(refMat::Particle, ff6, m6);
     p6.setPosition(pos6);
     particle_layout.addParticle(p6, 0.5);
     // add particle number 7:
-    FormFactorBox ff7(2.0 * Units::nanometer, 4.0 * Units::nanometer, 1.0 * Units::nanometer);
-    kvector_t pos7(5.0 * Units::nanometer, 5.0 * Units::nanometer, 0.0);
-    RotationZ m7(60 * Units::degree);
+    FormFactorBox ff7(2.0 * Units::nm, 4.0 * Units::nm, 1.0 * Units::nm);
+    kvector_t pos7(5.0 * Units::nm, 5.0 * Units::nm, 0.0);
+    RotationZ m7(60 * Units::deg);
     Particle p7(refMat::Particle, ff7, m7);
     p7.setPosition(pos7);
     particle_layout.addParticle(p7, 0.5);
     // add particle number 8:
-    FormFactorBox ff8(2.0 * Units::nanometer, 6.0 * Units::nanometer, 1.0 * Units::nanometer);
-    kvector_t pos8(-5.0 * Units::nanometer, -5.0 * Units::nanometer, 0.0);
-    RotationZ m8(70 * Units::degree);
+    FormFactorBox ff8(2.0 * Units::nm, 6.0 * Units::nm, 1.0 * Units::nm);
+    kvector_t pos8(-5.0 * Units::nm, -5.0 * Units::nm, 0.0);
+    RotationZ m8(70 * Units::deg);
     Particle p8(refMat::Particle, ff8, m8);
     p8.setPosition(pos8);
     particle_layout.addParticle(p8, 0.5);
     // add particle number 9:
-    FormFactorBox ff9(2.0 * Units::nanometer, 8.0 * Units::nanometer, 1.0 * Units::nanometer);
-    kvector_t pos9(5.0 * Units::nanometer, -5.0 * Units::nanometer, 0.0);
-    RotationZ m9(80 * Units::degree);
+    FormFactorBox ff9(2.0 * Units::nm, 8.0 * Units::nm, 1.0 * Units::nm);
+    kvector_t pos9(5.0 * Units::nm, -5.0 * Units::nm, 0.0);
+    RotationZ m9(80 * Units::deg);
     Particle p9(refMat::Particle, ff9, m9);
     p9.setPosition(pos9);
     particle_layout.addParticle(p9, 0.5);
     // add particle number 10:
-    FormFactorBox ff10(2.0 * Units::nanometer, 10.0 * Units::nanometer, 1.0 * Units::nanometer);
-    kvector_t pos10(-5.0 * Units::nanometer, 5.0 * Units::nanometer, 0.0);
-    RotationZ m10(90 * Units::degree);
+    FormFactorBox ff10(2.0 * Units::nm, 10.0 * Units::nm, 1.0 * Units::nm);
+    kvector_t pos10(-5.0 * Units::nm, 5.0 * Units::nm, 0.0);
+    RotationZ m10(90 * Units::deg);
     Particle p10(refMat::Particle, ff10, m10);
     p10.setPosition(pos10);
     particle_layout.addParticle(p10, 0.5);
diff --git a/Sample/StandardSamples/CylindersBuilder.cpp b/Sample/StandardSamples/CylindersBuilder.cpp
index 034d965458885668e83027e09bcbb6093f1a0abd..505a776f7eabe142bb163f15f71afd2137f57844 100644
--- a/Sample/StandardSamples/CylindersBuilder.cpp
+++ b/Sample/StandardSamples/CylindersBuilder.cpp
@@ -25,8 +25,7 @@
 // -----------------------------------------------------------------------------
 // Cylinders in DWBA
 // -----------------------------------------------------------------------------
-CylindersInDWBABuilder::CylindersInDWBABuilder()
-    : m_height(5 * Units::nanometer), m_radius(5 * Units::nanometer)
+CylindersInDWBABuilder::CylindersInDWBABuilder() : m_height(5 * Units::nm), m_radius(5 * Units::nm)
 {
 }
 
@@ -51,8 +50,7 @@ MultiLayer* CylindersInDWBABuilder::buildSample() const
 // -----------------------------------------------------------------------------
 // Cylinders in BA
 // -----------------------------------------------------------------------------
-CylindersInBABuilder::CylindersInBABuilder()
-    : m_height(5 * Units::nanometer), m_radius(5 * Units::nanometer)
+CylindersInBABuilder::CylindersInBABuilder() : m_height(5 * Units::nm), m_radius(5 * Units::nm)
 {
     registerParameter("height", &m_height);
     registerParameter("radius", &m_radius);
@@ -78,7 +76,7 @@ MultiLayer* CylindersInBABuilder::buildSample() const
 // Large cylinders in DWBA
 // -----------------------------------------------------------------------------
 LargeCylindersInDWBABuilder::LargeCylindersInDWBABuilder()
-    : m_height(1000 * Units::nanometer), m_radius(500 * Units::nanometer)
+    : m_height(1000 * Units::nm), m_radius(500 * Units::nm)
 {
 }
 
@@ -104,7 +102,7 @@ MultiLayer* LargeCylindersInDWBABuilder::buildSample() const
 // Rotated cylinders in DWBA
 // -----------------------------------------------------------------------------
 RotatedCylindersBuilder::RotatedCylindersBuilder()
-    : m_height(5 * Units::nanometer), m_radius(5 * Units::nanometer)
+    : m_height(5 * Units::nm), m_radius(5 * Units::nm)
 {
 }
 
diff --git a/Sample/StandardSamples/FeNiBilayerBuilder.cpp b/Sample/StandardSamples/FeNiBilayerBuilder.cpp
index 753d99dd1ad97e00d5fc5d174a2145f76c018f9e..474f116196e41ada42114808ccf2ce0984138723 100644
--- a/Sample/StandardSamples/FeNiBilayerBuilder.cpp
+++ b/Sample/StandardSamples/FeNiBilayerBuilder.cpp
@@ -185,14 +185,14 @@ MultiLayer* FeNiBilayerNCBuilder::buildSample() const
 
 MultiLayer* FeNiBilayerSpinFlipBuilder::buildSample() const
 {
-    auto sample = FeNiBilayer{Options().angle(38. * Units::degree)};
+    auto sample = FeNiBilayer{Options().angle(38. * Units::deg)};
     return sample.release();
 }
 
 MultiLayer* FeNiBilayerSpinFlipTanhBuilder::buildSample() const
 {
     auto sample = FeNiBilayer{Options()
-                                  .angle(38 * Units::degree)
+                                  .angle(38 * Units::deg)
                                   .sigmaRoughness(2. * Units::angstrom)
                                   .roughnessModel(RoughnessModel::TANH)};
     return sample.release();
@@ -201,7 +201,7 @@ MultiLayer* FeNiBilayerSpinFlipTanhBuilder::buildSample() const
 MultiLayer* FeNiBilayerSpinFlipNCBuilder::buildSample() const
 {
     auto sample = FeNiBilayer{Options()
-                                  .angle(38 * Units::degree)
+                                  .angle(38 * Units::deg)
                                   .sigmaRoughness(2. * Units::angstrom)
                                   .roughnessModel(RoughnessModel::NEVOT_CROCE)};
     return sample.release();
diff --git a/Sample/StandardSamples/LatticeBuilder.cpp b/Sample/StandardSamples/LatticeBuilder.cpp
index ac337f2da7b81dad50024e33b651f3e222990493..ff0eae3436ee742b32028eea57a289b6c3c98eab 100644
--- a/Sample/StandardSamples/LatticeBuilder.cpp
+++ b/Sample/StandardSamples/LatticeBuilder.cpp
@@ -26,11 +26,11 @@
 
 MultiLayer* Lattice1DBuilder::buildSample() const
 {
-    const double length(20.0 * Units::nanometer);
+    const double length(20.0 * Units::nm);
     const double xi(10.0 * Units::deg);
-    const double corr_length(1000.0 * Units::nanometer);
-    const double cylinder_height(5 * Units::nanometer);
-    const double cylinder_radius(5 * Units::nanometer);
+    const double corr_length(1000.0 * Units::nm);
+    const double cylinder_height(5 * Units::nm);
+    const double cylinder_radius(5 * Units::nm);
 
     Layer vacuum_layer(refMat::Vacuum);
     Layer substrate_layer(refMat::Substrate);
diff --git a/Sample/StandardSamples/LayersWithAbsorptionBuilder.cpp b/Sample/StandardSamples/LayersWithAbsorptionBuilder.cpp
index cce776fcf147a5a9b497f82455c3a09e2240e6bc..1885e852263abf1a3f332593b87a91992f132a9f 100644
--- a/Sample/StandardSamples/LayersWithAbsorptionBuilder.cpp
+++ b/Sample/StandardSamples/LayersWithAbsorptionBuilder.cpp
@@ -31,7 +31,7 @@ static const FormFactorComponents ff_components;
 } // namespace
 
 LayersWithAbsorptionBuilder::LayersWithAbsorptionBuilder()
-    : m_ff(new FormFactorFullSphere(5.0 * Units::nanometer))
+    : m_ff(new FormFactorFullSphere(5.0 * Units::nm))
 {
 }
 
@@ -39,12 +39,12 @@ LayersWithAbsorptionBuilder::~LayersWithAbsorptionBuilder() = default;
 
 MultiLayer* LayersWithAbsorptionBuilder::buildSample() const
 {
-    const double middle_layer_thickness(60.0 * Units::nanometer);
+    const double middle_layer_thickness(60.0 * Units::nm);
 
     Particle particle(refMat::Ag, *m_ff);
-    particle.setRotation(RotationZ(10.0 * Units::degree));
-    particle.rotate(RotationY(10.0 * Units::degree));
-    particle.rotate(RotationX(10.0 * Units::degree));
+    particle.setRotation(RotationZ(10.0 * Units::deg));
+    particle.rotate(RotationY(10.0 * Units::deg));
+    particle.rotate(RotationX(10.0 * Units::deg));
     particle.setPosition(kvector_t(0.0, 0.0, -middle_layer_thickness / 2.0));
 
     ParticleLayout layout;
diff --git a/Sample/StandardSamples/LayersWithAbsorptionBySLDBuilder.cpp b/Sample/StandardSamples/LayersWithAbsorptionBySLDBuilder.cpp
index 9d667bf45de689007573d4977f7c47dce7b798a9..642f7486438af9413f99c698cafe5b80d96d89f3 100644
--- a/Sample/StandardSamples/LayersWithAbsorptionBySLDBuilder.cpp
+++ b/Sample/StandardSamples/LayersWithAbsorptionBySLDBuilder.cpp
@@ -21,7 +21,7 @@
 #include "Sample/Multilayer/MultiLayer.h"
 #include "Sample/Particle/Particle.h"
 
-const double middle_layer_thickness(60.0 * Units::nanometer);
+const double middle_layer_thickness(60.0 * Units::nm);
 
 MultiLayer* LayersWithAbsorptionBySLDBuilder::buildSample() const
 {
@@ -30,12 +30,12 @@ MultiLayer* LayersWithAbsorptionBySLDBuilder::buildSample() const
     Material substrate_mat = MaterialBySLD("Substrate", 2.0728e-06, 2.3747e-11);
     Material particle_mat = MaterialBySLD("Ag", 3.4682e-06, 1.0309e-08);
 
-    FormFactorFullSphere ff(5.0 * Units::nanometer);
+    FormFactorFullSphere ff(5.0 * Units::nm);
 
     Particle particle(particle_mat, ff);
-    particle.setRotation(RotationZ(10.0 * Units::degree));
-    particle.rotate(RotationY(10.0 * Units::degree));
-    particle.rotate(RotationX(10.0 * Units::degree));
+    particle.setRotation(RotationZ(10.0 * Units::deg));
+    particle.rotate(RotationY(10.0 * Units::deg));
+    particle.rotate(RotationX(10.0 * Units::deg));
     particle.setPosition(kvector_t(0.0, 0.0, -middle_layer_thickness / 2.0));
 
     ParticleLayout layout;
diff --git a/Sample/StandardSamples/MagneticLayersBuilder.cpp b/Sample/StandardSamples/MagneticLayersBuilder.cpp
index ad99ae003d166fbff1171abc79c0604e0bd10f8f..677a4463620a7f0d5c957dacbafb5bc201f00c2b 100644
--- a/Sample/StandardSamples/MagneticLayersBuilder.cpp
+++ b/Sample/StandardSamples/MagneticLayersBuilder.cpp
@@ -26,7 +26,7 @@
 namespace
 {
 
-const double sphere_radius = 5 * Units::nanometer;
+const double sphere_radius = 5 * Units::nm;
 
 MultiLayer* parametricBuild(double sigmaRoughness, RoughnessModel roughnessModel)
 {
@@ -62,7 +62,7 @@ MultiLayer* MagneticSubstrateZeroFieldBuilder::buildSample() const
     Material particle_material = HomogeneousMaterial("MagParticle", 6e-4, 2e-8, particle_field);
 
     ParticleLayout particle_layout;
-    kvector_t position(0.0, 0.0, -10.0 * Units::nanometer);
+    kvector_t position(0.0, 0.0, -10.0 * Units::nm);
     FormFactorFullSphere ff_sphere(sphere_radius);
     Particle particle(particle_material, ff_sphere);
     particle_layout.addParticle(particle, 1.0, position);
@@ -164,7 +164,7 @@ MultiLayer* MagneticRotationBuilder::buildSample() const
     Material particle_material = HomogeneousMaterial("MagParticle", 6e-4, 2e-8, particle_field);
 
     ParticleLayout particle_layout;
-    kvector_t position(0.0, 0.0, -10.0 * Units::nanometer);
+    kvector_t position(0.0, 0.0, -10.0 * Units::nm);
     FormFactorFullSphere ff_sphere(sphere_radius);
     Particle particle(particle_material, ff_sphere);
     RotationZ rot_z(90 * Units::deg);
diff --git a/Sample/StandardSamples/MagneticParticlesBuilder.cpp b/Sample/StandardSamples/MagneticParticlesBuilder.cpp
index 8d2387fb7ff25c204e6a441ca767f68390c311ea..d61df724497790a0af6a53b316e9c729ba75bb3b 100644
--- a/Sample/StandardSamples/MagneticParticlesBuilder.cpp
+++ b/Sample/StandardSamples/MagneticParticlesBuilder.cpp
@@ -30,8 +30,8 @@
 
 MultiLayer* MagneticParticleZeroFieldBuilder::buildSample() const
 {
-    const double m_cylinder_radius(5 * Units::nanometer);
-    const double m_cylinder_height(5 * Units::nanometer);
+    const double m_cylinder_radius(5 * Units::nm);
+    const double m_cylinder_height(5 * Units::nm);
 
     Material vacuum_material = HomogeneousMaterial("Vacuum", 0.0, 0.0);
     Material substrate_material = HomogeneousMaterial("Substrate", 6e-6, 2e-8);
@@ -60,8 +60,8 @@ MultiLayer* MagneticParticleZeroFieldBuilder::buildSample() const
 
 MultiLayer* MagneticCylindersBuilder::buildSample() const
 {
-    const double m_cylinder_radius(5 * Units::nanometer);
-    const double m_cylinder_height(5 * Units::nanometer);
+    const double m_cylinder_radius(5 * Units::nm);
+    const double m_cylinder_height(5 * Units::nm);
 
     Material vacuum_material = HomogeneousMaterial("Vacuum", 0.0, 0.0);
     Material substrate_material = HomogeneousMaterial("Substrate", 15e-6, 0.0);
@@ -90,7 +90,7 @@ MultiLayer* MagneticCylindersBuilder::buildSample() const
 
 MultiLayer* MagneticSpheresBuilder::buildSample() const
 {
-    const double m_sphere_radius(5 * Units::nanometer);
+    const double m_sphere_radius(5 * Units::nm);
 
     kvector_t magnetization(0.0, 0.0, 1e7);
     Material particle_material = HomogeneousMaterial("Particle", 2e-5, 4e-7, magnetization);
diff --git a/Sample/StandardSamples/MesoCrystalBuilder.cpp b/Sample/StandardSamples/MesoCrystalBuilder.cpp
index df097025acd44c0c5a1b6e220677e2a47b9306e8..eeb593dc108a76cb5bb6538f8a6e9fa5d6aec804 100644
--- a/Sample/StandardSamples/MesoCrystalBuilder.cpp
+++ b/Sample/StandardSamples/MesoCrystalBuilder.cpp
@@ -30,7 +30,7 @@ MultiLayer* MesoCrystalBuilder::buildSample() const
     kvector_t lattice_basis_a(5.0, 0.0, 0.0);
     kvector_t lattice_basis_b(0.0, 5.0, 0.0);
     kvector_t lattice_basis_c(0.0, 0.0, 5.0);
-    Lattice lattice(lattice_basis_a, lattice_basis_b, lattice_basis_c);
+    Lattice3D lattice(lattice_basis_a, lattice_basis_b, lattice_basis_c);
 
     // spherical particle that forms the base of the mesocrystal
     FormFactorFullSphere sphere_ff(2.0);
diff --git a/Sample/StandardSamples/MultiLayerWithRoughnessBuilder.cpp b/Sample/StandardSamples/MultiLayerWithRoughnessBuilder.cpp
index ae885002037dd781a7979c9058c1f3f78c30a7e5..873d5dd4d3cd2faaf3706a9cae8bcc3c593a7ba2 100644
--- a/Sample/StandardSamples/MultiLayerWithRoughnessBuilder.cpp
+++ b/Sample/StandardSamples/MultiLayerWithRoughnessBuilder.cpp
@@ -21,12 +21,12 @@
 
 MultiLayer* MultiLayerWithRoughnessBuilder::buildSample() const
 {
-    const double thicknessA(2.5 * Units::nanometer);
-    const double thicknessB(5.0 * Units::nanometer);
-    const double sigma(1.0 * Units::nanometer);
+    const double thicknessA(2.5 * Units::nm);
+    const double thicknessB(5.0 * Units::nm);
+    const double sigma(1.0 * Units::nm);
     const double hurst(0.3);
-    const double lateralCorrLength(5.0 * Units::nanometer);
-    const double crossCorrLength(10.0 * Units::nanometer);
+    const double lateralCorrLength(5.0 * Units::nm);
+    const double crossCorrLength(10.0 * Units::nm);
 
     Material vacuum_material = HomogeneousMaterial("Vacuum", 0., 0.);
     Material substrate_material = HomogeneousMaterial("Substrate", 15e-6, 0.0);
diff --git a/Sample/StandardSamples/MultipleLayoutBuilder.cpp b/Sample/StandardSamples/MultipleLayoutBuilder.cpp
index 965c0f7b318d518f2995f58a3eb0acbf31e126fc..e652d16c4acc921b27a35e4de0f3ad783369ff4a 100644
--- a/Sample/StandardSamples/MultipleLayoutBuilder.cpp
+++ b/Sample/StandardSamples/MultipleLayoutBuilder.cpp
@@ -24,10 +24,10 @@
 
 MultiLayer* MultipleLayoutBuilder::buildSample() const
 {
-    const double cylinder_height(5 * Units::nanometer);
-    const double cylinder_radius(5 * Units::nanometer);
-    const double prisheight(5 * Units::nanometer);
-    const double prislength(10 * Units::nanometer);
+    const double cylinder_height(5 * Units::nm);
+    const double cylinder_radius(5 * Units::nm);
+    const double prisheight(5 * Units::nm);
+    const double prislength(10 * Units::nm);
     const double cylinder_weight(0.5);
 
     Layer vacuum_layer(refMat::Vacuum);
diff --git a/Sample/StandardSamples/ParaCrystalBuilder.cpp b/Sample/StandardSamples/ParaCrystalBuilder.cpp
index 207260ce8e4a2b03c2811a27824aaf55d52eff85..f3ce78de17d96fa8708b01acf2d5006431a08370 100644
--- a/Sample/StandardSamples/ParaCrystalBuilder.cpp
+++ b/Sample/StandardSamples/ParaCrystalBuilder.cpp
@@ -27,24 +27,23 @@
 
 MultiLayer* RadialParaCrystalBuilder::buildSample() const
 {
-    const double m_corr_peak_distance(20.0 * Units::nanometer);
-    const double m_corr_width(7 * Units::nanometer);
-    const double m_corr_length(1e3 * Units::nanometer);
-    const double m_cylinder_height(5 * Units::nanometer);
-    const double m_cylinder_radius(5 * Units::nanometer);
+    const double m_corr_peak_distance(20.0 * Units::nm);
+    const double m_corr_width(7 * Units::nm);
+    const double m_corr_length(1e3 * Units::nm);
+    const double m_cylinder_height(5 * Units::nm);
+    const double m_cylinder_radius(5 * Units::nm);
 
     Layer vacuum_layer(refMat::Vacuum);
     Layer substrate_layer(refMat::Substrate);
 
-    InterferenceFunctionRadialParaCrystal interference_function(m_corr_peak_distance,
-                                                                m_corr_length);
+    InterferenceFunctionRadialParaCrystal iff(m_corr_peak_distance, m_corr_length);
     FTDistribution1DGauss pdf(m_corr_width);
-    interference_function.setProbabilityDistribution(pdf);
+    iff.setProbabilityDistribution(pdf);
     FormFactorCylinder ff_cylinder(m_cylinder_radius, m_cylinder_height);
 
     Particle particle(refMat::Particle, ff_cylinder);
     ParticleLayout particle_layout(particle);
-    particle_layout.setInterferenceFunction(interference_function);
+    particle_layout.setInterferenceFunction(iff);
 
     vacuum_layer.addLayout(particle_layout);
 
@@ -59,8 +58,8 @@ MultiLayer* RadialParaCrystalBuilder::buildSample() const
 // -----------------------------------------------------------------------------
 
 Basic2DParaCrystalBuilder::Basic2DParaCrystalBuilder()
-    : m_pdf1(new FTDistribution2DCauchy(0.1 * Units::nanometer, 0.2 * Units::nanometer, 0))
-    , m_pdf2(new FTDistribution2DCauchy(0.3 * Units::nanometer, 0.4 * Units::nanometer, 0))
+    : m_pdf1(new FTDistribution2DCauchy(0.1 * Units::nm, 0.2 * Units::nm, 0))
+    , m_pdf2(new FTDistribution2DCauchy(0.3 * Units::nm, 0.4 * Units::nm, 0))
 {
 }
 
@@ -71,19 +70,17 @@ MultiLayer* Basic2DParaCrystalBuilder::buildSample() const
     Layer vacuum_layer(refMat::Vacuum);
     Layer substrate_layer(refMat::Substrate);
 
-    InterferenceFunction2DParaCrystal interference_function(
-        10.0 * Units::nanometer, 20.0 * Units::nanometer, 30.0 * Units::degree,
-        45.0 * Units::degree, 1000.0 * Units::nanometer);
+    InterferenceFunction2DParaCrystal iff(
+        BasicLattice(10.0 * Units::nm, 20.0 * Units::nm, 30.0 * Units::deg, 45.0 * Units::deg),
+        1000.0 * Units::nm, 20.0 * Units::micrometer, 40.0 * Units::micrometer);
 
-    interference_function.setDomainSizes(20.0 * Units::micrometer, 40.0 * Units::micrometer);
+    iff.setProbabilityDistributions(*m_pdf1, *m_pdf2);
 
-    interference_function.setProbabilityDistributions(*m_pdf1, *m_pdf2);
-
-    FormFactorCylinder ff_cylinder(5.0 * Units::nanometer, 5.0 * Units::nanometer);
+    FormFactorCylinder ff_cylinder(5.0 * Units::nm, 5.0 * Units::nm);
 
     Particle particle(refMat::Particle, ff_cylinder);
     ParticleLayout particle_layout(particle);
-    particle_layout.setInterferenceFunction(interference_function);
+    particle_layout.setInterferenceFunction(iff);
 
     vacuum_layer.addLayout(particle_layout);
 
@@ -111,27 +108,27 @@ MultiLayer* Basic2DParaCrystalBuilder::createSampleByIndex(size_t index)
 
 MultiLayer* HexParaCrystalBuilder::buildSample() const
 {
-    const double m_peak_distance(20.0 * Units::nanometer);
+    const double m_peak_distance(20.0 * Units::nm);
     const double m_corr_length(0.0);
     const double m_domain_size_1(20.0 * Units::micrometer);
     const double m_domain_size_2(20.0 * Units::micrometer);
-    const double m_cylinder_height(5 * Units::nanometer);
-    const double m_cylinder_radius(5 * Units::nanometer);
+    const double m_cylinder_height(5 * Units::nm);
+    const double m_cylinder_radius(5 * Units::nm);
 
     Layer vacuum_layer(refMat::Vacuum);
     Layer substrate_layer(refMat::Substrate);
 
-    std::unique_ptr<InterferenceFunction2DParaCrystal> P_interference_function{
-        InterferenceFunction2DParaCrystal::createHexagonal(m_peak_distance, m_corr_length,
-                                                           m_domain_size_1, m_domain_size_2)};
-    FTDistribution2DCauchy pdf(1.0 * Units::nanometer, 1.0 * Units::nanometer, 0);
-    P_interference_function->setProbabilityDistributions(pdf, pdf);
+    InterferenceFunction2DParaCrystal iff(HexagonalLattice(m_peak_distance, 0.0), m_corr_length,
+                                          m_domain_size_1, m_domain_size_2);
+    iff.setIntegrationOverXi(true);
+    FTDistribution2DCauchy pdf(1.0 * Units::nm, 1.0 * Units::nm, 0);
+    iff.setProbabilityDistributions(pdf, pdf);
 
     FormFactorCylinder ff_cylinder(m_cylinder_radius, m_cylinder_height);
     Particle cylinder(refMat::Particle, ff_cylinder);
 
     ParticleLayout particle_layout(cylinder);
-    particle_layout.setInterferenceFunction(*P_interference_function);
+    particle_layout.setInterferenceFunction(iff);
 
     vacuum_layer.addLayout(particle_layout);
 
@@ -150,20 +147,18 @@ MultiLayer* RectParaCrystalBuilder::buildSample() const
     Layer vacuum_layer(refMat::Vacuum);
     Layer substrate_layer(refMat::Substrate);
 
-    std::unique_ptr<InterferenceFunction2DParaCrystal> P_interference_function{
-        InterferenceFunction2DParaCrystal::createSquare(10 * Units::nanometer, 0 * Units::nanometer,
-                                                        0, 0)};
-
-    P_interference_function->setDomainSizes(20.0 * Units::micrometer, 20.0 * Units::micrometer);
-    FTDistribution2DCauchy pdf1(0.5 * Units::nanometer, 2.0 * Units::nanometer, 0);
-    FTDistribution2DCauchy pdf2(0.5 * Units::nanometer, 2.0 * Units::nanometer, 0);
-    P_interference_function->setProbabilityDistributions(pdf1, pdf2);
+    InterferenceFunction2DParaCrystal iff(SquareLattice(10 * Units::nm), 0, 0, 0);
+    iff.setIntegrationOverXi(true);
+    iff.setDomainSizes(20.0 * Units::micrometer, 20.0 * Units::micrometer);
+    FTDistribution2DCauchy pdf1(0.5 * Units::nm, 2.0 * Units::nm, 0);
+    FTDistribution2DCauchy pdf2(0.5 * Units::nm, 2.0 * Units::nm, 0);
+    iff.setProbabilityDistributions(pdf1, pdf2);
 
-    FormFactorCylinder ff_cylinder(5.0 * Units::nanometer, 5.0 * Units::nanometer);
+    FormFactorCylinder ff_cylinder(5.0 * Units::nm, 5.0 * Units::nm);
 
     Particle particle(refMat::Particle, ff_cylinder);
     ParticleLayout particle_layout(particle);
-    particle_layout.setInterferenceFunction(*P_interference_function);
+    particle_layout.setInterferenceFunction(iff);
 
     vacuum_layer.addLayout(particle_layout);
 
diff --git a/Sample/StandardSamples/ParticleCompositionBuilder.cpp b/Sample/StandardSamples/ParticleCompositionBuilder.cpp
index f8c8ac262745f8cbfa7f2cbbf7fe26a8389b025e..770fd27422b33c0a1c26a7bb45fa413941acac3b 100644
--- a/Sample/StandardSamples/ParticleCompositionBuilder.cpp
+++ b/Sample/StandardSamples/ParticleCompositionBuilder.cpp
@@ -30,7 +30,7 @@ MultiLayer* ParticleCompositionBuilder::buildSample() const
     Layer vacuum_layer(refMat::Vacuum);
     Layer substrate_layer(refMat::Substrate);
 
-    double radius(10.0 * Units::nanometer);
+    double radius(10.0 * Units::nm);
     FormFactorFullSphere sphere_ff(radius);
     Particle sphere(refMat::Particle, sphere_ff);
     ParticleLayout particle_layout;
@@ -43,12 +43,11 @@ MultiLayer* ParticleCompositionBuilder::buildSample() const
     basis.addParticles(sphere, positions);
     particle_layout.addParticle(basis);
 
-    std::unique_ptr<InterferenceFunction2DLattice> P_interference{
-        InterferenceFunction2DLattice::createHexagonal(radius * 2.0, 0)};
-    FTDecayFunction2DCauchy pdf(10 * Units::nanometer, 10 * Units::nanometer, 0);
-    P_interference->setDecayFunction(pdf);
+    InterferenceFunction2DLattice iff(HexagonalLattice(radius * 2.0, 0));
+    FTDecayFunction2DCauchy pdf(10 * Units::nm, 10 * Units::nm, 0);
+    iff.setDecayFunction(pdf);
 
-    particle_layout.setInterferenceFunction(*P_interference);
+    particle_layout.setInterferenceFunction(iff);
 
     vacuum_layer.addLayout(particle_layout);
 
diff --git a/Sample/StandardSamples/ParticleDistributionsBuilder.cpp b/Sample/StandardSamples/ParticleDistributionsBuilder.cpp
index 99c72d49fba994852f17c7b3fead633d52eed9c5..693bfac3f2f2d1f7c332b44159726472a9fb8b92 100644
--- a/Sample/StandardSamples/ParticleDistributionsBuilder.cpp
+++ b/Sample/StandardSamples/ParticleDistributionsBuilder.cpp
@@ -30,8 +30,8 @@
 
 MultiLayer* CylindersWithSizeDistributionBuilder::buildSample() const
 {
-    const double height(5 * Units::nanometer);
-    const double radius(5 * Units::nanometer);
+    const double height(5 * Units::nm);
+    const double radius(5 * Units::nm);
 
     Layer vacuum_layer(refMat::Vacuum);
 
@@ -64,10 +64,10 @@ MultiLayer* CylindersWithSizeDistributionBuilder::buildSample() const
 // ----------------------------------------------------------------------------
 
 TwoTypesCylindersDistributionBuilder::TwoTypesCylindersDistributionBuilder()
-    : m_radius1(5 * Units::nanometer)
-    , m_radius2(10 * Units::nanometer)
-    , m_height1(5 * Units::nanometer)
-    , m_height2(10 * Units::nanometer)
+    : m_radius1(5 * Units::nm)
+    , m_radius2(10 * Units::nm)
+    , m_height1(5 * Units::nm)
+    , m_height2(10 * Units::nm)
     , m_sigma1_ratio(0.2)
     , m_sigma2_ratio(0.02)
 {
@@ -118,10 +118,10 @@ MultiLayer* TwoTypesCylindersDistributionBuilder::buildSample() const
 // ----------------------------------------------------------------------------
 
 RotatedPyramidsDistributionBuilder::RotatedPyramidsDistributionBuilder()
-    : m_length(10 * Units::nanometer)
-    , m_height(5 * Units::nanometer)
+    : m_length(10 * Units::nm)
+    , m_height(5 * Units::nm)
     , m_alpha(Units::deg2rad(54.73))
-    , m_zangle(45. * Units::degree)
+    , m_zangle(45. * Units::deg)
 {
 }
 
diff --git a/Sample/StandardSamples/ParticleInVacuumBuilder.cpp b/Sample/StandardSamples/ParticleInVacuumBuilder.cpp
index 767ed3558454ffd4f526c4638b32c21c8ee4c1ad..e68a58a33181ee569a90f08736a8284bf35fd29c 100644
--- a/Sample/StandardSamples/ParticleInVacuumBuilder.cpp
+++ b/Sample/StandardSamples/ParticleInVacuumBuilder.cpp
@@ -27,8 +27,7 @@ namespace
 FormFactorComponents ff_components;
 }
 
-ParticleInVacuumBuilder::ParticleInVacuumBuilder()
-    : m_ff(new FormFactorFullSphere(5.0 * Units::nanometer))
+ParticleInVacuumBuilder::ParticleInVacuumBuilder() : m_ff(new FormFactorFullSphere(5.0 * Units::nm))
 {
 }
 
diff --git a/Sample/StandardSamples/PercusYevickBuilder.cpp b/Sample/StandardSamples/PercusYevickBuilder.cpp
index ee7d858701ac79e4fbca36d111e6f2552141a012..f489860e8cbd6c411b182655e76cb6e45b7eb39b 100644
--- a/Sample/StandardSamples/PercusYevickBuilder.cpp
+++ b/Sample/StandardSamples/PercusYevickBuilder.cpp
@@ -24,9 +24,9 @@
 
 MultiLayer* HardDiskBuilder::buildSample() const
 {
-    const double m_cylinder_height(5 * Units::nanometer);
-    const double m_cylinder_radius(5 * Units::nanometer);
-    const double m_disk_radius(5 * Units::nanometer);
+    const double m_cylinder_height(5 * Units::nm);
+    const double m_cylinder_radius(5 * Units::nm);
+    const double m_disk_radius(5 * Units::nm);
     const double m_density(0.006);
 
     Layer vacuum_layer(refMat::Vacuum);
diff --git a/Sample/StandardSamples/RipplesBuilder.cpp b/Sample/StandardSamples/RipplesBuilder.cpp
index 30e4aa415a0c2abafcb8ffc6af2dce93cef503b9..11c9f4809ef1c89bd440a39dd96d5c4853f495bc 100644
--- a/Sample/StandardSamples/RipplesBuilder.cpp
+++ b/Sample/StandardSamples/RipplesBuilder.cpp
@@ -48,7 +48,7 @@ MultiLayer* CosineRippleBuilder::buildSample() const
 
 // ----------------------------------------------------------------------------
 
-TriangularRippleBuilder::TriangularRippleBuilder() : m_d(0.0 * Units::nanometer)
+TriangularRippleBuilder::TriangularRippleBuilder() : m_d(0.0 * Units::nm)
 {
     registerParameter("asymmetry", &m_d);
 }
diff --git a/Sample/StandardSamples/RotatedPyramidsBuilder.cpp b/Sample/StandardSamples/RotatedPyramidsBuilder.cpp
index e292ff866b510ef06c21b4db7f80f521f9602800..390b3e3026e043db6f5e1629486900608eb1cada 100644
--- a/Sample/StandardSamples/RotatedPyramidsBuilder.cpp
+++ b/Sample/StandardSamples/RotatedPyramidsBuilder.cpp
@@ -23,10 +23,10 @@
 
 MultiLayer* RotatedPyramidsBuilder::buildSample() const
 {
-    const double m_length(10 * Units::nanometer);
-    const double m_height(5 * Units::nanometer);
+    const double m_length(10 * Units::nm);
+    const double m_height(5 * Units::nm);
     const double m_alpha(Units::deg2rad(54.73));
-    const double m_zangle(45. * Units::degree);
+    const double m_zangle(45. * Units::deg);
 
     Layer vacuum_layer(refMat::Vacuum);
     Layer substrate_layer(refMat::Substrate);
diff --git a/Sample/StandardSamples/SizeDistributionModelsBuilder.cpp b/Sample/StandardSamples/SizeDistributionModelsBuilder.cpp
index 4eb3c00f635a2edcb4e80d8ef6fc0606a82eb50e..20ada60484aede47072f8c986081d19f8cda0d81 100644
--- a/Sample/StandardSamples/SizeDistributionModelsBuilder.cpp
+++ b/Sample/StandardSamples/SizeDistributionModelsBuilder.cpp
@@ -28,21 +28,20 @@
 MultiLayer* SizeDistributionDAModelBuilder::buildSample() const
 {
     // cylindrical particle 1
-    double radius1(5 * Units::nanometer);
+    double radius1(5 * Units::nm);
     double height1 = radius1;
     FormFactorCylinder cylinder_ff1(radius1, height1);
     Particle cylinder1(refMat::Particle, cylinder_ff1);
 
     // cylindrical particle 2
-    double radius2(8 * Units::nanometer);
+    double radius2(8 * Units::nm);
     double height2(radius2);
     FormFactorCylinder cylinder_ff2(radius2, height2);
     Particle cylinder2(refMat::Particle, cylinder_ff2);
 
     // interference function
-    InterferenceFunctionRadialParaCrystal interference(18.0 * Units::nanometer,
-                                                       1e3 * Units::nanometer);
-    FTDistribution1DGauss pdf(3 * Units::nanometer);
+    InterferenceFunctionRadialParaCrystal interference(18.0 * Units::nm, 1e3 * Units::nm);
+    FTDistribution1DGauss pdf(3 * Units::nm);
     interference.setProbabilityDistribution(pdf);
 
     // assembling the sample
@@ -66,26 +65,24 @@ MultiLayer* SizeDistributionDAModelBuilder::buildSample() const
 MultiLayer* SizeDistributionLMAModelBuilder::buildSample() const
 {
     // cylindrical particle 1
-    double radius1(5 * Units::nanometer);
+    double radius1(5 * Units::nm);
     double height1 = radius1;
     FormFactorCylinder cylinder_ff1(radius1, height1);
     Particle cylinder1(refMat::Particle, cylinder_ff1);
 
     // cylindrical particle 2
-    double radius2(8 * Units::nanometer);
+    double radius2(8 * Units::nm);
     double height2(radius2);
     FormFactorCylinder cylinder_ff2(radius2, height2);
     Particle cylinder2(refMat::Particle, cylinder_ff2);
 
     // interference function1
-    InterferenceFunctionRadialParaCrystal interference1(16.8 * Units::nanometer,
-                                                        1e3 * Units::nanometer);
-    FTDistribution1DGauss pdf(3 * Units::nanometer);
+    InterferenceFunctionRadialParaCrystal interference1(16.8 * Units::nm, 1e3 * Units::nm);
+    FTDistribution1DGauss pdf(3 * Units::nm);
     interference1.setProbabilityDistribution(pdf);
 
     // interference function2
-    InterferenceFunctionRadialParaCrystal interference2(22.8 * Units::nanometer,
-                                                        1e3 * Units::nanometer);
+    InterferenceFunctionRadialParaCrystal interference2(22.8 * Units::nm, 1e3 * Units::nm);
     interference2.setProbabilityDistribution(pdf);
 
     // assembling the sample
@@ -113,21 +110,20 @@ MultiLayer* SizeDistributionLMAModelBuilder::buildSample() const
 MultiLayer* SizeDistributionSSCAModelBuilder::buildSample() const
 {
     // cylindrical particle 1
-    double radius1(5 * Units::nanometer);
+    double radius1(5 * Units::nm);
     double height1 = radius1;
     FormFactorCylinder cylinder_ff1(radius1, height1);
     Particle cylinder1(refMat::Particle, cylinder_ff1);
 
     // cylindrical particle 2
-    double radius2(8 * Units::nanometer);
+    double radius2(8 * Units::nm);
     double height2(radius2);
     FormFactorCylinder cylinder_ff2(radius2, height2);
     Particle cylinder2(refMat::Particle, cylinder_ff2);
 
     // interference function
-    InterferenceFunctionRadialParaCrystal interference(18.0 * Units::nanometer,
-                                                       1e3 * Units::nanometer);
-    FTDistribution1DGauss pdf(3 * Units::nanometer);
+    InterferenceFunctionRadialParaCrystal interference(18.0 * Units::nm, 1e3 * Units::nm);
+    FTDistribution1DGauss pdf(3 * Units::nm);
     interference.setProbabilityDistribution(pdf);
     interference.setKappa(1.0);
 
@@ -153,17 +149,16 @@ MultiLayer* CylindersInSSCABuilder::buildSample() const
 {
     Layer vacuum_layer(refMat::Vacuum);
 
-    InterferenceFunctionRadialParaCrystal interference_function(15.0 * Units::nanometer,
-                                                                1e3 * Units::nanometer);
-    FTDistribution1DGauss pdf(5 * Units::nanometer);
+    InterferenceFunctionRadialParaCrystal interference_function(15.0 * Units::nm, 1e3 * Units::nm);
+    FTDistribution1DGauss pdf(5 * Units::nm);
     interference_function.setProbabilityDistribution(pdf);
     interference_function.setKappa(4.02698);
     ParticleLayout particle_layout;
 
-    FormFactorCylinder ff_cylinder(5.0 * Units::nanometer, 5.0 * Units::nanometer);
+    FormFactorCylinder ff_cylinder(5.0 * Units::nm, 5.0 * Units::nm);
     Particle particle_prototype(refMat::Particle, ff_cylinder);
 
-    DistributionGaussian gauss(5.0 * Units::nanometer, 1.25 * Units::nanometer);
+    DistributionGaussian gauss(5.0 * Units::nm, 1.25 * Units::nm);
     ParameterPattern pattern_radius;
     pattern_radius.add("Particle").add("Cylinder").add("Radius");
     ParameterDistribution par_distr(pattern_radius.toStdString(), gauss, 30, 3.0);
diff --git a/Sample/StandardSamples/SlicedCylindersBuilder.cpp b/Sample/StandardSamples/SlicedCylindersBuilder.cpp
index 5feb948d3f1ab597d9d63b6133d00c5a3911c276..d93e693f079026f925eada56085842cf1095b8d7 100644
--- a/Sample/StandardSamples/SlicedCylindersBuilder.cpp
+++ b/Sample/StandardSamples/SlicedCylindersBuilder.cpp
@@ -24,8 +24,8 @@
 
 namespace
 {
-const double height(5 * Units::nanometer);
-const double radius(5 * Units::nanometer);
+const double height(5 * Units::nm);
+const double radius(5 * Units::nm);
 const double wavelength(0.154); // nm
 const int n_slices(3);
 
diff --git a/Sample/StandardSamples/TransformationsBuilder.cpp b/Sample/StandardSamples/TransformationsBuilder.cpp
index 55e85ef9d988e8cbdd5e1dc628c90e13af18bb71..6bbabc7f9aa5e363a8b5a63309acb14edec0a384 100644
--- a/Sample/StandardSamples/TransformationsBuilder.cpp
+++ b/Sample/StandardSamples/TransformationsBuilder.cpp
@@ -29,8 +29,8 @@ MultiLayer* TransformBoxBuilder::buildSample() const
     const double height(10);
 
     Particle box(refMat::Ag, FormFactorBox(length, width, height));
-    box.setRotation(RotationZ(90. * Units::degree));
-    box.rotate(RotationY(90. * Units::degree));
+    box.setRotation(RotationZ(90. * Units::deg));
+    box.rotate(RotationY(90. * Units::deg));
     box.setPosition(kvector_t(0, 0, -layer_thickness / 2.));
 
     ParticleLayout layout;
diff --git a/Sample/StandardSamples/TwoDimLatticeBuilder.cpp b/Sample/StandardSamples/TwoDimLatticeBuilder.cpp
index d2ffcee46552301d92dac8cd8b50086175b133cc..feb9207a5cac884c9fc96e4ee525c116579539a9 100644
--- a/Sample/StandardSamples/TwoDimLatticeBuilder.cpp
+++ b/Sample/StandardSamples/TwoDimLatticeBuilder.cpp
@@ -19,6 +19,7 @@
 #include "Sample/Aggregate/InterferenceFunctionFinite2DLattice.h"
 #include "Sample/Aggregate/ParticleLayout.h"
 #include "Sample/HardParticle/FormFactorCylinder.h"
+#include "Sample/Lattice/Lattice2D.h"
 #include "Sample/Multilayer/Layer.h"
 #include "Sample/Multilayer/MultiLayer.h"
 #include "Sample/Particle/Particle.h"
@@ -30,21 +31,19 @@ MultiLayer* Basic2DLatticeBuilder::buildSample() const
     Layer vacuum_layer(refMat::Vacuum);
     Layer substrate_layer(refMat::Substrate);
 
-    std::unique_ptr<InterferenceFunction2DLattice> P_interference_function(
-        new InterferenceFunction2DLattice(5.0 * Units::nanometer, 10.0 * Units::nanometer,
-                                          30.0 * Units::deg, 10.0 * Units::deg));
+    InterferenceFunction2DLattice iff(
+        BasicLattice(5.0 * Units::nm, 10.0 * Units::nm, 30.0 * Units::deg, 10.0 * Units::deg));
 
-    FTDecayFunction2DCauchy pdf(300.0 * Units::nanometer / 2.0 / M_PI,
-                                100.0 * Units::nanometer / 2.0 / M_PI, 0);
-    P_interference_function->setDecayFunction(pdf);
+    FTDecayFunction2DCauchy pdf(300.0 * Units::nm / 2.0 / M_PI, 100.0 * Units::nm / 2.0 / M_PI, 0);
+    iff.setDecayFunction(pdf);
 
     // particles
     ParticleLayout particle_layout;
-    FormFactorCylinder ff_cyl(5.0 * Units::nanometer, 5.0 * Units::nanometer);
+    FormFactorCylinder ff_cyl(5.0 * Units::nm, 5.0 * Units::nm);
     Particle particle(refMat::Particle, ff_cyl);
     particle_layout.addParticle(particle, 1.0);
 
-    particle_layout.setInterferenceFunction(*P_interference_function);
+    particle_layout.setInterferenceFunction(iff);
 
     vacuum_layer.addLayout(particle_layout);
 
@@ -62,19 +61,17 @@ MultiLayer* SquareLatticeBuilder::buildSample() const
     Layer vacuum_layer(refMat::Vacuum);
     Layer substrate_layer(refMat::Substrate);
 
-    std::unique_ptr<InterferenceFunction2DLattice> P_interference_function{
-        InterferenceFunction2DLattice::createSquare(10.0 * Units::nanometer, 0)};
-    FTDecayFunction2DCauchy pdf(300.0 * Units::nanometer / 2.0 / M_PI,
-                                100.0 * Units::nanometer / 2.0 / M_PI, 0);
-    P_interference_function->setDecayFunction(pdf);
+    InterferenceFunction2DLattice iff(SquareLattice(10.0 * Units::nm, 0));
+    FTDecayFunction2DCauchy pdf(300.0 * Units::nm / 2.0 / M_PI, 100.0 * Units::nm / 2.0 / M_PI, 0);
+    iff.setDecayFunction(pdf);
 
     // particles
     ParticleLayout particle_layout;
-    FormFactorCylinder ff_cyl(5.0 * Units::nanometer, 5.0 * Units::nanometer);
+    FormFactorCylinder ff_cyl(5.0 * Units::nm, 5.0 * Units::nm);
     Particle particle(refMat::Particle, ff_cyl);
     particle_layout.addParticle(particle, 1.0);
 
-    particle_layout.setInterferenceFunction(*P_interference_function);
+    particle_layout.setInterferenceFunction(iff);
 
     vacuum_layer.addLayout(particle_layout);
 
@@ -92,17 +89,16 @@ MultiLayer* CenteredSquareLatticeBuilder::buildSample() const
     Layer vacuum_layer(refMat::Vacuum);
     Layer substrate_layer(refMat::Substrate);
 
-    InterferenceFunction2DLattice interference_function(10.0 * Units::nanometer,
-                                                        10.0 * Units::nanometer, M_PI / 2.0, 0);
-    FTDecayFunction2DCauchy pdf(300.0 * Units::nanometer / 2.0 / M_PI,
-                                100.0 * Units::nanometer / 2.0 / M_PI, 0);
+    InterferenceFunction2DLattice interference_function(
+        BasicLattice(10.0 * Units::nm, 10.0 * Units::nm, M_PI / 2.0, 0));
+    FTDecayFunction2DCauchy pdf(300.0 * Units::nm / 2.0 / M_PI, 100.0 * Units::nm / 2.0 / M_PI, 0);
     interference_function.setDecayFunction(pdf);
 
-    FormFactorCylinder ff_cyl(5.0 * Units::nanometer, 5.0 * Units::nanometer);
+    FormFactorCylinder ff_cyl(5.0 * Units::nm, 5.0 * Units::nm);
     Particle cylinder(refMat::Particle, ff_cyl);
     std::vector<kvector_t> positions;
     kvector_t position_1(0.0, 0.0, 0.0);
-    kvector_t position_2(5.0 * Units::nanometer, -5.0 * Units::nanometer, 0.0);
+    kvector_t position_2(5.0 * Units::nm, -5.0 * Units::nm, 0.0);
     positions.push_back(position_1);
     positions.push_back(position_2);
     ParticleComposition basis;
@@ -127,20 +123,19 @@ MultiLayer* RotatedSquareLatticeBuilder::buildSample() const
     Layer vacuum_layer(refMat::Vacuum);
     Layer substrate_layer(refMat::Substrate);
 
-    std::unique_ptr<InterferenceFunction2DLattice> P_interference_function{
-        InterferenceFunction2DLattice::createSquare(10.0 * Units::nanometer, 30.0 * Units::degree)};
-    FTDecayFunction2DCauchy pdf(300.0 * Units::nanometer / 2.0 / M_PI,
-                                100.0 * Units::nanometer / 2.0 / M_PI, 30.0 * Units::degree);
-    P_interference_function->setDecayFunction(pdf);
+    InterferenceFunction2DLattice iff(SquareLattice(10.0 * Units::nm, 30.0 * Units::deg));
+    FTDecayFunction2DCauchy pdf(300.0 * Units::nm / 2.0 / M_PI, 100.0 * Units::nm / 2.0 / M_PI,
+                                30.0 * Units::deg);
+    iff.setDecayFunction(pdf);
 
     ParticleLayout particle_layout;
     // particle
-    FormFactorCylinder ff_cyl(5.0 * Units::nanometer, 5.0 * Units::nanometer);
+    FormFactorCylinder ff_cyl(5.0 * Units::nm, 5.0 * Units::nm);
     kvector_t position(0.0, 0.0, 0.0);
     Particle p(refMat::Particle, ff_cyl);
     p.setPosition(position);
     particle_layout.addParticle(p);
-    particle_layout.setInterferenceFunction(*P_interference_function);
+    particle_layout.setInterferenceFunction(iff);
 
     vacuum_layer.addLayout(particle_layout);
 
@@ -158,17 +153,16 @@ MultiLayer* FiniteSquareLatticeBuilder::buildSample() const
     Layer vacuum_layer(refMat::Vacuum);
     Layer substrate_layer(refMat::Substrate);
 
-    std::unique_ptr<InterferenceFunctionFinite2DLattice> P_interference_function{
-        InterferenceFunctionFinite2DLattice::createSquare(10.0 * Units::nanometer, 0.0, 40, 40)};
-    P_interference_function->setPositionVariance(1.0);
+    InterferenceFunctionFinite2DLattice iff(SquareLattice(10.0 * Units::nm, 0.0), 40, 40);
+    iff.setPositionVariance(1.0);
 
     // particles
     ParticleLayout particle_layout;
-    FormFactorCylinder ff_cyl(5.0 * Units::nanometer, 5.0 * Units::nanometer);
+    FormFactorCylinder ff_cyl(5.0 * Units::nm, 5.0 * Units::nm);
     Particle particle(refMat::Particle, ff_cyl);
     particle_layout.addParticle(particle, 1.0);
 
-    particle_layout.setInterferenceFunction(*P_interference_function);
+    particle_layout.setInterferenceFunction(iff);
 
     vacuum_layer.addLayout(particle_layout);
 
@@ -186,20 +180,18 @@ MultiLayer* SuperLatticeBuilder::buildSample() const
     Layer vacuum_layer(refMat::Vacuum);
     Layer substrate_layer(refMat::Substrate);
 
-    std::unique_ptr<InterferenceFunction2DSuperLattice> P_interference_function{
-        InterferenceFunction2DSuperLattice::createSquare(200.0 * Units::nanometer, 0.0, 40, 40)};
-    std::unique_ptr<InterferenceFunctionFinite2DLattice> P_substructure{
-        InterferenceFunctionFinite2DLattice::createSquare(10.0 * Units::nanometer, 0.0, 10, 10)};
-    P_interference_function->setSubstructureIFF(*P_substructure);
-    P_interference_function->setPositionVariance(1.0);
+    InterferenceFunction2DSuperLattice iff(SquareLattice(200.0 * Units::nm, 0.0), 40, 40);
+    InterferenceFunctionFinite2DLattice substructure(SquareLattice(10.0 * Units::nm, 0.0), 10, 10);
+    iff.setSubstructureIFF(substructure);
+    iff.setPositionVariance(1.0);
 
     // particles
     ParticleLayout particle_layout;
-    FormFactorCylinder ff_cyl(5.0 * Units::nanometer, 10.0 * Units::nanometer);
+    FormFactorCylinder ff_cyl(5.0 * Units::nm, 10.0 * Units::nm);
     Particle particle(refMat::Vacuum, ff_cyl);
-    particle_layout.addParticle(particle, 1.0, kvector_t(0.0, 0.0, -10.0 * Units::nanometer));
+    particle_layout.addParticle(particle, 1.0, kvector_t(0.0, 0.0, -10.0 * Units::nm));
 
-    particle_layout.setInterferenceFunction(*P_interference_function);
+    particle_layout.setInterferenceFunction(iff);
     particle_layout.setTotalParticleSurfaceDensity(100.0 / 4e4);
 
     substrate_layer.addLayout(particle_layout);
diff --git a/Sample/StandardSamples/TwoLayerRoughnessBuilder.cpp b/Sample/StandardSamples/TwoLayerRoughnessBuilder.cpp
index 85cf3acd83fd2dbd036e123f0b70dc25eb0c7332..a3c47d4bb91832f69a6e914cadca6d6ec8234332 100644
--- a/Sample/StandardSamples/TwoLayerRoughnessBuilder.cpp
+++ b/Sample/StandardSamples/TwoLayerRoughnessBuilder.cpp
@@ -21,9 +21,9 @@
 
 MultiLayer* TwoLayerRoughnessBuilder::buildSample() const
 {
-    const double m_sigma(1.0 * Units::nanometer);
+    const double m_sigma(1.0 * Units::nm);
     const double m_hurst(0.3);
-    const double m_lateralCorrLength(5.0 * Units::nanometer);
+    const double m_lateralCorrLength(5.0 * Units::nm);
 
     Layer vacuum_layer(refMat::Vacuum, 0);
     Layer substrate_layer(refMat::Substrate, 0);
diff --git a/Tests/Functional/Core/Fitting/AdjustMinimizerPlan.cpp b/Tests/Functional/Core/Fitting/AdjustMinimizerPlan.cpp
index ce96edc84fa9e1e72e2c7de37aced328b6e014f1..f427dacd1149e4109262e1479866676a410cbc9c 100644
--- a/Tests/Functional/Core/Fitting/AdjustMinimizerPlan.cpp
+++ b/Tests/Functional/Core/Fitting/AdjustMinimizerPlan.cpp
@@ -20,7 +20,7 @@
 
 namespace
 {
-const double nm = Units::nanometer;
+const double nm = Units::nm;
 }
 
 using namespace Fit;
diff --git a/Tests/Functional/Core/Fitting/PlanCases.cpp b/Tests/Functional/Core/Fitting/PlanCases.cpp
index 6b524ea4dfe99e499b36a409b200956b7abb2f92..954da961853a1fcff2c48cf7f9f0a90f5fe89c86 100644
--- a/Tests/Functional/Core/Fitting/PlanCases.cpp
+++ b/Tests/Functional/Core/Fitting/PlanCases.cpp
@@ -30,7 +30,7 @@ using namespace Fit;
 
 namespace
 {
-const double nm = Units::nanometer;
+const double nm = Units::nm;
 }
 
 CylindersInBAPlan::CylindersInBAPlan() : Plan("CylindersInBAPlan")
@@ -81,7 +81,7 @@ std::unique_ptr<ISimulation> RectDetPlan::createSimulation(const Parameters&) co
     RectangularDetector detector(20u, width, 18u, height);
     detector.setPerpendicularToSampleX(detector_distance, width / 2., 0.0);
 
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
     result->setDetector(detector);
     result->setRegionOfInterest(5.0, 6.0, 15.0, 12.0);
     result->addMask(Rectangle(0.0, 0.0, 2.0, 2.0), true);
diff --git a/Tests/Functional/Python/PyCore/mesocrystal1.py b/Tests/Functional/Python/PyCore/mesocrystal1.py
index b95cc239f04521a3336670cc9ba7e0274f21a5ed..4da5e4201652ef3d6011562ade02dc9f352dddbf 100644
--- a/Tests/Functional/Python/PyCore/mesocrystal1.py
+++ b/Tests/Functional/Python/PyCore/mesocrystal1.py
@@ -44,7 +44,7 @@ class MySampleBuilder(ISampleBuilder):
         avg_n_squared_meso = complex(0.7886*n_particle*n_particle + 0.2114)
         n_avg = complex(numpy.sqrt(self.surface_filling_ratio.value*avg_n_squared_meso + 1.0 - self.surface_filling_ratio.value))
         n_particle_adapted = complex(numpy.sqrt(n_avg*n_avg + n_particle*n_particle - 1.0))
-        ff_meso = FormFactorCylinder(self.meso_radius.value, self.meso_height.value)
+        ff = FormFactorCylinder(self.meso_radius.value, self.meso_height.value)
 
         # Create multilayer
         p_multi_layer = MultiLayer()
@@ -71,7 +71,7 @@ class MySampleBuilder(ISampleBuilder):
             for j in range(0, n_alpha_rotation_steps):
 
                 total_transform = RotationZ(phi_start + i*phi_step)
-                meso = self.createMesoCrystal(self.lattice_length_a.value, self.lattice_length_c.value, n_particle_adapted, ff_meso)
+                meso = self.createMesoCrystal(self.lattice_length_a.value, self.lattice_length_c.value, n_particle_adapted, ff)
                 meso.setPosition(0.0, 0.0, -self.meso_height.value)
                 particle_layout.addParticle(meso, 1.0, kvector_t(0,0,0), total_transform)
 
@@ -99,8 +99,8 @@ class MySampleBuilder(ISampleBuilder):
         bas_a = p_lat.getBasisVectorA()
         bas_b = p_lat.getBasisVectorB()
         bas_c = p_lat.getBasisVectorC()
-        ff_sphere = FormFactorSphereGaussianRadius(self.nanoparticle_radius.value, self.sigma_nanoparticle_radius.value)
-        particle = Particle(mParticle, ff_sphere )
+        ff = FormFactorSphereGaussianRadius(self.nanoparticle_radius.value, self.sigma_nanoparticle_radius.value)
+        particle = Particle(mParticle, ff )
         position_0 = kvector_t(0.0, 0.0, 0.0)
         position_1 = 1.0/3.0*(2.0*bas_a + bas_b + bas_c)
         position_2 = 1.0/3.0*(bas_a + 2.0*bas_b + 2.0*bas_c)
@@ -108,9 +108,8 @@ class MySampleBuilder(ISampleBuilder):
         basis = ParticleComposition()
         basis.addParticles(particle, positions)
 
-        npc = Crystal(basis, p_lat)
         position_variance = self.sigma_lattice_length_a.value*self.sigma_lattice_length_a.value/3.0
-        npc.setPositionVariance(position_variance)
+        npc = Crystal(basis, p_lat, position_variance)
         meso = MesoCrystal(npc, p_meso_form_factor)
         return meso
 
@@ -118,11 +117,9 @@ class MySampleBuilder(ISampleBuilder):
     # create lattice
     # -------------------------------------------------------------------------
     def createLattice(self, stacking_radius_a, stacking_radius_c):
-        lattice = Lattice.createHexagonalLattice(stacking_radius_a*2.0, stacking_radius_c*2.0*2.3)
-        p_result = Lattice(lattice)
-        selection_rule = SimpleSelectionRule(-1, 1, 1, 3)
-        p_result.setSelectionRule( selection_rule )
-        return p_result
+        result = createHexagonalLattice(stacking_radius_a*2.0, stacking_radius_c*2.0*2.3)
+        result.setSelectionRule(SimpleSelectionRule(-1, 1, 1, 3))
+        return result
 
 
 # -----------------------------------------------------------------------------
diff --git a/Tests/Performance/Core/Mesocrystal.cpp b/Tests/Performance/Core/Mesocrystal.cpp
index 17b0b6bb2e1e9a06c330e4cf1e45773eae566c14..4cf83ed8fabb612da93a1f3d2f822eda4139a605 100644
--- a/Tests/Performance/Core/Mesocrystal.cpp
+++ b/Tests/Performance/Core/Mesocrystal.cpp
@@ -18,6 +18,7 @@
 #include "Device/Detector/RectangularDetector.h"
 #include "Sample/Aggregate/ParticleLayout.h"
 #include "Sample/HardParticle/FormFactorCylinder.h"
+#include "Sample/Lattice/BakeLattice.h"
 #include "Sample/Lattice/ISelectionRule.h"
 #include "Sample/Material/MaterialFactoryFuncs.h"
 #include "Sample/Multilayer/Layer.h"
@@ -52,9 +53,9 @@ std::unique_ptr<RectangularDetector> create_detector()
     return result;
 }
 
-Lattice createLattice(double a, double c)
+Lattice3D createLattice(double a, double c)
 {
-    Lattice result = Lattice::createHexagonalLattice(a, c);
+    Lattice3D result = bake::createHexagonalLattice(a, c);
     result.setSelectionRule(SimpleSelectionRule(-1, 1, 1, 3));
     return result;
 }
@@ -186,9 +187,8 @@ MesoCrystalPerformanceBuilder::createMeso(Material material, const IFormFactor&
     std::vector<kvector_t> pos_vector = {position_0, position_1, position_2};
     ParticleComposition basis;
     basis.addParticles(particle, pos_vector);
-    Crystal npc(basis, lattice);
     double position_variance = m_sigma_lattice_length_a * m_sigma_lattice_length_a / 3.0;
-    npc.setPositionVariance(position_variance);
+    Crystal npc(basis, lattice, position_variance);
 
     return std::make_unique<MesoCrystal>(npc, form_factor);
 }
diff --git a/Tests/Performance/Core/ThreadingComponents.cpp b/Tests/Performance/Core/ThreadingComponents.cpp
index 734957a67ee9fdeba02c7fe8ab23f1d148b072ec..1eb550587e484fa6187dde1f005721547f8366da 100644
--- a/Tests/Performance/Core/ThreadingComponents.cpp
+++ b/Tests/Performance/Core/ThreadingComponents.cpp
@@ -76,7 +76,7 @@ std::unique_ptr<MultiLayer> createSampleSpheresDistribution(int nspheres)
 std::unique_ptr<ISimulation> CreateRealisticGISASSimulation()
 {
     auto result = std::make_unique<GISASSimulation>();
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
 
     // define detector
     const int pilatus_npx{981}, pilatus_npy{1043};
@@ -104,9 +104,9 @@ std::unique_ptr<ISimulation> CreateRealisticGISASSimulation()
 std::unique_ptr<ISimulation> TestComponents::CreateSimpleGISAS()
 {
     auto result = std::make_unique<GISASSimulation>();
-    result->setDetectorParameters(100, 0.0 * Units::degree, 2.0 * Units::degree, 100,
-                                  0.0 * Units::degree, 2.0 * Units::degree);
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setDetectorParameters(100, 0.0 * Units::deg, 2.0 * Units::deg, 100, 0.0 * Units::deg,
+                                  2.0 * Units::deg);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
 
     auto sample = std::unique_ptr<MultiLayer>(CylindersInDWBABuilder().buildSample());
     result->setSample(*sample);
@@ -146,9 +146,9 @@ std::unique_ptr<ISimulation> TestComponents::CreateGiganticGISAS()
 {
     const int nbins = 2048;
     auto result = std::make_unique<GISASSimulation>();
-    result->setDetectorParameters(nbins, -2.0 * Units::degree, 2.0 * Units::degree, nbins,
-                                  0.0 * Units::degree, 2.0 * Units::degree);
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setDetectorParameters(nbins, -2.0 * Units::deg, 2.0 * Units::deg, nbins,
+                                  0.0 * Units::deg, 2.0 * Units::deg);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
     auto sample = std::unique_ptr<MultiLayer>(CylindersInBABuilder().buildSample());
     result->setSample(*sample);
     return std::unique_ptr<ISimulation>(result.release());
@@ -162,9 +162,9 @@ std::unique_ptr<ISimulation> TestComponents::CreateWavelengthGISAS()
 {
     const int nbins = 64;
     auto result = std::make_unique<GISASSimulation>();
-    result->setDetectorParameters(nbins, -2.0 * Units::degree, 2.0 * Units::degree, nbins,
-                                  0.0 * Units::degree, 2.0 * Units::degree);
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setDetectorParameters(nbins, -2.0 * Units::deg, 2.0 * Units::deg, nbins,
+                                  0.0 * Units::deg, 2.0 * Units::deg);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
 
     // create parameter distribution
     DistributionLogNormal wavelength_distr(1.0 * Units::angstrom, 0.1);
@@ -184,9 +184,9 @@ std::unique_ptr<ISimulation> TestComponents::CreateWavelengthGISAS()
 std::unique_ptr<ISimulation> TestComponents::CreateMCGISAS()
 {
     auto result = std::make_unique<GISASSimulation>();
-    result->setDetectorParameters(100, 0.0 * Units::degree, 2.0 * Units::degree, 100,
-                                  0.0 * Units::degree, 2.0 * Units::degree);
-    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::degree, 0.0 * Units::degree);
+    result->setDetectorParameters(100, 0.0 * Units::deg, 2.0 * Units::deg, 100, 0.0 * Units::deg,
+                                  2.0 * Units::deg);
+    result->setBeamParameters(1.0 * Units::angstrom, 0.2 * Units::deg, 0.0 * Units::deg);
 
     auto sample = createSampleSpheresDistribution(10);
     result->setSample(*sample);
diff --git a/Tests/UnitTests/Core/Axes/ConstKBinAxisTest.cpp b/Tests/UnitTests/Core/Axes/ConstKBinAxisTest.cpp
index 39f1f2f06eb83516e5e64e673d1707ab19917413..27565872ba3ce73c1867be2b07a694138b1a6211 100644
--- a/Tests/UnitTests/Core/Axes/ConstKBinAxisTest.cpp
+++ b/Tests/UnitTests/Core/Axes/ConstKBinAxisTest.cpp
@@ -9,8 +9,8 @@ class ConstKBinAxisTest : public ::testing::Test
 protected:
     ConstKBinAxisTest()
         : m_nbins(10)
-        , m_start(-5.0 * Units::degree)
-        , m_end(5.0 * Units::degree)
+        , m_start(-5.0 * Units::deg)
+        , m_end(5.0 * Units::deg)
         , m_axis("name", m_nbins, m_start, m_end)
     {
         double start_sin = std::sin(m_start);
diff --git a/Tests/UnitTests/Core/Detector/RectangularDetectorTest.cpp b/Tests/UnitTests/Core/Detector/RectangularDetectorTest.cpp
index 9f474af04d898f87850235306d0de8103563e92b..071f362bf8344b8b1ed78bbafa6836795a87f7e5 100644
--- a/Tests/UnitTests/Core/Detector/RectangularDetectorTest.cpp
+++ b/Tests/UnitTests/Core/Detector/RectangularDetectorTest.cpp
@@ -11,8 +11,8 @@ class RectangularDetectorTest : public ::testing::Test
 protected:
     //    double phi(DetectorElement& element, double wavelength);
     //    double alpha(DetectorElement& element, double wavelength);
-    double phi(kvector_t k) { return k.phi() / Units::degree; }
-    double alpha(kvector_t k) { return 90.0 - k.theta() / Units::degree; }
+    double phi(kvector_t k) { return k.phi() / Units::deg; }
+    double alpha(kvector_t k) { return 90.0 - k.theta() / Units::deg; }
 
     bool isEqual(const kvector_t lhs, const kvector_t rhs)
     {
@@ -80,7 +80,7 @@ TEST_F(RectangularDetectorTest, PerpToSample)
 
     // initializing with the simulation
     GISASSimulation simulation;
-    simulation.setBeamParameters(1.0, 10.0 * Units::degree, 0.0);
+    simulation.setBeamParameters(1.0, 10.0 * Units::deg, 0.0);
     det.init(simulation.instrument().beam());
     EXPECT_TRUE(kvector_t(distance, 0, 0) == det.getNormalVector());
     EXPECT_TRUE(kvector_t(0.0, -1.0, 0.0) == det.getDirectionVector());
@@ -119,7 +119,7 @@ TEST_F(RectangularDetectorTest, PerpToDirectBeam)
     double distance(100.0), u0(20.0), v0(10.0);
     //    double dx = width / nbinsx;
     //    double dy = height / nbinsy;
-    double alpha_i(10.0 * Units::degree);
+    double alpha_i(10.0 * Units::deg);
 
     RectangularDetector det(nbinsx, width, nbinsy, height);
 
@@ -162,7 +162,7 @@ TEST_F(RectangularDetectorTest, PerpToReflectedBeam)
     double distance(100.0), u0(20.0), v0(10.0);
     //    double dx = width / nbinsx;
     //    double dy = height / nbinsy;
-    double alpha_i(10.0 * Units::degree);
+    double alpha_i(10.0 * Units::deg);
 
     RectangularDetector det(nbinsx, width, nbinsy, height);
 
@@ -207,7 +207,7 @@ TEST_F(RectangularDetectorTest, PerpToReflectedBeamDpos)
     double distance(100.0), u0(20.0), v0(10.0);
     //    double dx = width / nbinsx;
     //    double dy = height / nbinsy;
-    double alpha_i(10.0 * Units::degree);
+    double alpha_i(10.0 * Units::deg);
 
     RectangularDetector det(nbinsx, width, nbinsy, height);
 
@@ -345,12 +345,12 @@ TEST_F(RectangularDetectorTest, AnalyzerProperties)
 //{
 //    auto pixel = element.pixel();
 //    auto k_f = pixel->getK(0.5, 0.5, wavelength);
-//    return k_f.phi() / Units::degree;
+//    return k_f.phi() / Units::deg;
 //}
 
 // double RectangularDetectorTest::alpha(DetectorElement& element, double wavelength)
 //{
 //    auto pixel = element.pixel();
 //    auto k_f = pixel->getK(0.5, 0.5, wavelength);
-//    return ( M_PI_2 - k_f.theta() ) / Units::degree;
+//    return ( M_PI_2 - k_f.theta() ) / Units::deg;
 //}
diff --git a/Tests/UnitTests/Core/Fresnel/DepthProbeSimulationTest.cpp b/Tests/UnitTests/Core/Fresnel/DepthProbeSimulationTest.cpp
index d9355d539ecfda6cb65b778bee2263e52aee62eb..5d54b46eaeed3b63f7815bc7dd5259589aa476f6 100644
--- a/Tests/UnitTests/Core/Fresnel/DepthProbeSimulationTest.cpp
+++ b/Tests/UnitTests/Core/Fresnel/DepthProbeSimulationTest.cpp
@@ -30,7 +30,7 @@ DepthProbeSimulationTest::DepthProbeSimulationTest()
     Material mat2 = HomogeneousMaterial("substrate", 15e-6, 0.0);
 
     Layer layer0(mat0);
-    Layer layer1(mat1, 10 * Units::nanometer);
+    Layer layer1(mat1, 10 * Units::nm);
     Layer layer2(mat2);
 
     multilayer.addLayer(layer0);
@@ -41,8 +41,8 @@ DepthProbeSimulationTest::DepthProbeSimulationTest()
 std::unique_ptr<DepthProbeSimulation> DepthProbeSimulationTest::defaultSimulation()
 {
     std::unique_ptr<DepthProbeSimulation> result = std::make_unique<DepthProbeSimulation>();
-    result->setBeamParameters(1.0, 10, 0.0 * Units::degree, 2.0 * Units::degree);
-    result->setZSpan(12, -30.0 * Units::nanometer, 10.0 * Units::nanometer);
+    result->setBeamParameters(1.0, 10, 0.0 * Units::deg, 2.0 * Units::deg);
+    result->setZSpan(12, -30.0 * Units::nm, 10.0 * Units::nm);
     result->setSample(multilayer);
     return result;
 }
@@ -82,14 +82,14 @@ TEST_F(DepthProbeSimulationTest, CheckAxesOfDefaultSimulation)
     const auto alpha_axis = sim->getAlphaAxis();
     EXPECT_TRUE(dynamic_cast<const FixedBinAxis*>(alpha_axis));
     EXPECT_EQ(alpha_axis->size(), 10u);
-    EXPECT_EQ(alpha_axis->lowerBound(), 0.0 * Units::degree);
-    EXPECT_EQ(alpha_axis->upperBound(), 2.0 * Units::degree);
+    EXPECT_EQ(alpha_axis->lowerBound(), 0.0 * Units::deg);
+    EXPECT_EQ(alpha_axis->upperBound(), 2.0 * Units::deg);
 
     const auto z_axis = sim->getZAxis();
     EXPECT_TRUE(dynamic_cast<const FixedBinAxis*>(z_axis));
     EXPECT_EQ(z_axis->size(), 12u);
-    EXPECT_EQ(z_axis->lowerBound(), -30.0 * Units::nanometer);
-    EXPECT_EQ(z_axis->upperBound(), 10.0 * Units::nanometer);
+    EXPECT_EQ(z_axis->lowerBound(), -30.0 * Units::nm);
+    EXPECT_EQ(z_axis->upperBound(), 10.0 * Units::nm);
 
     const auto sim_clone = sim->clone();
     EXPECT_FALSE(alpha_axis == sim_clone->getAlphaAxis());
@@ -101,10 +101,10 @@ TEST_F(DepthProbeSimulationTest, SetBeamParameters)
     DepthProbeSimulation sim;
     const auto& beam = sim.instrument().beam();
 
-    sim.setBeamParameters(1.0, 10, 1.0 * Units::degree, 10.0 * Units::degree);
+    sim.setBeamParameters(1.0, 10, 1.0 * Units::deg, 10.0 * Units::deg);
     EXPECT_EQ(10u, sim.getAlphaAxis()->size());
-    EXPECT_EQ(1.0 * Units::degree, sim.getAlphaAxis()->lowerBound());
-    EXPECT_EQ(10.0 * Units::degree, sim.getAlphaAxis()->upperBound());
+    EXPECT_EQ(1.0 * Units::deg, sim.getAlphaAxis()->lowerBound());
+    EXPECT_EQ(10.0 * Units::deg, sim.getAlphaAxis()->upperBound());
     EXPECT_EQ(1.0, beam.getIntensity());
     EXPECT_EQ(1.0, beam.getWavelength());
     EXPECT_EQ(0.0, beam.getAlpha());
@@ -121,8 +121,8 @@ TEST_F(DepthProbeSimulationTest, SetBeamParameters)
     EXPECT_THROW(sim.setBeamParameters(-1.0, 1, 1.0, 2.0), std::runtime_error);
 
     EXPECT_EQ(10u, sim.getAlphaAxis()->size());
-    EXPECT_EQ(1.0 * Units::degree, sim.getAlphaAxis()->lowerBound());
-    EXPECT_EQ(10.0 * Units::degree, sim.getAlphaAxis()->upperBound());
+    EXPECT_EQ(1.0 * Units::deg, sim.getAlphaAxis()->lowerBound());
+    EXPECT_EQ(10.0 * Units::deg, sim.getAlphaAxis()->upperBound());
     EXPECT_EQ(2.0, beam.getIntensity());
     EXPECT_EQ(1.0, beam.getWavelength());
     EXPECT_EQ(0.0, beam.getAlpha());
diff --git a/Tests/UnitTests/Core/Fresnel/SpecularMagneticOldTest.cpp b/Tests/UnitTests/Core/Fresnel/SpecularMagneticOldTest.cpp
index 367af8391b7a428374228cab9786d5ca0d5e2a5c..7f855de46457be5214bb69e818f761f4696c1d27 100644
--- a/Tests/UnitTests/Core/Fresnel/SpecularMagneticOldTest.cpp
+++ b/Tests/UnitTests/Core/Fresnel/SpecularMagneticOldTest.cpp
@@ -21,7 +21,7 @@ TEST_F(SpecularMagneticOldTest, initial)
     // matrix.execute(mLayer, v, coeff);
 
     Material air = HomogeneousMaterial("Air", 0, 1.0);
-    Layer layer0(air, 0 * Units::nanometer);
+    Layer layer0(air, 0 * Units::nm);
     mLayer.addLayer(layer0);
     SimulationOptions options;
     ProcessedSample sample(mLayer, options);
diff --git a/Tests/UnitTests/Core/Fresnel/SpecularMagneticTest.cpp b/Tests/UnitTests/Core/Fresnel/SpecularMagneticTest.cpp
index 76c4ebfe8401599917798eb1f5e6ec047bb3db15..9b0910edd171febe6827dc525467648616b22d9a 100644
--- a/Tests/UnitTests/Core/Fresnel/SpecularMagneticTest.cpp
+++ b/Tests/UnitTests/Core/Fresnel/SpecularMagneticTest.cpp
@@ -85,7 +85,7 @@ std::unique_ptr<ProcessedSample> SpecularMagneticTest::sample_degenerate()
 {
     MultiLayer mLayer;
     Material air = HomogeneousMaterial("Vacuum", 0, 1.0);
-    mLayer.addLayer(Layer(air, 0 * Units::nanometer));
+    mLayer.addLayer(Layer(air, 0 * Units::nm));
     return std::make_unique<ProcessedSample>(mLayer, SimulationOptions());
 }
 
diff --git a/Tests/UnitTests/Core/Fresnel/SpecularSimulationTest.cpp b/Tests/UnitTests/Core/Fresnel/SpecularSimulationTest.cpp
index 9c54347380bfed24c13165e816c4ab8f7d70b318..4618559dfaf920ae2a5d6de4e4a61089a495298a 100644
--- a/Tests/UnitTests/Core/Fresnel/SpecularSimulationTest.cpp
+++ b/Tests/UnitTests/Core/Fresnel/SpecularSimulationTest.cpp
@@ -33,7 +33,7 @@ SpecularSimulationTest::SpecularSimulationTest()
     Material mat2 = HomogeneousMaterial("substrate", 15e-6, 0.0);
 
     Layer layer0(mat0);
-    Layer layer1(mat1, 10 * Units::nanometer);
+    Layer layer1(mat1, 10 * Units::nm);
     Layer layer2(mat2);
 
     multilayer.addLayer(layer0);
@@ -53,7 +53,7 @@ TEST_F(SpecularSimulationTest, InitialState)
 std::unique_ptr<SpecularSimulation> SpecularSimulationTest::defaultSimulation()
 {
     auto result = std::make_unique<SpecularSimulation>();
-    AngularSpecScan scan(1.0, FixedBinAxis("axis", 10, 0.0 * Units::degree, 2.0 * Units::degree));
+    AngularSpecScan scan(1.0, FixedBinAxis("axis", 10, 0.0 * Units::deg, 2.0 * Units::deg));
     result->setScan(scan);
     result->setSample(multilayer);
     return result;
@@ -101,23 +101,23 @@ TEST_F(SpecularSimulationTest, SetAngularScan)
     sim.setBeamIntensity(2.0);
     EXPECT_EQ(2.0, beam.getIntensity());
 
-    AngularSpecScan scan2(1.0, 10, 1.0 * Units::degree, 10.0 * Units::degree);
+    AngularSpecScan scan2(1.0, 10, 1.0 * Units::deg, 10.0 * Units::deg);
     sim.setScan(scan2);
     EXPECT_EQ(10u, sim.coordinateAxis()->size());
-    EXPECT_EQ(1.0 * Units::degree, sim.coordinateAxis()->lowerBound());
-    EXPECT_EQ(10.0 * Units::degree, sim.coordinateAxis()->upperBound());
+    EXPECT_EQ(1.0 * Units::deg, sim.coordinateAxis()->lowerBound());
+    EXPECT_EQ(10.0 * Units::deg, sim.coordinateAxis()->upperBound());
     EXPECT_EQ(2.0, beam.getIntensity());
     EXPECT_EQ(1.0, beam.getWavelength());
     EXPECT_EQ(0.0, beam.getAlpha());
     EXPECT_EQ(0.0, beam.getPhi());
     checkBeamState(sim);
 
-    AngularSpecScan scan3(1.0, 10, -1.0 * Units::degree, 2.0 * Units::degree);
+    AngularSpecScan scan3(1.0, 10, -1.0 * Units::deg, 2.0 * Units::deg);
     EXPECT_THROW(sim.setScan(scan3), std::runtime_error);
 
     EXPECT_EQ(10u, sim.coordinateAxis()->size());
-    EXPECT_EQ(1.0 * Units::degree, sim.coordinateAxis()->lowerBound());
-    EXPECT_EQ(10.0 * Units::degree, sim.coordinateAxis()->upperBound());
+    EXPECT_EQ(1.0 * Units::deg, sim.coordinateAxis()->lowerBound());
+    EXPECT_EQ(10.0 * Units::deg, sim.coordinateAxis()->upperBound());
     EXPECT_EQ(2.0, beam.getIntensity());
     EXPECT_EQ(1.0, beam.getWavelength());
     EXPECT_EQ(0.0, beam.getAlpha());
@@ -181,10 +181,9 @@ TEST_F(SpecularSimulationTest, ConstructSimulation)
     EXPECT_EQ(data->getAllocatedSize(), 10u);
     EXPECT_EQ(data->rank(), 1u);
 
-    EXPECT_NEAR(0.1 * Units::degree, sim_result.axis(Axes::Units::RADIANS).front(),
-                Units::degree * 1e-11);
-    EXPECT_NEAR(1.9 * Units::degree, sim_result.axis(Axes::Units::RADIANS).back(),
-                Units::degree * 1e-10);
+    EXPECT_NEAR(0.1 * Units::deg, sim_result.axis(Axes::Units::RADIANS).front(),
+                Units::deg * 1e-11);
+    EXPECT_NEAR(1.9 * Units::deg, sim_result.axis(Axes::Units::RADIANS).back(), Units::deg * 1e-10);
 
     checkBeamState(*sim);
 }
diff --git a/Tests/UnitTests/Core/Other/MaterialTest.cpp b/Tests/UnitTests/Core/Other/MaterialTest.cpp
index 6f5794efb075ddd93cc103f063ef8e1b15fe1ec7..79562f2f11e80269ecca5baa7254e49f0673ce6d 100644
--- a/Tests/UnitTests/Core/Other/MaterialTest.cpp
+++ b/Tests/UnitTests/Core/Other/MaterialTest.cpp
@@ -52,7 +52,7 @@ TEST_F(MaterialTest, MaterialTransform)
     complex_t material_data = complex_t(1.0, 0.0);
     complex_t refIndex = complex_t(1.0 - material_data.real(), material_data.imag());
     kvector_t magnetism = kvector_t(1.0, 0.0, 0.0);
-    RotationZ transform(90. * Units::degree);
+    RotationZ transform(90. * Units::deg);
     kvector_t transformed_mag = transform.transformed(magnetism);
 
     Material material = HomogeneousMaterial("Material", refIndex, magnetism);
diff --git a/Tests/UnitTests/Core/Other/Shape2DTest.cpp b/Tests/UnitTests/Core/Other/Shape2DTest.cpp
index fe6ffafd66e90493574fcd55a8594473c8e0ef48..4840929903a64d3b9d342ea8f2d4db4a3ab017c7 100644
--- a/Tests/UnitTests/Core/Other/Shape2DTest.cpp
+++ b/Tests/UnitTests/Core/Other/Shape2DTest.cpp
@@ -55,7 +55,7 @@ TEST_F(Shape2DTest, Ellipse)
     EXPECT_FALSE(ellipse.contains(4.0, -2.0));
     EXPECT_TRUE(ellipse.contains(6.0, -2.0));
 
-    Ellipse ellipse2(10.0, 1.0, 8.0, 4.0, 45.0 * Units::degree);
+    Ellipse ellipse2(10.0, 1.0, 8.0, 4.0, 45.0 * Units::deg);
     EXPECT_TRUE(ellipse2.contains(10.0, 1.0));
     EXPECT_FALSE(ellipse2.contains(15.0, 0.0));
     EXPECT_TRUE(ellipse2.contains(7.0, 3.0));
diff --git a/Tests/UnitTests/Core/Sample/CrystalTest.cpp b/Tests/UnitTests/Core/Sample/CrystalTest.cpp
index a89b873f9f4d13370c7fe33b24c25c3bf5b434ae..b51b5850086d87266606bbf6eb974aa653222334 100644
--- a/Tests/UnitTests/Core/Sample/CrystalTest.cpp
+++ b/Tests/UnitTests/Core/Sample/CrystalTest.cpp
@@ -1,4 +1,5 @@
 #include "Sample/Particle/Crystal.h"
+#include "Sample/Lattice/BakeLattice.h"
 #include "Sample/Particle/ParticleComposition.h"
 #include "Tests/GTestWrapper/google_test.h"
 
@@ -8,7 +9,7 @@ class CrystalTest : public ::testing::Test
 
 TEST_F(CrystalTest, getChildren)
 {
-    Lattice lattice = Lattice::createHexagonalLattice(1.0, 2.0);
+    Lattice3D lattice = bake::createHexagonalLattice(1.0, 2.0);
     ParticleComposition composition;
     Crystal crystal(composition, lattice);
 
diff --git a/Tests/UnitTests/Core/Sample/FormFactorBasicTest.cpp b/Tests/UnitTests/Core/Sample/FormFactorBasicTest.cpp
index d2dd1717fb3d96e700654cd1a7dd630dd8a43fef..a08450859dc917f3ba424e79890754d0c6395e23 100644
--- a/Tests/UnitTests/Core/Sample/FormFactorBasicTest.cpp
+++ b/Tests/UnitTests/Core/Sample/FormFactorBasicTest.cpp
@@ -119,11 +119,11 @@ TEST_F(FormFactorBasicTest, Box)
     EXPECT_EQ(0., particle.bottomZ(RotationZ(.42)));
     EXPECT_EQ(height, particle.topZ(RotationZ(.42)));
 
-    EXPECT_EQ(0., particle.bottomZ(RotationZ(17 * Units::degree)));
-    EXPECT_EQ(height, particle.topZ(RotationZ(39 * Units::degree)));
+    EXPECT_EQ(0., particle.bottomZ(RotationZ(17 * Units::deg)));
+    EXPECT_EQ(height, particle.topZ(RotationZ(39 * Units::deg)));
 
-    EXPECT_NEAR(-width / 2, particle.bottomZ(RotationX(90 * Units::degree)), 1e-12);
-    EXPECT_NEAR(-length / 2, particle.bottomZ(RotationY(90 * Units::degree)), 1e-12);
+    EXPECT_NEAR(-width / 2, particle.bottomZ(RotationX(90 * Units::deg)), 1e-12);
+    EXPECT_NEAR(-length / 2, particle.bottomZ(RotationY(90 * Units::deg)), 1e-12);
 
     test_ff(&particle);
 }
@@ -208,18 +208,18 @@ TEST_F(FormFactorBasicTest, Cylinder)
     EXPECT_EQ(0., particle.bottomZ(RotationZ(.42)));
     EXPECT_EQ(height, particle.topZ(RotationZ(.42)));
 
-    EXPECT_NEAR(-radius, particle.bottomZ(RotationX(90 * Units::degree)), 1e-13);
-    EXPECT_NEAR(+radius, particle.topZ(RotationX(90 * Units::degree)), 1e-13);
-    EXPECT_NEAR(-radius, particle.bottomZ(RotationY(90 * Units::degree)), 1e-13);
-    EXPECT_NEAR(+radius, particle.topZ(RotationY(90 * Units::degree)), 1e-13);
+    EXPECT_NEAR(-radius, particle.bottomZ(RotationX(90 * Units::deg)), 1e-13);
+    EXPECT_NEAR(+radius, particle.topZ(RotationX(90 * Units::deg)), 1e-13);
+    EXPECT_NEAR(-radius, particle.bottomZ(RotationY(90 * Units::deg)), 1e-13);
+    EXPECT_NEAR(+radius, particle.topZ(RotationY(90 * Units::deg)), 1e-13);
 
-    EXPECT_NEAR(-height, particle.bottomZ(RotationY(180 * Units::degree)), 1e-13);
-    EXPECT_NEAR(0, particle.topZ(RotationY(180 * Units::degree)), 1e-13);
+    EXPECT_NEAR(-height, particle.bottomZ(RotationY(180 * Units::deg)), 1e-13);
+    EXPECT_NEAR(0, particle.topZ(RotationY(180 * Units::deg)), 1e-13);
 
     for (double gamma : {1.123, -2.34, 7.5, -9.})
         // 7.5deg is worst case for 24-vertex circle
         EXPECT_NEAR(-radius,
-                    particle.bottomZ(RotationEuler(0, 90 * Units::degree, gamma * Units::degree)),
+                    particle.bottomZ(RotationEuler(0, 90 * Units::deg, gamma * Units::deg)),
                     3e-2); // TODO decrease epsilon after replacement of vertex-based approximation
 
     test_ff(&particle);
diff --git a/Tests/UnitTests/Core/Sample/LatticeTest.cpp b/Tests/UnitTests/Core/Sample/LatticeTest.cpp
index 4ffd2473a22787d7ca4a5fb63a304ad6efa0fe13..b381662e7c16c27772747cd70337bc31ee183245 100644
--- a/Tests/UnitTests/Core/Sample/LatticeTest.cpp
+++ b/Tests/UnitTests/Core/Sample/LatticeTest.cpp
@@ -1,6 +1,7 @@
-#include "Sample/Lattice/Lattice.h"
 #include "Base/Const/MathConstants.h"
 #include "Base/Vector/Transform3D.h"
+#include "Sample/Lattice/BakeLattice.h"
+#include "Sample/Lattice/Lattice3D.h"
 #include "Tests/GTestWrapper/google_test.h"
 
 class LatticeTest : public ::testing::Test
@@ -12,24 +13,24 @@ TEST_F(LatticeTest, declarationTest)
 {
     kvector_t a1(1, 0, 0), a2(0, 1, 0), a3(0, 0, 1);
 
-    Lattice l1(a1, a2, a3);
+    Lattice3D l1(a1, a2, a3);
     EXPECT_EQ(a1, l1.getBasisVectorA());
     EXPECT_EQ(a2, l1.getBasisVectorB());
     EXPECT_EQ(a3, l1.getBasisVectorC());
 
-    Lattice l2(l1);
+    Lattice3D l2(l1);
     EXPECT_EQ(a1, l2.getBasisVectorA());
     EXPECT_EQ(a2, l2.getBasisVectorB());
     EXPECT_EQ(a3, l2.getBasisVectorC());
 
     // calls and tests copy constructor
-    Lattice l3 = {l2};
+    Lattice3D l3 = {l2};
     EXPECT_EQ(a1, l3.getBasisVectorA());
     EXPECT_EQ(a2, l3.getBasisVectorB());
     EXPECT_EQ(a3, l3.getBasisVectorC());
 
     // calls and tests copy constructor
-    Lattice l4 = l3;
+    Lattice3D l4 = l3;
     EXPECT_EQ(a1, l4.getBasisVectorA());
     EXPECT_EQ(a2, l4.getBasisVectorB());
     EXPECT_EQ(a3, l4.getBasisVectorC());
@@ -40,15 +41,15 @@ TEST_F(LatticeTest, volumeTest)
 {
     kvector_t a1(4, 0, 0), a2(0, 2.1, 0), a3(0, 0, 1);
 
-    Lattice l1(a1, a2, a3);
-    EXPECT_EQ(8.4, l1.volume()); // 8.4 is the expected volume for the given lattice vectors
+    Lattice3D l1(a1, a2, a3);
+    EXPECT_EQ(8.4, l1.unitCellVolume()); // 8.4 is the expected volume for the given lattice vectors
 }
 
 // tests whether reciprocal lattice basis vectors have been initialized or not
 TEST_F(LatticeTest, reciprocalTest)
 {
     kvector_t a1(1, 0, 0), a2(0, 1, 0), a3(0, 0, 1);
-    Lattice l1(a1, a2, a3);
+    Lattice3D l1(a1, a2, a3);
 
     kvector_t b1, b2, b3, m_ra, m_rb, m_rc;
 
@@ -71,11 +72,11 @@ TEST_F(LatticeTest, reciprocalTest)
 TEST_F(LatticeTest, transformTest)
 {
     kvector_t a1(1, 0, 0), a2(0, 1, 0), a3(0, 0, 1);
-    Lattice l1(a1, a2, a3);
+    Lattice3D l1(a1, a2, a3);
 
     // use rotation by 90 degrees around z axis as a transformation
     Transform3D tr = Transform3D::createRotateZ(M_TWOPI / 4);
-    Lattice ltr = l1.transformed(tr);
+    Lattice3D ltr = l1.transformed(tr);
 
     // use EXPECT_NEAR as transform (matrix multiplication) uses double value for rotation angle
     // e.g. Rotating the vector (1,0,0) by 2*PI about z would give something like (0.99999,0,0)
@@ -88,28 +89,11 @@ TEST_F(LatticeTest, transformTest)
     EXPECT_EQ(a3, ltr.getBasisVectorC());
 }
 
-// REAL = real/physical
-// tests the nearest REAL LATTICE point to a given REAL SPACE vector
-TEST_F(LatticeTest, NearestRealLatticeVectorCoordinatesTest)
-{
-    kvector_t a1(1, 0, 0), a2(0, 1, 0), a3(0, 0, 1);
-    Lattice l1(a1, a2, a3);
-
-    // vector_in is in REAL SPACE coordinates
-    kvector_t vector_in(3.01, 1.51, 1.49);
-
-    // point_expected is in REAL LATTICE coordinates
-    ivector_t point_expected(3, 2, 1);
-
-    EXPECT_EQ(point_expected, l1.getNearestLatticeVectorCoordinates(vector_in));
-}
-
-// REC. = reciprocal
 // tests the nearest REC. LATTICE point to a given REC. SPACE vector
 TEST_F(LatticeTest, NearestReciprocalLatticeVectorCoordinatesTest)
 {
     kvector_t a1(1, 0, 0), a2(0, 1, 0), a3(0, 0, 1);
-    Lattice l1(a1, a2, a3);
+    Lattice3D l1(a1, a2, a3);
 
     // vector_in is in REC. SPACE coordinates
     kvector_t vector_in(2.8 * M_TWOPI, 0, 0);
@@ -125,7 +109,7 @@ TEST_F(LatticeTest, NearestReciprocalLatticeVectorCoordinatesTest)
 TEST_F(LatticeTest, reciprocalLatticeVectorsWithinRadiusTest)
 {
     kvector_t a1(1, 0, 0), a2(0, 1, 0), a3(0, 0, 1);
-    Lattice l1(a1, a2, a3);
+    Lattice3D l1(a1, a2, a3);
 
     kvector_t b1, b2, b3;
     l1.getReciprocalLatticeBasis(b1, b2, b3);
@@ -150,7 +134,7 @@ TEST_F(LatticeTest, reciprocalLatticeVectorsWithinRadiusTest)
 TEST_F(LatticeTest, FCCLatticeTest)
 {
     // creates FCC lattice onto a new Lattice instance l1
-    Lattice l1 = Lattice::createFCCLattice(1);
+    Lattice3D l1 = bake::createFCCLattice(1);
 
     kvector_t fcc1(0, 0.5, 0.5), fcc2(0.5, 0, 0.5), fcc3(0.5, 0.5, 0);
 
@@ -162,7 +146,7 @@ TEST_F(LatticeTest, FCCLatticeTest)
 // tests hexagonal lattice creation
 TEST_F(LatticeTest, HexagonalLatticeTest)
 {
-    Lattice l1 = Lattice::createHexagonalLattice(1, 4);
+    Lattice3D l1 = bake::createHexagonalLattice(1, 4);
 
     kvector_t tri1(1, 0.0, 0.0);
     kvector_t tri2(-1 / 2.0, std::sqrt(3.0) * 1 / 2.0, 0);
@@ -178,7 +162,7 @@ TEST_F(LatticeTest, HexagonalLatticeTest)
 TEST_F(LatticeTest, onChangeTest)
 {
     kvector_t a1(1, 0, 0), a2(0, 1, 0), a3(0, 0, 1);
-    Lattice l1(a1, a2, a3);
+    Lattice3D l1(a1, a2, a3);
 
     kvector_t b1, b2, b3, m_ra, m_rb, m_rc;
 
diff --git a/Tests/UnitTests/Core/Sample/LatticeUtilsTest.cpp b/Tests/UnitTests/Core/Sample/LatticeUtilsTest.cpp
deleted file mode 100644
index 74c4510f8a35d791e574578aeffebcbfc3ff7500..0000000000000000000000000000000000000000
--- a/Tests/UnitTests/Core/Sample/LatticeUtilsTest.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-#include "Sample/Lattice/LatticeUtils.h"
-#include "Sample/Lattice/ILatticeOrientation.h"
-#include "Tests/GTestWrapper/google_test.h"
-
-class LatticeUtilsTest : public ::testing::Test
-{
-};
-
-// tests the creation of an FCC lattice with the primitive cube aligned along the q-axes
-TEST_F(LatticeUtilsTest, cubeAlignedFCCTest)
-{
-    MillerIndexOrientation q_aligned(MillerIndexOrientation::QZ, {0, 0, 1},
-                                     MillerIndexOrientation::QY, {0, 1, 0});
-    auto lattice = LatticeUtils::createFCCLattice(2.0, q_aligned);
-    auto a1 = lattice.getBasisVectorA();
-    auto a2 = lattice.getBasisVectorB();
-    auto a3 = lattice.getBasisVectorC();
-
-    kvector_t v1{0.0, 1.0, 1.0};
-    kvector_t v2{1.0, 0.0, 1.0};
-    kvector_t v3{1.0, 1.0, 0.0};
-
-    EXPECT_EQ(a1, v1);
-    EXPECT_EQ(a2, v2);
-    EXPECT_EQ(a3, v3);
-}
-
-// tests the creation of an FCC lattice with the primitive cube aligned along Miller indices
-TEST_F(LatticeUtilsTest, diagonalAlignedFCCTest)
-{
-    MillerIndexOrientation diagonal_aligned(MillerIndexOrientation::QZ, {1, 1, 1},
-                                            MillerIndexOrientation::QX, {1, 1, 0});
-    auto lattice = LatticeUtils::createFCCLattice(2.0, diagonal_aligned);
-    auto a1 = lattice.getBasisVectorA();
-    auto a2 = lattice.getBasisVectorB();
-    auto a3 = lattice.getBasisVectorC();
-
-    EXPECT_NEAR(a1.z(), a2.z(), 1e-10);
-    EXPECT_NEAR(a2.z(), a3.z(), 1e-10);
-    EXPECT_NEAR(a1.x(), a2.x(), 1e-10);
-    EXPECT_NEAR(a1.y(), -a2.y(), 1e-10);
-}
-
-// tests the creation of an HCP lattice with a trivial orientation
-TEST_F(LatticeUtilsTest, trivialAlignedHCPTest)
-{
-    MillerIndexOrientation trivial_aligned(MillerIndexOrientation::QZ, {0, 0, 1},
-                                           MillerIndexOrientation::QX, {2, -1, 0});
-    auto lattice = LatticeUtils::createHCPLattice(2.0, 4.0, trivial_aligned);
-    auto a1 = lattice.getBasisVectorA();
-    auto a2 = lattice.getBasisVectorB();
-    auto a3 = lattice.getBasisVectorC();
-
-    kvector_t v1{2.0, 0.0, 0.0};
-    kvector_t v2{-1.0, std::sqrt(3.0), 0.0};
-    kvector_t v3{1.0, 1.0 / std::sqrt(3.0), 2.0};
-
-    EXPECT_EQ(a1, v1);
-    EXPECT_EQ(a2, v2);
-    EXPECT_EQ(a3, v3);
-}
-
-// tests the creation of an BCT lattice with the primitive tetragonal aligned along the q-axes
-TEST_F(LatticeUtilsTest, tetraAlignedFCCTest)
-{
-    MillerIndexOrientation q_aligned(MillerIndexOrientation::QZ, {0, 0, 1},
-                                     MillerIndexOrientation::QY, {0, 1, 0});
-    auto lattice = LatticeUtils::createBCTLattice(2.0, 2.0, q_aligned);
-    auto a1 = lattice.getBasisVectorA();
-    auto a2 = lattice.getBasisVectorB();
-    auto a3 = lattice.getBasisVectorC();
-
-    kvector_t v1{2.0, 0.0, 0.0};
-    kvector_t v2{0.0, 2.0, 0.0};
-    kvector_t v3{1.0, 1.0, 1.0};
-
-    EXPECT_EQ(a1, v1);
-    EXPECT_EQ(a2, v2);
-    EXPECT_EQ(a3, v3);
-}
-
-// tests the creation of an BCT lattice with the primitive tetragonal aligned along Miller indices
-TEST_F(LatticeUtilsTest, diagonalAlignedBCTTest)
-{
-    MillerIndexOrientation diagonal_aligned(MillerIndexOrientation::QZ, {1, 1, 1},
-                                            MillerIndexOrientation::QX, {1, 1, 0});
-    auto lattice = LatticeUtils::createBCTLattice(2.0, 2.0, diagonal_aligned);
-    auto a1 = lattice.getBasisVectorA();
-    auto a2 = lattice.getBasisVectorB();
-    auto a3 = lattice.getBasisVectorC();
-
-    EXPECT_NEAR(a1.z(), a2.z(), 1e-10);
-    EXPECT_NEAR(a1.x(), a2.x(), 1e-10);
-    EXPECT_NEAR(a1.y(), -a2.y(), 1e-10);
-    EXPECT_NEAR(a3.x(), 0.0, 1e-10);
-    EXPECT_NEAR(a3.y(), 0.0, 1e-10);
-    EXPECT_NEAR(a3.z(), std::sqrt(3.0), 1e-10);
-}
diff --git a/Tests/UnitTests/Core/Sample/LayerTest.cpp b/Tests/UnitTests/Core/Sample/LayerTest.cpp
index 3c56525536897d6d182e849749292bb083ff9e63..fec9a13b3ee69cc7ca6e2fe8a3a3d75d3267781e 100644
--- a/Tests/UnitTests/Core/Sample/LayerTest.cpp
+++ b/Tests/UnitTests/Core/Sample/LayerTest.cpp
@@ -11,7 +11,7 @@ class LayerTest : public ::testing::Test
 TEST_F(LayerTest, LayerGetAndSet)
 {
     Material vacuum = HomogeneousMaterial("Vacuum", 0, 0);
-    Layer layer(vacuum, 10 * Units::nanometer);
+    Layer layer(vacuum, 10 * Units::nm);
     EXPECT_EQ(vacuum, *layer.material());
     EXPECT_EQ(0u, layer.layouts().size());
     EXPECT_EQ(10, layer.thickness());
@@ -33,7 +33,7 @@ TEST_F(LayerTest, LayerAndDecoration)
     Material vacuum = HomogeneousMaterial("Vacuum", 0, 0);
     std::unique_ptr<ParticleLayout> layout1(new ParticleLayout());
 
-    Layer layer(vacuum, 10 * Units::nanometer);
+    Layer layer(vacuum, 10 * Units::nm);
     layer.addLayout(*layout1);
     EXPECT_EQ(layer.numberOfLayouts(), 1u);
 
diff --git a/Tests/UnitTests/Core/Sample/MesoCrystalTest.cpp b/Tests/UnitTests/Core/Sample/MesoCrystalTest.cpp
index 9b7489fd79ce9313d690bc73ef617c225fe72284..3b9b73e6329a8a7af06a7a1c96068bf99ed08894 100644
--- a/Tests/UnitTests/Core/Sample/MesoCrystalTest.cpp
+++ b/Tests/UnitTests/Core/Sample/MesoCrystalTest.cpp
@@ -1,5 +1,6 @@
 #include "Sample/Particle/MesoCrystal.h"
 #include "Sample/HardParticle/FormFactorFullSphere.h"
+#include "Sample/Lattice/BakeLattice.h"
 #include "Sample/Particle/Crystal.h"
 #include "Sample/Particle/ParticleComposition.h"
 #include "Sample/Scattering/Rotations.h"
@@ -11,7 +12,7 @@ class MesoCrystalTest : public ::testing::Test
 
 TEST_F(MesoCrystalTest, getChildren)
 {
-    Lattice lattice = Lattice::createHexagonalLattice(1.0, 2.0);
+    Lattice3D lattice = bake::createHexagonalLattice(1.0, 2.0);
     ParticleComposition composition;
     Crystal crystal(composition, lattice);
     MesoCrystal meso(crystal, FormFactorFullSphere(1.0));
diff --git a/Tests/UnitTests/Core/Sample/MultiLayerTest.cpp b/Tests/UnitTests/Core/Sample/MultiLayerTest.cpp
index f8459d2e2d16f1b4fadd899890269473f4ee1275..05c71649a231cd9a70fff94cebcba3d7d38e2767 100644
--- a/Tests/UnitTests/Core/Sample/MultiLayerTest.cpp
+++ b/Tests/UnitTests/Core/Sample/MultiLayerTest.cpp
@@ -22,10 +22,10 @@ protected:
         , iron(HomogeneousMaterial("iron", 2e-5, 8e-5))
         , chromium(HomogeneousMaterial("chromium", 3e-7, 7e-6))
         , stone(HomogeneousMaterial("stone", 4e-4, 8e-7))
-        , topLayer(air, 0 * Units::nanometer)
-        , layer1(iron, 20 * Units::nanometer)
-        , layer2(chromium, 40 * Units::nanometer)
-        , substrate(stone, 0 * Units::nanometer)
+        , topLayer(air, 0 * Units::nm)
+        , layer1(iron, 20 * Units::nm)
+        , layer2(chromium, 40 * Units::nm)
+        , substrate(stone, 0 * Units::nm)
     {
     }
     void set_four()
@@ -246,10 +246,10 @@ TEST_F(MultiLayerTest, MultiLayerCompositeTest)
     Material magMaterial0 = HomogeneousMaterial("MagMat0", 6e-4, 2e-8, magnetic_field);
     Material magMaterial1 = HomogeneousMaterial("MagMat1", -5.6, 10, magnetic_field);
 
-    Layer layer1(iron, 10 * Units::nanometer);
-    Layer layer2(magMaterial0, 20 * Units::nanometer);
-    Layer layer3(magMaterial1, 30 * Units::nanometer);
-    Layer layer4(stone, 40 * Units::nanometer);
+    Layer layer1(iron, 10 * Units::nm);
+    Layer layer2(magMaterial0, 20 * Units::nm);
+    Layer layer3(magMaterial1, 30 * Units::nm);
+    Layer layer4(stone, 40 * Units::nm);
 
     mLayer.addLayer(topLayer);
     mLayer.addLayer(layer1);
diff --git a/Tests/UnitTests/Core/Sample/ParticleCoreShellTest.cpp b/Tests/UnitTests/Core/Sample/ParticleCoreShellTest.cpp
index e58d4be7aeaf26de7d63d90b49e23c8d32a34908..f337fa2782de15a84c50fe4e184e81583ea0d9ab 100644
--- a/Tests/UnitTests/Core/Sample/ParticleCoreShellTest.cpp
+++ b/Tests/UnitTests/Core/Sample/ParticleCoreShellTest.cpp
@@ -58,7 +58,7 @@ TEST_F(ParticleCoreShellTest, ComplexCoreShellClone)
     Particle shell(mShell, FormFactorBox(shell_length, shell_width, shell_height));
     kvector_t relative_pos(0, 0, (shell_height - core_height) / 2);
     ParticleCoreShell coreshell(shell, core, relative_pos);
-    coreshell.setRotation(RotationY(90 * Units::degree));
+    coreshell.setRotation(RotationY(90 * Units::deg));
     coreshell.setPosition(kvector_t(0, 0, -10));
 
     ParticleCoreShell* clone = coreshell.clone();
diff --git a/Tests/UnitTests/Core/Sample/ParticleLayoutTest.cpp b/Tests/UnitTests/Core/Sample/ParticleLayoutTest.cpp
index 100bdefa61cf695beaf6a5dd4d90ae96842fe5e9..3206b310b5ad30f1e5a200cc8a1d873ac7a7dddb 100644
--- a/Tests/UnitTests/Core/Sample/ParticleLayoutTest.cpp
+++ b/Tests/UnitTests/Core/Sample/ParticleLayoutTest.cpp
@@ -49,8 +49,8 @@ TEST_F(ParticleLayoutTest, ParticleLayoutAddParticle)
     Particle particle3;
     Particle particle4;
 
-    RotationZ transform3(45. * Units::degree);
-    RotationZ transform4(45. * Units::degree);
+    RotationZ transform3(45. * Units::deg);
+    RotationZ transform4(45. * Units::deg);
 
     particleDecoration.addParticle(particle1);
     particleDecoration.addParticle(particle2, 2.2);
@@ -86,8 +86,8 @@ TEST_F(ParticleLayoutTest, ParticleLayoutAbundanceFraction)
     Particle particle3;
     Particle particle4;
 
-    RotationY transform3(45. * Units::degree);
-    RotationZ transform4(45. * Units::degree);
+    RotationY transform3(45. * Units::deg);
+    RotationZ transform4(45. * Units::deg);
 
     particleDecoration.addParticle(particle1);
     particleDecoration.addParticle(particle2, 2.0);
@@ -105,8 +105,8 @@ TEST_F(ParticleLayoutTest, ParticleLayoutClone)
     Particle particle3;
     Particle particle4;
 
-    RotationY transform3(45. * Units::degree);
-    RotationZ transform4(45. * Units::degree);
+    RotationY transform3(45. * Units::deg);
+    RotationZ transform4(45. * Units::deg);
 
     particleDecoration.addParticle(particle1);
     particleDecoration.addParticle(particle2, 2.0);
diff --git a/Tests/UnitTests/Core/Sample/ParticleTest.cpp b/Tests/UnitTests/Core/Sample/ParticleTest.cpp
index 29ae90dec891888667e0d4f782aaf3f80d3218ba..d64eaff8eca020b48b198037b6f90279ad5004fa 100644
--- a/Tests/UnitTests/Core/Sample/ParticleTest.cpp
+++ b/Tests/UnitTests/Core/Sample/ParticleTest.cpp
@@ -30,7 +30,7 @@ TEST_F(ParticleTest, Constructors)
 {
     Material mat = HomogeneousMaterial("Vacuum", 0, 0);
     FormFactorFullSphere sphere(1.0);
-    RotationZ transform(45. * Units::degree);
+    RotationZ transform(45. * Units::deg);
 
     // construction with material
     std::unique_ptr<Particle> p1(new Particle(mat));
@@ -54,7 +54,7 @@ TEST_F(ParticleTest, setters)
 {
     Material mat = HomogeneousMaterial("Vacuum", 0, 0);
     FormFactorFullSphere sphere(2.1);
-    RotationY transform(45. * Units::degree);
+    RotationY transform(45. * Units::deg);
 
     Particle particle;
     Material vacuum = HomogeneousMaterial();
diff --git a/Tests/UnitTests/GUI/TestGUICoreObjectCorrespondence.cpp b/Tests/UnitTests/GUI/TestGUICoreObjectCorrespondence.cpp
index 3c4e4d46e5ccfc21c7662a6bde84487860e0e260..cbccf1f51b80183081de02164f0a934b6536e40c 100644
--- a/Tests/UnitTests/GUI/TestGUICoreObjectCorrespondence.cpp
+++ b/Tests/UnitTests/GUI/TestGUICoreObjectCorrespondence.cpp
@@ -26,7 +26,7 @@ public:
 TEST_F(TestGUICoreObjectCorrespondence, test_AnisoPyramid)
 {
     AnisoPyramidItem gui_anisopyramid;
-    FormFactorAnisoPyramid core_anisopyramid(1.0, 2.0, 0.1, 45.0 * Units::degree);
+    FormFactorAnisoPyramid core_anisopyramid(1.0, 2.0, 0.1, 45.0 * Units::deg);
     GUICoreObjectCorrespondence(gui_anisopyramid, core_anisopyramid);
 }
 
@@ -40,21 +40,21 @@ TEST_F(TestGUICoreObjectCorrespondence, test_Box)
 TEST_F(TestGUICoreObjectCorrespondence, test_Cone)
 {
     ConeItem gui_cone;
-    FormFactorCone core_cone(1.0, 0.2, 45.0 * Units::degree);
+    FormFactorCone core_cone(1.0, 0.2, 45.0 * Units::deg);
     GUICoreObjectCorrespondence(gui_cone, core_cone);
 }
 
 TEST_F(TestGUICoreObjectCorrespondence, test_Cone6)
 {
     Cone6Item gui_cone6;
-    FormFactorCone6 core_cone6(1.0, 0.2, 45.0 * Units::degree);
+    FormFactorCone6 core_cone6(1.0, 0.2, 45.0 * Units::deg);
     GUICoreObjectCorrespondence(gui_cone6, core_cone6);
 }
 
 TEST_F(TestGUICoreObjectCorrespondence, test_Cuboctahedron)
 {
     CuboctahedronItem gui_cuboctahedron;
-    FormFactorCuboctahedron core_cuboctahedron(1.0, 0.4, 1.0, 45.0 * Units::degree);
+    FormFactorCuboctahedron core_cuboctahedron(1.0, 0.4, 1.0, 45.0 * Units::deg);
     GUICoreObjectCorrespondence(gui_cuboctahedron, core_cuboctahedron);
 }
 
@@ -131,7 +131,7 @@ TEST_F(TestGUICoreObjectCorrespondence, test_Prism6)
 TEST_F(TestGUICoreObjectCorrespondence, test_Pyramid)
 {
     PyramidItem gui_pyramid;
-    FormFactorPyramid core_pyramid(1.0, 0.2, 45.0 * Units::degree);
+    FormFactorPyramid core_pyramid(1.0, 0.2, 45.0 * Units::deg);
     GUICoreObjectCorrespondence(gui_pyramid, core_pyramid);
 }
 
@@ -152,7 +152,7 @@ TEST_F(TestGUICoreObjectCorrespondence, test_SawtoothRippleBox)
 TEST_F(TestGUICoreObjectCorrespondence, test_Tetrahedron)
 {
     TetrahedronItem gui_tetrahedron;
-    FormFactorTetrahedron core_tetrahedron(1.0, 0.1, 45.0 * Units::degree);
+    FormFactorTetrahedron core_tetrahedron(1.0, 0.1, 45.0 * Units::deg);
     GUICoreObjectCorrespondence(gui_tetrahedron, core_tetrahedron);
 }
 
diff --git a/Wrap/swig/libBornAgainSample.i b/Wrap/swig/libBornAgainSample.i
index e78c1ad828040ad7d1818d3ef9c849f08ba6154b..e60916f093b26e4a6e0bbe1626cc5f272acef5d5 100644
--- a/Wrap/swig/libBornAgainSample.i
+++ b/Wrap/swig/libBornAgainSample.i
@@ -54,7 +54,6 @@
 #include "Sample/Correlations/FTDecay2D.h"
 #include "Sample/Correlations/FTDistributions1D.h"
 #include "Sample/Correlations/FTDistributions2D.h"
-#include "Sample/Correlations/ILayout.h"
 #include "Sample/Correlations/IPeakShape.h"
 #include "Sample/HardParticle/FormFactorAnisoPyramid.h"
 #include "Sample/HardParticle/FormFactorBar.h"
@@ -85,11 +84,10 @@
 #include "Sample/HardParticle/FormFactorTruncatedSpheroid.h"
 #include "Sample/HardParticle/IFormFactorPolyhedron.h"
 #include "Sample/HardParticle/IFormFactorPrism.h"
-#include "Sample/Lattice/ILatticeOrientation.h"
 #include "Sample/Lattice/ISelectionRule.h"
-#include "Sample/Lattice/Lattice.h"
+#include "Sample/Lattice/Lattice3D.h"
 #include "Sample/Lattice/Lattice2D.h"
-#include "Sample/Lattice/LatticeUtils.h"
+#include "Sample/Lattice/BakeLattice.h"
 #include "Sample/Material/MaterialFactoryFuncs.h"
 #include "Sample/Material/WavevectorInfo.h"
 #include "Sample/Multilayer/Layer.h"
@@ -100,7 +98,6 @@
 #include "Sample/Particle/FormFactorCrystal.h"
 #include "Sample/Particle/FormFactorWeighted.h"
 #include "Sample/Particle/IAbstractParticle.h"
-#include "Sample/Particle/IClusteredParticles.h"
 #include "Sample/Particle/IParticle.h"
 #include "Sample/Particle/MesoCrystal.h"
 #include "Sample/Particle/Particle.h"
@@ -162,7 +159,6 @@
 %include "Sample/Particle/FormFactorCrystal.h"
 %include "Sample/Particle/FormFactorWeighted.h"
 %include "Sample/Particle/IAbstractParticle.h"
-%include "Sample/Particle/IClusteredParticles.h"
 %include "Sample/Particle/Crystal.h"
 %include "Sample/Particle/IParticle.h"
 %include "Sample/Particle/MesoCrystal.h"
@@ -177,7 +173,6 @@
 %include "Sample/Correlations/FTDistributions2D.h"
 %include "Sample/Correlations/FTDecay1D.h"
 %include "Sample/Correlations/FTDecay2D.h"
-%include "Sample/Correlations/ILayout.h"
 %include "Sample/Correlations/IPeakShape.h"
 
 %include "Sample/Aggregate/IInterferenceFunction.h"
@@ -237,11 +232,10 @@
 %include "Sample/SoftParticle/FormFactorSphereGaussianRadius.h"
 %include "Sample/SoftParticle/FormFactorSphereLogNormalRadius.h"
 
-%include "Sample/Lattice/ILatticeOrientation.h"
 %include "Sample/Lattice/ISelectionRule.h"
-%include "Sample/Lattice/Lattice.h"
+%include "Sample/Lattice/Lattice3D.h"
 %include "Sample/Lattice/Lattice2D.h"
-%include "Sample/Lattice/LatticeUtils.h"
+%include "Sample/Lattice/BakeLattice.h"
 
 %include "Sample/SampleBuilderEngine/ISampleBuilder.h"
 %include "Sample/StandardSamples/SampleBuilderFactory.h"
diff --git a/auto/Wrap/doxygenCore.i b/auto/Wrap/doxygenCore.i
index 7cf03ffa4ef5958b3ad0b3d8e94d6503f994aabb..9da439c9a8fe4f88549f41a0e770214ef49840c7 100644
--- a/auto/Wrap/doxygenCore.i
+++ b/auto/Wrap/doxygenCore.i
@@ -1555,7 +1555,7 @@ If particles in the layout crossed the limits of the layer slices, these particl
 C++ includes: ProcessedLayout.h
 ";
 
-%feature("docstring")  ProcessedLayout::ProcessedLayout "ProcessedLayout::ProcessedLayout(const ILayout &layout, const std::vector< Slice > &slices, double z_ref, const IFresnelMap *p_fresnel_map, bool polarized)
+%feature("docstring")  ProcessedLayout::ProcessedLayout "ProcessedLayout::ProcessedLayout(const ParticleLayout &layout, const std::vector< Slice > &slices, double z_ref, const IFresnelMap *p_fresnel_map, bool polarized)
 ";
 
 %feature("docstring")  ProcessedLayout::ProcessedLayout "ProcessedLayout::ProcessedLayout(ProcessedLayout &&other)
@@ -1955,7 +1955,10 @@ C++ includes: SampleLabelHandler.h
 %feature("docstring")  SampleLabelHandler::materialMap "materials_t* SampleLabelHandler::materialMap()
 ";
 
-%feature("docstring")  SampleLabelHandler::latticeMap "lattices_t* SampleLabelHandler::latticeMap()
+%feature("docstring")  SampleLabelHandler::lattice2DMap "lattices2D_t* SampleLabelHandler::lattice2DMap()
+";
+
+%feature("docstring")  SampleLabelHandler::lattice3DMap "lattices3D_t* SampleLabelHandler::lattice3DMap()
 ";
 
 %feature("docstring")  SampleLabelHandler::mesocrystalMap "mesocrystals_t* SampleLabelHandler::mesocrystalMap()
@@ -1994,13 +1997,16 @@ C++ includes: SampleLabelHandler.h
 %feature("docstring")  SampleLabelHandler::labelLayer "std::string SampleLabelHandler::labelLayer(const Layer *sample)
 ";
 
-%feature("docstring")  SampleLabelHandler::labelLayout "std::string SampleLabelHandler::labelLayout(const ILayout *sample)
+%feature("docstring")  SampleLabelHandler::labelLayout "std::string SampleLabelHandler::labelLayout(const ParticleLayout *sample)
 ";
 
 %feature("docstring")  SampleLabelHandler::labelMaterial "std::string SampleLabelHandler::labelMaterial(const Material *sample)
 ";
 
-%feature("docstring")  SampleLabelHandler::labelLattice "std::string SampleLabelHandler::labelLattice(const Lattice *sample)
+%feature("docstring")  SampleLabelHandler::labelLattice2D "std::string SampleLabelHandler::labelLattice2D(const Lattice2D *sample)
+";
+
+%feature("docstring")  SampleLabelHandler::labelLattice3D "std::string SampleLabelHandler::labelLattice3D(const Lattice3D *sample)
 ";
 
 %feature("docstring")  SampleLabelHandler::labelMultiLayer "std::string SampleLabelHandler::labelMultiLayer(const MultiLayer *sample)
@@ -2027,13 +2033,16 @@ C++ includes: SampleLabelHandler.h
 %feature("docstring")  SampleLabelHandler::insertLayer "void SampleLabelHandler::insertLayer(const Layer *sample)
 ";
 
-%feature("docstring")  SampleLabelHandler::insertLayout "void SampleLabelHandler::insertLayout(const ILayout *sample)
+%feature("docstring")  SampleLabelHandler::insertLayout "void SampleLabelHandler::insertLayout(const ParticleLayout *sample)
 ";
 
 %feature("docstring")  SampleLabelHandler::insertMaterial "void SampleLabelHandler::insertMaterial(const Material *sample)
 ";
 
-%feature("docstring")  SampleLabelHandler::insertLattice "void SampleLabelHandler::insertLattice(const Lattice *sample)
+%feature("docstring")  SampleLabelHandler::insertLattice2D "void SampleLabelHandler::insertLattice2D(const Lattice2D *sample)
+";
+
+%feature("docstring")  SampleLabelHandler::insertLattice3D "void SampleLabelHandler::insertLattice3D(const Lattice3D *sample)
 ";
 
 %feature("docstring")  SampleLabelHandler::insertMesoCrystal "void SampleLabelHandler::insertMesoCrystal(const MesoCrystal *sample)
diff --git a/auto/Wrap/doxygenParam.i b/auto/Wrap/doxygenParam.i
index 5c19b79f85deca3bf342f56ab56a989e59404719..1ec208aa17de078ba0de5f7e11c2b65bda4f258b 100644
--- a/auto/Wrap/doxygenParam.i
+++ b/auto/Wrap/doxygenParam.i
@@ -733,7 +733,7 @@ C++ includes: INodeVisitor.h
 %feature("docstring")  INodeVisitor::visit "virtual void INodeVisitor::visit(const IInterferenceFunction *)
 ";
 
-%feature("docstring")  INodeVisitor::visit "virtual void INodeVisitor::visit(const ILayout *)
+%feature("docstring")  INodeVisitor::visit "virtual void INodeVisitor::visit(const ParticleLayout *)
 ";
 
 %feature("docstring")  INodeVisitor::visit "virtual void INodeVisitor::visit(const INode *)
@@ -820,9 +820,6 @@ C++ includes: INodeVisitor.h
 %feature("docstring")  INodeVisitor::visit "virtual void INodeVisitor::visit(const ParticleDistribution *)
 ";
 
-%feature("docstring")  INodeVisitor::visit "virtual void INodeVisitor::visit(const ParticleLayout *)
-";
-
 %feature("docstring")  INodeVisitor::visit "virtual void INodeVisitor::visit(const PoissonNoiseBackground *)
 ";
 
diff --git a/auto/Wrap/doxygenSample.i b/auto/Wrap/doxygenSample.i
index bedb5409bc49fa109285d649b9529c9b58781506..02230198739f71a2f7314ef1d951a37698589a29 100644
--- a/auto/Wrap/doxygenSample.i
+++ b/auto/Wrap/doxygenSample.i
@@ -312,12 +312,18 @@ C++ includes: RipplesBuilder.h
 // File: classCrystal.xml
 %feature("docstring") Crystal "
 
-A crystal structure with a  ParticleComposition as a basis. Used in  MesoCrystal, where it is given an outer shape.
+A crystal structure, defined by a Bravais lattice, a basis, and a position variance.
+
+The basis is either a  Particle or a  ParticleComposition.
+
+Computations are delegated to class  FormFactorCrystal.
+
+Used in  MesoCrystal, where it is given an outer shape.
 
 C++ includes: Crystal.h
 ";
 
-%feature("docstring")  Crystal::Crystal "Crystal::Crystal(const IParticle &lattice_basis, const Lattice &lattice)
+%feature("docstring")  Crystal::Crystal "Crystal::Crystal(const IParticle &basis, const Lattice3D &lattice, double position_variance=0)
 ";
 
 %feature("docstring")  Crystal::~Crystal "Crystal::~Crystal()
@@ -331,20 +337,13 @@ Returns a clone of this  ISample object.
 %feature("docstring")  Crystal::accept "void Crystal::accept(INodeVisitor *visitor) const override final
 ";
 
-%feature("docstring")  Crystal::createTotalFormFactor "IFormFactor * Crystal::createTotalFormFactor(const IFormFactor &meso_crystal_form_factor, const IRotation *p_rotation, const kvector_t &translation) const override final
-
-Creates a total form factor for the mesocrystal with a specific shape and content The bulk content of the mesocrystal is encapsulated by the  IClusteredParticles object itself 
-";
-
-%feature("docstring")  Crystal::homogeneousRegions "std::vector< HomogeneousRegion > Crystal::homogeneousRegions() const override final
-
-Creates region information with volumetric densities instead of absolute volume These densities need to be multiplied by the total mesocrystal volume 
+%feature("docstring")  Crystal::createTotalFormFactor "IFormFactor * Crystal::createTotalFormFactor(const IFormFactor &meso_crystal_form_factor, const IRotation *p_rotation, const kvector_t &translation) const
 ";
 
-%feature("docstring")  Crystal::transformedLattice "Lattice Crystal::transformedLattice(const IRotation *p_rotation=nullptr) const
+%feature("docstring")  Crystal::homogeneousRegions "std::vector< HomogeneousRegion > Crystal::homogeneousRegions() const
 ";
 
-%feature("docstring")  Crystal::setPositionVariance "void Crystal::setPositionVariance(double position_variance)
+%feature("docstring")  Crystal::transformedLattice "Lattice3D Crystal::transformedLattice(const IRotation *p_rotation=nullptr) const
 ";
 
 %feature("docstring")  Crystal::getChildren "std::vector< const INode * > Crystal::getChildren() const override final
@@ -1106,7 +1105,7 @@ The form factor of a  MesoCrystal.
 C++ includes: FormFactorCrystal.h
 ";
 
-%feature("docstring")  FormFactorCrystal::FormFactorCrystal "FormFactorCrystal::FormFactorCrystal(const Lattice &lattice, const IFormFactor &basis_form_factor, const IFormFactor &meso_form_factor, double position_variance=0.0)
+%feature("docstring")  FormFactorCrystal::FormFactorCrystal "FormFactorCrystal::FormFactorCrystal(const Lattice3D &lattice, const IFormFactor &basis_form_factor, const IFormFactor &meso_form_factor, double position_variance=0.0)
 ";
 
 %feature("docstring")  FormFactorCrystal::~FormFactorCrystal "FormFactorCrystal::~FormFactorCrystal() override final
@@ -3032,30 +3031,6 @@ Applies the given rotation to the particle.
 ";
 
 
-// File: classIClusteredParticles.xml
-%feature("docstring") IClusteredParticles "
-
-An ordered assembly of particles. Currently, the only child class is  Crystal.
-
-C++ includes: IClusteredParticles.h
-";
-
-%feature("docstring")  IClusteredParticles::clone "IClusteredParticles* IClusteredParticles::clone() const override=0
-
-Returns a clone of this  ISample object. 
-";
-
-%feature("docstring")  IClusteredParticles::createTotalFormFactor "virtual IFormFactor* IClusteredParticles::createTotalFormFactor(const IFormFactor &, const IRotation *, const kvector_t &) const =0
-
-Creates a total form factor for the mesocrystal with a specific shape and content The bulk content of the mesocrystal is encapsulated by the  IClusteredParticles object itself 
-";
-
-%feature("docstring")  IClusteredParticles::homogeneousRegions "virtual std::vector<HomogeneousRegion> IClusteredParticles::homogeneousRegions() const =0
-
-Creates region information with volumetric densities instead of absolute volume These densities need to be multiplied by the total mesocrystal volume 
-";
-
-
 // File: classICosineRipple.xml
 %feature("docstring") ICosineRipple "
 
@@ -3639,27 +3614,6 @@ Calculates the intensity for scalar particles/interactions.
 ";
 
 
-// File: classILatticeOrientation.xml
-%feature("docstring") ILatticeOrientation "
-
-Pure virtual base of classes that specify a lattice orientation. Currently only inherited by  MillerIndexOrientation.
-
-C++ includes: ILatticeOrientation.h
-";
-
-%feature("docstring")  ILatticeOrientation::~ILatticeOrientation "ILatticeOrientation::~ILatticeOrientation()
-";
-
-%feature("docstring")  ILatticeOrientation::clone "virtual ILatticeOrientation* ILatticeOrientation::clone() const =0
-";
-
-%feature("docstring")  ILatticeOrientation::usePrimitiveLattice "virtual void ILatticeOrientation::usePrimitiveLattice(const Lattice &lattice)=0
-";
-
-%feature("docstring")  ILatticeOrientation::transformation "virtual Transform3D ILatticeOrientation::transformation() const =0
-";
-
-
 // File: classILayerRTCoefficients.xml
 %feature("docstring") ILayerRTCoefficients "
 
@@ -3720,64 +3674,6 @@ Scalar value getters; these throw errors by default as they should only be used
 ";
 
 
-// File: classILayout.xml
-%feature("docstring") ILayout "
-
-Pure virtual interface class to equip a sample layer with scattering properties. Currently only inherited by  ParticleLayout; in the future also by domain structure.
-
-C++ includes: ILayout.h
-";
-
-%feature("docstring")  ILayout::ILayout "ILayout::ILayout()
-";
-
-%feature("docstring")  ILayout::~ILayout "ILayout::~ILayout()
-";
-
-%feature("docstring")  ILayout::clone "virtual ILayout* ILayout::clone() const =0
-
-Returns a clone of this  ISample object. 
-";
-
-%feature("docstring")  ILayout::accept "virtual void ILayout::accept(INodeVisitor *visitor) const =0
-";
-
-%feature("docstring")  ILayout::particles "virtual SafePointerVector<IParticle> ILayout::particles() const =0
-
-Returns information on all particles (type and abundance) and generates new particles if an  IAbstractParticle denotes a collection 
-";
-
-%feature("docstring")  ILayout::interferenceFunction "virtual const IInterferenceFunction* ILayout::interferenceFunction() const =0
-
-Returns the interference function. 
-";
-
-%feature("docstring")  ILayout::getTotalAbundance "virtual double ILayout::getTotalAbundance() const =0
-
-Get total abundance of all particles. 
-";
-
-%feature("docstring")  ILayout::totalParticleSurfaceDensity "virtual double ILayout::totalParticleSurfaceDensity() const =0
-
-Returns surface density of all particles. 
-";
-
-%feature("docstring")  ILayout::setTotalParticleSurfaceDensity "virtual void ILayout::setTotalParticleSurfaceDensity(double particle_density)=0
-
-Sets surface density of all particles. 
-";
-
-%feature("docstring")  ILayout::weight "double ILayout::weight() const
-
-Returns the relative weight of this layout. 
-";
-
-%feature("docstring")  ILayout::setWeight "void ILayout::setWeight(double weight)
-
-Sets the relative weight of this layout. 
-";
-
-
 // File: classIntegratorMCMiser.xml
 %feature("docstring") IntegratorMCMiser "";
 
@@ -4118,7 +4014,7 @@ Interference function of a 3D lattice.
 C++ includes: InterferenceFunction3DLattice.h
 ";
 
-%feature("docstring")  InterferenceFunction3DLattice::InterferenceFunction3DLattice "InterferenceFunction3DLattice::InterferenceFunction3DLattice(const Lattice &lattice)
+%feature("docstring")  InterferenceFunction3DLattice::InterferenceFunction3DLattice "InterferenceFunction3DLattice::InterferenceFunction3DLattice(const Lattice3D &lattice)
 ";
 
 %feature("docstring")  InterferenceFunction3DLattice::~InterferenceFunction3DLattice "InterferenceFunction3DLattice::~InterferenceFunction3DLattice() final
@@ -4135,7 +4031,7 @@ Returns a clone of this  ISample object.
 %feature("docstring")  InterferenceFunction3DLattice::setPeakShape "void InterferenceFunction3DLattice::setPeakShape(const IPeakShape &peak_shape)
 ";
 
-%feature("docstring")  InterferenceFunction3DLattice::lattice "const Lattice & InterferenceFunction3DLattice::lattice() const
+%feature("docstring")  InterferenceFunction3DLattice::lattice "const Lattice3D & InterferenceFunction3DLattice::lattice() const
 ";
 
 %feature("docstring")  InterferenceFunction3DLattice::supportsMultilayer "bool InterferenceFunction3DLattice::supportsMultilayer() const override final
@@ -4244,7 +4140,7 @@ Interference function of a finite 3D lattice.
 C++ includes: InterferenceFunctionFinite3DLattice.h
 ";
 
-%feature("docstring")  InterferenceFunctionFinite3DLattice::InterferenceFunctionFinite3DLattice "InterferenceFunctionFinite3DLattice::InterferenceFunctionFinite3DLattice(const Lattice &lattice, unsigned N_1, unsigned N_2, unsigned N_3)
+%feature("docstring")  InterferenceFunctionFinite3DLattice::InterferenceFunctionFinite3DLattice "InterferenceFunctionFinite3DLattice::InterferenceFunctionFinite3DLattice(const Lattice3D &lattice, unsigned N_1, unsigned N_2, unsigned N_3)
 ";
 
 %feature("docstring")  InterferenceFunctionFinite3DLattice::~InterferenceFunctionFinite3DLattice "InterferenceFunctionFinite3DLattice::~InterferenceFunctionFinite3DLattice() final
@@ -4267,7 +4163,7 @@ Returns a clone of this  ISample object.
 %feature("docstring")  InterferenceFunctionFinite3DLattice::numberUnitCells3 "unsigned InterferenceFunctionFinite3DLattice::numberUnitCells3() const
 ";
 
-%feature("docstring")  InterferenceFunctionFinite3DLattice::lattice "const Lattice & InterferenceFunctionFinite3DLattice::lattice() const
+%feature("docstring")  InterferenceFunctionFinite3DLattice::lattice "const Lattice3D & InterferenceFunctionFinite3DLattice::lattice() const
 ";
 
 %feature("docstring")  InterferenceFunctionFinite3DLattice::supportsMultilayer "bool InterferenceFunctionFinite3DLattice::supportsMultilayer() const override final
@@ -4880,141 +4776,132 @@ C++ includes: CylindersBuilder.h
 ";
 
 
-// File: classLattice.xml
-%feature("docstring") Lattice "
+// File: classLattice1DBuilder.xml
+%feature("docstring") Lattice1DBuilder "
 
-A lattice with three basis vectors.
+Builds sample: cylinders with 1DDL structure factor.
 
-C++ includes: Lattice.h
+C++ includes: LatticeBuilder.h
 ";
 
-%feature("docstring")  Lattice::Lattice "Lattice::Lattice()
+%feature("docstring")  Lattice1DBuilder::buildSample "MultiLayer * Lattice1DBuilder::buildSample() const
 ";
 
-%feature("docstring")  Lattice::Lattice "Lattice::Lattice(const kvector_t a1, const kvector_t a2, const kvector_t a3)
-";
 
-%feature("docstring")  Lattice::Lattice "Lattice::Lattice(const Lattice &lattice)
-";
+// File: classLattice2D.xml
+%feature("docstring") Lattice2D "";
 
-%feature("docstring")  Lattice::~Lattice "Lattice::~Lattice() override
+%feature("docstring")  Lattice2D::Lattice2D "Lattice2D::Lattice2D(const NodeMeta &meta, const std::vector< double > &PValues)
 ";
 
-%feature("docstring")  Lattice::accept "void Lattice::accept(INodeVisitor *visitor) const override
+%feature("docstring")  Lattice2D::Lattice2D "Lattice2D::Lattice2D(double xi)
 ";
 
-%feature("docstring")  Lattice::transformed "Lattice Lattice::transformed(const Transform3D &transform) const
-
-Creates transformed lattice. 
+%feature("docstring")  Lattice2D::clone "virtual Lattice2D* Lattice2D::clone() const =0
 ";
 
-%feature("docstring")  Lattice::initialize "void Lattice::initialize() const
-
-Initializes cached data. 
+%feature("docstring")  Lattice2D::length1 "virtual double Lattice2D::length1() const =0
 ";
 
-%feature("docstring")  Lattice::getBasisVectorA "kvector_t Lattice::getBasisVectorA() const
+%feature("docstring")  Lattice2D::length2 "virtual double Lattice2D::length2() const =0
+";
 
-Returns basis vector a. 
+%feature("docstring")  Lattice2D::latticeAngle "virtual double Lattice2D::latticeAngle() const =0
 ";
 
-%feature("docstring")  Lattice::getBasisVectorB "kvector_t Lattice::getBasisVectorB() const
+%feature("docstring")  Lattice2D::unitCellArea "virtual double Lattice2D::unitCellArea() const =0
+";
 
-Returns basis vector b. 
+%feature("docstring")  Lattice2D::rotationAngle "double Lattice2D::rotationAngle() const
 ";
 
-%feature("docstring")  Lattice::getBasisVectorC "kvector_t Lattice::getBasisVectorC() const
+%feature("docstring")  Lattice2D::reciprocalBases "Lattice2D::ReciprocalBases Lattice2D::reciprocalBases() const
+";
 
-Returns basis vector c. 
+%feature("docstring")  Lattice2D::setRotationEnabled "void Lattice2D::setRotationEnabled(bool enabled)
 ";
 
-%feature("docstring")  Lattice::resetBasis "void Lattice::resetBasis(const kvector_t a1, const kvector_t a2, const kvector_t a3)
 
-Resets the basis vectors. 
-";
+// File: classLattice3D.xml
+%feature("docstring") Lattice3D "
 
-%feature("docstring")  Lattice::getMillerDirection "kvector_t Lattice::getMillerDirection(double h, double k, double l) const
+A Bravais lattice, characterized by three basis vectors, and optionally an  ISelectionRule.
 
-Returns normalized direction corresponding to the given Miller indices. 
+C++ includes: Lattice3D.h
 ";
 
-%feature("docstring")  Lattice::volume "double Lattice::volume() const
-
-Returns the volume of the unit cell. 
+%feature("docstring")  Lattice3D::Lattice3D "Lattice3D::Lattice3D()=delete
 ";
 
-%feature("docstring")  Lattice::getReciprocalLatticeBasis "void Lattice::getReciprocalLatticeBasis(kvector_t &b1, kvector_t &b2, kvector_t &b3) const
+%feature("docstring")  Lattice3D::Lattice3D "Lattice3D::Lattice3D(const kvector_t a, const kvector_t b, const kvector_t c)
+";
 
-Returns the reciprocal basis vectors. 
+%feature("docstring")  Lattice3D::Lattice3D "Lattice3D::Lattice3D(const Lattice3D &lattice)
 ";
 
-%feature("docstring")  Lattice::getNearestLatticeVectorCoordinates "ivector_t Lattice::getNearestLatticeVectorCoordinates(const kvector_t vector_in) const
+%feature("docstring")  Lattice3D::~Lattice3D "Lattice3D::~Lattice3D() override
+";
 
-Returns the nearest lattice point from a given vector. 
+%feature("docstring")  Lattice3D::accept "void Lattice3D::accept(INodeVisitor *visitor) const override
 ";
 
-%feature("docstring")  Lattice::getNearestReciprocalLatticeVectorCoordinates "ivector_t Lattice::getNearestReciprocalLatticeVectorCoordinates(const kvector_t vector_in) const
+%feature("docstring")  Lattice3D::transformed "Lattice3D Lattice3D::transformed(const Transform3D &transform) const
 
-Returns the nearest reciprocal lattice point from a given vector. 
+Creates transformed lattice. 
 ";
 
-%feature("docstring")  Lattice::reciprocalLatticeVectorsWithinRadius "std::vector< kvector_t > Lattice::reciprocalLatticeVectorsWithinRadius(const kvector_t input_vector, double radius) const
+%feature("docstring")  Lattice3D::initialize "void Lattice3D::initialize()
 
-Computes a list of reciprocal lattice vectors within a specified distance of a given vector. 
+Initializes cached data. 
 ";
 
-%feature("docstring")  Lattice::setSelectionRule "void Lattice::setSelectionRule(const ISelectionRule &p_selection_rule)
+%feature("docstring")  Lattice3D::getBasisVectorA "kvector_t Lattice3D::getBasisVectorA() const
 
-Sets a selection rule for the reciprocal vectors. 
+Returns basis vector a. 
 ";
 
-%feature("docstring")  Lattice::onChange "void Lattice::onChange() override
+%feature("docstring")  Lattice3D::getBasisVectorB "kvector_t Lattice3D::getBasisVectorB() const
+
+Returns basis vector b. 
 ";
 
+%feature("docstring")  Lattice3D::getBasisVectorC "kvector_t Lattice3D::getBasisVectorC() const
 
-// File: classLattice1DBuilder.xml
-%feature("docstring") Lattice1DBuilder "
+Returns basis vector c. 
+";
 
-Builds sample: cylinders with 1DDL structure factor.
+%feature("docstring")  Lattice3D::getMillerDirection "kvector_t Lattice3D::getMillerDirection(double h, double k, double l) const
 
-C++ includes: LatticeBuilder.h
-";
+Returns normalized direction corresponding to the given Miller indices.
 
-%feature("docstring")  Lattice1DBuilder::buildSample "MultiLayer * Lattice1DBuilder::buildSample() const
+Currently unused but may be useful for checks. 
 ";
 
+%feature("docstring")  Lattice3D::unitCellVolume "double Lattice3D::unitCellVolume() const
 
-// File: classLattice2D.xml
-%feature("docstring") Lattice2D "";
-
-%feature("docstring")  Lattice2D::Lattice2D "Lattice2D::Lattice2D(const NodeMeta &meta, const std::vector< double > &PValues)
+Returns the volume of the unit cell. 
 ";
 
-%feature("docstring")  Lattice2D::Lattice2D "Lattice2D::Lattice2D(double xi)
-";
+%feature("docstring")  Lattice3D::getReciprocalLatticeBasis "void Lattice3D::getReciprocalLatticeBasis(kvector_t &ra, kvector_t &rb, kvector_t &rc) const
 
-%feature("docstring")  Lattice2D::clone "virtual Lattice2D* Lattice2D::clone() const =0
-";
+Returns the reciprocal basis vectors.
 
-%feature("docstring")  Lattice2D::length1 "virtual double Lattice2D::length1() const =0
+Currently only used in tests. 
 ";
 
-%feature("docstring")  Lattice2D::length2 "virtual double Lattice2D::length2() const =0
-";
+%feature("docstring")  Lattice3D::getNearestReciprocalLatticeVectorCoordinates "ivector_t Lattice3D::getNearestReciprocalLatticeVectorCoordinates(const kvector_t q) const
 
-%feature("docstring")  Lattice2D::latticeAngle "virtual double Lattice2D::latticeAngle() const =0
+Returns the nearest reciprocal lattice point from a given vector. 
 ";
 
-%feature("docstring")  Lattice2D::unitCellArea "virtual double Lattice2D::unitCellArea() const =0
-";
+%feature("docstring")  Lattice3D::reciprocalLatticeVectorsWithinRadius "std::vector< kvector_t > Lattice3D::reciprocalLatticeVectorsWithinRadius(const kvector_t q, double dq) const
 
-%feature("docstring")  Lattice2D::rotationAngle "double Lattice2D::rotationAngle() const
+Returns a list of reciprocal lattice vectors within distance dq of a vector q. 
 ";
 
-%feature("docstring")  Lattice2D::reciprocalBases "Lattice2D::ReciprocalBases Lattice2D::reciprocalBases() const
-";
+%feature("docstring")  Lattice3D::setSelectionRule "void Lattice3D::setSelectionRule(const ISelectionRule &selection_rule)
 
-%feature("docstring")  Lattice2D::setRotationEnabled "void Lattice2D::setRotationEnabled(bool enabled)
+Sets a selection rule for the reciprocal vectors. 
 ";
 
 
@@ -5067,13 +4954,13 @@ Returns nullptr, unless overwritten to return a specific material.
 %feature("docstring")  Layer::setMaterial "void Layer::setMaterial(Material material)
 ";
 
-%feature("docstring")  Layer::addLayout "void Layer::addLayout(const ILayout &decoration)
+%feature("docstring")  Layer::addLayout "void Layer::addLayout(const ParticleLayout &decoration)
 ";
 
 %feature("docstring")  Layer::numberOfLayouts "size_t Layer::numberOfLayouts() const
 ";
 
-%feature("docstring")  Layer::layouts "std::vector< const ILayout * > Layer::layouts() const
+%feature("docstring")  Layer::layouts "std::vector< const ParticleLayout * > Layer::layouts() const
 ";
 
 %feature("docstring")  Layer::getChildren "std::vector< const INode * > Layer::getChildren() const override final
@@ -5789,7 +5676,7 @@ A particle with an internal structure of smaller particles.
 C++ includes: MesoCrystal.h
 ";
 
-%feature("docstring")  MesoCrystal::MesoCrystal "MesoCrystal::MesoCrystal(const IClusteredParticles &particle_structure, const IFormFactor &form_factor)
+%feature("docstring")  MesoCrystal::MesoCrystal "MesoCrystal::MesoCrystal(const Crystal &particle_structure, const IFormFactor &form_factor)
 ";
 
 %feature("docstring")  MesoCrystal::~MesoCrystal "MesoCrystal::~MesoCrystal()
@@ -5824,44 +5711,6 @@ C++ includes: MesoCrystalBuilder.h
 ";
 
 
-// File: structMillerIndex.xml
-%feature("docstring") MillerIndex "
-
-A direction in reciprocal space, specified by double-valued indices hkl.
-
-C++ includes: ILatticeOrientation.h
-";
-
-%feature("docstring")  MillerIndex::MillerIndex "MillerIndex::MillerIndex(double h_, double k_, double l_)
-";
-
-
-// File: classMillerIndexOrientation.xml
-%feature("docstring") MillerIndexOrientation "
-
-Specifies a rotation of a lattice through the Miller indices of two coordinate axes.
-
-C++ includes: ILatticeOrientation.h
-";
-
-%feature("docstring")  MillerIndexOrientation::MillerIndexOrientation "MillerIndexOrientation::MillerIndexOrientation(QComponent q1, MillerIndex index1, QComponent q2, MillerIndex index2)
-
-This constructor is best explained by an example. Arguments QX, (1,1,0), QY, (0,2,1) mean: Rotate the lattice such that the axis [110] points into x direction, and the axis [021], projected into the yz plane, points into z direction. 
-";
-
-%feature("docstring")  MillerIndexOrientation::~MillerIndexOrientation "MillerIndexOrientation::~MillerIndexOrientation() override
-";
-
-%feature("docstring")  MillerIndexOrientation::clone "MillerIndexOrientation * MillerIndexOrientation::clone() const override
-";
-
-%feature("docstring")  MillerIndexOrientation::usePrimitiveLattice "void MillerIndexOrientation::usePrimitiveLattice(const Lattice &lattice) override
-";
-
-%feature("docstring")  MillerIndexOrientation::transformation "Transform3D MillerIndexOrientation::transformation() const override
-";
-
-
 // File: classMisesFisherGaussPeakShape.xml
 %feature("docstring") MisesFisherGaussPeakShape "
 
@@ -6298,12 +6147,12 @@ C++ includes: ParticleLayout.h
 %feature("docstring")  ParticleLayout::~ParticleLayout "ParticleLayout::~ParticleLayout() override
 ";
 
-%feature("docstring")  ParticleLayout::clone "ParticleLayout * ParticleLayout::clone() const final override
+%feature("docstring")  ParticleLayout::clone "ParticleLayout * ParticleLayout::clone() const override
 
 Returns a clone of this  ISample object. 
 ";
 
-%feature("docstring")  ParticleLayout::accept "void ParticleLayout::accept(INodeVisitor *visitor) const final override
+%feature("docstring")  ParticleLayout::accept "void ParticleLayout::accept(INodeVisitor *visitor) const override
 ";
 
 %feature("docstring")  ParticleLayout::addParticle "void ParticleLayout::addParticle(const IAbstractParticle &particle, double abundance=-1.0, const kvector_t position={}, const IRotation &rotation=IdentityRotation())
@@ -6326,19 +6175,15 @@ rotation:
  Particle rotation 
 ";
 
-%feature("docstring")  ParticleLayout::particles "SafePointerVector< IParticle > ParticleLayout::particles() const final override
+%feature("docstring")  ParticleLayout::particles "SafePointerVector< IParticle > ParticleLayout::particles() const
 
 Returns information on all particles (type and abundance) and generates new particles if an  IAbstractParticle denotes a collection 
 ";
 
-%feature("docstring")  ParticleLayout::interferenceFunction "const IInterferenceFunction * ParticleLayout::interferenceFunction() const final override
-
-Returns the interference function. 
+%feature("docstring")  ParticleLayout::interferenceFunction "const IInterferenceFunction * ParticleLayout::interferenceFunction() const
 ";
 
-%feature("docstring")  ParticleLayout::getTotalAbundance "double ParticleLayout::getTotalAbundance() const final override
-
-Get total abundance of all particles. 
+%feature("docstring")  ParticleLayout::getTotalAbundance "double ParticleLayout::getTotalAbundance() const
 ";
 
 %feature("docstring")  ParticleLayout::setInterferenceFunction "void ParticleLayout::setInterferenceFunction(const IInterferenceFunction &interference_function)
@@ -6346,12 +6191,10 @@ Get total abundance of all particles.
 Adds interference functions. 
 ";
 
-%feature("docstring")  ParticleLayout::totalParticleSurfaceDensity "double ParticleLayout::totalParticleSurfaceDensity() const final override
-
-Returns surface density of all particles. 
+%feature("docstring")  ParticleLayout::totalParticleSurfaceDensity "double ParticleLayout::totalParticleSurfaceDensity() const
 ";
 
-%feature("docstring")  ParticleLayout::setTotalParticleSurfaceDensity "void ParticleLayout::setTotalParticleSurfaceDensity(double particle_density) final override
+%feature("docstring")  ParticleLayout::setTotalParticleSurfaceDensity "void ParticleLayout::setTotalParticleSurfaceDensity(double particle_density)
 
 Sets total particle surface density.
 
@@ -6362,7 +6205,17 @@ particle_density:
 number of particles per square nanometer 
 ";
 
-%feature("docstring")  ParticleLayout::getChildren "std::vector< const INode * > ParticleLayout::getChildren() const final override
+%feature("docstring")  ParticleLayout::getChildren "std::vector< const INode * > ParticleLayout::getChildren() const override
+";
+
+%feature("docstring")  ParticleLayout::weight "double ParticleLayout::weight() const
+
+Returns the relative weight of this layout. 
+";
+
+%feature("docstring")  ParticleLayout::setWeight "void ParticleLayout::setWeight(double weight)
+
+Sets the relative weight of this layout. 
 ";
 
 
@@ -7760,13 +7613,13 @@ C++ includes: ZLimits.h
 ";
 
 
-// File: namespace_0d114.xml
+// File: namespace_0d112.xml
 
 
-// File: namespace_0d117.xml
+// File: namespace_0d115.xml
 
 
-// File: namespace_0d133.xml
+// File: namespace_0d141.xml
 
 
 // File: namespace_0d145.xml
@@ -7775,132 +7628,150 @@ C++ includes: ZLimits.h
 // File: namespace_0d149.xml
 
 
-// File: namespace_0d153.xml
+// File: namespace_0d159.xml
 
 
 // File: namespace_0d16.xml
 
 
-// File: namespace_0d163.xml
+// File: namespace_0d161.xml
 
 
-// File: namespace_0d165.xml
+// File: namespace_0d163.xml
 
 
-// File: namespace_0d167.xml
+// File: namespace_0d173.xml
 
 
-// File: namespace_0d177.xml
+// File: namespace_0d194.xml
 
 
-// File: namespace_0d199.xml
+// File: namespace_0d196.xml
 
 
 // File: namespace_0d2.xml
 
 
-// File: namespace_0d201.xml
+// File: namespace_0d206.xml
 
 
-// File: namespace_0d211.xml
+// File: namespace_0d222.xml
 
 
-// File: namespace_0d227.xml
+// File: namespace_0d224.xml
 
 
-// File: namespace_0d229.xml
+// File: namespace_0d231.xml
 
 
-// File: namespace_0d236.xml
+// File: namespace_0d249.xml
 
 
 // File: namespace_0d25.xml
 
 
-// File: namespace_0d254.xml
+// File: namespace_0d257.xml
 
 
-// File: namespace_0d262.xml
+// File: namespace_0d267.xml
 
 
-// File: namespace_0d272.xml
+// File: namespace_0d269.xml
 
 
-// File: namespace_0d274.xml
+// File: namespace_0d271.xml
 
 
-// File: namespace_0d276.xml
+// File: namespace_0d273.xml
 
 
-// File: namespace_0d278.xml
+// File: namespace_0d275.xml
 
 
-// File: namespace_0d280.xml
+// File: namespace_0d279.xml
 
 
-// File: namespace_0d284.xml
+// File: namespace_0d281.xml
 
 
-// File: namespace_0d286.xml
+// File: namespace_0d283.xml
 
 
-// File: namespace_0d288.xml
+// File: namespace_0d295.xml
 
 
-// File: namespace_0d300.xml
+// File: namespace_0d301.xml
 
 
-// File: namespace_0d306.xml
+// File: namespace_0d305.xml
 
 
 // File: namespace_0d31.xml
 
 
-// File: namespace_0d310.xml
+// File: namespace_0d323.xml
 
 
-// File: namespace_0d328.xml
+// File: namespace_0d342.xml
 
 
-// File: namespace_0d347.xml
+// File: namespace_0d37.xml
 
 
-// File: namespace_0d37.xml
+// File: namespace_0d39.xml
 
 
 // File: namespace_0d4.xml
 
 
-// File: namespace_0d41.xml
+// File: namespacebake.xml
+%feature("docstring")  bake::createCubicLattice "Lattice3D bake::createCubicLattice(double a)
 
+Returns a primitive cubic (cP) lattice with edge length a. 
+";
 
-// File: namespaceFormFactorPrecompute.xml
-%feature("docstring")  FormFactorPrecompute::scalar "std::vector< complex_t > FormFactorPrecompute::scalar(const SimulationElement &sim_element, const std::vector< FormFactorCoherentSum > &ff_wrappers)
+%feature("docstring")  bake::createFCCLattice "Lattice3D bake::createFCCLattice(double a)
+
+Returns a face-centered cubic (cF) lattice with edge length a. 
 ";
 
-%feature("docstring")  FormFactorPrecompute::polarized "FormFactorPrecompute::matrixFFVector_t FormFactorPrecompute::polarized(const SimulationElement &sim_element, const std::vector< FormFactorCoherentSum > &ff_wrappers)
+%feature("docstring")  bake::createHexagonalLattice "Lattice3D bake::createHexagonalLattice(double a, double c)
+
+Returns a primitive hexagonal (hP) lattice with hexagonal edge a and height c. 
 ";
 
+%feature("docstring")  bake::createHCPLattice "Lattice3D bake::createHCPLattice(double a, double c)
 
-// File: namespaceKzComputation.xml
-%feature("docstring")  KzComputation::computeReducedKz "std::vector< complex_t > KzComputation::computeReducedKz(const std::vector< Slice > &slices, kvector_t k)
+TODO: Clarify how this is meant: HCP is not a Bravais lattice. 
 ";
 
-%feature("docstring")  KzComputation::computeKzFromSLDs "std::vector< complex_t > KzComputation::computeKzFromSLDs(const std::vector< Slice > &slices, double kz)
+%feature("docstring")  bake::createTetragonalLattice "Lattice3D bake::createTetragonalLattice(double a, double c)
+
+Returns a primitive tetragonal (tP) lattice with square base edge a and height c. 
 ";
 
-%feature("docstring")  KzComputation::computeKzFromRefIndices "std::vector< complex_t > KzComputation::computeKzFromRefIndices(const std::vector< Slice > &slices, kvector_t k)
+%feature("docstring")  bake::createBCTLattice "Lattice3D bake::createBCTLattice(double a, double c)
+
+Returns a body-centered cubic (cI) lattice with edge length a. TODO: Clarify meaning of c 
 ";
 
 
-// File: namespaceLatticeUtils.xml
-%feature("docstring")  LatticeUtils::createFCCLattice "Lattice LatticeUtils::createFCCLattice(double lattice_constant, const ILatticeOrientation &orientation)
+// File: namespaceFormFactorPrecompute.xml
+%feature("docstring")  FormFactorPrecompute::scalar "std::vector< complex_t > FormFactorPrecompute::scalar(const SimulationElement &sim_element, const std::vector< FormFactorCoherentSum > &ff_wrappers)
 ";
 
-%feature("docstring")  LatticeUtils::createHCPLattice "Lattice LatticeUtils::createHCPLattice(double a, double c, const ILatticeOrientation &orientation)
+%feature("docstring")  FormFactorPrecompute::polarized "FormFactorPrecompute::matrixFFVector_t FormFactorPrecompute::polarized(const SimulationElement &sim_element, const std::vector< FormFactorCoherentSum > &ff_wrappers)
 ";
 
-%feature("docstring")  LatticeUtils::createBCTLattice "Lattice LatticeUtils::createBCTLattice(double a, double c, const ILatticeOrientation &orientation)
+
+// File: namespaceKzComputation.xml
+%feature("docstring")  KzComputation::computeReducedKz "std::vector< complex_t > KzComputation::computeReducedKz(const std::vector< Slice > &slices, kvector_t k)
+";
+
+%feature("docstring")  KzComputation::computeKzFromSLDs "std::vector< complex_t > KzComputation::computeKzFromSLDs(const std::vector< Slice > &slices, double kz)
+";
+
+%feature("docstring")  KzComputation::computeKzFromRefIndices "std::vector< complex_t > KzComputation::computeKzFromRefIndices(const std::vector< Slice > &slices, kvector_t k)
 ";
 
 
@@ -8152,12 +8023,6 @@ Used by the hard sphere and by several soft sphere classes.
 // File: IDistribution2DSampler_8h.xml
 
 
-// File: ILayout_8cpp.xml
-
-
-// File: ILayout_8h.xml
-
-
 // File: IPeakShape_8cpp.xml
 
 
@@ -8434,31 +8299,25 @@ Used by the hard sphere and by several soft sphere classes.
 // File: SSCApproximationStrategy_8h.xml
 
 
-// File: ILatticeOrientation_8cpp.xml
+// File: BakeLattice_8cpp.xml
 
 
-// File: ILatticeOrientation_8h.xml
+// File: BakeLattice_8h.xml
 
 
 // File: ISelectionRule_8h.xml
 
 
-// File: Lattice_8cpp.xml
-
-
-// File: Lattice_8h.xml
-
-
 // File: Lattice2D_8cpp.xml
 
 
 // File: Lattice2D_8h.xml
 
 
-// File: LatticeUtils_8cpp.xml
+// File: Lattice3D_8cpp.xml
 
 
-// File: LatticeUtils_8h.xml
+// File: Lattice3D_8h.xml
 
 
 // File: SomeFormFactors_8cpp.xml
@@ -8654,9 +8513,6 @@ Creates averaged material. Square refractive index of returned material is arith
 // File: IAbstractParticle_8h.xml
 
 
-// File: IClusteredParticles_8h.xml
-
-
 // File: IParticle_8cpp.xml
 
 
@@ -9086,7 +8942,7 @@ Generate vertices of centered ellipse with given semi-axes at height z.
 
 
 // File: LayersWithAbsorptionBySLDBuilder_8cpp.xml
-%feature("docstring")  middle_layer_thickness "const double middle_layer_thickness(60.0 *Units::nanometer)
+%feature("docstring")  middle_layer_thickness "const double middle_layer_thickness(60.0 *Units::nm)
 ";
 
 
diff --git a/auto/Wrap/libBornAgainParam.py b/auto/Wrap/libBornAgainParam.py
index bdaa25c87a16d62dc73ec775fa93dd33a11372f5..eb21700ad62a1840d19f50014b7fa8d5a8a0a743 100644
--- a/auto/Wrap/libBornAgainParam.py
+++ b/auto/Wrap/libBornAgainParam.py
@@ -3378,7 +3378,7 @@ class INodeVisitor(object):
         visit(INodeVisitor self, IFormFactorBorn const * arg2)
         visit(INodeVisitor self, IFormFactorDecorator const * arg2)
         visit(INodeVisitor self, IInterferenceFunction const * arg2)
-        visit(INodeVisitor self, ILayout const * arg2)
+        visit(INodeVisitor self, ParticleLayout const * arg2)
         visit(INodeVisitor self, INode arg2)
         visit(INodeVisitor self, Instrument const * arg2)
         visit(INodeVisitor self, InterferenceFunction1DLattice const * arg2)
@@ -3407,7 +3407,6 @@ class INodeVisitor(object):
         visit(INodeVisitor self, ParticleComposition const * arg2)
         visit(INodeVisitor self, ParticleCoreShell const * arg2)
         visit(INodeVisitor self, ParticleDistribution const * arg2)
-        visit(INodeVisitor self, ParticleLayout const * arg2)
         visit(INodeVisitor self, PoissonNoiseBackground const * arg2)
         visit(INodeVisitor self, RectangularDetector const * arg2)
         visit(INodeVisitor self, ResolutionFunction2DGaussian const * arg2)
diff --git a/auto/Wrap/libBornAgainParam_wrap.cpp b/auto/Wrap/libBornAgainParam_wrap.cpp
index 6ab9f2becdd4e00010cab6a22816fab27bb67b1b..29087bfebd50fd9fab8bd1879376f7dafe6d8c05 100644
--- a/auto/Wrap/libBornAgainParam_wrap.cpp
+++ b/auto/Wrap/libBornAgainParam_wrap.cpp
@@ -3185,121 +3185,120 @@ namespace Swig {
 #define SWIGTYPE_p_IFormFactorBorn swig_types[85]
 #define SWIGTYPE_p_IFormFactorDecorator swig_types[86]
 #define SWIGTYPE_p_IInterferenceFunction swig_types[87]
-#define SWIGTYPE_p_ILayout swig_types[88]
-#define SWIGTYPE_p_INode swig_types[89]
-#define SWIGTYPE_p_INodeVisitor swig_types[90]
-#define SWIGTYPE_p_IParameterT_double_t swig_types[91]
-#define SWIGTYPE_p_IParameterized swig_types[92]
-#define SWIGTYPE_p_IParticle swig_types[93]
-#define SWIGTYPE_p_IPeakShape swig_types[94]
-#define SWIGTYPE_p_IRotation swig_types[95]
-#define SWIGTYPE_p_ISample swig_types[96]
-#define SWIGTYPE_p_IdentityRotation swig_types[97]
-#define SWIGTYPE_p_Instrument swig_types[98]
-#define SWIGTYPE_p_InterferenceFunction1DLattice swig_types[99]
-#define SWIGTYPE_p_InterferenceFunction2DLattice swig_types[100]
-#define SWIGTYPE_p_InterferenceFunction2DParaCrystal swig_types[101]
-#define SWIGTYPE_p_InterferenceFunction2DSuperLattice swig_types[102]
-#define SWIGTYPE_p_InterferenceFunction3DLattice swig_types[103]
-#define SWIGTYPE_p_InterferenceFunctionFinite2DLattice swig_types[104]
-#define SWIGTYPE_p_InterferenceFunctionFinite3DLattice swig_types[105]
-#define SWIGTYPE_p_InterferenceFunctionHardDisk swig_types[106]
-#define SWIGTYPE_p_InterferenceFunctionNone swig_types[107]
-#define SWIGTYPE_p_InterferenceFunctionRadialParaCrystal swig_types[108]
-#define SWIGTYPE_p_InterferenceFunctionTwin swig_types[109]
-#define SWIGTYPE_p_IsGISAXSDetector swig_types[110]
-#define SWIGTYPE_p_Layer swig_types[111]
-#define SWIGTYPE_p_LayerInterface swig_types[112]
-#define SWIGTYPE_p_LayerRoughness swig_types[113]
-#define SWIGTYPE_p_MesoCrystal swig_types[114]
-#define SWIGTYPE_p_MultiLayer swig_types[115]
-#define SWIGTYPE_p_NodeMeta swig_types[116]
-#define SWIGTYPE_p_OffSpecSimulation swig_types[117]
-#define SWIGTYPE_p_ParaMeta swig_types[118]
-#define SWIGTYPE_p_ParameterDistribution swig_types[119]
-#define SWIGTYPE_p_ParameterPool swig_types[120]
-#define SWIGTYPE_p_ParameterSample swig_types[121]
-#define SWIGTYPE_p_Particle swig_types[122]
-#define SWIGTYPE_p_ParticleComposition swig_types[123]
-#define SWIGTYPE_p_ParticleCoreShell swig_types[124]
-#define SWIGTYPE_p_ParticleDistribution swig_types[125]
-#define SWIGTYPE_p_ParticleLayout swig_types[126]
-#define SWIGTYPE_p_PoissonNoiseBackground swig_types[127]
-#define SWIGTYPE_p_RangedDistribution swig_types[128]
-#define SWIGTYPE_p_RangedDistributionCosine swig_types[129]
-#define SWIGTYPE_p_RangedDistributionGate swig_types[130]
-#define SWIGTYPE_p_RangedDistributionGaussian swig_types[131]
-#define SWIGTYPE_p_RangedDistributionLogNormal swig_types[132]
-#define SWIGTYPE_p_RangedDistributionLorentz swig_types[133]
-#define SWIGTYPE_p_RealLimits swig_types[134]
-#define SWIGTYPE_p_RealParameter swig_types[135]
-#define SWIGTYPE_p_RectangularDetector swig_types[136]
-#define SWIGTYPE_p_ResolutionFunction2DGaussian swig_types[137]
-#define SWIGTYPE_p_RotationEuler swig_types[138]
-#define SWIGTYPE_p_RotationX swig_types[139]
-#define SWIGTYPE_p_RotationY swig_types[140]
-#define SWIGTYPE_p_RotationZ swig_types[141]
-#define SWIGTYPE_p_SpecularDetector1D swig_types[142]
-#define SWIGTYPE_p_SpecularSimulation swig_types[143]
-#define SWIGTYPE_p_SphericalDetector swig_types[144]
-#define SWIGTYPE_p_SquareLattice swig_types[145]
-#define SWIGTYPE_p_allocator_type swig_types[146]
-#define SWIGTYPE_p_char swig_types[147]
-#define SWIGTYPE_p_difference_type swig_types[148]
-#define SWIGTYPE_p_double swig_types[149]
-#define SWIGTYPE_p_first_type swig_types[150]
-#define SWIGTYPE_p_int swig_types[151]
-#define SWIGTYPE_p_key_type swig_types[152]
-#define SWIGTYPE_p_long_long swig_types[153]
-#define SWIGTYPE_p_mapped_type swig_types[154]
-#define SWIGTYPE_p_p_PyObject swig_types[155]
-#define SWIGTYPE_p_second_type swig_types[156]
-#define SWIGTYPE_p_short swig_types[157]
-#define SWIGTYPE_p_signed_char swig_types[158]
-#define SWIGTYPE_p_size_type swig_types[159]
-#define SWIGTYPE_p_std__allocatorT_BasicVector3DT_double_t_t swig_types[160]
-#define SWIGTYPE_p_std__allocatorT_BasicVector3DT_std__complexT_double_t_t_t swig_types[161]
-#define SWIGTYPE_p_std__allocatorT_INode_const_p_t swig_types[162]
-#define SWIGTYPE_p_std__allocatorT_INode_p_t swig_types[163]
-#define SWIGTYPE_p_std__allocatorT_ParameterSample_t swig_types[164]
-#define SWIGTYPE_p_std__allocatorT_double_t swig_types[165]
-#define SWIGTYPE_p_std__allocatorT_int_t swig_types[166]
-#define SWIGTYPE_p_std__allocatorT_std__complexT_double_t_t swig_types[167]
-#define SWIGTYPE_p_std__allocatorT_std__pairT_double_double_t_t swig_types[168]
-#define SWIGTYPE_p_std__allocatorT_std__pairT_std__string_const_double_t_t swig_types[169]
-#define SWIGTYPE_p_std__allocatorT_std__string_t swig_types[170]
-#define SWIGTYPE_p_std__allocatorT_std__vectorT_double_std__allocatorT_double_t_t_t swig_types[171]
-#define SWIGTYPE_p_std__allocatorT_std__vectorT_int_std__allocatorT_int_t_t_t swig_types[172]
-#define SWIGTYPE_p_std__allocatorT_unsigned_long_t swig_types[173]
-#define SWIGTYPE_p_std__complexT_double_t swig_types[174]
-#define SWIGTYPE_p_std__functionT_void_fF_t swig_types[175]
-#define SWIGTYPE_p_std__invalid_argument swig_types[176]
-#define SWIGTYPE_p_std__lessT_std__string_t swig_types[177]
-#define SWIGTYPE_p_std__mapT_std__string_double_std__lessT_std__string_t_std__allocatorT_std__pairT_std__string_const_double_t_t_t swig_types[178]
-#define SWIGTYPE_p_std__pairT_double_double_t swig_types[179]
-#define SWIGTYPE_p_std__vectorT_BasicVector3DT_double_t_std__allocatorT_BasicVector3DT_double_t_t_t swig_types[180]
-#define SWIGTYPE_p_std__vectorT_BasicVector3DT_std__complexT_double_t_t_std__allocatorT_BasicVector3DT_std__complexT_double_t_t_t_t swig_types[181]
-#define SWIGTYPE_p_std__vectorT_INode_const_p_std__allocatorT_INode_const_p_t_t swig_types[182]
-#define SWIGTYPE_p_std__vectorT_INode_p_std__allocatorT_INode_p_t_t swig_types[183]
-#define SWIGTYPE_p_std__vectorT_ParaMeta_std__allocatorT_ParaMeta_t_t swig_types[184]
-#define SWIGTYPE_p_std__vectorT_ParameterSample_std__allocatorT_ParameterSample_t_t swig_types[185]
-#define SWIGTYPE_p_std__vectorT_RealParameter_p_std__allocatorT_RealParameter_p_t_t swig_types[186]
-#define SWIGTYPE_p_std__vectorT_double_std__allocatorT_double_t_t swig_types[187]
-#define SWIGTYPE_p_std__vectorT_int_std__allocatorT_int_t_t swig_types[188]
-#define SWIGTYPE_p_std__vectorT_std__complexT_double_t_std__allocatorT_std__complexT_double_t_t_t swig_types[189]
-#define SWIGTYPE_p_std__vectorT_std__pairT_double_double_t_std__allocatorT_std__pairT_double_double_t_t_t swig_types[190]
-#define SWIGTYPE_p_std__vectorT_std__string_std__allocatorT_std__string_t_t swig_types[191]
-#define SWIGTYPE_p_std__vectorT_std__vectorT_double_std__allocatorT_double_t_t_std__allocatorT_std__vectorT_double_std__allocatorT_double_t_t_t_t swig_types[192]
-#define SWIGTYPE_p_std__vectorT_std__vectorT_int_std__allocatorT_int_t_t_std__allocatorT_std__vectorT_int_std__allocatorT_int_t_t_t_t swig_types[193]
-#define SWIGTYPE_p_std__vectorT_unsigned_long_std__allocatorT_unsigned_long_t_t swig_types[194]
-#define SWIGTYPE_p_swig__SwigPyIterator swig_types[195]
-#define SWIGTYPE_p_unsigned_char swig_types[196]
-#define SWIGTYPE_p_unsigned_int swig_types[197]
-#define SWIGTYPE_p_unsigned_long_long swig_types[198]
-#define SWIGTYPE_p_unsigned_short swig_types[199]
-#define SWIGTYPE_p_value_type swig_types[200]
-static swig_type_info *swig_types[202];
-static swig_module_info swig_module = {swig_types, 201, 0, 0, 0, 0};
+#define SWIGTYPE_p_INode swig_types[88]
+#define SWIGTYPE_p_INodeVisitor swig_types[89]
+#define SWIGTYPE_p_IParameterT_double_t swig_types[90]
+#define SWIGTYPE_p_IParameterized swig_types[91]
+#define SWIGTYPE_p_IParticle swig_types[92]
+#define SWIGTYPE_p_IPeakShape swig_types[93]
+#define SWIGTYPE_p_IRotation swig_types[94]
+#define SWIGTYPE_p_ISample swig_types[95]
+#define SWIGTYPE_p_IdentityRotation swig_types[96]
+#define SWIGTYPE_p_Instrument swig_types[97]
+#define SWIGTYPE_p_InterferenceFunction1DLattice swig_types[98]
+#define SWIGTYPE_p_InterferenceFunction2DLattice swig_types[99]
+#define SWIGTYPE_p_InterferenceFunction2DParaCrystal swig_types[100]
+#define SWIGTYPE_p_InterferenceFunction2DSuperLattice swig_types[101]
+#define SWIGTYPE_p_InterferenceFunction3DLattice swig_types[102]
+#define SWIGTYPE_p_InterferenceFunctionFinite2DLattice swig_types[103]
+#define SWIGTYPE_p_InterferenceFunctionFinite3DLattice swig_types[104]
+#define SWIGTYPE_p_InterferenceFunctionHardDisk swig_types[105]
+#define SWIGTYPE_p_InterferenceFunctionNone swig_types[106]
+#define SWIGTYPE_p_InterferenceFunctionRadialParaCrystal swig_types[107]
+#define SWIGTYPE_p_InterferenceFunctionTwin swig_types[108]
+#define SWIGTYPE_p_IsGISAXSDetector swig_types[109]
+#define SWIGTYPE_p_Layer swig_types[110]
+#define SWIGTYPE_p_LayerInterface swig_types[111]
+#define SWIGTYPE_p_LayerRoughness swig_types[112]
+#define SWIGTYPE_p_MesoCrystal swig_types[113]
+#define SWIGTYPE_p_MultiLayer swig_types[114]
+#define SWIGTYPE_p_NodeMeta swig_types[115]
+#define SWIGTYPE_p_OffSpecSimulation swig_types[116]
+#define SWIGTYPE_p_ParaMeta swig_types[117]
+#define SWIGTYPE_p_ParameterDistribution swig_types[118]
+#define SWIGTYPE_p_ParameterPool swig_types[119]
+#define SWIGTYPE_p_ParameterSample swig_types[120]
+#define SWIGTYPE_p_Particle swig_types[121]
+#define SWIGTYPE_p_ParticleComposition swig_types[122]
+#define SWIGTYPE_p_ParticleCoreShell swig_types[123]
+#define SWIGTYPE_p_ParticleDistribution swig_types[124]
+#define SWIGTYPE_p_ParticleLayout swig_types[125]
+#define SWIGTYPE_p_PoissonNoiseBackground swig_types[126]
+#define SWIGTYPE_p_RangedDistribution swig_types[127]
+#define SWIGTYPE_p_RangedDistributionCosine swig_types[128]
+#define SWIGTYPE_p_RangedDistributionGate swig_types[129]
+#define SWIGTYPE_p_RangedDistributionGaussian swig_types[130]
+#define SWIGTYPE_p_RangedDistributionLogNormal swig_types[131]
+#define SWIGTYPE_p_RangedDistributionLorentz swig_types[132]
+#define SWIGTYPE_p_RealLimits swig_types[133]
+#define SWIGTYPE_p_RealParameter swig_types[134]
+#define SWIGTYPE_p_RectangularDetector swig_types[135]
+#define SWIGTYPE_p_ResolutionFunction2DGaussian swig_types[136]
+#define SWIGTYPE_p_RotationEuler swig_types[137]
+#define SWIGTYPE_p_RotationX swig_types[138]
+#define SWIGTYPE_p_RotationY swig_types[139]
+#define SWIGTYPE_p_RotationZ swig_types[140]
+#define SWIGTYPE_p_SpecularDetector1D swig_types[141]
+#define SWIGTYPE_p_SpecularSimulation swig_types[142]
+#define SWIGTYPE_p_SphericalDetector swig_types[143]
+#define SWIGTYPE_p_SquareLattice swig_types[144]
+#define SWIGTYPE_p_allocator_type swig_types[145]
+#define SWIGTYPE_p_char swig_types[146]
+#define SWIGTYPE_p_difference_type swig_types[147]
+#define SWIGTYPE_p_double swig_types[148]
+#define SWIGTYPE_p_first_type swig_types[149]
+#define SWIGTYPE_p_int swig_types[150]
+#define SWIGTYPE_p_key_type swig_types[151]
+#define SWIGTYPE_p_long_long swig_types[152]
+#define SWIGTYPE_p_mapped_type swig_types[153]
+#define SWIGTYPE_p_p_PyObject swig_types[154]
+#define SWIGTYPE_p_second_type swig_types[155]
+#define SWIGTYPE_p_short swig_types[156]
+#define SWIGTYPE_p_signed_char swig_types[157]
+#define SWIGTYPE_p_size_type swig_types[158]
+#define SWIGTYPE_p_std__allocatorT_BasicVector3DT_double_t_t swig_types[159]
+#define SWIGTYPE_p_std__allocatorT_BasicVector3DT_std__complexT_double_t_t_t swig_types[160]
+#define SWIGTYPE_p_std__allocatorT_INode_const_p_t swig_types[161]
+#define SWIGTYPE_p_std__allocatorT_INode_p_t swig_types[162]
+#define SWIGTYPE_p_std__allocatorT_ParameterSample_t swig_types[163]
+#define SWIGTYPE_p_std__allocatorT_double_t swig_types[164]
+#define SWIGTYPE_p_std__allocatorT_int_t swig_types[165]
+#define SWIGTYPE_p_std__allocatorT_std__complexT_double_t_t swig_types[166]
+#define SWIGTYPE_p_std__allocatorT_std__pairT_double_double_t_t swig_types[167]
+#define SWIGTYPE_p_std__allocatorT_std__pairT_std__string_const_double_t_t swig_types[168]
+#define SWIGTYPE_p_std__allocatorT_std__string_t swig_types[169]
+#define SWIGTYPE_p_std__allocatorT_std__vectorT_double_std__allocatorT_double_t_t_t swig_types[170]
+#define SWIGTYPE_p_std__allocatorT_std__vectorT_int_std__allocatorT_int_t_t_t swig_types[171]
+#define SWIGTYPE_p_std__allocatorT_unsigned_long_t swig_types[172]
+#define SWIGTYPE_p_std__complexT_double_t swig_types[173]
+#define SWIGTYPE_p_std__functionT_void_fF_t swig_types[174]
+#define SWIGTYPE_p_std__invalid_argument swig_types[175]
+#define SWIGTYPE_p_std__lessT_std__string_t swig_types[176]
+#define SWIGTYPE_p_std__mapT_std__string_double_std__lessT_std__string_t_std__allocatorT_std__pairT_std__string_const_double_t_t_t swig_types[177]
+#define SWIGTYPE_p_std__pairT_double_double_t swig_types[178]
+#define SWIGTYPE_p_std__vectorT_BasicVector3DT_double_t_std__allocatorT_BasicVector3DT_double_t_t_t swig_types[179]
+#define SWIGTYPE_p_std__vectorT_BasicVector3DT_std__complexT_double_t_t_std__allocatorT_BasicVector3DT_std__complexT_double_t_t_t_t swig_types[180]
+#define SWIGTYPE_p_std__vectorT_INode_const_p_std__allocatorT_INode_const_p_t_t swig_types[181]
+#define SWIGTYPE_p_std__vectorT_INode_p_std__allocatorT_INode_p_t_t swig_types[182]
+#define SWIGTYPE_p_std__vectorT_ParaMeta_std__allocatorT_ParaMeta_t_t swig_types[183]
+#define SWIGTYPE_p_std__vectorT_ParameterSample_std__allocatorT_ParameterSample_t_t swig_types[184]
+#define SWIGTYPE_p_std__vectorT_RealParameter_p_std__allocatorT_RealParameter_p_t_t swig_types[185]
+#define SWIGTYPE_p_std__vectorT_double_std__allocatorT_double_t_t swig_types[186]
+#define SWIGTYPE_p_std__vectorT_int_std__allocatorT_int_t_t swig_types[187]
+#define SWIGTYPE_p_std__vectorT_std__complexT_double_t_std__allocatorT_std__complexT_double_t_t_t swig_types[188]
+#define SWIGTYPE_p_std__vectorT_std__pairT_double_double_t_std__allocatorT_std__pairT_double_double_t_t_t swig_types[189]
+#define SWIGTYPE_p_std__vectorT_std__string_std__allocatorT_std__string_t_t swig_types[190]
+#define SWIGTYPE_p_std__vectorT_std__vectorT_double_std__allocatorT_double_t_t_std__allocatorT_std__vectorT_double_std__allocatorT_double_t_t_t_t swig_types[191]
+#define SWIGTYPE_p_std__vectorT_std__vectorT_int_std__allocatorT_int_t_t_std__allocatorT_std__vectorT_int_std__allocatorT_int_t_t_t_t swig_types[192]
+#define SWIGTYPE_p_std__vectorT_unsigned_long_std__allocatorT_unsigned_long_t_t swig_types[193]
+#define SWIGTYPE_p_swig__SwigPyIterator swig_types[194]
+#define SWIGTYPE_p_unsigned_char swig_types[195]
+#define SWIGTYPE_p_unsigned_int swig_types[196]
+#define SWIGTYPE_p_unsigned_long_long swig_types[197]
+#define SWIGTYPE_p_unsigned_short swig_types[198]
+#define SWIGTYPE_p_value_type swig_types[199]
+static swig_type_info *swig_types[201];
+static swig_module_info swig_module = {swig_types, 200, 0, 0, 0, 0};
 #define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
 #define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
 
@@ -39217,7 +39216,7 @@ fail:
 SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_83(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
   INodeVisitor *arg1 = (INodeVisitor *) 0 ;
-  ILayout *arg2 = (ILayout *) 0 ;
+  ParticleLayout *arg2 = (ParticleLayout *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
@@ -39229,12 +39228,12 @@ SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_83(PyObject *SWIGUNUSEDPARM(
     SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "INodeVisitor_visit" "', argument " "1"" of type '" "INodeVisitor *""'"); 
   }
   arg1 = reinterpret_cast< INodeVisitor * >(argp1);
-  res2 = SWIG_ConvertPtr(swig_obj[1], &argp2,SWIGTYPE_p_ILayout, 0 |  0 );
+  res2 = SWIG_ConvertPtr(swig_obj[1], &argp2,SWIGTYPE_p_ParticleLayout, 0 |  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "INodeVisitor_visit" "', argument " "2"" of type '" "ILayout const *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "INodeVisitor_visit" "', argument " "2"" of type '" "ParticleLayout const *""'"); 
   }
-  arg2 = reinterpret_cast< ILayout * >(argp2);
-  (arg1)->visit((ILayout const *)arg2);
+  arg2 = reinterpret_cast< ParticleLayout * >(argp2);
+  (arg1)->visit((ParticleLayout const *)arg2);
   resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
@@ -40027,34 +40026,6 @@ fail:
 
 
 SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_112(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
-  PyObject *resultobj = 0;
-  INodeVisitor *arg1 = (INodeVisitor *) 0 ;
-  ParticleLayout *arg2 = (ParticleLayout *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
-  
-  if ((nobjs < 2) || (nobjs > 2)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_INodeVisitor, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "INodeVisitor_visit" "', argument " "1"" of type '" "INodeVisitor *""'"); 
-  }
-  arg1 = reinterpret_cast< INodeVisitor * >(argp1);
-  res2 = SWIG_ConvertPtr(swig_obj[1], &argp2,SWIGTYPE_p_ParticleLayout, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "INodeVisitor_visit" "', argument " "2"" of type '" "ParticleLayout const *""'"); 
-  }
-  arg2 = reinterpret_cast< ParticleLayout * >(argp2);
-  (arg1)->visit((ParticleLayout const *)arg2);
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_113(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
   INodeVisitor *arg1 = (INodeVisitor *) 0 ;
   PoissonNoiseBackground *arg2 = (PoissonNoiseBackground *) 0 ;
@@ -40082,7 +40053,7 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_114(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
+SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_113(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
   INodeVisitor *arg1 = (INodeVisitor *) 0 ;
   RectangularDetector *arg2 = (RectangularDetector *) 0 ;
@@ -40110,7 +40081,7 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_115(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
+SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_114(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
   INodeVisitor *arg1 = (INodeVisitor *) 0 ;
   ResolutionFunction2DGaussian *arg2 = (ResolutionFunction2DGaussian *) 0 ;
@@ -40138,7 +40109,7 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_116(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
+SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_115(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
   INodeVisitor *arg1 = (INodeVisitor *) 0 ;
   RotationEuler *arg2 = (RotationEuler *) 0 ;
@@ -40166,7 +40137,7 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_117(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
+SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_116(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
   INodeVisitor *arg1 = (INodeVisitor *) 0 ;
   RotationX *arg2 = (RotationX *) 0 ;
@@ -40194,7 +40165,7 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_118(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
+SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_117(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
   INodeVisitor *arg1 = (INodeVisitor *) 0 ;
   RotationY *arg2 = (RotationY *) 0 ;
@@ -40222,7 +40193,7 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_119(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
+SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_118(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
   INodeVisitor *arg1 = (INodeVisitor *) 0 ;
   RotationZ *arg2 = (RotationZ *) 0 ;
@@ -40250,7 +40221,7 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_120(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
+SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_119(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
   INodeVisitor *arg1 = (INodeVisitor *) 0 ;
   SpecularDetector1D *arg2 = (SpecularDetector1D *) 0 ;
@@ -40278,7 +40249,7 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_121(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
+SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_120(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
   INodeVisitor *arg1 = (INodeVisitor *) 0 ;
   SpecularSimulation *arg2 = (SpecularSimulation *) 0 ;
@@ -40306,7 +40277,7 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_122(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
+SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_121(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
   INodeVisitor *arg1 = (INodeVisitor *) 0 ;
   SphericalDetector *arg2 = (SphericalDetector *) 0 ;
@@ -40334,7 +40305,7 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_123(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
+SWIGINTERN PyObject *_wrap_INodeVisitor_visit__SWIG_122(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
   INodeVisitor *arg1 = (INodeVisitor *) 0 ;
   SquareLattice *arg2 = (SquareLattice *) 0 ;
@@ -41539,7 +41510,7 @@ SWIGINTERN PyObject *_wrap_INodeVisitor_visit(PyObject *self, PyObject *args) {
     _v = SWIG_CheckState(res);
     if (_v) {
       void *vptr = 0;
-      int res = SWIG_ConvertPtr(argv[1], &vptr, SWIGTYPE_p_ILayout, 0);
+      int res = SWIG_ConvertPtr(argv[1], &vptr, SWIGTYPE_p_ParticleLayout, 0);
       _v = SWIG_CheckState(res);
       if (_v) {
         return _wrap_INodeVisitor_visit__SWIG_83(self, argc, argv);
@@ -41938,20 +41909,6 @@ SWIGINTERN PyObject *_wrap_INodeVisitor_visit(PyObject *self, PyObject *args) {
       }
     }
   }
-  if (argc == 2) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_INodeVisitor, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      void *vptr = 0;
-      int res = SWIG_ConvertPtr(argv[1], &vptr, SWIGTYPE_p_ParticleLayout, 0);
-      _v = SWIG_CheckState(res);
-      if (_v) {
-        return _wrap_INodeVisitor_visit__SWIG_112(self, argc, argv);
-      }
-    }
-  }
   if (argc == 2) {
     int _v;
     void *vptr = 0;
@@ -41962,7 +41919,7 @@ SWIGINTERN PyObject *_wrap_INodeVisitor_visit(PyObject *self, PyObject *args) {
       int res = SWIG_ConvertPtr(argv[1], &vptr, SWIGTYPE_p_PoissonNoiseBackground, 0);
       _v = SWIG_CheckState(res);
       if (_v) {
-        return _wrap_INodeVisitor_visit__SWIG_113(self, argc, argv);
+        return _wrap_INodeVisitor_visit__SWIG_112(self, argc, argv);
       }
     }
   }
@@ -41976,7 +41933,7 @@ SWIGINTERN PyObject *_wrap_INodeVisitor_visit(PyObject *self, PyObject *args) {
       int res = SWIG_ConvertPtr(argv[1], &vptr, SWIGTYPE_p_RectangularDetector, 0);
       _v = SWIG_CheckState(res);
       if (_v) {
-        return _wrap_INodeVisitor_visit__SWIG_114(self, argc, argv);
+        return _wrap_INodeVisitor_visit__SWIG_113(self, argc, argv);
       }
     }
   }
@@ -41990,7 +41947,7 @@ SWIGINTERN PyObject *_wrap_INodeVisitor_visit(PyObject *self, PyObject *args) {
       int res = SWIG_ConvertPtr(argv[1], &vptr, SWIGTYPE_p_ResolutionFunction2DGaussian, 0);
       _v = SWIG_CheckState(res);
       if (_v) {
-        return _wrap_INodeVisitor_visit__SWIG_115(self, argc, argv);
+        return _wrap_INodeVisitor_visit__SWIG_114(self, argc, argv);
       }
     }
   }
@@ -42004,7 +41961,7 @@ SWIGINTERN PyObject *_wrap_INodeVisitor_visit(PyObject *self, PyObject *args) {
       int res = SWIG_ConvertPtr(argv[1], &vptr, SWIGTYPE_p_RotationEuler, 0);
       _v = SWIG_CheckState(res);
       if (_v) {
-        return _wrap_INodeVisitor_visit__SWIG_116(self, argc, argv);
+        return _wrap_INodeVisitor_visit__SWIG_115(self, argc, argv);
       }
     }
   }
@@ -42018,7 +41975,7 @@ SWIGINTERN PyObject *_wrap_INodeVisitor_visit(PyObject *self, PyObject *args) {
       int res = SWIG_ConvertPtr(argv[1], &vptr, SWIGTYPE_p_RotationX, 0);
       _v = SWIG_CheckState(res);
       if (_v) {
-        return _wrap_INodeVisitor_visit__SWIG_117(self, argc, argv);
+        return _wrap_INodeVisitor_visit__SWIG_116(self, argc, argv);
       }
     }
   }
@@ -42032,7 +41989,7 @@ SWIGINTERN PyObject *_wrap_INodeVisitor_visit(PyObject *self, PyObject *args) {
       int res = SWIG_ConvertPtr(argv[1], &vptr, SWIGTYPE_p_RotationY, 0);
       _v = SWIG_CheckState(res);
       if (_v) {
-        return _wrap_INodeVisitor_visit__SWIG_118(self, argc, argv);
+        return _wrap_INodeVisitor_visit__SWIG_117(self, argc, argv);
       }
     }
   }
@@ -42046,7 +42003,7 @@ SWIGINTERN PyObject *_wrap_INodeVisitor_visit(PyObject *self, PyObject *args) {
       int res = SWIG_ConvertPtr(argv[1], &vptr, SWIGTYPE_p_RotationZ, 0);
       _v = SWIG_CheckState(res);
       if (_v) {
-        return _wrap_INodeVisitor_visit__SWIG_119(self, argc, argv);
+        return _wrap_INodeVisitor_visit__SWIG_118(self, argc, argv);
       }
     }
   }
@@ -42060,7 +42017,7 @@ SWIGINTERN PyObject *_wrap_INodeVisitor_visit(PyObject *self, PyObject *args) {
       int res = SWIG_ConvertPtr(argv[1], &vptr, SWIGTYPE_p_SpecularDetector1D, 0);
       _v = SWIG_CheckState(res);
       if (_v) {
-        return _wrap_INodeVisitor_visit__SWIG_120(self, argc, argv);
+        return _wrap_INodeVisitor_visit__SWIG_119(self, argc, argv);
       }
     }
   }
@@ -42074,7 +42031,7 @@ SWIGINTERN PyObject *_wrap_INodeVisitor_visit(PyObject *self, PyObject *args) {
       int res = SWIG_ConvertPtr(argv[1], &vptr, SWIGTYPE_p_SpecularSimulation, 0);
       _v = SWIG_CheckState(res);
       if (_v) {
-        return _wrap_INodeVisitor_visit__SWIG_121(self, argc, argv);
+        return _wrap_INodeVisitor_visit__SWIG_120(self, argc, argv);
       }
     }
   }
@@ -42088,7 +42045,7 @@ SWIGINTERN PyObject *_wrap_INodeVisitor_visit(PyObject *self, PyObject *args) {
       int res = SWIG_ConvertPtr(argv[1], &vptr, SWIGTYPE_p_SphericalDetector, 0);
       _v = SWIG_CheckState(res);
       if (_v) {
-        return _wrap_INodeVisitor_visit__SWIG_122(self, argc, argv);
+        return _wrap_INodeVisitor_visit__SWIG_121(self, argc, argv);
       }
     }
   }
@@ -42102,7 +42059,7 @@ SWIGINTERN PyObject *_wrap_INodeVisitor_visit(PyObject *self, PyObject *args) {
       int res = SWIG_ConvertPtr(argv[1], &vptr, SWIGTYPE_p_SquareLattice, 0);
       _v = SWIG_CheckState(res);
       if (_v) {
-        return _wrap_INodeVisitor_visit__SWIG_123(self, argc, argv);
+        return _wrap_INodeVisitor_visit__SWIG_122(self, argc, argv);
       }
     }
   }
@@ -42193,7 +42150,7 @@ fail:
     "    INodeVisitor::visit(IFormFactorBorn const *)\n"
     "    INodeVisitor::visit(IFormFactorDecorator const *)\n"
     "    INodeVisitor::visit(IInterferenceFunction const *)\n"
-    "    INodeVisitor::visit(ILayout const *)\n"
+    "    INodeVisitor::visit(ParticleLayout const *)\n"
     "    INodeVisitor::visit(INode const *)\n"
     "    INodeVisitor::visit(Instrument const *)\n"
     "    INodeVisitor::visit(InterferenceFunction1DLattice const *)\n"
@@ -42222,7 +42179,6 @@ fail:
     "    INodeVisitor::visit(ParticleComposition const *)\n"
     "    INodeVisitor::visit(ParticleCoreShell const *)\n"
     "    INodeVisitor::visit(ParticleDistribution const *)\n"
-    "    INodeVisitor::visit(ParticleLayout const *)\n"
     "    INodeVisitor::visit(PoissonNoiseBackground const *)\n"
     "    INodeVisitor::visit(RectangularDetector const *)\n"
     "    INodeVisitor::visit(ResolutionFunction2DGaussian const *)\n"
@@ -51274,7 +51230,7 @@ static PyMethodDef SwigMethods[] = {
 		"INodeVisitor_visit(INodeVisitor self, IFormFactorBorn const * arg2)\n"
 		"INodeVisitor_visit(INodeVisitor self, IFormFactorDecorator const * arg2)\n"
 		"INodeVisitor_visit(INodeVisitor self, IInterferenceFunction const * arg2)\n"
-		"INodeVisitor_visit(INodeVisitor self, ILayout const * arg2)\n"
+		"INodeVisitor_visit(INodeVisitor self, ParticleLayout const * arg2)\n"
 		"INodeVisitor_visit(INodeVisitor self, INode arg2)\n"
 		"INodeVisitor_visit(INodeVisitor self, Instrument const * arg2)\n"
 		"INodeVisitor_visit(INodeVisitor self, InterferenceFunction1DLattice const * arg2)\n"
@@ -51303,7 +51259,6 @@ static PyMethodDef SwigMethods[] = {
 		"INodeVisitor_visit(INodeVisitor self, ParticleComposition const * arg2)\n"
 		"INodeVisitor_visit(INodeVisitor self, ParticleCoreShell const * arg2)\n"
 		"INodeVisitor_visit(INodeVisitor self, ParticleDistribution const * arg2)\n"
-		"INodeVisitor_visit(INodeVisitor self, ParticleLayout const * arg2)\n"
 		"INodeVisitor_visit(INodeVisitor self, PoissonNoiseBackground const * arg2)\n"
 		"INodeVisitor_visit(INodeVisitor self, RectangularDetector const * arg2)\n"
 		"INodeVisitor_visit(INodeVisitor self, ResolutionFunction2DGaussian const * arg2)\n"
@@ -52236,7 +52191,6 @@ static swig_type_info _swigt__p_IFormFactor = {"_p_IFormFactor", "IFormFactor *"
 static swig_type_info _swigt__p_IFormFactorBorn = {"_p_IFormFactorBorn", "IFormFactorBorn *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_IFormFactorDecorator = {"_p_IFormFactorDecorator", "IFormFactorDecorator *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_IInterferenceFunction = {"_p_IInterferenceFunction", "IInterferenceFunction *", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_ILayout = {"_p_ILayout", "ILayout *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_INode = {"_p_INode", "INode *|std::vector< INode * >::value_type|std::vector< INode const * >::value_type", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_INodeVisitor = {"_p_INodeVisitor", "INodeVisitor *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_IParameterT_double_t = {"_p_IParameterT_double_t", "IParameter< double > *", 0, 0, (void*)0, 0};
@@ -52439,7 +52393,6 @@ static swig_type_info *swig_type_initial[] = {
   &_swigt__p_IFormFactorBorn,
   &_swigt__p_IFormFactorDecorator,
   &_swigt__p_IInterferenceFunction,
-  &_swigt__p_ILayout,
   &_swigt__p_INode,
   &_swigt__p_INodeVisitor,
   &_swigt__p_IParameterT_double_t,
@@ -52642,7 +52595,6 @@ static swig_cast_info _swigc__p_IFormFactor[] = {  {&_swigt__p_IFormFactor, 0, 0
 static swig_cast_info _swigc__p_IFormFactorBorn[] = {  {&_swigt__p_IFormFactorBorn, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_IFormFactorDecorator[] = {  {&_swigt__p_IFormFactorDecorator, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_IInterferenceFunction[] = {  {&_swigt__p_IInterferenceFunction, 0, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_ILayout[] = {  {&_swigt__p_ILayout, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_INode[] = {  {&_swigt__p_INode, 0, 0, 0},  {&_swigt__p_DistributionCosine, _p_DistributionCosineTo_p_INode, 0, 0},  {&_swigt__p_DistributionLorentz, _p_DistributionLorentzTo_p_INode, 0, 0},  {&_swigt__p_DistributionGaussian, _p_DistributionGaussianTo_p_INode, 0, 0},  {&_swigt__p_IDistribution1D, _p_IDistribution1DTo_p_INode, 0, 0},  {&_swigt__p_DistributionGate, _p_DistributionGateTo_p_INode, 0, 0},  {&_swigt__p_DistributionTrapezoid, _p_DistributionTrapezoidTo_p_INode, 0, 0},  {&_swigt__p_DistributionLogNormal, _p_DistributionLogNormalTo_p_INode, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_INodeVisitor[] = {  {&_swigt__p_INodeVisitor, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_IParameterT_double_t[] = {  {&_swigt__p_IParameterT_double_t, 0, 0, 0},  {&_swigt__p_RealParameter, _p_RealParameterTo_p_IParameterT_double_t, 0, 0},{0, 0, 0, 0}};
@@ -52845,7 +52797,6 @@ static swig_cast_info *swig_cast_initial[] = {
   _swigc__p_IFormFactorBorn,
   _swigc__p_IFormFactorDecorator,
   _swigc__p_IInterferenceFunction,
-  _swigc__p_ILayout,
   _swigc__p_INode,
   _swigc__p_INodeVisitor,
   _swigc__p_IParameterT_double_t,
diff --git a/auto/Wrap/libBornAgainSample.py b/auto/Wrap/libBornAgainSample.py
index 697a6fd0aba96c9639ebc86253b405b0c74ff293..a2d99c80baa8328bb5576bd3903270acce4682ae 100644
--- a/auto/Wrap/libBornAgainSample.py
+++ b/auto/Wrap/libBornAgainSample.py
@@ -4056,8 +4056,8 @@ class FormFactorCrystal(IFormFactor):
 
     def __init__(self, lattice, basis_form_factor, meso_form_factor, position_variance=0.0):
         r"""
-        __init__(FormFactorCrystal self, Lattice lattice, IFormFactor basis_form_factor, IFormFactor meso_form_factor, double position_variance=0.0) -> FormFactorCrystal
-        FormFactorCrystal::FormFactorCrystal(const Lattice &lattice, const IFormFactor &basis_form_factor, const IFormFactor &meso_form_factor, double position_variance=0.0)
+        __init__(FormFactorCrystal self, Lattice3D lattice, IFormFactor basis_form_factor, IFormFactor meso_form_factor, double position_variance=0.0) -> FormFactorCrystal
+        FormFactorCrystal::FormFactorCrystal(const Lattice3D &lattice, const IFormFactor &basis_form_factor, const IFormFactor &meso_form_factor, double position_variance=0.0)
 
         """
         _libBornAgainSample.FormFactorCrystal_swiginit(self, _libBornAgainSample.new_FormFactorCrystal(lattice, basis_form_factor, meso_form_factor, position_variance))
@@ -4331,61 +4331,17 @@ class IAbstractParticle(ISample):
 # Register IAbstractParticle in _libBornAgainSample:
 _libBornAgainSample.IAbstractParticle_swigregister(IAbstractParticle)
 
-class IClusteredParticles(ISample):
+class Crystal(ISample):
     r"""
 
 
-    An ordered assembly of particles. Currently, the only child class is  Crystal.
+    A crystal structure, defined by a Bravais lattice, a basis, and a position variance.
 
-    C++ includes: IClusteredParticles.h
+    The basis is either a  Particle or a  ParticleComposition.
 
-    """
-
-    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
-
-    def __init__(self, *args, **kwargs):
-        raise AttributeError("No constructor defined - class is abstract")
-    __repr__ = _swig_repr
-
-    def clone(self):
-        r"""
-        clone(IClusteredParticles self) -> IClusteredParticles
-        IClusteredParticles* IClusteredParticles::clone() const override=0
-
-        Returns a clone of this  ISample object. 
-
-        """
-        return _libBornAgainSample.IClusteredParticles_clone(self)
+    Computations are delegated to class  FormFactorCrystal.
 
-    def createTotalFormFactor(self, arg2, arg3, arg4):
-        r"""
-        createTotalFormFactor(IClusteredParticles self, IFormFactor arg2, IRotation arg3, kvector_t arg4) -> IFormFactor
-        virtual IFormFactor* IClusteredParticles::createTotalFormFactor(const IFormFactor &, const IRotation *, const kvector_t &) const =0
-
-        Creates a total form factor for the mesocrystal with a specific shape and content The bulk content of the mesocrystal is encapsulated by the  IClusteredParticles object itself 
-
-        """
-        return _libBornAgainSample.IClusteredParticles_createTotalFormFactor(self, arg2, arg3, arg4)
-
-    def homogeneousRegions(self):
-        r"""
-        homogeneousRegions(IClusteredParticles self) -> std::vector< HomogeneousRegion,std::allocator< HomogeneousRegion > >
-        virtual std::vector<HomogeneousRegion> IClusteredParticles::homogeneousRegions() const =0
-
-        Creates region information with volumetric densities instead of absolute volume These densities need to be multiplied by the total mesocrystal volume 
-
-        """
-        return _libBornAgainSample.IClusteredParticles_homogeneousRegions(self)
-    __swig_destroy__ = _libBornAgainSample.delete_IClusteredParticles
-
-# Register IClusteredParticles in _libBornAgainSample:
-_libBornAgainSample.IClusteredParticles_swigregister(IClusteredParticles)
-
-class Crystal(IClusteredParticles):
-    r"""
-
-
-    A crystal structure with a  ParticleComposition as a basis. Used in  MesoCrystal, where it is given an outer shape.
+    Used in  MesoCrystal, where it is given an outer shape.
 
     C++ includes: Crystal.h
 
@@ -4394,13 +4350,13 @@ class Crystal(IClusteredParticles):
     thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
     __repr__ = _swig_repr
 
-    def __init__(self, lattice_basis, lattice):
+    def __init__(self, basis, lattice, position_variance=0):
         r"""
-        __init__(Crystal self, IParticle lattice_basis, Lattice lattice) -> Crystal
-        Crystal::Crystal(const IParticle &lattice_basis, const Lattice &lattice)
+        __init__(Crystal self, IParticle basis, Lattice3D lattice, double position_variance=0) -> Crystal
+        Crystal::Crystal(const IParticle &basis, const Lattice3D &lattice, double position_variance=0)
 
         """
-        _libBornAgainSample.Crystal_swiginit(self, _libBornAgainSample.new_Crystal(lattice_basis, lattice))
+        _libBornAgainSample.Crystal_swiginit(self, _libBornAgainSample.new_Crystal(basis, lattice, position_variance))
     __swig_destroy__ = _libBornAgainSample.delete_Crystal
 
     def clone(self):
@@ -4424,9 +4380,7 @@ class Crystal(IClusteredParticles):
     def createTotalFormFactor(self, meso_crystal_form_factor, p_rotation, translation):
         r"""
         createTotalFormFactor(Crystal self, IFormFactor meso_crystal_form_factor, IRotation p_rotation, kvector_t translation) -> IFormFactor
-        IFormFactor * Crystal::createTotalFormFactor(const IFormFactor &meso_crystal_form_factor, const IRotation *p_rotation, const kvector_t &translation) const override final
-
-        Creates a total form factor for the mesocrystal with a specific shape and content The bulk content of the mesocrystal is encapsulated by the  IClusteredParticles object itself 
+        IFormFactor * Crystal::createTotalFormFactor(const IFormFactor &meso_crystal_form_factor, const IRotation *p_rotation, const kvector_t &translation) const
 
         """
         return _libBornAgainSample.Crystal_createTotalFormFactor(self, meso_crystal_form_factor, p_rotation, translation)
@@ -4434,29 +4388,19 @@ class Crystal(IClusteredParticles):
     def homogeneousRegions(self):
         r"""
         homogeneousRegions(Crystal self) -> std::vector< HomogeneousRegion,std::allocator< HomogeneousRegion > >
-        std::vector< HomogeneousRegion > Crystal::homogeneousRegions() const override final
-
-        Creates region information with volumetric densities instead of absolute volume These densities need to be multiplied by the total mesocrystal volume 
+        std::vector< HomogeneousRegion > Crystal::homogeneousRegions() const
 
         """
         return _libBornAgainSample.Crystal_homogeneousRegions(self)
 
     def transformedLattice(self, p_rotation=None):
         r"""
-        transformedLattice(Crystal self, IRotation p_rotation=None) -> Lattice
-        Lattice Crystal::transformedLattice(const IRotation *p_rotation=nullptr) const
+        transformedLattice(Crystal self, IRotation p_rotation=None) -> Lattice3D
+        Lattice3D Crystal::transformedLattice(const IRotation *p_rotation=nullptr) const
 
         """
         return _libBornAgainSample.Crystal_transformedLattice(self, p_rotation)
 
-    def setPositionVariance(self, position_variance):
-        r"""
-        setPositionVariance(Crystal self, double position_variance)
-        void Crystal::setPositionVariance(double position_variance)
-
-        """
-        return _libBornAgainSample.Crystal_setPositionVariance(self, position_variance)
-
     def getChildren(self):
         r"""
         getChildren(Crystal self) -> swig_dummy_type_const_inode_vector
@@ -4652,8 +4596,8 @@ class MesoCrystal(IParticle):
 
     def __init__(self, particle_structure, form_factor):
         r"""
-        __init__(MesoCrystal self, IClusteredParticles particle_structure, IFormFactor form_factor) -> MesoCrystal
-        MesoCrystal::MesoCrystal(const IClusteredParticles &particle_structure, const IFormFactor &form_factor)
+        __init__(MesoCrystal self, Crystal particle_structure, IFormFactor form_factor) -> MesoCrystal
+        MesoCrystal::MesoCrystal(const Crystal &particle_structure, const IFormFactor &form_factor)
 
         """
         _libBornAgainSample.MesoCrystal_swiginit(self, _libBornAgainSample.new_MesoCrystal(particle_structure, form_factor))
@@ -6357,114 +6301,6 @@ class FTDistribution2DVoigt(IFTDistribution2D):
 # Register FTDistribution2DVoigt in _libBornAgainSample:
 _libBornAgainSample.FTDistribution2DVoigt_swigregister(FTDistribution2DVoigt)
 
-class ILayout(ISample):
-    r"""
-
-
-    Pure virtual interface class to equip a sample layer with scattering properties. Currently only inherited by  ParticleLayout; in the future also by domain structure.
-
-    C++ includes: ILayout.h
-
-    """
-
-    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
-
-    def __init__(self, *args, **kwargs):
-        raise AttributeError("No constructor defined - class is abstract")
-    __repr__ = _swig_repr
-    __swig_destroy__ = _libBornAgainSample.delete_ILayout
-
-    def clone(self):
-        r"""
-        clone(ILayout self) -> ILayout
-        virtual ILayout* ILayout::clone() const =0
-
-        Returns a clone of this  ISample object. 
-
-        """
-        return _libBornAgainSample.ILayout_clone(self)
-
-    def accept(self, visitor):
-        r"""
-        accept(ILayout self, INodeVisitor * visitor)
-        virtual void ILayout::accept(INodeVisitor *visitor) const =0
-
-        """
-        return _libBornAgainSample.ILayout_accept(self, visitor)
-
-    def particles(self):
-        r"""
-        particles(ILayout self) -> SafePointerVector< IParticle >
-        virtual SafePointerVector<IParticle> ILayout::particles() const =0
-
-        Returns information on all particles (type and abundance) and generates new particles if an  IAbstractParticle denotes a collection 
-
-        """
-        return _libBornAgainSample.ILayout_particles(self)
-
-    def interferenceFunction(self):
-        r"""
-        interferenceFunction(ILayout self) -> IInterferenceFunction
-        virtual const IInterferenceFunction* ILayout::interferenceFunction() const =0
-
-        Returns the interference function. 
-
-        """
-        return _libBornAgainSample.ILayout_interferenceFunction(self)
-
-    def getTotalAbundance(self):
-        r"""
-        getTotalAbundance(ILayout self) -> double
-        virtual double ILayout::getTotalAbundance() const =0
-
-        Get total abundance of all particles. 
-
-        """
-        return _libBornAgainSample.ILayout_getTotalAbundance(self)
-
-    def totalParticleSurfaceDensity(self):
-        r"""
-        totalParticleSurfaceDensity(ILayout self) -> double
-        virtual double ILayout::totalParticleSurfaceDensity() const =0
-
-        Returns surface density of all particles. 
-
-        """
-        return _libBornAgainSample.ILayout_totalParticleSurfaceDensity(self)
-
-    def setTotalParticleSurfaceDensity(self, particle_density):
-        r"""
-        setTotalParticleSurfaceDensity(ILayout self, double particle_density)
-        virtual void ILayout::setTotalParticleSurfaceDensity(double particle_density)=0
-
-        Sets surface density of all particles. 
-
-        """
-        return _libBornAgainSample.ILayout_setTotalParticleSurfaceDensity(self, particle_density)
-
-    def weight(self):
-        r"""
-        weight(ILayout self) -> double
-        double ILayout::weight() const
-
-        Returns the relative weight of this layout. 
-
-        """
-        return _libBornAgainSample.ILayout_weight(self)
-
-    def setWeight(self, weight):
-        r"""
-        setWeight(ILayout self, double weight)
-        void ILayout::setWeight(double weight)
-
-        Sets the relative weight of this layout. 
-
-        """
-        return _libBornAgainSample.ILayout_setWeight(self, weight)
-
-# Register ILayout in _libBornAgainSample:
-_libBornAgainSample.ILayout_swigregister(ILayout)
-
 class IPeakShape(ISample):
     r"""
 
@@ -7098,16 +6934,6 @@ class InterferenceFunction2DLattice(IInterferenceFunction):
         """
         return _libBornAgainSample.InterferenceFunction2DLattice_accept(self, visitor)
 
-    @staticmethod
-    def createSquare(lattice_length, xi):
-        r"""createSquare(double lattice_length, double xi) -> InterferenceFunction2DLattice"""
-        return _libBornAgainSample.InterferenceFunction2DLattice_createSquare(lattice_length, xi)
-
-    @staticmethod
-    def createHexagonal(lattice_length, xi):
-        r"""createHexagonal(double lattice_length, double xi) -> InterferenceFunction2DLattice"""
-        return _libBornAgainSample.InterferenceFunction2DLattice_createHexagonal(lattice_length, xi)
-
     def setDecayFunction(self, decay):
         r"""
         setDecayFunction(InterferenceFunction2DLattice self, IFTDecayFunction2D decay)
@@ -7177,14 +7003,6 @@ class InterferenceFunction2DLattice(IInterferenceFunction):
 # Register InterferenceFunction2DLattice in _libBornAgainSample:
 _libBornAgainSample.InterferenceFunction2DLattice_swigregister(InterferenceFunction2DLattice)
 
-def InterferenceFunction2DLattice_createSquare(lattice_length, xi):
-    r"""InterferenceFunction2DLattice_createSquare(double lattice_length, double xi) -> InterferenceFunction2DLattice"""
-    return _libBornAgainSample.InterferenceFunction2DLattice_createSquare(lattice_length, xi)
-
-def InterferenceFunction2DLattice_createHexagonal(lattice_length, xi):
-    r"""InterferenceFunction2DLattice_createHexagonal(double lattice_length, double xi) -> InterferenceFunction2DLattice"""
-    return _libBornAgainSample.InterferenceFunction2DLattice_createHexagonal(lattice_length, xi)
-
 class InterferenceFunction2DParaCrystal(IInterferenceFunction):
     r"""
 
@@ -7246,16 +7064,6 @@ class InterferenceFunction2DParaCrystal(IInterferenceFunction):
         """
         return _libBornAgainSample.InterferenceFunction2DParaCrystal_accept(self, visitor)
 
-    @staticmethod
-    def createSquare(lattice_length, damping_length, domain_size_1, domain_size_2):
-        r"""createSquare(double lattice_length, double damping_length, double domain_size_1, double domain_size_2) -> InterferenceFunction2DParaCrystal"""
-        return _libBornAgainSample.InterferenceFunction2DParaCrystal_createSquare(lattice_length, damping_length, domain_size_1, domain_size_2)
-
-    @staticmethod
-    def createHexagonal(lattice_length, damping_length, domain_size_1, domain_size_2):
-        r"""createHexagonal(double lattice_length, double damping_length, double domain_size_1, double domain_size_2) -> InterferenceFunction2DParaCrystal"""
-        return _libBornAgainSample.InterferenceFunction2DParaCrystal_createHexagonal(lattice_length, damping_length, domain_size_1, domain_size_2)
-
     def setDomainSizes(self, size_1, size_2):
         r"""
         setDomainSizes(InterferenceFunction2DParaCrystal self, double size_1, double size_2)
@@ -7395,14 +7203,6 @@ class InterferenceFunction2DParaCrystal(IInterferenceFunction):
 # Register InterferenceFunction2DParaCrystal in _libBornAgainSample:
 _libBornAgainSample.InterferenceFunction2DParaCrystal_swigregister(InterferenceFunction2DParaCrystal)
 
-def InterferenceFunction2DParaCrystal_createSquare(lattice_length, damping_length, domain_size_1, domain_size_2):
-    r"""InterferenceFunction2DParaCrystal_createSquare(double lattice_length, double damping_length, double domain_size_1, double domain_size_2) -> InterferenceFunction2DParaCrystal"""
-    return _libBornAgainSample.InterferenceFunction2DParaCrystal_createSquare(lattice_length, damping_length, domain_size_1, domain_size_2)
-
-def InterferenceFunction2DParaCrystal_createHexagonal(lattice_length, damping_length, domain_size_1, domain_size_2):
-    r"""InterferenceFunction2DParaCrystal_createHexagonal(double lattice_length, double damping_length, double domain_size_1, double domain_size_2) -> InterferenceFunction2DParaCrystal"""
-    return _libBornAgainSample.InterferenceFunction2DParaCrystal_createHexagonal(lattice_length, damping_length, domain_size_1, domain_size_2)
-
 class InterferenceFunction2DSuperLattice(IInterferenceFunction):
     r"""
 
@@ -7483,16 +7283,6 @@ class InterferenceFunction2DSuperLattice(IInterferenceFunction):
         """
         return _libBornAgainSample.InterferenceFunction2DSuperLattice_substructureIFF(self)
 
-    @staticmethod
-    def createSquare(lattice_length, xi, size_1, size_2):
-        r"""createSquare(double lattice_length, double xi, unsigned int size_1, unsigned int size_2) -> InterferenceFunction2DSuperLattice"""
-        return _libBornAgainSample.InterferenceFunction2DSuperLattice_createSquare(lattice_length, xi, size_1, size_2)
-
-    @staticmethod
-    def createHexagonal(lattice_length, xi, size_1, size_2):
-        r"""createHexagonal(double lattice_length, double xi, unsigned int size_1, unsigned int size_2) -> InterferenceFunction2DSuperLattice"""
-        return _libBornAgainSample.InterferenceFunction2DSuperLattice_createHexagonal(lattice_length, xi, size_1, size_2)
-
     def evaluate(self, q, outer_iff=1.0):
         r"""
         evaluate(InterferenceFunction2DSuperLattice self, kvector_t q, double outer_iff=1.0) -> double
@@ -7554,14 +7344,6 @@ class InterferenceFunction2DSuperLattice(IInterferenceFunction):
 # Register InterferenceFunction2DSuperLattice in _libBornAgainSample:
 _libBornAgainSample.InterferenceFunction2DSuperLattice_swigregister(InterferenceFunction2DSuperLattice)
 
-def InterferenceFunction2DSuperLattice_createSquare(lattice_length, xi, size_1, size_2):
-    r"""InterferenceFunction2DSuperLattice_createSquare(double lattice_length, double xi, unsigned int size_1, unsigned int size_2) -> InterferenceFunction2DSuperLattice"""
-    return _libBornAgainSample.InterferenceFunction2DSuperLattice_createSquare(lattice_length, xi, size_1, size_2)
-
-def InterferenceFunction2DSuperLattice_createHexagonal(lattice_length, xi, size_1, size_2):
-    r"""InterferenceFunction2DSuperLattice_createHexagonal(double lattice_length, double xi, unsigned int size_1, unsigned int size_2) -> InterferenceFunction2DSuperLattice"""
-    return _libBornAgainSample.InterferenceFunction2DSuperLattice_createHexagonal(lattice_length, xi, size_1, size_2)
-
 class InterferenceFunction3DLattice(IInterferenceFunction):
     r"""
 
@@ -7577,8 +7359,8 @@ class InterferenceFunction3DLattice(IInterferenceFunction):
 
     def __init__(self, lattice):
         r"""
-        __init__(InterferenceFunction3DLattice self, Lattice lattice) -> InterferenceFunction3DLattice
-        InterferenceFunction3DLattice::InterferenceFunction3DLattice(const Lattice &lattice)
+        __init__(InterferenceFunction3DLattice self, Lattice3D lattice) -> InterferenceFunction3DLattice
+        InterferenceFunction3DLattice::InterferenceFunction3DLattice(const Lattice3D &lattice)
 
         """
         _libBornAgainSample.InterferenceFunction3DLattice_swiginit(self, _libBornAgainSample.new_InterferenceFunction3DLattice(lattice))
@@ -7612,8 +7394,8 @@ class InterferenceFunction3DLattice(IInterferenceFunction):
 
     def lattice(self):
         r"""
-        lattice(InterferenceFunction3DLattice self) -> Lattice
-        const Lattice & InterferenceFunction3DLattice::lattice() const
+        lattice(InterferenceFunction3DLattice self) -> Lattice3D
+        const Lattice3D & InterferenceFunction3DLattice::lattice() const
 
         """
         return _libBornAgainSample.InterferenceFunction3DLattice_lattice(self)
@@ -7711,16 +7493,6 @@ class InterferenceFunctionFinite2DLattice(IInterferenceFunction):
         """
         return _libBornAgainSample.InterferenceFunctionFinite2DLattice_accept(self, visitor)
 
-    @staticmethod
-    def createSquare(lattice_length, xi, N_1, N_2):
-        r"""createSquare(double lattice_length, double xi, unsigned int N_1, unsigned int N_2) -> InterferenceFunctionFinite2DLattice"""
-        return _libBornAgainSample.InterferenceFunctionFinite2DLattice_createSquare(lattice_length, xi, N_1, N_2)
-
-    @staticmethod
-    def createHexagonal(lattice_length, xi, N_1, N_2):
-        r"""createHexagonal(double lattice_length, double xi, unsigned int N_1, unsigned int N_2) -> InterferenceFunctionFinite2DLattice"""
-        return _libBornAgainSample.InterferenceFunctionFinite2DLattice_createHexagonal(lattice_length, xi, N_1, N_2)
-
     def numberUnitCells1(self):
         r"""
         numberUnitCells1(InterferenceFunctionFinite2DLattice self) -> unsigned int
@@ -7782,14 +7554,6 @@ class InterferenceFunctionFinite2DLattice(IInterferenceFunction):
 # Register InterferenceFunctionFinite2DLattice in _libBornAgainSample:
 _libBornAgainSample.InterferenceFunctionFinite2DLattice_swigregister(InterferenceFunctionFinite2DLattice)
 
-def InterferenceFunctionFinite2DLattice_createSquare(lattice_length, xi, N_1, N_2):
-    r"""InterferenceFunctionFinite2DLattice_createSquare(double lattice_length, double xi, unsigned int N_1, unsigned int N_2) -> InterferenceFunctionFinite2DLattice"""
-    return _libBornAgainSample.InterferenceFunctionFinite2DLattice_createSquare(lattice_length, xi, N_1, N_2)
-
-def InterferenceFunctionFinite2DLattice_createHexagonal(lattice_length, xi, N_1, N_2):
-    r"""InterferenceFunctionFinite2DLattice_createHexagonal(double lattice_length, double xi, unsigned int N_1, unsigned int N_2) -> InterferenceFunctionFinite2DLattice"""
-    return _libBornAgainSample.InterferenceFunctionFinite2DLattice_createHexagonal(lattice_length, xi, N_1, N_2)
-
 class InterferenceFunctionFinite3DLattice(IInterferenceFunction):
     r"""
 
@@ -7805,8 +7569,8 @@ class InterferenceFunctionFinite3DLattice(IInterferenceFunction):
 
     def __init__(self, lattice, N_1, N_2, N_3):
         r"""
-        __init__(InterferenceFunctionFinite3DLattice self, Lattice lattice, unsigned int N_1, unsigned int N_2, unsigned int N_3) -> InterferenceFunctionFinite3DLattice
-        InterferenceFunctionFinite3DLattice::InterferenceFunctionFinite3DLattice(const Lattice &lattice, unsigned N_1, unsigned N_2, unsigned N_3)
+        __init__(InterferenceFunctionFinite3DLattice self, Lattice3D lattice, unsigned int N_1, unsigned int N_2, unsigned int N_3) -> InterferenceFunctionFinite3DLattice
+        InterferenceFunctionFinite3DLattice::InterferenceFunctionFinite3DLattice(const Lattice3D &lattice, unsigned N_1, unsigned N_2, unsigned N_3)
 
         """
         _libBornAgainSample.InterferenceFunctionFinite3DLattice_swiginit(self, _libBornAgainSample.new_InterferenceFunctionFinite3DLattice(lattice, N_1, N_2, N_3))
@@ -7856,8 +7620,8 @@ class InterferenceFunctionFinite3DLattice(IInterferenceFunction):
 
     def lattice(self):
         r"""
-        lattice(InterferenceFunctionFinite3DLattice self) -> Lattice
-        const Lattice & InterferenceFunctionFinite3DLattice::lattice() const
+        lattice(InterferenceFunctionFinite3DLattice self) -> Lattice3D
+        const Lattice3D & InterferenceFunctionFinite3DLattice::lattice() const
 
         """
         return _libBornAgainSample.InterferenceFunctionFinite3DLattice_lattice(self)
@@ -8216,7 +7980,7 @@ class InterferenceFunctionTwin(IInterferenceFunction):
 # Register InterferenceFunctionTwin in _libBornAgainSample:
 _libBornAgainSample.InterferenceFunctionTwin_swigregister(InterferenceFunctionTwin)
 
-class ParticleLayout(ILayout):
+class ParticleLayout(ISample):
     r"""
 
 
@@ -8242,7 +8006,7 @@ class ParticleLayout(ILayout):
     def clone(self):
         r"""
         clone(ParticleLayout self) -> ParticleLayout
-        ParticleLayout * ParticleLayout::clone() const final override
+        ParticleLayout * ParticleLayout::clone() const override
 
         Returns a clone of this  ISample object. 
 
@@ -8252,7 +8016,7 @@ class ParticleLayout(ILayout):
     def accept(self, visitor):
         r"""
         accept(ParticleLayout self, INodeVisitor * visitor)
-        void ParticleLayout::accept(INodeVisitor *visitor) const final override
+        void ParticleLayout::accept(INodeVisitor *visitor) const override
 
         """
         return _libBornAgainSample.ParticleLayout_accept(self, visitor)
@@ -8285,7 +8049,7 @@ class ParticleLayout(ILayout):
     def particles(self):
         r"""
         particles(ParticleLayout self) -> SafePointerVector< IParticle >
-        SafePointerVector< IParticle > ParticleLayout::particles() const final override
+        SafePointerVector< IParticle > ParticleLayout::particles() const
 
         Returns information on all particles (type and abundance) and generates new particles if an  IAbstractParticle denotes a collection 
 
@@ -8295,9 +8059,7 @@ class ParticleLayout(ILayout):
     def interferenceFunction(self):
         r"""
         interferenceFunction(ParticleLayout self) -> IInterferenceFunction
-        const IInterferenceFunction * ParticleLayout::interferenceFunction() const final override
-
-        Returns the interference function. 
+        const IInterferenceFunction * ParticleLayout::interferenceFunction() const
 
         """
         return _libBornAgainSample.ParticleLayout_interferenceFunction(self)
@@ -8305,9 +8067,7 @@ class ParticleLayout(ILayout):
     def getTotalAbundance(self):
         r"""
         getTotalAbundance(ParticleLayout self) -> double
-        double ParticleLayout::getTotalAbundance() const final override
-
-        Get total abundance of all particles. 
+        double ParticleLayout::getTotalAbundance() const
 
         """
         return _libBornAgainSample.ParticleLayout_getTotalAbundance(self)
@@ -8325,9 +8085,7 @@ class ParticleLayout(ILayout):
     def totalParticleSurfaceDensity(self):
         r"""
         totalParticleSurfaceDensity(ParticleLayout self) -> double
-        double ParticleLayout::totalParticleSurfaceDensity() const final override
-
-        Returns surface density of all particles. 
+        double ParticleLayout::totalParticleSurfaceDensity() const
 
         """
         return _libBornAgainSample.ParticleLayout_totalParticleSurfaceDensity(self)
@@ -8335,7 +8093,7 @@ class ParticleLayout(ILayout):
     def setTotalParticleSurfaceDensity(self, particle_density):
         r"""
         setTotalParticleSurfaceDensity(ParticleLayout self, double particle_density)
-        void ParticleLayout::setTotalParticleSurfaceDensity(double particle_density) final override
+        void ParticleLayout::setTotalParticleSurfaceDensity(double particle_density)
 
         Sets total particle surface density.
 
@@ -8351,11 +8109,31 @@ class ParticleLayout(ILayout):
     def getChildren(self):
         r"""
         getChildren(ParticleLayout self) -> swig_dummy_type_const_inode_vector
-        std::vector< const INode * > ParticleLayout::getChildren() const final override
+        std::vector< const INode * > ParticleLayout::getChildren() const override
 
         """
         return _libBornAgainSample.ParticleLayout_getChildren(self)
 
+    def weight(self):
+        r"""
+        weight(ParticleLayout self) -> double
+        double ParticleLayout::weight() const
+
+        Returns the relative weight of this layout. 
+
+        """
+        return _libBornAgainSample.ParticleLayout_weight(self)
+
+    def setWeight(self, weight):
+        r"""
+        setWeight(ParticleLayout self, double weight)
+        void ParticleLayout::setWeight(double weight)
+
+        Sets the relative weight of this layout. 
+
+        """
+        return _libBornAgainSample.ParticleLayout_setWeight(self, weight)
+
 # Register ParticleLayout in _libBornAgainSample:
 _libBornAgainSample.ParticleLayout_swigregister(ParticleLayout)
 
@@ -8448,8 +8226,8 @@ class Layer(ISample):
 
     def addLayout(self, decoration):
         r"""
-        addLayout(Layer self, ILayout decoration)
-        void Layer::addLayout(const ILayout &decoration)
+        addLayout(Layer self, ParticleLayout decoration)
+        void Layer::addLayout(const ParticleLayout &decoration)
 
         """
         return _libBornAgainSample.Layer_addLayout(self, decoration)
@@ -8464,8 +8242,8 @@ class Layer(ISample):
 
     def layouts(self):
         r"""
-        layouts(Layer self) -> std::vector< ILayout const *,std::allocator< ILayout const * > >
-        std::vector< const ILayout * > Layer::layouts() const
+        layouts(Layer self) -> std::vector< ParticleLayout const *,std::allocator< ParticleLayout const * > >
+        std::vector< const ParticleLayout * > Layer::layouts() const
 
         """
         return _libBornAgainSample.Layer_layouts(self)
@@ -11381,135 +11159,6 @@ class FormFactorSphereLogNormalRadius(IFormFactorBorn):
 # Register FormFactorSphereLogNormalRadius in _libBornAgainSample:
 _libBornAgainSample.FormFactorSphereLogNormalRadius_swigregister(FormFactorSphereLogNormalRadius)
 
-class ILatticeOrientation(object):
-    r"""
-
-
-    Pure virtual base of classes that specify a lattice orientation. Currently only inherited by  MillerIndexOrientation.
-
-    C++ includes: ILatticeOrientation.h
-
-    """
-
-    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
-
-    def __init__(self, *args, **kwargs):
-        raise AttributeError("No constructor defined - class is abstract")
-    __repr__ = _swig_repr
-    __swig_destroy__ = _libBornAgainSample.delete_ILatticeOrientation
-
-    def clone(self):
-        r"""
-        clone(ILatticeOrientation self) -> ILatticeOrientation
-        virtual ILatticeOrientation* ILatticeOrientation::clone() const =0
-
-        """
-        return _libBornAgainSample.ILatticeOrientation_clone(self)
-
-    def usePrimitiveLattice(self, lattice):
-        r"""
-        usePrimitiveLattice(ILatticeOrientation self, Lattice lattice)
-        virtual void ILatticeOrientation::usePrimitiveLattice(const Lattice &lattice)=0
-
-        """
-        return _libBornAgainSample.ILatticeOrientation_usePrimitiveLattice(self, lattice)
-
-    def transformation(self):
-        r"""
-        transformation(ILatticeOrientation self) -> Transform3D
-        virtual Transform3D ILatticeOrientation::transformation() const =0
-
-        """
-        return _libBornAgainSample.ILatticeOrientation_transformation(self)
-
-# Register ILatticeOrientation in _libBornAgainSample:
-_libBornAgainSample.ILatticeOrientation_swigregister(ILatticeOrientation)
-
-class MillerIndex(object):
-    r"""
-
-
-    A direction in reciprocal space, specified by double-valued indices hkl.
-
-    C++ includes: ILatticeOrientation.h
-
-    """
-
-    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
-    __repr__ = _swig_repr
-
-    def __init__(self, h_, k_, l_):
-        r"""
-        __init__(MillerIndex self, double h_, double k_, double l_) -> MillerIndex
-        MillerIndex::MillerIndex(double h_, double k_, double l_)
-
-        """
-        _libBornAgainSample.MillerIndex_swiginit(self, _libBornAgainSample.new_MillerIndex(h_, k_, l_))
-    h = property(_libBornAgainSample.MillerIndex_h_get, _libBornAgainSample.MillerIndex_h_set, doc=r"""h : double""")
-    k = property(_libBornAgainSample.MillerIndex_k_get, _libBornAgainSample.MillerIndex_k_set, doc=r"""k : double""")
-    l = property(_libBornAgainSample.MillerIndex_l_get, _libBornAgainSample.MillerIndex_l_set, doc=r"""l : double""")
-    __swig_destroy__ = _libBornAgainSample.delete_MillerIndex
-
-# Register MillerIndex in _libBornAgainSample:
-_libBornAgainSample.MillerIndex_swigregister(MillerIndex)
-
-class MillerIndexOrientation(ILatticeOrientation):
-    r"""
-
-
-    Specifies a rotation of a lattice through the Miller indices of two coordinate axes.
-
-    C++ includes: ILatticeOrientation.h
-
-    """
-
-    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
-    __repr__ = _swig_repr
-    QX = _libBornAgainSample.MillerIndexOrientation_QX
-    
-    QY = _libBornAgainSample.MillerIndexOrientation_QY
-    
-    QZ = _libBornAgainSample.MillerIndexOrientation_QZ
-    
-
-    def __init__(self, q1, index1, q2, index2):
-        r"""
-        __init__(MillerIndexOrientation self, MillerIndexOrientation::QComponent q1, MillerIndex index1, MillerIndexOrientation::QComponent q2, MillerIndex index2) -> MillerIndexOrientation
-        MillerIndexOrientation::MillerIndexOrientation(QComponent q1, MillerIndex index1, QComponent q2, MillerIndex index2)
-
-        This constructor is best explained by an example. Arguments QX, (1,1,0), QY, (0,2,1) mean: Rotate the lattice such that the axis [110] points into x direction, and the axis [021], projected into the yz plane, points into z direction. 
-
-        """
-        _libBornAgainSample.MillerIndexOrientation_swiginit(self, _libBornAgainSample.new_MillerIndexOrientation(q1, index1, q2, index2))
-    __swig_destroy__ = _libBornAgainSample.delete_MillerIndexOrientation
-
-    def clone(self):
-        r"""
-        clone(MillerIndexOrientation self) -> MillerIndexOrientation
-        MillerIndexOrientation * MillerIndexOrientation::clone() const override
-
-        """
-        return _libBornAgainSample.MillerIndexOrientation_clone(self)
-
-    def usePrimitiveLattice(self, lattice):
-        r"""
-        usePrimitiveLattice(MillerIndexOrientation self, Lattice lattice)
-        void MillerIndexOrientation::usePrimitiveLattice(const Lattice &lattice) override
-
-        """
-        return _libBornAgainSample.MillerIndexOrientation_usePrimitiveLattice(self, lattice)
-
-    def transformation(self):
-        r"""
-        transformation(MillerIndexOrientation self) -> Transform3D
-        Transform3D MillerIndexOrientation::transformation() const override
-
-        """
-        return _libBornAgainSample.MillerIndexOrientation_transformation(self)
-
-# Register MillerIndexOrientation in _libBornAgainSample:
-_libBornAgainSample.MillerIndexOrientation_swigregister(MillerIndexOrientation)
-
 class ISelectionRule(object):
     r"""
 
@@ -11587,13 +11236,13 @@ class SimpleSelectionRule(ISelectionRule):
 # Register SimpleSelectionRule in _libBornAgainSample:
 _libBornAgainSample.SimpleSelectionRule_swigregister(SimpleSelectionRule)
 
-class Lattice(libBornAgainParam.INode):
+class Lattice3D(libBornAgainParam.INode):
     r"""
 
 
-    A lattice with three basis vectors.
+    A Bravais lattice, characterized by three basis vectors, and optionally an  ISelectionRule.
 
-    C++ includes: Lattice.h
+    C++ includes: Lattice3D.h
 
     """
 
@@ -11602,217 +11251,138 @@ class Lattice(libBornAgainParam.INode):
 
     def __init__(self, *args):
         r"""
-        __init__(Lattice self) -> Lattice
-        __init__(Lattice self, kvector_t a1, kvector_t a2, kvector_t a3) -> Lattice
-        __init__(Lattice self, Lattice lattice) -> Lattice
-        Lattice::Lattice(const Lattice &lattice)
+        __init__(Lattice3D self, kvector_t a, kvector_t b, kvector_t c) -> Lattice3D
+        __init__(Lattice3D self, Lattice3D lattice) -> Lattice3D
+        Lattice3D::Lattice3D(const Lattice3D &lattice)
 
         """
-        _libBornAgainSample.Lattice_swiginit(self, _libBornAgainSample.new_Lattice(*args))
-    __swig_destroy__ = _libBornAgainSample.delete_Lattice
+        _libBornAgainSample.Lattice3D_swiginit(self, _libBornAgainSample.new_Lattice3D(*args))
+    __swig_destroy__ = _libBornAgainSample.delete_Lattice3D
 
     def accept(self, visitor):
         r"""
-        accept(Lattice self, INodeVisitor * visitor)
-        void Lattice::accept(INodeVisitor *visitor) const override
+        accept(Lattice3D self, INodeVisitor * visitor)
+        void Lattice3D::accept(INodeVisitor *visitor) const override
 
         """
-        return _libBornAgainSample.Lattice_accept(self, visitor)
+        return _libBornAgainSample.Lattice3D_accept(self, visitor)
 
     def transformed(self, transform):
         r"""
-        transformed(Lattice self, Transform3D const & transform) -> Lattice
-        Lattice Lattice::transformed(const Transform3D &transform) const
+        transformed(Lattice3D self, Transform3D const & transform) -> Lattice3D
+        Lattice3D Lattice3D::transformed(const Transform3D &transform) const
 
         Creates transformed lattice. 
 
         """
-        return _libBornAgainSample.Lattice_transformed(self, transform)
+        return _libBornAgainSample.Lattice3D_transformed(self, transform)
 
     def initialize(self):
         r"""
-        initialize(Lattice self)
-        void Lattice::initialize() const
+        initialize(Lattice3D self)
+        void Lattice3D::initialize()
 
         Initializes cached data. 
 
         """
-        return _libBornAgainSample.Lattice_initialize(self)
+        return _libBornAgainSample.Lattice3D_initialize(self)
 
     def getBasisVectorA(self):
         r"""
-        getBasisVectorA(Lattice self) -> kvector_t
-        kvector_t Lattice::getBasisVectorA() const
+        getBasisVectorA(Lattice3D self) -> kvector_t
+        kvector_t Lattice3D::getBasisVectorA() const
 
         Returns basis vector a. 
 
         """
-        return _libBornAgainSample.Lattice_getBasisVectorA(self)
+        return _libBornAgainSample.Lattice3D_getBasisVectorA(self)
 
     def getBasisVectorB(self):
         r"""
-        getBasisVectorB(Lattice self) -> kvector_t
-        kvector_t Lattice::getBasisVectorB() const
+        getBasisVectorB(Lattice3D self) -> kvector_t
+        kvector_t Lattice3D::getBasisVectorB() const
 
         Returns basis vector b. 
 
         """
-        return _libBornAgainSample.Lattice_getBasisVectorB(self)
+        return _libBornAgainSample.Lattice3D_getBasisVectorB(self)
 
     def getBasisVectorC(self):
         r"""
-        getBasisVectorC(Lattice self) -> kvector_t
-        kvector_t Lattice::getBasisVectorC() const
+        getBasisVectorC(Lattice3D self) -> kvector_t
+        kvector_t Lattice3D::getBasisVectorC() const
 
         Returns basis vector c. 
 
         """
-        return _libBornAgainSample.Lattice_getBasisVectorC(self)
-
-    def resetBasis(self, a1, a2, a3):
-        r"""
-        resetBasis(Lattice self, kvector_t a1, kvector_t a2, kvector_t a3)
-        void Lattice::resetBasis(const kvector_t a1, const kvector_t a2, const kvector_t a3)
-
-        Resets the basis vectors. 
-
-        """
-        return _libBornAgainSample.Lattice_resetBasis(self, a1, a2, a3)
+        return _libBornAgainSample.Lattice3D_getBasisVectorC(self)
 
     def getMillerDirection(self, h, k, l):
         r"""
-        getMillerDirection(Lattice self, double h, double k, double l) -> kvector_t
-        kvector_t Lattice::getMillerDirection(double h, double k, double l) const
+        getMillerDirection(Lattice3D self, double h, double k, double l) -> kvector_t
+        kvector_t Lattice3D::getMillerDirection(double h, double k, double l) const
+
+        Returns normalized direction corresponding to the given Miller indices.
 
-        Returns normalized direction corresponding to the given Miller indices. 
+        Currently unused but may be useful for checks. 
 
         """
-        return _libBornAgainSample.Lattice_getMillerDirection(self, h, k, l)
+        return _libBornAgainSample.Lattice3D_getMillerDirection(self, h, k, l)
 
-    def volume(self):
+    def unitCellVolume(self):
         r"""
-        volume(Lattice self) -> double
-        double Lattice::volume() const
+        unitCellVolume(Lattice3D self) -> double
+        double Lattice3D::unitCellVolume() const
 
         Returns the volume of the unit cell. 
 
         """
-        return _libBornAgainSample.Lattice_volume(self)
+        return _libBornAgainSample.Lattice3D_unitCellVolume(self)
 
-    def getReciprocalLatticeBasis(self, b1, b2, b3):
+    def getReciprocalLatticeBasis(self, ra, rb, rc):
         r"""
-        getReciprocalLatticeBasis(Lattice self, kvector_t b1, kvector_t b2, kvector_t b3)
-        void Lattice::getReciprocalLatticeBasis(kvector_t &b1, kvector_t &b2, kvector_t &b3) const
-
-        Returns the reciprocal basis vectors. 
+        getReciprocalLatticeBasis(Lattice3D self, kvector_t ra, kvector_t rb, kvector_t rc)
+        void Lattice3D::getReciprocalLatticeBasis(kvector_t &ra, kvector_t &rb, kvector_t &rc) const
 
-        """
-        return _libBornAgainSample.Lattice_getReciprocalLatticeBasis(self, b1, b2, b3)
+        Returns the reciprocal basis vectors.
 
-    def getNearestLatticeVectorCoordinates(self, vector_in):
-        r"""
-        getNearestLatticeVectorCoordinates(Lattice self, kvector_t vector_in) -> ivector_t
-        ivector_t Lattice::getNearestLatticeVectorCoordinates(const kvector_t vector_in) const
-
-        Returns the nearest lattice point from a given vector. 
+        Currently only used in tests. 
 
         """
-        return _libBornAgainSample.Lattice_getNearestLatticeVectorCoordinates(self, vector_in)
+        return _libBornAgainSample.Lattice3D_getReciprocalLatticeBasis(self, ra, rb, rc)
 
-    def getNearestReciprocalLatticeVectorCoordinates(self, vector_in):
+    def getNearestReciprocalLatticeVectorCoordinates(self, q):
         r"""
-        getNearestReciprocalLatticeVectorCoordinates(Lattice self, kvector_t vector_in) -> ivector_t
-        ivector_t Lattice::getNearestReciprocalLatticeVectorCoordinates(const kvector_t vector_in) const
+        getNearestReciprocalLatticeVectorCoordinates(Lattice3D self, kvector_t q) -> ivector_t
+        ivector_t Lattice3D::getNearestReciprocalLatticeVectorCoordinates(const kvector_t q) const
 
         Returns the nearest reciprocal lattice point from a given vector. 
 
         """
-        return _libBornAgainSample.Lattice_getNearestReciprocalLatticeVectorCoordinates(self, vector_in)
+        return _libBornAgainSample.Lattice3D_getNearestReciprocalLatticeVectorCoordinates(self, q)
 
-    def reciprocalLatticeVectorsWithinRadius(self, input_vector, radius):
+    def reciprocalLatticeVectorsWithinRadius(self, q, dq):
         r"""
-        reciprocalLatticeVectorsWithinRadius(Lattice self, kvector_t input_vector, double radius) -> vector_kvector_t
-        std::vector< kvector_t > Lattice::reciprocalLatticeVectorsWithinRadius(const kvector_t input_vector, double radius) const
+        reciprocalLatticeVectorsWithinRadius(Lattice3D self, kvector_t q, double dq) -> vector_kvector_t
+        std::vector< kvector_t > Lattice3D::reciprocalLatticeVectorsWithinRadius(const kvector_t q, double dq) const
 
-        Computes a list of reciprocal lattice vectors within a specified distance of a given vector. 
+        Returns a list of reciprocal lattice vectors within distance dq of a vector q. 
 
         """
-        return _libBornAgainSample.Lattice_reciprocalLatticeVectorsWithinRadius(self, input_vector, radius)
+        return _libBornAgainSample.Lattice3D_reciprocalLatticeVectorsWithinRadius(self, q, dq)
 
-    def setSelectionRule(self, p_selection_rule):
+    def setSelectionRule(self, selection_rule):
         r"""
-        setSelectionRule(Lattice self, ISelectionRule p_selection_rule)
-        void Lattice::setSelectionRule(const ISelectionRule &p_selection_rule)
+        setSelectionRule(Lattice3D self, ISelectionRule selection_rule)
+        void Lattice3D::setSelectionRule(const ISelectionRule &selection_rule)
 
         Sets a selection rule for the reciprocal vectors. 
 
         """
-        return _libBornAgainSample.Lattice_setSelectionRule(self, p_selection_rule)
-
-    @staticmethod
-    def createCubicLattice(a):
-        r"""createCubicLattice(double a) -> Lattice"""
-        return _libBornAgainSample.Lattice_createCubicLattice(a)
-
-    @staticmethod
-    def createFCCLattice(a):
-        r"""createFCCLattice(double a) -> Lattice"""
-        return _libBornAgainSample.Lattice_createFCCLattice(a)
-
-    @staticmethod
-    def createHexagonalLattice(a, c):
-        r"""createHexagonalLattice(double a, double c) -> Lattice"""
-        return _libBornAgainSample.Lattice_createHexagonalLattice(a, c)
-
-    @staticmethod
-    def createHCPLattice(a, c):
-        r"""createHCPLattice(double a, double c) -> Lattice"""
-        return _libBornAgainSample.Lattice_createHCPLattice(a, c)
-
-    @staticmethod
-    def createTetragonalLattice(a, c):
-        r"""createTetragonalLattice(double a, double c) -> Lattice"""
-        return _libBornAgainSample.Lattice_createTetragonalLattice(a, c)
-
-    @staticmethod
-    def createBCTLattice(a, c):
-        r"""createBCTLattice(double a, double c) -> Lattice"""
-        return _libBornAgainSample.Lattice_createBCTLattice(a, c)
-
-    def onChange(self):
-        r"""
-        onChange(Lattice self)
-        void Lattice::onChange() override
-
-        """
-        return _libBornAgainSample.Lattice_onChange(self)
-
-# Register Lattice in _libBornAgainSample:
-_libBornAgainSample.Lattice_swigregister(Lattice)
-
-def Lattice_createCubicLattice(a):
-    r"""Lattice_createCubicLattice(double a) -> Lattice"""
-    return _libBornAgainSample.Lattice_createCubicLattice(a)
-
-def Lattice_createFCCLattice(a):
-    r"""Lattice_createFCCLattice(double a) -> Lattice"""
-    return _libBornAgainSample.Lattice_createFCCLattice(a)
+        return _libBornAgainSample.Lattice3D_setSelectionRule(self, selection_rule)
 
-def Lattice_createHexagonalLattice(a, c):
-    r"""Lattice_createHexagonalLattice(double a, double c) -> Lattice"""
-    return _libBornAgainSample.Lattice_createHexagonalLattice(a, c)
-
-def Lattice_createHCPLattice(a, c):
-    r"""Lattice_createHCPLattice(double a, double c) -> Lattice"""
-    return _libBornAgainSample.Lattice_createHCPLattice(a, c)
-
-def Lattice_createTetragonalLattice(a, c):
-    r"""Lattice_createTetragonalLattice(double a, double c) -> Lattice"""
-    return _libBornAgainSample.Lattice_createTetragonalLattice(a, c)
-
-def Lattice_createBCTLattice(a, c):
-    r"""Lattice_createBCTLattice(double a, double c) -> Lattice"""
-    return _libBornAgainSample.Lattice_createBCTLattice(a, c)
+# Register Lattice3D in _libBornAgainSample:
+_libBornAgainSample.Lattice3D_swigregister(Lattice3D)
 
 class Lattice2D(libBornAgainBase.ICloneable, libBornAgainParam.INode):
     r"""Proxy of C++ Lattice2D class."""
@@ -12090,29 +11660,65 @@ class HexagonalLattice(Lattice2D):
 _libBornAgainSample.HexagonalLattice_swigregister(HexagonalLattice)
 
 
-def createFCCLattice(lattice_constant, orientation):
+def createCubicLattice(a):
+    r"""
+    createCubicLattice(double a) -> Lattice3D
+    Lattice3D bake::createCubicLattice(double a)
+
+    Returns a primitive cubic (cP) lattice with edge length a. 
+
+    """
+    return _libBornAgainSample.createCubicLattice(a)
+
+def createFCCLattice(a):
     r"""
-    createFCCLattice(double lattice_constant, ILatticeOrientation orientation) -> Lattice
-    Lattice LatticeUtils::createFCCLattice(double lattice_constant, const ILatticeOrientation &orientation)
+    createFCCLattice(double a) -> Lattice3D
+    Lattice3D bake::createFCCLattice(double a)
+
+    Returns a face-centered cubic (cF) lattice with edge length a. 
 
     """
-    return _libBornAgainSample.createFCCLattice(lattice_constant, orientation)
+    return _libBornAgainSample.createFCCLattice(a)
 
-def createHCPLattice(a, c, orientation):
+def createHexagonalLattice(a, c):
     r"""
-    createHCPLattice(double a, double c, ILatticeOrientation orientation) -> Lattice
-    Lattice LatticeUtils::createHCPLattice(double a, double c, const ILatticeOrientation &orientation)
+    createHexagonalLattice(double a, double c) -> Lattice3D
+    Lattice3D bake::createHexagonalLattice(double a, double c)
+
+    Returns a primitive hexagonal (hP) lattice with hexagonal edge a and height c. 
 
     """
-    return _libBornAgainSample.createHCPLattice(a, c, orientation)
+    return _libBornAgainSample.createHexagonalLattice(a, c)
 
-def createBCTLattice(a, c, orientation):
+def createHCPLattice(a, c):
     r"""
-    createBCTLattice(double a, double c, ILatticeOrientation orientation) -> Lattice
-    Lattice LatticeUtils::createBCTLattice(double a, double c, const ILatticeOrientation &orientation)
+    createHCPLattice(double a, double c) -> Lattice3D
+    Lattice3D bake::createHCPLattice(double a, double c)
+
+    TODO: Clarify how this is meant: HCP is not a Bravais lattice. 
+
+    """
+    return _libBornAgainSample.createHCPLattice(a, c)
+
+def createTetragonalLattice(a, c):
+    r"""
+    createTetragonalLattice(double a, double c) -> Lattice3D
+    Lattice3D bake::createTetragonalLattice(double a, double c)
+
+    Returns a primitive tetragonal (tP) lattice with square base edge a and height c. 
+
+    """
+    return _libBornAgainSample.createTetragonalLattice(a, c)
+
+def createBCTLattice(a, c):
+    r"""
+    createBCTLattice(double a, double c) -> Lattice3D
+    Lattice3D bake::createBCTLattice(double a, double c)
+
+    Returns a body-centered cubic (cI) lattice with edge length a. TODO: Clarify meaning of c 
 
     """
-    return _libBornAgainSample.createBCTLattice(a, c, orientation)
+    return _libBornAgainSample.createBCTLattice(a, c)
 class ISampleBuilder(libBornAgainParam.IParameterized):
     r"""
 
diff --git a/auto/Wrap/libBornAgainSample_wrap.cpp b/auto/Wrap/libBornAgainSample_wrap.cpp
index 4360cb94ec10271257bf6cb5c0f5567935c4ed37..7ee98b2a221e8bca86032db23fa98ee46f5b97b9 100644
--- a/auto/Wrap/libBornAgainSample_wrap.cpp
+++ b/auto/Wrap/libBornAgainSample_wrap.cpp
@@ -3161,146 +3161,141 @@ namespace Swig {
 #define SWIGTYPE_p_HexagonalLattice swig_types[61]
 #define SWIGTYPE_p_IAbstractParticle swig_types[62]
 #define SWIGTYPE_p_ICloneable swig_types[63]
-#define SWIGTYPE_p_IClusteredParticles swig_types[64]
-#define SWIGTYPE_p_ICosineRipple swig_types[65]
-#define SWIGTYPE_p_IFTDecayFunction1D swig_types[66]
-#define SWIGTYPE_p_IFTDecayFunction2D swig_types[67]
-#define SWIGTYPE_p_IFTDistribution1D swig_types[68]
-#define SWIGTYPE_p_IFTDistribution2D swig_types[69]
-#define SWIGTYPE_p_IFactoryT_std__string_ISampleBuilder_t swig_types[70]
-#define SWIGTYPE_p_IFormFactor swig_types[71]
-#define SWIGTYPE_p_IFormFactorBorn swig_types[72]
-#define SWIGTYPE_p_IFormFactorDecorator swig_types[73]
-#define SWIGTYPE_p_IFormFactorPolyhedron swig_types[74]
-#define SWIGTYPE_p_IFormFactorPrism swig_types[75]
-#define SWIGTYPE_p_IInterferenceFunction swig_types[76]
-#define SWIGTYPE_p_ILatticeOrientation swig_types[77]
-#define SWIGTYPE_p_ILayout swig_types[78]
-#define SWIGTYPE_p_INode swig_types[79]
-#define SWIGTYPE_p_INodeVisitor swig_types[80]
-#define SWIGTYPE_p_IParameterized swig_types[81]
-#define SWIGTYPE_p_IParticle swig_types[82]
-#define SWIGTYPE_p_IPeakShape swig_types[83]
-#define SWIGTYPE_p_IProfileRectangularRipple swig_types[84]
-#define SWIGTYPE_p_IProfileRipple swig_types[85]
-#define SWIGTYPE_p_IRotation swig_types[86]
-#define SWIGTYPE_p_ISample swig_types[87]
-#define SWIGTYPE_p_ISampleBuilder swig_types[88]
-#define SWIGTYPE_p_ISawtoothRipple swig_types[89]
-#define SWIGTYPE_p_ISelectionRule swig_types[90]
-#define SWIGTYPE_p_IdentityRotation swig_types[91]
-#define SWIGTYPE_p_InterferenceFunction1DLattice swig_types[92]
-#define SWIGTYPE_p_InterferenceFunction2DLattice swig_types[93]
-#define SWIGTYPE_p_InterferenceFunction2DParaCrystal swig_types[94]
-#define SWIGTYPE_p_InterferenceFunction2DSuperLattice swig_types[95]
-#define SWIGTYPE_p_InterferenceFunction3DLattice swig_types[96]
-#define SWIGTYPE_p_InterferenceFunctionFinite2DLattice swig_types[97]
-#define SWIGTYPE_p_InterferenceFunctionFinite3DLattice swig_types[98]
-#define SWIGTYPE_p_InterferenceFunctionHardDisk swig_types[99]
-#define SWIGTYPE_p_InterferenceFunctionNone swig_types[100]
-#define SWIGTYPE_p_InterferenceFunctionRadialParaCrystal swig_types[101]
-#define SWIGTYPE_p_InterferenceFunctionTwin swig_types[102]
-#define SWIGTYPE_p_IsotropicGaussPeakShape swig_types[103]
-#define SWIGTYPE_p_IsotropicLorentzPeakShape swig_types[104]
-#define SWIGTYPE_p_Lattice swig_types[105]
-#define SWIGTYPE_p_Lattice2D swig_types[106]
-#define SWIGTYPE_p_Lattice2D__ReciprocalBases swig_types[107]
-#define SWIGTYPE_p_Layer swig_types[108]
-#define SWIGTYPE_p_LayerInterface swig_types[109]
-#define SWIGTYPE_p_LayerRoughness swig_types[110]
-#define SWIGTYPE_p_LorentzFisherPeakShape swig_types[111]
-#define SWIGTYPE_p_Material swig_types[112]
-#define SWIGTYPE_p_MesoCrystal swig_types[113]
-#define SWIGTYPE_p_MillerIndex swig_types[114]
-#define SWIGTYPE_p_MillerIndexOrientation swig_types[115]
-#define SWIGTYPE_p_MisesFisherGaussPeakShape swig_types[116]
-#define SWIGTYPE_p_MisesGaussPeakShape swig_types[117]
-#define SWIGTYPE_p_MultiLayer swig_types[118]
-#define SWIGTYPE_p_NodeMeta swig_types[119]
-#define SWIGTYPE_p_ParameterDistribution swig_types[120]
-#define SWIGTYPE_p_ParameterPool swig_types[121]
-#define SWIGTYPE_p_Particle swig_types[122]
-#define SWIGTYPE_p_ParticleComposition swig_types[123]
-#define SWIGTYPE_p_ParticleCoreShell swig_types[124]
-#define SWIGTYPE_p_ParticleDistribution swig_types[125]
-#define SWIGTYPE_p_ParticleLayout swig_types[126]
-#define SWIGTYPE_p_ParticleLimits swig_types[127]
-#define SWIGTYPE_p_RealParameter swig_types[128]
-#define SWIGTYPE_p_RotationEuler swig_types[129]
-#define SWIGTYPE_p_RotationX swig_types[130]
-#define SWIGTYPE_p_RotationY swig_types[131]
-#define SWIGTYPE_p_RotationZ swig_types[132]
-#define SWIGTYPE_p_RoughnessModelWrap swig_types[133]
-#define SWIGTYPE_p_RoughnessModelWrap__RoughnessModel swig_types[134]
-#define SWIGTYPE_p_SafePointerVectorT_IParticle_t swig_types[135]
-#define SWIGTYPE_p_SampleBuilderFactory swig_types[136]
-#define SWIGTYPE_p_SimpleSelectionRule swig_types[137]
-#define SWIGTYPE_p_SimulationOptions swig_types[138]
-#define SWIGTYPE_p_SlicedParticle swig_types[139]
-#define SWIGTYPE_p_SlicingEffects swig_types[140]
-#define SWIGTYPE_p_SquareLattice swig_types[141]
-#define SWIGTYPE_p_ThreadInfo swig_types[142]
-#define SWIGTYPE_p_Transform3D swig_types[143]
-#define SWIGTYPE_p_WavevectorInfo swig_types[144]
-#define SWIGTYPE_p_ZLimits swig_types[145]
-#define SWIGTYPE_p_allocator_type swig_types[146]
-#define SWIGTYPE_p_char swig_types[147]
-#define SWIGTYPE_p_difference_type swig_types[148]
-#define SWIGTYPE_p_first_type swig_types[149]
-#define SWIGTYPE_p_int swig_types[150]
-#define SWIGTYPE_p_key_type swig_types[151]
-#define SWIGTYPE_p_long_long swig_types[152]
-#define SWIGTYPE_p_mapped_type swig_types[153]
-#define SWIGTYPE_p_p_PyObject swig_types[154]
-#define SWIGTYPE_p_second_type swig_types[155]
-#define SWIGTYPE_p_short swig_types[156]
-#define SWIGTYPE_p_signed_char swig_types[157]
-#define SWIGTYPE_p_size_type swig_types[158]
-#define SWIGTYPE_p_std__allocatorT_BasicVector3DT_double_t_t swig_types[159]
-#define SWIGTYPE_p_std__allocatorT_BasicVector3DT_std__complexT_double_t_t_t swig_types[160]
-#define SWIGTYPE_p_std__allocatorT_IFormFactor_p_t swig_types[161]
-#define SWIGTYPE_p_std__allocatorT_INode_const_p_t swig_types[162]
-#define SWIGTYPE_p_std__allocatorT_INode_p_t swig_types[163]
-#define SWIGTYPE_p_std__allocatorT_double_t swig_types[164]
-#define SWIGTYPE_p_std__allocatorT_int_t swig_types[165]
-#define SWIGTYPE_p_std__allocatorT_std__complexT_double_t_t swig_types[166]
-#define SWIGTYPE_p_std__allocatorT_std__pairT_double_double_t_t swig_types[167]
-#define SWIGTYPE_p_std__allocatorT_std__pairT_std__string_const_double_t_t swig_types[168]
-#define SWIGTYPE_p_std__allocatorT_std__string_t swig_types[169]
-#define SWIGTYPE_p_std__allocatorT_std__vectorT_double_std__allocatorT_double_t_t_t swig_types[170]
-#define SWIGTYPE_p_std__allocatorT_std__vectorT_int_std__allocatorT_int_t_t_t swig_types[171]
-#define SWIGTYPE_p_std__allocatorT_unsigned_long_t swig_types[172]
-#define SWIGTYPE_p_std__complexT_double_t swig_types[173]
-#define SWIGTYPE_p_std__functionT_ISampleBuilder_pfF_t swig_types[174]
-#define SWIGTYPE_p_std__invalid_argument swig_types[175]
-#define SWIGTYPE_p_std__lessT_std__string_t swig_types[176]
-#define SWIGTYPE_p_std__mapT_std__string_double_std__lessT_std__string_t_std__allocatorT_std__pairT_std__string_const_double_t_t_t swig_types[177]
-#define SWIGTYPE_p_std__pairT_double_double_t swig_types[178]
-#define SWIGTYPE_p_std__shared_ptrT_ISampleBuilder_t swig_types[179]
-#define SWIGTYPE_p_std__vectorT_BasicVector3DT_double_t_std__allocatorT_BasicVector3DT_double_t_t_t swig_types[180]
-#define SWIGTYPE_p_std__vectorT_BasicVector3DT_std__complexT_double_t_t_std__allocatorT_BasicVector3DT_std__complexT_double_t_t_t_t swig_types[181]
-#define SWIGTYPE_p_std__vectorT_HomogeneousRegion_std__allocatorT_HomogeneousRegion_t_t swig_types[182]
-#define SWIGTYPE_p_std__vectorT_IFormFactor_p_std__allocatorT_IFormFactor_p_t_t swig_types[183]
-#define SWIGTYPE_p_std__vectorT_ILayout_const_p_std__allocatorT_ILayout_const_p_t_t swig_types[184]
-#define SWIGTYPE_p_std__vectorT_INode_const_p_std__allocatorT_INode_const_p_t_t swig_types[185]
-#define SWIGTYPE_p_std__vectorT_INode_p_std__allocatorT_INode_p_t_t swig_types[186]
-#define SWIGTYPE_p_std__vectorT_Material_const_p_std__allocatorT_Material_const_p_t_t swig_types[187]
-#define SWIGTYPE_p_std__vectorT_double_std__allocatorT_double_t_t swig_types[188]
-#define SWIGTYPE_p_std__vectorT_int_std__allocatorT_int_t_t swig_types[189]
-#define SWIGTYPE_p_std__vectorT_std__complexT_double_t_std__allocatorT_std__complexT_double_t_t_t swig_types[190]
-#define SWIGTYPE_p_std__vectorT_std__pairT_double_double_t_std__allocatorT_std__pairT_double_double_t_t_t swig_types[191]
-#define SWIGTYPE_p_std__vectorT_std__string_std__allocatorT_std__string_t_t swig_types[192]
-#define SWIGTYPE_p_std__vectorT_std__vectorT_double_std__allocatorT_double_t_t_std__allocatorT_std__vectorT_double_std__allocatorT_double_t_t_t_t swig_types[193]
-#define SWIGTYPE_p_std__vectorT_std__vectorT_int_std__allocatorT_int_t_t_std__allocatorT_std__vectorT_int_std__allocatorT_int_t_t_t_t swig_types[194]
-#define SWIGTYPE_p_std__vectorT_unsigned_long_std__allocatorT_unsigned_long_t_t swig_types[195]
-#define SWIGTYPE_p_swig__SwigPyIterator swig_types[196]
-#define SWIGTYPE_p_unsigned_char swig_types[197]
-#define SWIGTYPE_p_unsigned_int swig_types[198]
-#define SWIGTYPE_p_unsigned_long_long swig_types[199]
-#define SWIGTYPE_p_unsigned_short swig_types[200]
-#define SWIGTYPE_p_value_type swig_types[201]
-static swig_type_info *swig_types[203];
-static swig_module_info swig_module = {swig_types, 202, 0, 0, 0, 0};
+#define SWIGTYPE_p_ICosineRipple swig_types[64]
+#define SWIGTYPE_p_IFTDecayFunction1D swig_types[65]
+#define SWIGTYPE_p_IFTDecayFunction2D swig_types[66]
+#define SWIGTYPE_p_IFTDistribution1D swig_types[67]
+#define SWIGTYPE_p_IFTDistribution2D swig_types[68]
+#define SWIGTYPE_p_IFactoryT_std__string_ISampleBuilder_t swig_types[69]
+#define SWIGTYPE_p_IFormFactor swig_types[70]
+#define SWIGTYPE_p_IFormFactorBorn swig_types[71]
+#define SWIGTYPE_p_IFormFactorDecorator swig_types[72]
+#define SWIGTYPE_p_IFormFactorPolyhedron swig_types[73]
+#define SWIGTYPE_p_IFormFactorPrism swig_types[74]
+#define SWIGTYPE_p_IInterferenceFunction swig_types[75]
+#define SWIGTYPE_p_INode swig_types[76]
+#define SWIGTYPE_p_INodeVisitor swig_types[77]
+#define SWIGTYPE_p_IParameterized swig_types[78]
+#define SWIGTYPE_p_IParticle swig_types[79]
+#define SWIGTYPE_p_IPeakShape swig_types[80]
+#define SWIGTYPE_p_IProfileRectangularRipple swig_types[81]
+#define SWIGTYPE_p_IProfileRipple swig_types[82]
+#define SWIGTYPE_p_IRotation swig_types[83]
+#define SWIGTYPE_p_ISample swig_types[84]
+#define SWIGTYPE_p_ISampleBuilder swig_types[85]
+#define SWIGTYPE_p_ISawtoothRipple swig_types[86]
+#define SWIGTYPE_p_ISelectionRule swig_types[87]
+#define SWIGTYPE_p_IdentityRotation swig_types[88]
+#define SWIGTYPE_p_InterferenceFunction1DLattice swig_types[89]
+#define SWIGTYPE_p_InterferenceFunction2DLattice swig_types[90]
+#define SWIGTYPE_p_InterferenceFunction2DParaCrystal swig_types[91]
+#define SWIGTYPE_p_InterferenceFunction2DSuperLattice swig_types[92]
+#define SWIGTYPE_p_InterferenceFunction3DLattice swig_types[93]
+#define SWIGTYPE_p_InterferenceFunctionFinite2DLattice swig_types[94]
+#define SWIGTYPE_p_InterferenceFunctionFinite3DLattice swig_types[95]
+#define SWIGTYPE_p_InterferenceFunctionHardDisk swig_types[96]
+#define SWIGTYPE_p_InterferenceFunctionNone swig_types[97]
+#define SWIGTYPE_p_InterferenceFunctionRadialParaCrystal swig_types[98]
+#define SWIGTYPE_p_InterferenceFunctionTwin swig_types[99]
+#define SWIGTYPE_p_IsotropicGaussPeakShape swig_types[100]
+#define SWIGTYPE_p_IsotropicLorentzPeakShape swig_types[101]
+#define SWIGTYPE_p_Lattice2D swig_types[102]
+#define SWIGTYPE_p_Lattice2D__ReciprocalBases swig_types[103]
+#define SWIGTYPE_p_Lattice3D swig_types[104]
+#define SWIGTYPE_p_Layer swig_types[105]
+#define SWIGTYPE_p_LayerInterface swig_types[106]
+#define SWIGTYPE_p_LayerRoughness swig_types[107]
+#define SWIGTYPE_p_LorentzFisherPeakShape swig_types[108]
+#define SWIGTYPE_p_Material swig_types[109]
+#define SWIGTYPE_p_MesoCrystal swig_types[110]
+#define SWIGTYPE_p_MisesFisherGaussPeakShape swig_types[111]
+#define SWIGTYPE_p_MisesGaussPeakShape swig_types[112]
+#define SWIGTYPE_p_MultiLayer swig_types[113]
+#define SWIGTYPE_p_NodeMeta swig_types[114]
+#define SWIGTYPE_p_ParameterDistribution swig_types[115]
+#define SWIGTYPE_p_ParameterPool swig_types[116]
+#define SWIGTYPE_p_Particle swig_types[117]
+#define SWIGTYPE_p_ParticleComposition swig_types[118]
+#define SWIGTYPE_p_ParticleCoreShell swig_types[119]
+#define SWIGTYPE_p_ParticleDistribution swig_types[120]
+#define SWIGTYPE_p_ParticleLayout swig_types[121]
+#define SWIGTYPE_p_ParticleLimits swig_types[122]
+#define SWIGTYPE_p_RealParameter swig_types[123]
+#define SWIGTYPE_p_RotationEuler swig_types[124]
+#define SWIGTYPE_p_RotationX swig_types[125]
+#define SWIGTYPE_p_RotationY swig_types[126]
+#define SWIGTYPE_p_RotationZ swig_types[127]
+#define SWIGTYPE_p_RoughnessModelWrap swig_types[128]
+#define SWIGTYPE_p_RoughnessModelWrap__RoughnessModel swig_types[129]
+#define SWIGTYPE_p_SafePointerVectorT_IParticle_t swig_types[130]
+#define SWIGTYPE_p_SampleBuilderFactory swig_types[131]
+#define SWIGTYPE_p_SimpleSelectionRule swig_types[132]
+#define SWIGTYPE_p_SimulationOptions swig_types[133]
+#define SWIGTYPE_p_SlicedParticle swig_types[134]
+#define SWIGTYPE_p_SlicingEffects swig_types[135]
+#define SWIGTYPE_p_SquareLattice swig_types[136]
+#define SWIGTYPE_p_ThreadInfo swig_types[137]
+#define SWIGTYPE_p_Transform3D swig_types[138]
+#define SWIGTYPE_p_WavevectorInfo swig_types[139]
+#define SWIGTYPE_p_ZLimits swig_types[140]
+#define SWIGTYPE_p_allocator_type swig_types[141]
+#define SWIGTYPE_p_char swig_types[142]
+#define SWIGTYPE_p_difference_type swig_types[143]
+#define SWIGTYPE_p_first_type swig_types[144]
+#define SWIGTYPE_p_int swig_types[145]
+#define SWIGTYPE_p_key_type swig_types[146]
+#define SWIGTYPE_p_long_long swig_types[147]
+#define SWIGTYPE_p_mapped_type swig_types[148]
+#define SWIGTYPE_p_p_PyObject swig_types[149]
+#define SWIGTYPE_p_second_type swig_types[150]
+#define SWIGTYPE_p_short swig_types[151]
+#define SWIGTYPE_p_signed_char swig_types[152]
+#define SWIGTYPE_p_size_type swig_types[153]
+#define SWIGTYPE_p_std__allocatorT_BasicVector3DT_double_t_t swig_types[154]
+#define SWIGTYPE_p_std__allocatorT_BasicVector3DT_std__complexT_double_t_t_t swig_types[155]
+#define SWIGTYPE_p_std__allocatorT_IFormFactor_p_t swig_types[156]
+#define SWIGTYPE_p_std__allocatorT_INode_const_p_t swig_types[157]
+#define SWIGTYPE_p_std__allocatorT_INode_p_t swig_types[158]
+#define SWIGTYPE_p_std__allocatorT_double_t swig_types[159]
+#define SWIGTYPE_p_std__allocatorT_int_t swig_types[160]
+#define SWIGTYPE_p_std__allocatorT_std__complexT_double_t_t swig_types[161]
+#define SWIGTYPE_p_std__allocatorT_std__pairT_double_double_t_t swig_types[162]
+#define SWIGTYPE_p_std__allocatorT_std__pairT_std__string_const_double_t_t swig_types[163]
+#define SWIGTYPE_p_std__allocatorT_std__string_t swig_types[164]
+#define SWIGTYPE_p_std__allocatorT_std__vectorT_double_std__allocatorT_double_t_t_t swig_types[165]
+#define SWIGTYPE_p_std__allocatorT_std__vectorT_int_std__allocatorT_int_t_t_t swig_types[166]
+#define SWIGTYPE_p_std__allocatorT_unsigned_long_t swig_types[167]
+#define SWIGTYPE_p_std__complexT_double_t swig_types[168]
+#define SWIGTYPE_p_std__functionT_ISampleBuilder_pfF_t swig_types[169]
+#define SWIGTYPE_p_std__invalid_argument swig_types[170]
+#define SWIGTYPE_p_std__lessT_std__string_t swig_types[171]
+#define SWIGTYPE_p_std__mapT_std__string_double_std__lessT_std__string_t_std__allocatorT_std__pairT_std__string_const_double_t_t_t swig_types[172]
+#define SWIGTYPE_p_std__pairT_double_double_t swig_types[173]
+#define SWIGTYPE_p_std__shared_ptrT_ISampleBuilder_t swig_types[174]
+#define SWIGTYPE_p_std__vectorT_BasicVector3DT_double_t_std__allocatorT_BasicVector3DT_double_t_t_t swig_types[175]
+#define SWIGTYPE_p_std__vectorT_BasicVector3DT_std__complexT_double_t_t_std__allocatorT_BasicVector3DT_std__complexT_double_t_t_t_t swig_types[176]
+#define SWIGTYPE_p_std__vectorT_HomogeneousRegion_std__allocatorT_HomogeneousRegion_t_t swig_types[177]
+#define SWIGTYPE_p_std__vectorT_IFormFactor_p_std__allocatorT_IFormFactor_p_t_t swig_types[178]
+#define SWIGTYPE_p_std__vectorT_INode_const_p_std__allocatorT_INode_const_p_t_t swig_types[179]
+#define SWIGTYPE_p_std__vectorT_INode_p_std__allocatorT_INode_p_t_t swig_types[180]
+#define SWIGTYPE_p_std__vectorT_Material_const_p_std__allocatorT_Material_const_p_t_t swig_types[181]
+#define SWIGTYPE_p_std__vectorT_ParticleLayout_const_p_std__allocatorT_ParticleLayout_const_p_t_t swig_types[182]
+#define SWIGTYPE_p_std__vectorT_double_std__allocatorT_double_t_t swig_types[183]
+#define SWIGTYPE_p_std__vectorT_int_std__allocatorT_int_t_t swig_types[184]
+#define SWIGTYPE_p_std__vectorT_std__complexT_double_t_std__allocatorT_std__complexT_double_t_t_t swig_types[185]
+#define SWIGTYPE_p_std__vectorT_std__pairT_double_double_t_std__allocatorT_std__pairT_double_double_t_t_t swig_types[186]
+#define SWIGTYPE_p_std__vectorT_std__string_std__allocatorT_std__string_t_t swig_types[187]
+#define SWIGTYPE_p_std__vectorT_std__vectorT_double_std__allocatorT_double_t_t_std__allocatorT_std__vectorT_double_std__allocatorT_double_t_t_t_t swig_types[188]
+#define SWIGTYPE_p_std__vectorT_std__vectorT_int_std__allocatorT_int_t_t_std__allocatorT_std__vectorT_int_std__allocatorT_int_t_t_t_t swig_types[189]
+#define SWIGTYPE_p_std__vectorT_unsigned_long_std__allocatorT_unsigned_long_t_t swig_types[190]
+#define SWIGTYPE_p_swig__SwigPyIterator swig_types[191]
+#define SWIGTYPE_p_unsigned_char swig_types[192]
+#define SWIGTYPE_p_unsigned_int swig_types[193]
+#define SWIGTYPE_p_unsigned_long_long swig_types[194]
+#define SWIGTYPE_p_unsigned_short swig_types[195]
+#define SWIGTYPE_p_value_type swig_types[196]
+static swig_type_info *swig_types[198];
+static swig_module_info swig_module = {swig_types, 197, 0, 0, 0, 0};
 #define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
 #define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
 
@@ -6810,7 +6805,6 @@ SWIGINTERN void std_vector_Sl_std_pair_Sl_double_Sc_double_Sg__Sg__insert__SWIG_
 #include "Sample/Correlations/FTDecay2D.h"
 #include "Sample/Correlations/FTDistributions1D.h"
 #include "Sample/Correlations/FTDistributions2D.h"
-#include "Sample/Correlations/ILayout.h"
 #include "Sample/Correlations/IPeakShape.h"
 #include "Sample/HardParticle/FormFactorAnisoPyramid.h"
 #include "Sample/HardParticle/FormFactorBar.h"
@@ -6841,11 +6835,10 @@ SWIGINTERN void std_vector_Sl_std_pair_Sl_double_Sc_double_Sg__Sg__insert__SWIG_
 #include "Sample/HardParticle/FormFactorTruncatedSpheroid.h"
 #include "Sample/HardParticle/IFormFactorPolyhedron.h"
 #include "Sample/HardParticle/IFormFactorPrism.h"
-#include "Sample/Lattice/ILatticeOrientation.h"
 #include "Sample/Lattice/ISelectionRule.h"
-#include "Sample/Lattice/Lattice.h"
+#include "Sample/Lattice/Lattice3D.h"
 #include "Sample/Lattice/Lattice2D.h"
-#include "Sample/Lattice/LatticeUtils.h"
+#include "Sample/Lattice/BakeLattice.h"
 #include "Sample/Material/MaterialFactoryFuncs.h"
 #include "Sample/Material/WavevectorInfo.h"
 #include "Sample/Multilayer/Layer.h"
@@ -6856,7 +6849,6 @@ SWIGINTERN void std_vector_Sl_std_pair_Sl_double_Sc_double_Sg__Sg__insert__SWIG_
 #include "Sample/Particle/FormFactorCrystal.h"
 #include "Sample/Particle/FormFactorWeighted.h"
 #include "Sample/Particle/IAbstractParticle.h"
-#include "Sample/Particle/IClusteredParticles.h"
 #include "Sample/Particle/IParticle.h"
 #include "Sample/Particle/MesoCrystal.h"
 #include "Sample/Particle/Particle.h"
@@ -41804,7 +41796,7 @@ SWIGINTERN PyObject *RotationEuler_swiginit(PyObject *SWIGUNUSEDPARM(self), PyOb
 
 SWIGINTERN PyObject *_wrap_new_FormFactorCrystal__SWIG_0(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
-  Lattice *arg1 = 0 ;
+  Lattice3D *arg1 = 0 ;
   IFormFactor *arg2 = 0 ;
   IFormFactor *arg3 = 0 ;
   double arg4 ;
@@ -41819,14 +41811,14 @@ SWIGINTERN PyObject *_wrap_new_FormFactorCrystal__SWIG_0(PyObject *SWIGUNUSEDPAR
   FormFactorCrystal *result = 0 ;
   
   if ((nobjs < 4) || (nobjs > 4)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1, SWIGTYPE_p_Lattice,  0  | 0);
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1, SWIGTYPE_p_Lattice3D,  0  | 0);
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_FormFactorCrystal" "', argument " "1"" of type '" "Lattice const &""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_FormFactorCrystal" "', argument " "1"" of type '" "Lattice3D const &""'"); 
   }
   if (!argp1) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_FormFactorCrystal" "', argument " "1"" of type '" "Lattice const &""'"); 
+    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_FormFactorCrystal" "', argument " "1"" of type '" "Lattice3D const &""'"); 
   }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
+  arg1 = reinterpret_cast< Lattice3D * >(argp1);
   res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_IFormFactor,  0  | 0);
   if (!SWIG_IsOK(res2)) {
     SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "new_FormFactorCrystal" "', argument " "2"" of type '" "IFormFactor const &""'"); 
@@ -41848,7 +41840,7 @@ SWIGINTERN PyObject *_wrap_new_FormFactorCrystal__SWIG_0(PyObject *SWIGUNUSEDPAR
     SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "new_FormFactorCrystal" "', argument " "4"" of type '" "double""'");
   } 
   arg4 = static_cast< double >(val4);
-  result = (FormFactorCrystal *)new FormFactorCrystal((Lattice const &)*arg1,(IFormFactor const &)*arg2,(IFormFactor const &)*arg3,arg4);
+  result = (FormFactorCrystal *)new FormFactorCrystal((Lattice3D const &)*arg1,(IFormFactor const &)*arg2,(IFormFactor const &)*arg3,arg4);
   resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_FormFactorCrystal, SWIG_POINTER_NEW |  0 );
   return resultobj;
 fail:
@@ -41858,7 +41850,7 @@ fail:
 
 SWIGINTERN PyObject *_wrap_new_FormFactorCrystal__SWIG_1(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
-  Lattice *arg1 = 0 ;
+  Lattice3D *arg1 = 0 ;
   IFormFactor *arg2 = 0 ;
   IFormFactor *arg3 = 0 ;
   void *argp1 = 0 ;
@@ -41870,14 +41862,14 @@ SWIGINTERN PyObject *_wrap_new_FormFactorCrystal__SWIG_1(PyObject *SWIGUNUSEDPAR
   FormFactorCrystal *result = 0 ;
   
   if ((nobjs < 3) || (nobjs > 3)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1, SWIGTYPE_p_Lattice,  0  | 0);
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1, SWIGTYPE_p_Lattice3D,  0  | 0);
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_FormFactorCrystal" "', argument " "1"" of type '" "Lattice const &""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_FormFactorCrystal" "', argument " "1"" of type '" "Lattice3D const &""'"); 
   }
   if (!argp1) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_FormFactorCrystal" "', argument " "1"" of type '" "Lattice const &""'"); 
+    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_FormFactorCrystal" "', argument " "1"" of type '" "Lattice3D const &""'"); 
   }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
+  arg1 = reinterpret_cast< Lattice3D * >(argp1);
   res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_IFormFactor,  0  | 0);
   if (!SWIG_IsOK(res2)) {
     SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "new_FormFactorCrystal" "', argument " "2"" of type '" "IFormFactor const &""'"); 
@@ -41894,7 +41886,7 @@ SWIGINTERN PyObject *_wrap_new_FormFactorCrystal__SWIG_1(PyObject *SWIGUNUSEDPAR
     SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_FormFactorCrystal" "', argument " "3"" of type '" "IFormFactor const &""'"); 
   }
   arg3 = reinterpret_cast< IFormFactor * >(argp3);
-  result = (FormFactorCrystal *)new FormFactorCrystal((Lattice const &)*arg1,(IFormFactor const &)*arg2,(IFormFactor const &)*arg3);
+  result = (FormFactorCrystal *)new FormFactorCrystal((Lattice3D const &)*arg1,(IFormFactor const &)*arg2,(IFormFactor const &)*arg3);
   resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_FormFactorCrystal, SWIG_POINTER_NEW |  0 );
   return resultobj;
 fail:
@@ -41912,7 +41904,7 @@ SWIGINTERN PyObject *_wrap_new_FormFactorCrystal(PyObject *self, PyObject *args)
   --argc;
   if (argc == 3) {
     int _v;
-    int res = SWIG_ConvertPtr(argv[0], 0, SWIGTYPE_p_Lattice, SWIG_POINTER_NO_NULL | 0);
+    int res = SWIG_ConvertPtr(argv[0], 0, SWIGTYPE_p_Lattice3D, SWIG_POINTER_NO_NULL | 0);
     _v = SWIG_CheckState(res);
     if (_v) {
       int res = SWIG_ConvertPtr(argv[1], 0, SWIGTYPE_p_IFormFactor, SWIG_POINTER_NO_NULL | 0);
@@ -41928,7 +41920,7 @@ SWIGINTERN PyObject *_wrap_new_FormFactorCrystal(PyObject *self, PyObject *args)
   }
   if (argc == 4) {
     int _v;
-    int res = SWIG_ConvertPtr(argv[0], 0, SWIGTYPE_p_Lattice, SWIG_POINTER_NO_NULL | 0);
+    int res = SWIG_ConvertPtr(argv[0], 0, SWIGTYPE_p_Lattice3D, SWIG_POINTER_NO_NULL | 0);
     _v = SWIG_CheckState(res);
     if (_v) {
       int res = SWIG_ConvertPtr(argv[1], 0, SWIGTYPE_p_IFormFactor, SWIG_POINTER_NO_NULL | 0);
@@ -41952,8 +41944,8 @@ SWIGINTERN PyObject *_wrap_new_FormFactorCrystal(PyObject *self, PyObject *args)
 fail:
   SWIG_Python_RaiseOrModifyTypeError("Wrong number or type of arguments for overloaded function 'new_FormFactorCrystal'.\n"
     "  Possible C/C++ prototypes are:\n"
-    "    FormFactorCrystal::FormFactorCrystal(Lattice const &,IFormFactor const &,IFormFactor const &,double)\n"
-    "    FormFactorCrystal::FormFactorCrystal(Lattice const &,IFormFactor const &,IFormFactor const &)\n");
+    "    FormFactorCrystal::FormFactorCrystal(Lattice3D const &,IFormFactor const &,IFormFactor const &,double)\n"
+    "    FormFactorCrystal::FormFactorCrystal(Lattice3D const &,IFormFactor const &,IFormFactor const &)\n");
   return 0;
 }
 
@@ -42794,152 +42786,60 @@ SWIGINTERN PyObject *IAbstractParticle_swigregister(PyObject *SWIGUNUSEDPARM(sel
   return SWIG_Py_Void();
 }
 
-SWIGINTERN PyObject *_wrap_IClusteredParticles_clone(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_new_Crystal__SWIG_0(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
-  IClusteredParticles *arg1 = (IClusteredParticles *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  IClusteredParticles *result = 0 ;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_IClusteredParticles, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "IClusteredParticles_clone" "', argument " "1"" of type '" "IClusteredParticles const *""'"); 
-  }
-  arg1 = reinterpret_cast< IClusteredParticles * >(argp1);
-  result = (IClusteredParticles *)((IClusteredParticles const *)arg1)->clone();
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_IClusteredParticles, 0 |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_IClusteredParticles_createTotalFormFactor(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  IClusteredParticles *arg1 = (IClusteredParticles *) 0 ;
-  IFormFactor *arg2 = 0 ;
-  IRotation *arg3 = (IRotation *) 0 ;
-  kvector_t *arg4 = 0 ;
+  IParticle *arg1 = 0 ;
+  Lattice3D *arg2 = 0 ;
+  double arg3 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
   int res2 = 0 ;
-  void *argp3 = 0 ;
-  int res3 = 0 ;
-  void *argp4 = 0 ;
-  int res4 = 0 ;
-  PyObject *swig_obj[4] ;
-  Swig::Director *director = 0;
-  IFormFactor *result = 0 ;
+  double val3 ;
+  int ecode3 = 0 ;
+  Crystal *result = 0 ;
   
-  if (!SWIG_Python_UnpackTuple(args, "IClusteredParticles_createTotalFormFactor", 4, 4, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_IClusteredParticles, 0 |  0 );
+  if ((nobjs < 3) || (nobjs > 3)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1, SWIGTYPE_p_IParticle,  0  | 0);
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "IClusteredParticles_createTotalFormFactor" "', argument " "1"" of type '" "IClusteredParticles const *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_Crystal" "', argument " "1"" of type '" "IParticle const &""'"); 
   }
-  arg1 = reinterpret_cast< IClusteredParticles * >(argp1);
-  res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_IFormFactor,  0  | 0);
+  if (!argp1) {
+    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_Crystal" "', argument " "1"" of type '" "IParticle const &""'"); 
+  }
+  arg1 = reinterpret_cast< IParticle * >(argp1);
+  res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_Lattice3D,  0  | 0);
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "IClusteredParticles_createTotalFormFactor" "', argument " "2"" of type '" "IFormFactor const &""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "new_Crystal" "', argument " "2"" of type '" "Lattice3D const &""'"); 
   }
   if (!argp2) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "IClusteredParticles_createTotalFormFactor" "', argument " "2"" of type '" "IFormFactor const &""'"); 
+    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_Crystal" "', argument " "2"" of type '" "Lattice3D const &""'"); 
   }
-  arg2 = reinterpret_cast< IFormFactor * >(argp2);
-  res3 = SWIG_ConvertPtr(swig_obj[2], &argp3,SWIGTYPE_p_IRotation, 0 |  0 );
-  if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "IClusteredParticles_createTotalFormFactor" "', argument " "3"" of type '" "IRotation const *""'"); 
-  }
-  arg3 = reinterpret_cast< IRotation * >(argp3);
-  res4 = SWIG_ConvertPtr(swig_obj[3], &argp4, SWIGTYPE_p_BasicVector3DT_double_t,  0  | 0);
-  if (!SWIG_IsOK(res4)) {
-    SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "IClusteredParticles_createTotalFormFactor" "', argument " "4"" of type '" "kvector_t const &""'"); 
-  }
-  if (!argp4) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "IClusteredParticles_createTotalFormFactor" "', argument " "4"" of type '" "kvector_t const &""'"); 
-  }
-  arg4 = reinterpret_cast< kvector_t * >(argp4);
-  result = (IFormFactor *)((IClusteredParticles const *)arg1)->createTotalFormFactor((IFormFactor const &)*arg2,(IRotation const *)arg3,(kvector_t const &)*arg4);
-  director = SWIG_DIRECTOR_CAST(result);
-  if (director) {
-    resultobj = director->swig_get_self();
-    Py_INCREF(resultobj);
-  } else {
-    resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_IFormFactor, 0 |  0 );
-  }
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_IClusteredParticles_homogeneousRegions(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  IClusteredParticles *arg1 = (IClusteredParticles *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  SwigValueWrapper< std::vector< HomogeneousRegion,std::allocator< HomogeneousRegion > > > result;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_IClusteredParticles, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "IClusteredParticles_homogeneousRegions" "', argument " "1"" of type '" "IClusteredParticles const *""'"); 
-  }
-  arg1 = reinterpret_cast< IClusteredParticles * >(argp1);
-  result = ((IClusteredParticles const *)arg1)->homogeneousRegions();
-  resultobj = SWIG_NewPointerObj((new std::vector< HomogeneousRegion,std::allocator< HomogeneousRegion > >(static_cast< const std::vector< HomogeneousRegion,std::allocator< HomogeneousRegion > >& >(result))), SWIGTYPE_p_std__vectorT_HomogeneousRegion_std__allocatorT_HomogeneousRegion_t_t, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_delete_IClusteredParticles(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  IClusteredParticles *arg1 = (IClusteredParticles *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_IClusteredParticles, SWIG_POINTER_DISOWN |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_IClusteredParticles" "', argument " "1"" of type '" "IClusteredParticles *""'"); 
-  }
-  arg1 = reinterpret_cast< IClusteredParticles * >(argp1);
-  delete arg1;
-  resultobj = SWIG_Py_Void();
+  arg2 = reinterpret_cast< Lattice3D * >(argp2);
+  ecode3 = SWIG_AsVal_double(swig_obj[2], &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "new_Crystal" "', argument " "3"" of type '" "double""'");
+  } 
+  arg3 = static_cast< double >(val3);
+  result = (Crystal *)new Crystal((IParticle const &)*arg1,(Lattice3D const &)*arg2,arg3);
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Crystal, SWIG_POINTER_NEW |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *IClusteredParticles_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *obj;
-  if (!SWIG_Python_UnpackTuple(args, "swigregister", 1, 1, &obj)) return NULL;
-  SWIG_TypeNewClientData(SWIGTYPE_p_IClusteredParticles, SWIG_NewClientData(obj));
-  return SWIG_Py_Void();
-}
-
-SWIGINTERN PyObject *_wrap_new_Crystal(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_new_Crystal__SWIG_1(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
   IParticle *arg1 = 0 ;
-  Lattice *arg2 = 0 ;
+  Lattice3D *arg2 = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
   int res2 = 0 ;
-  PyObject *swig_obj[2] ;
   Crystal *result = 0 ;
   
-  if (!SWIG_Python_UnpackTuple(args, "new_Crystal", 2, 2, swig_obj)) SWIG_fail;
+  if ((nobjs < 2) || (nobjs > 2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(swig_obj[0], &argp1, SWIGTYPE_p_IParticle,  0  | 0);
   if (!SWIG_IsOK(res1)) {
     SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_Crystal" "', argument " "1"" of type '" "IParticle const &""'"); 
@@ -42948,15 +42848,15 @@ SWIGINTERN PyObject *_wrap_new_Crystal(PyObject *SWIGUNUSEDPARM(self), PyObject
     SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_Crystal" "', argument " "1"" of type '" "IParticle const &""'"); 
   }
   arg1 = reinterpret_cast< IParticle * >(argp1);
-  res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_Lattice,  0  | 0);
+  res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_Lattice3D,  0  | 0);
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "new_Crystal" "', argument " "2"" of type '" "Lattice const &""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "new_Crystal" "', argument " "2"" of type '" "Lattice3D const &""'"); 
   }
   if (!argp2) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_Crystal" "', argument " "2"" of type '" "Lattice const &""'"); 
+    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_Crystal" "', argument " "2"" of type '" "Lattice3D const &""'"); 
   }
-  arg2 = reinterpret_cast< Lattice * >(argp2);
-  result = (Crystal *)new Crystal((IParticle const &)*arg1,(Lattice const &)*arg2);
+  arg2 = reinterpret_cast< Lattice3D * >(argp2);
+  result = (Crystal *)new Crystal((IParticle const &)*arg1,(Lattice3D const &)*arg2);
   resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Crystal, SWIG_POINTER_NEW |  0 );
   return resultobj;
 fail:
@@ -42964,6 +42864,54 @@ fail:
 }
 
 
+SWIGINTERN PyObject *_wrap_new_Crystal(PyObject *self, PyObject *args) {
+  Py_ssize_t argc;
+  PyObject *argv[4] = {
+    0
+  };
+  
+  if (!(argc = SWIG_Python_UnpackTuple(args, "new_Crystal", 0, 3, argv))) SWIG_fail;
+  --argc;
+  if (argc == 2) {
+    int _v;
+    int res = SWIG_ConvertPtr(argv[0], 0, SWIGTYPE_p_IParticle, SWIG_POINTER_NO_NULL | 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      int res = SWIG_ConvertPtr(argv[1], 0, SWIGTYPE_p_Lattice3D, SWIG_POINTER_NO_NULL | 0);
+      _v = SWIG_CheckState(res);
+      if (_v) {
+        return _wrap_new_Crystal__SWIG_1(self, argc, argv);
+      }
+    }
+  }
+  if (argc == 3) {
+    int _v;
+    int res = SWIG_ConvertPtr(argv[0], 0, SWIGTYPE_p_IParticle, SWIG_POINTER_NO_NULL | 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      int res = SWIG_ConvertPtr(argv[1], 0, SWIGTYPE_p_Lattice3D, SWIG_POINTER_NO_NULL | 0);
+      _v = SWIG_CheckState(res);
+      if (_v) {
+        {
+          int res = SWIG_AsVal_double(argv[2], NULL);
+          _v = SWIG_CheckState(res);
+        }
+        if (_v) {
+          return _wrap_new_Crystal__SWIG_0(self, argc, argv);
+        }
+      }
+    }
+  }
+  
+fail:
+  SWIG_Python_RaiseOrModifyTypeError("Wrong number or type of arguments for overloaded function 'new_Crystal'.\n"
+    "  Possible C/C++ prototypes are:\n"
+    "    Crystal::Crystal(IParticle const &,Lattice3D const &,double)\n"
+    "    Crystal::Crystal(IParticle const &,Lattice3D const &)\n");
+  return 0;
+}
+
+
 SWIGINTERN PyObject *_wrap_delete_Crystal(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   Crystal *arg1 = (Crystal *) 0 ;
@@ -43128,7 +43076,7 @@ SWIGINTERN PyObject *_wrap_Crystal_transformedLattice__SWIG_0(PyObject *SWIGUNUS
   int res1 = 0 ;
   void *argp2 = 0 ;
   int res2 = 0 ;
-  SwigValueWrapper< Lattice > result;
+  SwigValueWrapper< Lattice3D > result;
   
   if ((nobjs < 2) || (nobjs > 2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Crystal, 0 |  0 );
@@ -43142,7 +43090,7 @@ SWIGINTERN PyObject *_wrap_Crystal_transformedLattice__SWIG_0(PyObject *SWIGUNUS
   }
   arg2 = reinterpret_cast< IRotation * >(argp2);
   result = ((Crystal const *)arg1)->transformedLattice((IRotation const *)arg2);
-  resultobj = SWIG_NewPointerObj((new Lattice(static_cast< const Lattice& >(result))), SWIGTYPE_p_Lattice, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_NewPointerObj((new Lattice3D(static_cast< const Lattice3D& >(result))), SWIGTYPE_p_Lattice3D, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
@@ -43154,7 +43102,7 @@ SWIGINTERN PyObject *_wrap_Crystal_transformedLattice__SWIG_1(PyObject *SWIGUNUS
   Crystal *arg1 = (Crystal *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  SwigValueWrapper< Lattice > result;
+  SwigValueWrapper< Lattice3D > result;
   
   if ((nobjs < 1) || (nobjs > 1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Crystal, 0 |  0 );
@@ -43163,7 +43111,7 @@ SWIGINTERN PyObject *_wrap_Crystal_transformedLattice__SWIG_1(PyObject *SWIGUNUS
   }
   arg1 = reinterpret_cast< Crystal * >(argp1);
   result = ((Crystal const *)arg1)->transformedLattice();
-  resultobj = SWIG_NewPointerObj((new Lattice(static_cast< const Lattice& >(result))), SWIGTYPE_p_Lattice, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_NewPointerObj((new Lattice3D(static_cast< const Lattice3D& >(result))), SWIGTYPE_p_Lattice3D, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
@@ -43211,35 +43159,6 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Crystal_setPositionVariance(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  Crystal *arg1 = (Crystal *) 0 ;
-  double arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  PyObject *swig_obj[2] ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "Crystal_setPositionVariance", 2, 2, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Crystal, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Crystal_setPositionVariance" "', argument " "1"" of type '" "Crystal *""'"); 
-  }
-  arg1 = reinterpret_cast< Crystal * >(argp1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Crystal_setPositionVariance" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  (arg1)->setPositionVariance(arg2);
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
 SWIGINTERN PyObject *_wrap_Crystal_getChildren(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   Crystal *arg1 = (Crystal *) 0 ;
@@ -43932,7 +43851,7 @@ SWIGINTERN PyObject *IParticle_swigregister(PyObject *SWIGUNUSEDPARM(self), PyOb
 
 SWIGINTERN PyObject *_wrap_new_MesoCrystal(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  IClusteredParticles *arg1 = 0 ;
+  Crystal *arg1 = 0 ;
   IFormFactor *arg2 = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
@@ -43942,14 +43861,14 @@ SWIGINTERN PyObject *_wrap_new_MesoCrystal(PyObject *SWIGUNUSEDPARM(self), PyObj
   MesoCrystal *result = 0 ;
   
   if (!SWIG_Python_UnpackTuple(args, "new_MesoCrystal", 2, 2, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1, SWIGTYPE_p_IClusteredParticles,  0  | 0);
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1, SWIGTYPE_p_Crystal,  0  | 0);
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_MesoCrystal" "', argument " "1"" of type '" "IClusteredParticles const &""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_MesoCrystal" "', argument " "1"" of type '" "Crystal const &""'"); 
   }
   if (!argp1) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_MesoCrystal" "', argument " "1"" of type '" "IClusteredParticles const &""'"); 
+    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_MesoCrystal" "', argument " "1"" of type '" "Crystal const &""'"); 
   }
-  arg1 = reinterpret_cast< IClusteredParticles * >(argp1);
+  arg1 = reinterpret_cast< Crystal * >(argp1);
   res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_IFormFactor,  0  | 0);
   if (!SWIG_IsOK(res2)) {
     SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "new_MesoCrystal" "', argument " "2"" of type '" "IFormFactor const &""'"); 
@@ -43958,7 +43877,7 @@ SWIGINTERN PyObject *_wrap_new_MesoCrystal(PyObject *SWIGUNUSEDPARM(self), PyObj
     SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_MesoCrystal" "', argument " "2"" of type '" "IFormFactor const &""'"); 
   }
   arg2 = reinterpret_cast< IFormFactor * >(argp2);
-  result = (MesoCrystal *)new MesoCrystal((IClusteredParticles const &)*arg1,(IFormFactor const &)*arg2);
+  result = (MesoCrystal *)new MesoCrystal((Crystal const &)*arg1,(IFormFactor const &)*arg2);
   resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_MesoCrystal, SWIG_POINTER_NEW |  0 );
   return resultobj;
 fail:
@@ -50352,260 +50271,6 @@ SWIGINTERN PyObject *FTDistribution2DVoigt_swiginit(PyObject *SWIGUNUSEDPARM(sel
   return SWIG_Python_InitShadowInstance(args);
 }
 
-SWIGINTERN PyObject *_wrap_delete_ILayout(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  ILayout *arg1 = (ILayout *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ILayout, SWIG_POINTER_DISOWN |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_ILayout" "', argument " "1"" of type '" "ILayout *""'"); 
-  }
-  arg1 = reinterpret_cast< ILayout * >(argp1);
-  delete arg1;
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_ILayout_clone(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  ILayout *arg1 = (ILayout *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  ILayout *result = 0 ;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ILayout, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ILayout_clone" "', argument " "1"" of type '" "ILayout const *""'"); 
-  }
-  arg1 = reinterpret_cast< ILayout * >(argp1);
-  result = (ILayout *)((ILayout const *)arg1)->clone();
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ILayout, 0 |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_ILayout_accept(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  ILayout *arg1 = (ILayout *) 0 ;
-  INodeVisitor *arg2 = (INodeVisitor *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
-  PyObject *swig_obj[2] ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "ILayout_accept", 2, 2, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ILayout, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ILayout_accept" "', argument " "1"" of type '" "ILayout const *""'"); 
-  }
-  arg1 = reinterpret_cast< ILayout * >(argp1);
-  res2 = SWIG_ConvertPtr(swig_obj[1], &argp2,SWIGTYPE_p_INodeVisitor, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ILayout_accept" "', argument " "2"" of type '" "INodeVisitor *""'"); 
-  }
-  arg2 = reinterpret_cast< INodeVisitor * >(argp2);
-  ((ILayout const *)arg1)->accept(arg2);
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_ILayout_particles(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  ILayout *arg1 = (ILayout *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  SwigValueWrapper< SafePointerVector< IParticle > > result;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ILayout, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ILayout_particles" "', argument " "1"" of type '" "ILayout const *""'"); 
-  }
-  arg1 = reinterpret_cast< ILayout * >(argp1);
-  result = ((ILayout const *)arg1)->particles();
-  resultobj = SWIG_NewPointerObj((new SafePointerVector< IParticle >(static_cast< const SafePointerVector< IParticle >& >(result))), SWIGTYPE_p_SafePointerVectorT_IParticle_t, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_ILayout_interferenceFunction(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  ILayout *arg1 = (ILayout *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  IInterferenceFunction *result = 0 ;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ILayout, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ILayout_interferenceFunction" "', argument " "1"" of type '" "ILayout const *""'"); 
-  }
-  arg1 = reinterpret_cast< ILayout * >(argp1);
-  result = (IInterferenceFunction *)((ILayout const *)arg1)->interferenceFunction();
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_IInterferenceFunction, 0 |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_ILayout_getTotalAbundance(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  ILayout *arg1 = (ILayout *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  double result;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ILayout, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ILayout_getTotalAbundance" "', argument " "1"" of type '" "ILayout const *""'"); 
-  }
-  arg1 = reinterpret_cast< ILayout * >(argp1);
-  result = (double)((ILayout const *)arg1)->getTotalAbundance();
-  resultobj = SWIG_From_double(static_cast< double >(result));
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_ILayout_totalParticleSurfaceDensity(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  ILayout *arg1 = (ILayout *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  double result;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ILayout, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ILayout_totalParticleSurfaceDensity" "', argument " "1"" of type '" "ILayout const *""'"); 
-  }
-  arg1 = reinterpret_cast< ILayout * >(argp1);
-  result = (double)((ILayout const *)arg1)->totalParticleSurfaceDensity();
-  resultobj = SWIG_From_double(static_cast< double >(result));
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_ILayout_setTotalParticleSurfaceDensity(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  ILayout *arg1 = (ILayout *) 0 ;
-  double arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  PyObject *swig_obj[2] ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "ILayout_setTotalParticleSurfaceDensity", 2, 2, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ILayout, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ILayout_setTotalParticleSurfaceDensity" "', argument " "1"" of type '" "ILayout *""'"); 
-  }
-  arg1 = reinterpret_cast< ILayout * >(argp1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ILayout_setTotalParticleSurfaceDensity" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  (arg1)->setTotalParticleSurfaceDensity(arg2);
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_ILayout_weight(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  ILayout *arg1 = (ILayout *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  double result;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ILayout, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ILayout_weight" "', argument " "1"" of type '" "ILayout const *""'"); 
-  }
-  arg1 = reinterpret_cast< ILayout * >(argp1);
-  result = (double)((ILayout const *)arg1)->weight();
-  resultobj = SWIG_From_double(static_cast< double >(result));
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_ILayout_setWeight(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  ILayout *arg1 = (ILayout *) 0 ;
-  double arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  PyObject *swig_obj[2] ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "ILayout_setWeight", 2, 2, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ILayout, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ILayout_setWeight" "', argument " "1"" of type '" "ILayout *""'"); 
-  }
-  arg1 = reinterpret_cast< ILayout * >(argp1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ILayout_setWeight" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  (arg1)->setWeight(arg2);
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *ILayout_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *obj;
-  if (!SWIG_Python_UnpackTuple(args, "swigregister", 1, 1, &obj)) return NULL;
-  SWIG_TypeNewClientData(SWIGTYPE_p_ILayout, SWIG_NewClientData(obj));
-  return SWIG_Py_Void();
-}
-
 SWIGINTERN PyObject *_wrap_delete_IPeakShape(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   IPeakShape *arg1 = (IPeakShape *) 0 ;
@@ -52646,66 +52311,6 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_InterferenceFunction2DLattice_createSquare(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  double arg1 ;
-  double arg2 ;
-  double val1 ;
-  int ecode1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  PyObject *swig_obj[2] ;
-  InterferenceFunction2DLattice *result = 0 ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "InterferenceFunction2DLattice_createSquare", 2, 2, swig_obj)) SWIG_fail;
-  ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
-  if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "InterferenceFunction2DLattice_createSquare" "', argument " "1"" of type '" "double""'");
-  } 
-  arg1 = static_cast< double >(val1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "InterferenceFunction2DLattice_createSquare" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  result = (InterferenceFunction2DLattice *)InterferenceFunction2DLattice::createSquare(arg1,arg2);
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_InterferenceFunction2DLattice, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_InterferenceFunction2DLattice_createHexagonal(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  double arg1 ;
-  double arg2 ;
-  double val1 ;
-  int ecode1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  PyObject *swig_obj[2] ;
-  InterferenceFunction2DLattice *result = 0 ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "InterferenceFunction2DLattice_createHexagonal", 2, 2, swig_obj)) SWIG_fail;
-  ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
-  if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "InterferenceFunction2DLattice_createHexagonal" "', argument " "1"" of type '" "double""'");
-  } 
-  arg1 = static_cast< double >(val1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "InterferenceFunction2DLattice_createHexagonal" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  result = (InterferenceFunction2DLattice *)InterferenceFunction2DLattice::createHexagonal(arg1,arg2);
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_InterferenceFunction2DLattice, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
 SWIGINTERN PyObject *_wrap_InterferenceFunction2DLattice_setDecayFunction(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   InterferenceFunction2DLattice *arg1 = (InterferenceFunction2DLattice *) 0 ;
@@ -53145,98 +52750,6 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_InterferenceFunction2DParaCrystal_createSquare(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  double arg1 ;
-  double arg2 ;
-  double arg3 ;
-  double arg4 ;
-  double val1 ;
-  int ecode1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  double val3 ;
-  int ecode3 = 0 ;
-  double val4 ;
-  int ecode4 = 0 ;
-  PyObject *swig_obj[4] ;
-  InterferenceFunction2DParaCrystal *result = 0 ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "InterferenceFunction2DParaCrystal_createSquare", 4, 4, swig_obj)) SWIG_fail;
-  ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
-  if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "InterferenceFunction2DParaCrystal_createSquare" "', argument " "1"" of type '" "double""'");
-  } 
-  arg1 = static_cast< double >(val1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "InterferenceFunction2DParaCrystal_createSquare" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  ecode3 = SWIG_AsVal_double(swig_obj[2], &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "InterferenceFunction2DParaCrystal_createSquare" "', argument " "3"" of type '" "double""'");
-  } 
-  arg3 = static_cast< double >(val3);
-  ecode4 = SWIG_AsVal_double(swig_obj[3], &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "InterferenceFunction2DParaCrystal_createSquare" "', argument " "4"" of type '" "double""'");
-  } 
-  arg4 = static_cast< double >(val4);
-  result = (InterferenceFunction2DParaCrystal *)InterferenceFunction2DParaCrystal::createSquare(arg1,arg2,arg3,arg4);
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_InterferenceFunction2DParaCrystal, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_InterferenceFunction2DParaCrystal_createHexagonal(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  double arg1 ;
-  double arg2 ;
-  double arg3 ;
-  double arg4 ;
-  double val1 ;
-  int ecode1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  double val3 ;
-  int ecode3 = 0 ;
-  double val4 ;
-  int ecode4 = 0 ;
-  PyObject *swig_obj[4] ;
-  InterferenceFunction2DParaCrystal *result = 0 ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "InterferenceFunction2DParaCrystal_createHexagonal", 4, 4, swig_obj)) SWIG_fail;
-  ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
-  if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "InterferenceFunction2DParaCrystal_createHexagonal" "', argument " "1"" of type '" "double""'");
-  } 
-  arg1 = static_cast< double >(val1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "InterferenceFunction2DParaCrystal_createHexagonal" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  ecode3 = SWIG_AsVal_double(swig_obj[2], &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "InterferenceFunction2DParaCrystal_createHexagonal" "', argument " "3"" of type '" "double""'");
-  } 
-  arg3 = static_cast< double >(val3);
-  ecode4 = SWIG_AsVal_double(swig_obj[3], &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "InterferenceFunction2DParaCrystal_createHexagonal" "', argument " "4"" of type '" "double""'");
-  } 
-  arg4 = static_cast< double >(val4);
-  result = (InterferenceFunction2DParaCrystal *)InterferenceFunction2DParaCrystal::createHexagonal(arg1,arg2,arg3,arg4);
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_InterferenceFunction2DParaCrystal, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
 SWIGINTERN PyObject *_wrap_InterferenceFunction2DParaCrystal_setDomainSizes(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   InterferenceFunction2DParaCrystal *arg1 = (InterferenceFunction2DParaCrystal *) 0 ;
@@ -53878,98 +53391,6 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_InterferenceFunction2DSuperLattice_createSquare(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  double arg1 ;
-  double arg2 ;
-  unsigned int arg3 ;
-  unsigned int arg4 ;
-  double val1 ;
-  int ecode1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  unsigned int val3 ;
-  int ecode3 = 0 ;
-  unsigned int val4 ;
-  int ecode4 = 0 ;
-  PyObject *swig_obj[4] ;
-  InterferenceFunction2DSuperLattice *result = 0 ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "InterferenceFunction2DSuperLattice_createSquare", 4, 4, swig_obj)) SWIG_fail;
-  ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
-  if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "InterferenceFunction2DSuperLattice_createSquare" "', argument " "1"" of type '" "double""'");
-  } 
-  arg1 = static_cast< double >(val1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "InterferenceFunction2DSuperLattice_createSquare" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  ecode3 = SWIG_AsVal_unsigned_SS_int(swig_obj[2], &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "InterferenceFunction2DSuperLattice_createSquare" "', argument " "3"" of type '" "unsigned int""'");
-  } 
-  arg3 = static_cast< unsigned int >(val3);
-  ecode4 = SWIG_AsVal_unsigned_SS_int(swig_obj[3], &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "InterferenceFunction2DSuperLattice_createSquare" "', argument " "4"" of type '" "unsigned int""'");
-  } 
-  arg4 = static_cast< unsigned int >(val4);
-  result = (InterferenceFunction2DSuperLattice *)InterferenceFunction2DSuperLattice::createSquare(arg1,arg2,arg3,arg4);
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_InterferenceFunction2DSuperLattice, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_InterferenceFunction2DSuperLattice_createHexagonal(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  double arg1 ;
-  double arg2 ;
-  unsigned int arg3 ;
-  unsigned int arg4 ;
-  double val1 ;
-  int ecode1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  unsigned int val3 ;
-  int ecode3 = 0 ;
-  unsigned int val4 ;
-  int ecode4 = 0 ;
-  PyObject *swig_obj[4] ;
-  InterferenceFunction2DSuperLattice *result = 0 ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "InterferenceFunction2DSuperLattice_createHexagonal", 4, 4, swig_obj)) SWIG_fail;
-  ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
-  if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "InterferenceFunction2DSuperLattice_createHexagonal" "', argument " "1"" of type '" "double""'");
-  } 
-  arg1 = static_cast< double >(val1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "InterferenceFunction2DSuperLattice_createHexagonal" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  ecode3 = SWIG_AsVal_unsigned_SS_int(swig_obj[2], &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "InterferenceFunction2DSuperLattice_createHexagonal" "', argument " "3"" of type '" "unsigned int""'");
-  } 
-  arg3 = static_cast< unsigned int >(val3);
-  ecode4 = SWIG_AsVal_unsigned_SS_int(swig_obj[3], &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "InterferenceFunction2DSuperLattice_createHexagonal" "', argument " "4"" of type '" "unsigned int""'");
-  } 
-  arg4 = static_cast< unsigned int >(val4);
-  result = (InterferenceFunction2DSuperLattice *)InterferenceFunction2DSuperLattice::createHexagonal(arg1,arg2,arg3,arg4);
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_InterferenceFunction2DSuperLattice, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
 SWIGINTERN PyObject *_wrap_InterferenceFunction2DSuperLattice_evaluate__SWIG_0(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
   InterferenceFunction2DSuperLattice *arg1 = (InterferenceFunction2DSuperLattice *) 0 ;
@@ -54259,7 +53680,7 @@ SWIGINTERN PyObject *InterferenceFunction2DSuperLattice_swiginit(PyObject *SWIGU
 
 SWIGINTERN PyObject *_wrap_new_InterferenceFunction3DLattice(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  Lattice *arg1 = 0 ;
+  Lattice3D *arg1 = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
@@ -54267,15 +53688,15 @@ SWIGINTERN PyObject *_wrap_new_InterferenceFunction3DLattice(PyObject *SWIGUNUSE
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1, SWIGTYPE_p_Lattice,  0  | 0);
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1, SWIGTYPE_p_Lattice3D,  0  | 0);
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_InterferenceFunction3DLattice" "', argument " "1"" of type '" "Lattice const &""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_InterferenceFunction3DLattice" "', argument " "1"" of type '" "Lattice3D const &""'"); 
   }
   if (!argp1) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_InterferenceFunction3DLattice" "', argument " "1"" of type '" "Lattice const &""'"); 
+    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_InterferenceFunction3DLattice" "', argument " "1"" of type '" "Lattice3D const &""'"); 
   }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
-  result = (InterferenceFunction3DLattice *)new InterferenceFunction3DLattice((Lattice const &)*arg1);
+  arg1 = reinterpret_cast< Lattice3D * >(argp1);
+  result = (InterferenceFunction3DLattice *)new InterferenceFunction3DLattice((Lattice3D const &)*arg1);
   resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_InterferenceFunction3DLattice, SWIG_POINTER_NEW |  0 );
   return resultobj;
 fail:
@@ -54395,7 +53816,7 @@ SWIGINTERN PyObject *_wrap_InterferenceFunction3DLattice_lattice(PyObject *SWIGU
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  Lattice *result = 0 ;
+  Lattice3D *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -54404,8 +53825,8 @@ SWIGINTERN PyObject *_wrap_InterferenceFunction3DLattice_lattice(PyObject *SWIGU
     SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "InterferenceFunction3DLattice_lattice" "', argument " "1"" of type '" "InterferenceFunction3DLattice const *""'"); 
   }
   arg1 = reinterpret_cast< InterferenceFunction3DLattice * >(argp1);
-  result = (Lattice *) &((InterferenceFunction3DLattice const *)arg1)->lattice();
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Lattice, 0 |  0 );
+  result = (Lattice3D *) &((InterferenceFunction3DLattice const *)arg1)->lattice();
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Lattice3D, 0 |  0 );
   return resultobj;
 fail:
   return NULL;
@@ -54744,98 +54165,6 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_InterferenceFunctionFinite2DLattice_createSquare(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  double arg1 ;
-  double arg2 ;
-  unsigned int arg3 ;
-  unsigned int arg4 ;
-  double val1 ;
-  int ecode1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  unsigned int val3 ;
-  int ecode3 = 0 ;
-  unsigned int val4 ;
-  int ecode4 = 0 ;
-  PyObject *swig_obj[4] ;
-  InterferenceFunctionFinite2DLattice *result = 0 ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "InterferenceFunctionFinite2DLattice_createSquare", 4, 4, swig_obj)) SWIG_fail;
-  ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
-  if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "InterferenceFunctionFinite2DLattice_createSquare" "', argument " "1"" of type '" "double""'");
-  } 
-  arg1 = static_cast< double >(val1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "InterferenceFunctionFinite2DLattice_createSquare" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  ecode3 = SWIG_AsVal_unsigned_SS_int(swig_obj[2], &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "InterferenceFunctionFinite2DLattice_createSquare" "', argument " "3"" of type '" "unsigned int""'");
-  } 
-  arg3 = static_cast< unsigned int >(val3);
-  ecode4 = SWIG_AsVal_unsigned_SS_int(swig_obj[3], &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "InterferenceFunctionFinite2DLattice_createSquare" "', argument " "4"" of type '" "unsigned int""'");
-  } 
-  arg4 = static_cast< unsigned int >(val4);
-  result = (InterferenceFunctionFinite2DLattice *)InterferenceFunctionFinite2DLattice::createSquare(arg1,arg2,arg3,arg4);
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_InterferenceFunctionFinite2DLattice, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_InterferenceFunctionFinite2DLattice_createHexagonal(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  double arg1 ;
-  double arg2 ;
-  unsigned int arg3 ;
-  unsigned int arg4 ;
-  double val1 ;
-  int ecode1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  unsigned int val3 ;
-  int ecode3 = 0 ;
-  unsigned int val4 ;
-  int ecode4 = 0 ;
-  PyObject *swig_obj[4] ;
-  InterferenceFunctionFinite2DLattice *result = 0 ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "InterferenceFunctionFinite2DLattice_createHexagonal", 4, 4, swig_obj)) SWIG_fail;
-  ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
-  if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "InterferenceFunctionFinite2DLattice_createHexagonal" "', argument " "1"" of type '" "double""'");
-  } 
-  arg1 = static_cast< double >(val1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "InterferenceFunctionFinite2DLattice_createHexagonal" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  ecode3 = SWIG_AsVal_unsigned_SS_int(swig_obj[2], &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "InterferenceFunctionFinite2DLattice_createHexagonal" "', argument " "3"" of type '" "unsigned int""'");
-  } 
-  arg3 = static_cast< unsigned int >(val3);
-  ecode4 = SWIG_AsVal_unsigned_SS_int(swig_obj[3], &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "InterferenceFunctionFinite2DLattice_createHexagonal" "', argument " "4"" of type '" "unsigned int""'");
-  } 
-  arg4 = static_cast< unsigned int >(val4);
-  result = (InterferenceFunctionFinite2DLattice *)InterferenceFunctionFinite2DLattice::createHexagonal(arg1,arg2,arg3,arg4);
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_InterferenceFunctionFinite2DLattice, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
 SWIGINTERN PyObject *_wrap_InterferenceFunctionFinite2DLattice_numberUnitCells1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   InterferenceFunctionFinite2DLattice *arg1 = (InterferenceFunctionFinite2DLattice *) 0 ;
@@ -55016,7 +54345,7 @@ SWIGINTERN PyObject *InterferenceFunctionFinite2DLattice_swiginit(PyObject *SWIG
 
 SWIGINTERN PyObject *_wrap_new_InterferenceFunctionFinite3DLattice(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  Lattice *arg1 = 0 ;
+  Lattice3D *arg1 = 0 ;
   unsigned int arg2 ;
   unsigned int arg3 ;
   unsigned int arg4 ;
@@ -55032,14 +54361,14 @@ SWIGINTERN PyObject *_wrap_new_InterferenceFunctionFinite3DLattice(PyObject *SWI
   InterferenceFunctionFinite3DLattice *result = 0 ;
   
   if (!SWIG_Python_UnpackTuple(args, "new_InterferenceFunctionFinite3DLattice", 4, 4, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1, SWIGTYPE_p_Lattice,  0  | 0);
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1, SWIGTYPE_p_Lattice3D,  0  | 0);
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_InterferenceFunctionFinite3DLattice" "', argument " "1"" of type '" "Lattice const &""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_InterferenceFunctionFinite3DLattice" "', argument " "1"" of type '" "Lattice3D const &""'"); 
   }
   if (!argp1) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_InterferenceFunctionFinite3DLattice" "', argument " "1"" of type '" "Lattice const &""'"); 
+    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_InterferenceFunctionFinite3DLattice" "', argument " "1"" of type '" "Lattice3D const &""'"); 
   }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
+  arg1 = reinterpret_cast< Lattice3D * >(argp1);
   ecode2 = SWIG_AsVal_unsigned_SS_int(swig_obj[1], &val2);
   if (!SWIG_IsOK(ecode2)) {
     SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "new_InterferenceFunctionFinite3DLattice" "', argument " "2"" of type '" "unsigned int""'");
@@ -55055,7 +54384,7 @@ SWIGINTERN PyObject *_wrap_new_InterferenceFunctionFinite3DLattice(PyObject *SWI
     SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "new_InterferenceFunctionFinite3DLattice" "', argument " "4"" of type '" "unsigned int""'");
   } 
   arg4 = static_cast< unsigned int >(val4);
-  result = (InterferenceFunctionFinite3DLattice *)new InterferenceFunctionFinite3DLattice((Lattice const &)*arg1,arg2,arg3,arg4);
+  result = (InterferenceFunctionFinite3DLattice *)new InterferenceFunctionFinite3DLattice((Lattice3D const &)*arg1,arg2,arg3,arg4);
   resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_InterferenceFunctionFinite3DLattice, SWIG_POINTER_NEW |  0 );
   return resultobj;
 fail:
@@ -55212,7 +54541,7 @@ SWIGINTERN PyObject *_wrap_InterferenceFunctionFinite3DLattice_lattice(PyObject
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  Lattice *result = 0 ;
+  Lattice3D *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -55221,8 +54550,8 @@ SWIGINTERN PyObject *_wrap_InterferenceFunctionFinite3DLattice_lattice(PyObject
     SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "InterferenceFunctionFinite3DLattice_lattice" "', argument " "1"" of type '" "InterferenceFunctionFinite3DLattice const *""'"); 
   }
   arg1 = reinterpret_cast< InterferenceFunctionFinite3DLattice * >(argp1);
-  result = (Lattice *) &((InterferenceFunctionFinite3DLattice const *)arg1)->lattice();
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Lattice, 0 |  0 );
+  result = (Lattice3D *) &((InterferenceFunctionFinite3DLattice const *)arg1)->lattice();
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Lattice3D, 0 |  0 );
   return resultobj;
 fail:
   return NULL;
@@ -56884,6 +56213,58 @@ fail:
 }
 
 
+SWIGINTERN PyObject *_wrap_ParticleLayout_weight(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  ParticleLayout *arg1 = (ParticleLayout *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject *swig_obj[1] ;
+  double result;
+  
+  if (!args) SWIG_fail;
+  swig_obj[0] = args;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ParticleLayout, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ParticleLayout_weight" "', argument " "1"" of type '" "ParticleLayout const *""'"); 
+  }
+  arg1 = reinterpret_cast< ParticleLayout * >(argp1);
+  result = (double)((ParticleLayout const *)arg1)->weight();
+  resultobj = SWIG_From_double(static_cast< double >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_ParticleLayout_setWeight(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  ParticleLayout *arg1 = (ParticleLayout *) 0 ;
+  double arg2 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  double val2 ;
+  int ecode2 = 0 ;
+  PyObject *swig_obj[2] ;
+  
+  if (!SWIG_Python_UnpackTuple(args, "ParticleLayout_setWeight", 2, 2, swig_obj)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ParticleLayout, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ParticleLayout_setWeight" "', argument " "1"" of type '" "ParticleLayout *""'"); 
+  }
+  arg1 = reinterpret_cast< ParticleLayout * >(argp1);
+  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ParticleLayout_setWeight" "', argument " "2"" of type '" "double""'");
+  } 
+  arg2 = static_cast< double >(val2);
+  (arg1)->setWeight(arg2);
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
 SWIGINTERN PyObject *ParticleLayout_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *obj;
   if (!SWIG_Python_UnpackTuple(args, "swigregister", 1, 1, &obj)) return NULL;
@@ -57190,7 +56571,7 @@ fail:
 SWIGINTERN PyObject *_wrap_Layer_addLayout(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   Layer *arg1 = (Layer *) 0 ;
-  ILayout *arg2 = 0 ;
+  ParticleLayout *arg2 = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
@@ -57203,15 +56584,15 @@ SWIGINTERN PyObject *_wrap_Layer_addLayout(PyObject *SWIGUNUSEDPARM(self), PyObj
     SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_addLayout" "', argument " "1"" of type '" "Layer *""'"); 
   }
   arg1 = reinterpret_cast< Layer * >(argp1);
-  res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_ILayout,  0  | 0);
+  res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_ParticleLayout,  0  | 0);
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_addLayout" "', argument " "2"" of type '" "ILayout const &""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_addLayout" "', argument " "2"" of type '" "ParticleLayout const &""'"); 
   }
   if (!argp2) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Layer_addLayout" "', argument " "2"" of type '" "ILayout const &""'"); 
+    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Layer_addLayout" "', argument " "2"" of type '" "ParticleLayout const &""'"); 
   }
-  arg2 = reinterpret_cast< ILayout * >(argp2);
-  (arg1)->addLayout((ILayout const &)*arg2);
+  arg2 = reinterpret_cast< ParticleLayout * >(argp2);
+  (arg1)->addLayout((ParticleLayout const &)*arg2);
   resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
@@ -57248,7 +56629,7 @@ SWIGINTERN PyObject *_wrap_Layer_layouts(PyObject *SWIGUNUSEDPARM(self), PyObjec
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  SwigValueWrapper< std::vector< ILayout const *,std::allocator< ILayout const * > > > result;
+  SwigValueWrapper< std::vector< ParticleLayout const *,std::allocator< ParticleLayout const * > > > result;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -57258,7 +56639,7 @@ SWIGINTERN PyObject *_wrap_Layer_layouts(PyObject *SWIGUNUSEDPARM(self), PyObjec
   }
   arg1 = reinterpret_cast< Layer * >(argp1);
   result = ((Layer const *)arg1)->layouts();
-  resultobj = SWIG_NewPointerObj((new std::vector< ILayout const *,std::allocator< ILayout const * > >(static_cast< const std::vector< ILayout const *,std::allocator< ILayout const * > >& >(result))), SWIGTYPE_p_std__vectorT_ILayout_const_p_std__allocatorT_ILayout_const_p_t_t, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_NewPointerObj((new std::vector< ParticleLayout const *,std::allocator< ParticleLayout const * > >(static_cast< const std::vector< ParticleLayout const *,std::allocator< ParticleLayout const * > >& >(result))), SWIGTYPE_p_std__vectorT_ParticleLayout_const_p_std__allocatorT_ParticleLayout_const_p_t_t, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
@@ -67791,513 +67172,6 @@ SWIGINTERN PyObject *FormFactorSphereLogNormalRadius_swiginit(PyObject *SWIGUNUS
   return SWIG_Python_InitShadowInstance(args);
 }
 
-SWIGINTERN PyObject *_wrap_delete_ILatticeOrientation(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  ILatticeOrientation *arg1 = (ILatticeOrientation *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ILatticeOrientation, SWIG_POINTER_DISOWN |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_ILatticeOrientation" "', argument " "1"" of type '" "ILatticeOrientation *""'"); 
-  }
-  arg1 = reinterpret_cast< ILatticeOrientation * >(argp1);
-  delete arg1;
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_ILatticeOrientation_clone(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  ILatticeOrientation *arg1 = (ILatticeOrientation *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  ILatticeOrientation *result = 0 ;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ILatticeOrientation, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ILatticeOrientation_clone" "', argument " "1"" of type '" "ILatticeOrientation const *""'"); 
-  }
-  arg1 = reinterpret_cast< ILatticeOrientation * >(argp1);
-  result = (ILatticeOrientation *)((ILatticeOrientation const *)arg1)->clone();
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ILatticeOrientation, 0 |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_ILatticeOrientation_usePrimitiveLattice(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  ILatticeOrientation *arg1 = (ILatticeOrientation *) 0 ;
-  Lattice *arg2 = 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
-  PyObject *swig_obj[2] ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "ILatticeOrientation_usePrimitiveLattice", 2, 2, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ILatticeOrientation, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ILatticeOrientation_usePrimitiveLattice" "', argument " "1"" of type '" "ILatticeOrientation *""'"); 
-  }
-  arg1 = reinterpret_cast< ILatticeOrientation * >(argp1);
-  res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_Lattice,  0  | 0);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ILatticeOrientation_usePrimitiveLattice" "', argument " "2"" of type '" "Lattice const &""'"); 
-  }
-  if (!argp2) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "ILatticeOrientation_usePrimitiveLattice" "', argument " "2"" of type '" "Lattice const &""'"); 
-  }
-  arg2 = reinterpret_cast< Lattice * >(argp2);
-  (arg1)->usePrimitiveLattice((Lattice const &)*arg2);
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_ILatticeOrientation_transformation(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  ILatticeOrientation *arg1 = (ILatticeOrientation *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  Transform3D result;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ILatticeOrientation, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ILatticeOrientation_transformation" "', argument " "1"" of type '" "ILatticeOrientation const *""'"); 
-  }
-  arg1 = reinterpret_cast< ILatticeOrientation * >(argp1);
-  result = ((ILatticeOrientation const *)arg1)->transformation();
-  resultobj = SWIG_NewPointerObj((new Transform3D(static_cast< const Transform3D& >(result))), SWIGTYPE_p_Transform3D, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *ILatticeOrientation_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *obj;
-  if (!SWIG_Python_UnpackTuple(args, "swigregister", 1, 1, &obj)) return NULL;
-  SWIG_TypeNewClientData(SWIGTYPE_p_ILatticeOrientation, SWIG_NewClientData(obj));
-  return SWIG_Py_Void();
-}
-
-SWIGINTERN PyObject *_wrap_new_MillerIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  double arg1 ;
-  double arg2 ;
-  double arg3 ;
-  double val1 ;
-  int ecode1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  double val3 ;
-  int ecode3 = 0 ;
-  PyObject *swig_obj[3] ;
-  MillerIndex *result = 0 ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "new_MillerIndex", 3, 3, swig_obj)) SWIG_fail;
-  ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
-  if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "new_MillerIndex" "', argument " "1"" of type '" "double""'");
-  } 
-  arg1 = static_cast< double >(val1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "new_MillerIndex" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  ecode3 = SWIG_AsVal_double(swig_obj[2], &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "new_MillerIndex" "', argument " "3"" of type '" "double""'");
-  } 
-  arg3 = static_cast< double >(val3);
-  result = (MillerIndex *)new MillerIndex(arg1,arg2,arg3);
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_MillerIndex, SWIG_POINTER_NEW |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_MillerIndex_h_set(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  MillerIndex *arg1 = (MillerIndex *) 0 ;
-  double arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  PyObject *swig_obj[2] ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "MillerIndex_h_set", 2, 2, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_MillerIndex, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MillerIndex_h_set" "', argument " "1"" of type '" "MillerIndex *""'"); 
-  }
-  arg1 = reinterpret_cast< MillerIndex * >(argp1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "MillerIndex_h_set" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  if (arg1) (arg1)->h = arg2;
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_MillerIndex_h_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  MillerIndex *arg1 = (MillerIndex *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  double result;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_MillerIndex, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MillerIndex_h_get" "', argument " "1"" of type '" "MillerIndex *""'"); 
-  }
-  arg1 = reinterpret_cast< MillerIndex * >(argp1);
-  result = (double) ((arg1)->h);
-  resultobj = SWIG_From_double(static_cast< double >(result));
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_MillerIndex_k_set(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  MillerIndex *arg1 = (MillerIndex *) 0 ;
-  double arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  PyObject *swig_obj[2] ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "MillerIndex_k_set", 2, 2, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_MillerIndex, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MillerIndex_k_set" "', argument " "1"" of type '" "MillerIndex *""'"); 
-  }
-  arg1 = reinterpret_cast< MillerIndex * >(argp1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "MillerIndex_k_set" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  if (arg1) (arg1)->k = arg2;
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_MillerIndex_k_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  MillerIndex *arg1 = (MillerIndex *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  double result;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_MillerIndex, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MillerIndex_k_get" "', argument " "1"" of type '" "MillerIndex *""'"); 
-  }
-  arg1 = reinterpret_cast< MillerIndex * >(argp1);
-  result = (double) ((arg1)->k);
-  resultobj = SWIG_From_double(static_cast< double >(result));
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_MillerIndex_l_set(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  MillerIndex *arg1 = (MillerIndex *) 0 ;
-  double arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  PyObject *swig_obj[2] ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "MillerIndex_l_set", 2, 2, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_MillerIndex, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MillerIndex_l_set" "', argument " "1"" of type '" "MillerIndex *""'"); 
-  }
-  arg1 = reinterpret_cast< MillerIndex * >(argp1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "MillerIndex_l_set" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  if (arg1) (arg1)->l = arg2;
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_MillerIndex_l_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  MillerIndex *arg1 = (MillerIndex *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  double result;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_MillerIndex, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MillerIndex_l_get" "', argument " "1"" of type '" "MillerIndex *""'"); 
-  }
-  arg1 = reinterpret_cast< MillerIndex * >(argp1);
-  result = (double) ((arg1)->l);
-  resultobj = SWIG_From_double(static_cast< double >(result));
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_delete_MillerIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  MillerIndex *arg1 = (MillerIndex *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_MillerIndex, SWIG_POINTER_DISOWN |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_MillerIndex" "', argument " "1"" of type '" "MillerIndex *""'"); 
-  }
-  arg1 = reinterpret_cast< MillerIndex * >(argp1);
-  delete arg1;
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *MillerIndex_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *obj;
-  if (!SWIG_Python_UnpackTuple(args, "swigregister", 1, 1, &obj)) return NULL;
-  SWIG_TypeNewClientData(SWIGTYPE_p_MillerIndex, SWIG_NewClientData(obj));
-  return SWIG_Py_Void();
-}
-
-SWIGINTERN PyObject *MillerIndex_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  return SWIG_Python_InitShadowInstance(args);
-}
-
-SWIGINTERN PyObject *_wrap_new_MillerIndexOrientation(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  MillerIndexOrientation::QComponent arg1 ;
-  SwigValueWrapper< MillerIndex > arg2 ;
-  MillerIndexOrientation::QComponent arg3 ;
-  SwigValueWrapper< MillerIndex > arg4 ;
-  int val1 ;
-  int ecode1 = 0 ;
-  void *argp2 ;
-  int res2 = 0 ;
-  int val3 ;
-  int ecode3 = 0 ;
-  void *argp4 ;
-  int res4 = 0 ;
-  PyObject *swig_obj[4] ;
-  MillerIndexOrientation *result = 0 ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "new_MillerIndexOrientation", 4, 4, swig_obj)) SWIG_fail;
-  ecode1 = SWIG_AsVal_int(swig_obj[0], &val1);
-  if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "new_MillerIndexOrientation" "', argument " "1"" of type '" "MillerIndexOrientation::QComponent""'");
-  } 
-  arg1 = static_cast< MillerIndexOrientation::QComponent >(val1);
-  {
-    res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_MillerIndex,  0  | 0);
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "new_MillerIndexOrientation" "', argument " "2"" of type '" "MillerIndex""'"); 
-    }  
-    if (!argp2) {
-      SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_MillerIndexOrientation" "', argument " "2"" of type '" "MillerIndex""'");
-    } else {
-      MillerIndex * temp = reinterpret_cast< MillerIndex * >(argp2);
-      arg2 = *temp;
-      if (SWIG_IsNewObj(res2)) delete temp;
-    }
-  }
-  ecode3 = SWIG_AsVal_int(swig_obj[2], &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "new_MillerIndexOrientation" "', argument " "3"" of type '" "MillerIndexOrientation::QComponent""'");
-  } 
-  arg3 = static_cast< MillerIndexOrientation::QComponent >(val3);
-  {
-    res4 = SWIG_ConvertPtr(swig_obj[3], &argp4, SWIGTYPE_p_MillerIndex,  0  | 0);
-    if (!SWIG_IsOK(res4)) {
-      SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "new_MillerIndexOrientation" "', argument " "4"" of type '" "MillerIndex""'"); 
-    }  
-    if (!argp4) {
-      SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_MillerIndexOrientation" "', argument " "4"" of type '" "MillerIndex""'");
-    } else {
-      MillerIndex * temp = reinterpret_cast< MillerIndex * >(argp4);
-      arg4 = *temp;
-      if (SWIG_IsNewObj(res4)) delete temp;
-    }
-  }
-  result = (MillerIndexOrientation *)new MillerIndexOrientation(arg1,arg2,arg3,arg4);
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_MillerIndexOrientation, SWIG_POINTER_NEW |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_delete_MillerIndexOrientation(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  MillerIndexOrientation *arg1 = (MillerIndexOrientation *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_MillerIndexOrientation, SWIG_POINTER_DISOWN |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_MillerIndexOrientation" "', argument " "1"" of type '" "MillerIndexOrientation *""'"); 
-  }
-  arg1 = reinterpret_cast< MillerIndexOrientation * >(argp1);
-  delete arg1;
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_MillerIndexOrientation_clone(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  MillerIndexOrientation *arg1 = (MillerIndexOrientation *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  MillerIndexOrientation *result = 0 ;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_MillerIndexOrientation, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MillerIndexOrientation_clone" "', argument " "1"" of type '" "MillerIndexOrientation const *""'"); 
-  }
-  arg1 = reinterpret_cast< MillerIndexOrientation * >(argp1);
-  result = (MillerIndexOrientation *)((MillerIndexOrientation const *)arg1)->clone();
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_MillerIndexOrientation, 0 |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_MillerIndexOrientation_usePrimitiveLattice(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  MillerIndexOrientation *arg1 = (MillerIndexOrientation *) 0 ;
-  Lattice *arg2 = 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
-  PyObject *swig_obj[2] ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "MillerIndexOrientation_usePrimitiveLattice", 2, 2, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_MillerIndexOrientation, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MillerIndexOrientation_usePrimitiveLattice" "', argument " "1"" of type '" "MillerIndexOrientation *""'"); 
-  }
-  arg1 = reinterpret_cast< MillerIndexOrientation * >(argp1);
-  res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_Lattice,  0  | 0);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "MillerIndexOrientation_usePrimitiveLattice" "', argument " "2"" of type '" "Lattice const &""'"); 
-  }
-  if (!argp2) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "MillerIndexOrientation_usePrimitiveLattice" "', argument " "2"" of type '" "Lattice const &""'"); 
-  }
-  arg2 = reinterpret_cast< Lattice * >(argp2);
-  (arg1)->usePrimitiveLattice((Lattice const &)*arg2);
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_MillerIndexOrientation_transformation(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  MillerIndexOrientation *arg1 = (MillerIndexOrientation *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  Transform3D result;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_MillerIndexOrientation, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MillerIndexOrientation_transformation" "', argument " "1"" of type '" "MillerIndexOrientation const *""'"); 
-  }
-  arg1 = reinterpret_cast< MillerIndexOrientation * >(argp1);
-  result = ((MillerIndexOrientation const *)arg1)->transformation();
-  resultobj = SWIG_NewPointerObj((new Transform3D(static_cast< const Transform3D& >(result))), SWIGTYPE_p_Transform3D, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *MillerIndexOrientation_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *obj;
-  if (!SWIG_Python_UnpackTuple(args, "swigregister", 1, 1, &obj)) return NULL;
-  SWIG_TypeNewClientData(SWIGTYPE_p_MillerIndexOrientation, SWIG_NewClientData(obj));
-  return SWIG_Py_Void();
-}
-
-SWIGINTERN PyObject *MillerIndexOrientation_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  return SWIG_Python_InitShadowInstance(args);
-}
-
 SWIGINTERN PyObject *_wrap_delete_ISelectionRule(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ISelectionRule *arg1 = (ISelectionRule *) 0 ;
@@ -68518,20 +67392,7 @@ SWIGINTERN PyObject *SimpleSelectionRule_swiginit(PyObject *SWIGUNUSEDPARM(self)
   return SWIG_Python_InitShadowInstance(args);
 }
 
-SWIGINTERN PyObject *_wrap_new_Lattice__SWIG_0(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **SWIGUNUSEDPARM(swig_obj)) {
-  PyObject *resultobj = 0;
-  Lattice *result = 0 ;
-  
-  if ((nobjs < 0) || (nobjs > 0)) SWIG_fail;
-  result = (Lattice *)new Lattice();
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Lattice, SWIG_POINTER_NEW |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_new_Lattice__SWIG_1(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
+SWIGINTERN PyObject *_wrap_new_Lattice3D__SWIG_0(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
   kvector_t arg1 ;
   kvector_t arg2 ;
@@ -68542,16 +67403,16 @@ SWIGINTERN PyObject *_wrap_new_Lattice__SWIG_1(PyObject *SWIGUNUSEDPARM(self), P
   int res2 = 0 ;
   void *argp3 ;
   int res3 = 0 ;
-  Lattice *result = 0 ;
+  Lattice3D *result = 0 ;
   
   if ((nobjs < 3) || (nobjs > 3)) SWIG_fail;
   {
     res1 = SWIG_ConvertPtr(swig_obj[0], &argp1, SWIGTYPE_p_BasicVector3DT_double_t,  0  | 0);
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_Lattice" "', argument " "1"" of type '" "kvector_t const""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_Lattice3D" "', argument " "1"" of type '" "kvector_t const""'"); 
     }  
     if (!argp1) {
-      SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_Lattice" "', argument " "1"" of type '" "kvector_t const""'");
+      SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_Lattice3D" "', argument " "1"" of type '" "kvector_t const""'");
     } else {
       kvector_t * temp = reinterpret_cast< kvector_t * >(argp1);
       arg1 = *temp;
@@ -68561,10 +67422,10 @@ SWIGINTERN PyObject *_wrap_new_Lattice__SWIG_1(PyObject *SWIGUNUSEDPARM(self), P
   {
     res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_BasicVector3DT_double_t,  0  | 0);
     if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "new_Lattice" "', argument " "2"" of type '" "kvector_t const""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "new_Lattice3D" "', argument " "2"" of type '" "kvector_t const""'"); 
     }  
     if (!argp2) {
-      SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_Lattice" "', argument " "2"" of type '" "kvector_t const""'");
+      SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_Lattice3D" "', argument " "2"" of type '" "kvector_t const""'");
     } else {
       kvector_t * temp = reinterpret_cast< kvector_t * >(argp2);
       arg2 = *temp;
@@ -68574,65 +67435,62 @@ SWIGINTERN PyObject *_wrap_new_Lattice__SWIG_1(PyObject *SWIGUNUSEDPARM(self), P
   {
     res3 = SWIG_ConvertPtr(swig_obj[2], &argp3, SWIGTYPE_p_BasicVector3DT_double_t,  0  | 0);
     if (!SWIG_IsOK(res3)) {
-      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "new_Lattice" "', argument " "3"" of type '" "kvector_t const""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "new_Lattice3D" "', argument " "3"" of type '" "kvector_t const""'"); 
     }  
     if (!argp3) {
-      SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_Lattice" "', argument " "3"" of type '" "kvector_t const""'");
+      SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_Lattice3D" "', argument " "3"" of type '" "kvector_t const""'");
     } else {
       kvector_t * temp = reinterpret_cast< kvector_t * >(argp3);
       arg3 = *temp;
       if (SWIG_IsNewObj(res3)) delete temp;
     }
   }
-  result = (Lattice *)new Lattice(arg1,arg2,arg3);
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Lattice, SWIG_POINTER_NEW |  0 );
+  result = (Lattice3D *)new Lattice3D(arg1,arg2,arg3);
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Lattice3D, SWIG_POINTER_NEW |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_new_Lattice__SWIG_2(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
+SWIGINTERN PyObject *_wrap_new_Lattice3D__SWIG_1(PyObject *SWIGUNUSEDPARM(self), Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
-  Lattice *arg1 = 0 ;
+  Lattice3D *arg1 = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  Lattice *result = 0 ;
+  Lattice3D *result = 0 ;
   
   if ((nobjs < 1) || (nobjs > 1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1, SWIGTYPE_p_Lattice,  0  | 0);
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1, SWIGTYPE_p_Lattice3D,  0  | 0);
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_Lattice" "', argument " "1"" of type '" "Lattice const &""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_Lattice3D" "', argument " "1"" of type '" "Lattice3D const &""'"); 
   }
   if (!argp1) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_Lattice" "', argument " "1"" of type '" "Lattice const &""'"); 
+    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "new_Lattice3D" "', argument " "1"" of type '" "Lattice3D const &""'"); 
   }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
-  result = (Lattice *)new Lattice((Lattice const &)*arg1);
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Lattice, SWIG_POINTER_NEW |  0 );
+  arg1 = reinterpret_cast< Lattice3D * >(argp1);
+  result = (Lattice3D *)new Lattice3D((Lattice3D const &)*arg1);
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Lattice3D, SWIG_POINTER_NEW |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_new_Lattice(PyObject *self, PyObject *args) {
+SWIGINTERN PyObject *_wrap_new_Lattice3D(PyObject *self, PyObject *args) {
   Py_ssize_t argc;
   PyObject *argv[4] = {
     0
   };
   
-  if (!(argc = SWIG_Python_UnpackTuple(args, "new_Lattice", 0, 3, argv))) SWIG_fail;
+  if (!(argc = SWIG_Python_UnpackTuple(args, "new_Lattice3D", 0, 3, argv))) SWIG_fail;
   --argc;
-  if (argc == 0) {
-    return _wrap_new_Lattice__SWIG_0(self, argc, argv);
-  }
   if (argc == 1) {
     int _v;
-    int res = SWIG_ConvertPtr(argv[0], 0, SWIGTYPE_p_Lattice, SWIG_POINTER_NO_NULL | 0);
+    int res = SWIG_ConvertPtr(argv[0], 0, SWIGTYPE_p_Lattice3D, SWIG_POINTER_NO_NULL | 0);
     _v = SWIG_CheckState(res);
     if (_v) {
-      return _wrap_new_Lattice__SWIG_2(self, argc, argv);
+      return _wrap_new_Lattice3D__SWIG_1(self, argc, argv);
     }
   }
   if (argc == 3) {
@@ -68646,36 +67504,35 @@ SWIGINTERN PyObject *_wrap_new_Lattice(PyObject *self, PyObject *args) {
         int res = SWIG_ConvertPtr(argv[2], 0, SWIGTYPE_p_BasicVector3DT_double_t, SWIG_POINTER_NO_NULL | 0);
         _v = SWIG_CheckState(res);
         if (_v) {
-          return _wrap_new_Lattice__SWIG_1(self, argc, argv);
+          return _wrap_new_Lattice3D__SWIG_0(self, argc, argv);
         }
       }
     }
   }
   
 fail:
-  SWIG_Python_RaiseOrModifyTypeError("Wrong number or type of arguments for overloaded function 'new_Lattice'.\n"
+  SWIG_Python_RaiseOrModifyTypeError("Wrong number or type of arguments for overloaded function 'new_Lattice3D'.\n"
     "  Possible C/C++ prototypes are:\n"
-    "    Lattice::Lattice()\n"
-    "    Lattice::Lattice(kvector_t const,kvector_t const,kvector_t const)\n"
-    "    Lattice::Lattice(Lattice const &)\n");
+    "    Lattice3D::Lattice3D(kvector_t const,kvector_t const,kvector_t const)\n"
+    "    Lattice3D::Lattice3D(Lattice3D const &)\n");
   return 0;
 }
 
 
-SWIGINTERN PyObject *_wrap_delete_Lattice(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_delete_Lattice3D(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  Lattice *arg1 = (Lattice *) 0 ;
+  Lattice3D *arg1 = (Lattice3D *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice, SWIG_POINTER_DISOWN |  0 );
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice3D, SWIG_POINTER_DISOWN |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_Lattice" "', argument " "1"" of type '" "Lattice *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_Lattice3D" "', argument " "1"" of type '" "Lattice3D *""'"); 
   }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
+  arg1 = reinterpret_cast< Lattice3D * >(argp1);
   delete arg1;
   resultobj = SWIG_Py_Void();
   return resultobj;
@@ -68684,9 +67541,9 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Lattice_accept(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Lattice3D_accept(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  Lattice *arg1 = (Lattice *) 0 ;
+  Lattice3D *arg1 = (Lattice3D *) 0 ;
   INodeVisitor *arg2 = (INodeVisitor *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
@@ -68694,18 +67551,18 @@ SWIGINTERN PyObject *_wrap_Lattice_accept(PyObject *SWIGUNUSEDPARM(self), PyObje
   int res2 = 0 ;
   PyObject *swig_obj[2] ;
   
-  if (!SWIG_Python_UnpackTuple(args, "Lattice_accept", 2, 2, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice, 0 |  0 );
+  if (!SWIG_Python_UnpackTuple(args, "Lattice3D_accept", 2, 2, swig_obj)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice3D, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice_accept" "', argument " "1"" of type '" "Lattice const *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice3D_accept" "', argument " "1"" of type '" "Lattice3D const *""'"); 
   }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
+  arg1 = reinterpret_cast< Lattice3D * >(argp1);
   res2 = SWIG_ConvertPtr(swig_obj[1], &argp2,SWIGTYPE_p_INodeVisitor, 0 |  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Lattice_accept" "', argument " "2"" of type '" "INodeVisitor *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Lattice3D_accept" "', argument " "2"" of type '" "INodeVisitor *""'"); 
   }
   arg2 = reinterpret_cast< INodeVisitor * >(argp2);
-  ((Lattice const *)arg1)->accept(arg2);
+  ((Lattice3D const *)arg1)->accept(arg2);
   resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
@@ -68713,54 +67570,54 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Lattice_transformed(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Lattice3D_transformed(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  Lattice *arg1 = (Lattice *) 0 ;
+  Lattice3D *arg1 = (Lattice3D *) 0 ;
   Transform3D *arg2 = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
   int res2 = 0 ;
   PyObject *swig_obj[2] ;
-  SwigValueWrapper< Lattice > result;
+  SwigValueWrapper< Lattice3D > result;
   
-  if (!SWIG_Python_UnpackTuple(args, "Lattice_transformed", 2, 2, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice, 0 |  0 );
+  if (!SWIG_Python_UnpackTuple(args, "Lattice3D_transformed", 2, 2, swig_obj)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice3D, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice_transformed" "', argument " "1"" of type '" "Lattice const *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice3D_transformed" "', argument " "1"" of type '" "Lattice3D const *""'"); 
   }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
+  arg1 = reinterpret_cast< Lattice3D * >(argp1);
   res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_Transform3D,  0  | 0);
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Lattice_transformed" "', argument " "2"" of type '" "Transform3D const &""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Lattice3D_transformed" "', argument " "2"" of type '" "Transform3D const &""'"); 
   }
   if (!argp2) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Lattice_transformed" "', argument " "2"" of type '" "Transform3D const &""'"); 
+    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Lattice3D_transformed" "', argument " "2"" of type '" "Transform3D const &""'"); 
   }
   arg2 = reinterpret_cast< Transform3D * >(argp2);
-  result = ((Lattice const *)arg1)->transformed((Transform3D const &)*arg2);
-  resultobj = SWIG_NewPointerObj((new Lattice(static_cast< const Lattice& >(result))), SWIGTYPE_p_Lattice, SWIG_POINTER_OWN |  0 );
+  result = ((Lattice3D const *)arg1)->transformed((Transform3D const &)*arg2);
+  resultobj = SWIG_NewPointerObj((new Lattice3D(static_cast< const Lattice3D& >(result))), SWIGTYPE_p_Lattice3D, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Lattice_initialize(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Lattice3D_initialize(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  Lattice *arg1 = (Lattice *) 0 ;
+  Lattice3D *arg1 = (Lattice3D *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice, 0 |  0 );
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice3D, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice_initialize" "', argument " "1"" of type '" "Lattice const *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice3D_initialize" "', argument " "1"" of type '" "Lattice3D *""'"); 
   }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
-  ((Lattice const *)arg1)->initialize();
+  arg1 = reinterpret_cast< Lattice3D * >(argp1);
+  (arg1)->initialize();
   resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
@@ -68768,9 +67625,9 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Lattice_getBasisVectorA(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Lattice3D_getBasisVectorA(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  Lattice *arg1 = (Lattice *) 0 ;
+  Lattice3D *arg1 = (Lattice3D *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
@@ -68778,12 +67635,12 @@ SWIGINTERN PyObject *_wrap_Lattice_getBasisVectorA(PyObject *SWIGUNUSEDPARM(self
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice, 0 |  0 );
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice3D, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice_getBasisVectorA" "', argument " "1"" of type '" "Lattice const *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice3D_getBasisVectorA" "', argument " "1"" of type '" "Lattice3D const *""'"); 
   }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
-  result = ((Lattice const *)arg1)->getBasisVectorA();
+  arg1 = reinterpret_cast< Lattice3D * >(argp1);
+  result = ((Lattice3D const *)arg1)->getBasisVectorA();
   resultobj = SWIG_NewPointerObj((new kvector_t(static_cast< const kvector_t& >(result))), SWIGTYPE_p_BasicVector3DT_double_t, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
@@ -68791,9 +67648,9 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Lattice_getBasisVectorB(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Lattice3D_getBasisVectorB(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  Lattice *arg1 = (Lattice *) 0 ;
+  Lattice3D *arg1 = (Lattice3D *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
@@ -68801,12 +67658,12 @@ SWIGINTERN PyObject *_wrap_Lattice_getBasisVectorB(PyObject *SWIGUNUSEDPARM(self
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice, 0 |  0 );
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice3D, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice_getBasisVectorB" "', argument " "1"" of type '" "Lattice const *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice3D_getBasisVectorB" "', argument " "1"" of type '" "Lattice3D const *""'"); 
   }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
-  result = ((Lattice const *)arg1)->getBasisVectorB();
+  arg1 = reinterpret_cast< Lattice3D * >(argp1);
+  result = ((Lattice3D const *)arg1)->getBasisVectorB();
   resultobj = SWIG_NewPointerObj((new kvector_t(static_cast< const kvector_t& >(result))), SWIGTYPE_p_BasicVector3DT_double_t, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
@@ -68814,9 +67671,9 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Lattice_getBasisVectorC(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Lattice3D_getBasisVectorC(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  Lattice *arg1 = (Lattice *) 0 ;
+  Lattice3D *arg1 = (Lattice3D *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
@@ -68824,12 +67681,12 @@ SWIGINTERN PyObject *_wrap_Lattice_getBasisVectorC(PyObject *SWIGUNUSEDPARM(self
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice, 0 |  0 );
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice3D, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice_getBasisVectorC" "', argument " "1"" of type '" "Lattice const *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice3D_getBasisVectorC" "', argument " "1"" of type '" "Lattice3D const *""'"); 
   }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
-  result = ((Lattice const *)arg1)->getBasisVectorC();
+  arg1 = reinterpret_cast< Lattice3D * >(argp1);
+  result = ((Lattice3D const *)arg1)->getBasisVectorC();
   resultobj = SWIG_NewPointerObj((new kvector_t(static_cast< const kvector_t& >(result))), SWIGTYPE_p_BasicVector3DT_double_t, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
@@ -68837,78 +67694,9 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Lattice_resetBasis(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Lattice3D_getMillerDirection(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  Lattice *arg1 = (Lattice *) 0 ;
-  kvector_t arg2 ;
-  kvector_t arg3 ;
-  kvector_t arg4 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  void *argp2 ;
-  int res2 = 0 ;
-  void *argp3 ;
-  int res3 = 0 ;
-  void *argp4 ;
-  int res4 = 0 ;
-  PyObject *swig_obj[4] ;
-  
-  if (!SWIG_Python_UnpackTuple(args, "Lattice_resetBasis", 4, 4, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice_resetBasis" "', argument " "1"" of type '" "Lattice *""'"); 
-  }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
-  {
-    res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_BasicVector3DT_double_t,  0  | 0);
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Lattice_resetBasis" "', argument " "2"" of type '" "kvector_t const""'"); 
-    }  
-    if (!argp2) {
-      SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Lattice_resetBasis" "', argument " "2"" of type '" "kvector_t const""'");
-    } else {
-      kvector_t * temp = reinterpret_cast< kvector_t * >(argp2);
-      arg2 = *temp;
-      if (SWIG_IsNewObj(res2)) delete temp;
-    }
-  }
-  {
-    res3 = SWIG_ConvertPtr(swig_obj[2], &argp3, SWIGTYPE_p_BasicVector3DT_double_t,  0  | 0);
-    if (!SWIG_IsOK(res3)) {
-      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Lattice_resetBasis" "', argument " "3"" of type '" "kvector_t const""'"); 
-    }  
-    if (!argp3) {
-      SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Lattice_resetBasis" "', argument " "3"" of type '" "kvector_t const""'");
-    } else {
-      kvector_t * temp = reinterpret_cast< kvector_t * >(argp3);
-      arg3 = *temp;
-      if (SWIG_IsNewObj(res3)) delete temp;
-    }
-  }
-  {
-    res4 = SWIG_ConvertPtr(swig_obj[3], &argp4, SWIGTYPE_p_BasicVector3DT_double_t,  0  | 0);
-    if (!SWIG_IsOK(res4)) {
-      SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "Lattice_resetBasis" "', argument " "4"" of type '" "kvector_t const""'"); 
-    }  
-    if (!argp4) {
-      SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Lattice_resetBasis" "', argument " "4"" of type '" "kvector_t const""'");
-    } else {
-      kvector_t * temp = reinterpret_cast< kvector_t * >(argp4);
-      arg4 = *temp;
-      if (SWIG_IsNewObj(res4)) delete temp;
-    }
-  }
-  (arg1)->resetBasis(arg2,arg3,arg4);
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Lattice_getMillerDirection(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  Lattice *arg1 = (Lattice *) 0 ;
+  Lattice3D *arg1 = (Lattice3D *) 0 ;
   double arg2 ;
   double arg3 ;
   double arg4 ;
@@ -68923,28 +67711,28 @@ SWIGINTERN PyObject *_wrap_Lattice_getMillerDirection(PyObject *SWIGUNUSEDPARM(s
   PyObject *swig_obj[4] ;
   kvector_t result;
   
-  if (!SWIG_Python_UnpackTuple(args, "Lattice_getMillerDirection", 4, 4, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice, 0 |  0 );
+  if (!SWIG_Python_UnpackTuple(args, "Lattice3D_getMillerDirection", 4, 4, swig_obj)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice3D, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice_getMillerDirection" "', argument " "1"" of type '" "Lattice const *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice3D_getMillerDirection" "', argument " "1"" of type '" "Lattice3D const *""'"); 
   }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
+  arg1 = reinterpret_cast< Lattice3D * >(argp1);
   ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Lattice_getMillerDirection" "', argument " "2"" of type '" "double""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Lattice3D_getMillerDirection" "', argument " "2"" of type '" "double""'");
   } 
   arg2 = static_cast< double >(val2);
   ecode3 = SWIG_AsVal_double(swig_obj[2], &val3);
   if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Lattice_getMillerDirection" "', argument " "3"" of type '" "double""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Lattice3D_getMillerDirection" "', argument " "3"" of type '" "double""'");
   } 
   arg3 = static_cast< double >(val3);
   ecode4 = SWIG_AsVal_double(swig_obj[3], &val4);
   if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Lattice_getMillerDirection" "', argument " "4"" of type '" "double""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Lattice3D_getMillerDirection" "', argument " "4"" of type '" "double""'");
   } 
   arg4 = static_cast< double >(val4);
-  result = ((Lattice const *)arg1)->getMillerDirection(arg2,arg3,arg4);
+  result = ((Lattice3D const *)arg1)->getMillerDirection(arg2,arg3,arg4);
   resultobj = SWIG_NewPointerObj((new kvector_t(static_cast< const kvector_t& >(result))), SWIGTYPE_p_BasicVector3DT_double_t, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
@@ -68952,9 +67740,9 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Lattice_volume(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Lattice3D_unitCellVolume(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  Lattice *arg1 = (Lattice *) 0 ;
+  Lattice3D *arg1 = (Lattice3D *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
@@ -68962,12 +67750,12 @@ SWIGINTERN PyObject *_wrap_Lattice_volume(PyObject *SWIGUNUSEDPARM(self), PyObje
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice, 0 |  0 );
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice3D, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice_volume" "', argument " "1"" of type '" "Lattice const *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice3D_unitCellVolume" "', argument " "1"" of type '" "Lattice3D const *""'"); 
   }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
-  result = (double)((Lattice const *)arg1)->volume();
+  arg1 = reinterpret_cast< Lattice3D * >(argp1);
+  result = (double)((Lattice3D const *)arg1)->unitCellVolume();
   resultobj = SWIG_From_double(static_cast< double >(result));
   return resultobj;
 fail:
@@ -68975,9 +67763,9 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Lattice_getReciprocalLatticeBasis(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Lattice3D_getReciprocalLatticeBasis(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  Lattice *arg1 = (Lattice *) 0 ;
+  Lattice3D *arg1 = (Lattice3D *) 0 ;
   kvector_t *arg2 = 0 ;
   kvector_t *arg3 = 0 ;
   kvector_t *arg4 = 0 ;
@@ -68991,37 +67779,37 @@ SWIGINTERN PyObject *_wrap_Lattice_getReciprocalLatticeBasis(PyObject *SWIGUNUSE
   int res4 = 0 ;
   PyObject *swig_obj[4] ;
   
-  if (!SWIG_Python_UnpackTuple(args, "Lattice_getReciprocalLatticeBasis", 4, 4, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice, 0 |  0 );
+  if (!SWIG_Python_UnpackTuple(args, "Lattice3D_getReciprocalLatticeBasis", 4, 4, swig_obj)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice3D, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice_getReciprocalLatticeBasis" "', argument " "1"" of type '" "Lattice const *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice3D_getReciprocalLatticeBasis" "', argument " "1"" of type '" "Lattice3D const *""'"); 
   }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
+  arg1 = reinterpret_cast< Lattice3D * >(argp1);
   res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_BasicVector3DT_double_t,  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Lattice_getReciprocalLatticeBasis" "', argument " "2"" of type '" "kvector_t &""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Lattice3D_getReciprocalLatticeBasis" "', argument " "2"" of type '" "kvector_t &""'"); 
   }
   if (!argp2) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Lattice_getReciprocalLatticeBasis" "', argument " "2"" of type '" "kvector_t &""'"); 
+    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Lattice3D_getReciprocalLatticeBasis" "', argument " "2"" of type '" "kvector_t &""'"); 
   }
   arg2 = reinterpret_cast< kvector_t * >(argp2);
   res3 = SWIG_ConvertPtr(swig_obj[2], &argp3, SWIGTYPE_p_BasicVector3DT_double_t,  0 );
   if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Lattice_getReciprocalLatticeBasis" "', argument " "3"" of type '" "kvector_t &""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Lattice3D_getReciprocalLatticeBasis" "', argument " "3"" of type '" "kvector_t &""'"); 
   }
   if (!argp3) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Lattice_getReciprocalLatticeBasis" "', argument " "3"" of type '" "kvector_t &""'"); 
+    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Lattice3D_getReciprocalLatticeBasis" "', argument " "3"" of type '" "kvector_t &""'"); 
   }
   arg3 = reinterpret_cast< kvector_t * >(argp3);
   res4 = SWIG_ConvertPtr(swig_obj[3], &argp4, SWIGTYPE_p_BasicVector3DT_double_t,  0 );
   if (!SWIG_IsOK(res4)) {
-    SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "Lattice_getReciprocalLatticeBasis" "', argument " "4"" of type '" "kvector_t &""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "Lattice3D_getReciprocalLatticeBasis" "', argument " "4"" of type '" "kvector_t &""'"); 
   }
   if (!argp4) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Lattice_getReciprocalLatticeBasis" "', argument " "4"" of type '" "kvector_t &""'"); 
+    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Lattice3D_getReciprocalLatticeBasis" "', argument " "4"" of type '" "kvector_t &""'"); 
   }
   arg4 = reinterpret_cast< kvector_t * >(argp4);
-  ((Lattice const *)arg1)->getReciprocalLatticeBasis(*arg2,*arg3,*arg4);
+  ((Lattice3D const *)arg1)->getReciprocalLatticeBasis(*arg2,*arg3,*arg4);
   resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
@@ -69029,47 +67817,9 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Lattice_getNearestLatticeVectorCoordinates(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  Lattice *arg1 = (Lattice *) 0 ;
-  kvector_t arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  void *argp2 ;
-  int res2 = 0 ;
-  PyObject *swig_obj[2] ;
-  SwigValueWrapper< BasicVector3D< int > > result;
-  
-  if (!SWIG_Python_UnpackTuple(args, "Lattice_getNearestLatticeVectorCoordinates", 2, 2, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice_getNearestLatticeVectorCoordinates" "', argument " "1"" of type '" "Lattice const *""'"); 
-  }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
-  {
-    res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_BasicVector3DT_double_t,  0  | 0);
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Lattice_getNearestLatticeVectorCoordinates" "', argument " "2"" of type '" "kvector_t const""'"); 
-    }  
-    if (!argp2) {
-      SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Lattice_getNearestLatticeVectorCoordinates" "', argument " "2"" of type '" "kvector_t const""'");
-    } else {
-      kvector_t * temp = reinterpret_cast< kvector_t * >(argp2);
-      arg2 = *temp;
-      if (SWIG_IsNewObj(res2)) delete temp;
-    }
-  }
-  result = ((Lattice const *)arg1)->getNearestLatticeVectorCoordinates(arg2);
-  resultobj = SWIG_NewPointerObj((new ivector_t(static_cast< const ivector_t& >(result))), SWIGTYPE_p_BasicVector3DT_int_t, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Lattice_getNearestReciprocalLatticeVectorCoordinates(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Lattice3D_getNearestReciprocalLatticeVectorCoordinates(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  Lattice *arg1 = (Lattice *) 0 ;
+  Lattice3D *arg1 = (Lattice3D *) 0 ;
   kvector_t arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
@@ -69078,26 +67828,26 @@ SWIGINTERN PyObject *_wrap_Lattice_getNearestReciprocalLatticeVectorCoordinates(
   PyObject *swig_obj[2] ;
   SwigValueWrapper< BasicVector3D< int > > result;
   
-  if (!SWIG_Python_UnpackTuple(args, "Lattice_getNearestReciprocalLatticeVectorCoordinates", 2, 2, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice, 0 |  0 );
+  if (!SWIG_Python_UnpackTuple(args, "Lattice3D_getNearestReciprocalLatticeVectorCoordinates", 2, 2, swig_obj)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice3D, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice_getNearestReciprocalLatticeVectorCoordinates" "', argument " "1"" of type '" "Lattice const *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice3D_getNearestReciprocalLatticeVectorCoordinates" "', argument " "1"" of type '" "Lattice3D const *""'"); 
   }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
+  arg1 = reinterpret_cast< Lattice3D * >(argp1);
   {
     res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_BasicVector3DT_double_t,  0  | 0);
     if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Lattice_getNearestReciprocalLatticeVectorCoordinates" "', argument " "2"" of type '" "kvector_t const""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Lattice3D_getNearestReciprocalLatticeVectorCoordinates" "', argument " "2"" of type '" "kvector_t const""'"); 
     }  
     if (!argp2) {
-      SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Lattice_getNearestReciprocalLatticeVectorCoordinates" "', argument " "2"" of type '" "kvector_t const""'");
+      SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Lattice3D_getNearestReciprocalLatticeVectorCoordinates" "', argument " "2"" of type '" "kvector_t const""'");
     } else {
       kvector_t * temp = reinterpret_cast< kvector_t * >(argp2);
       arg2 = *temp;
       if (SWIG_IsNewObj(res2)) delete temp;
     }
   }
-  result = ((Lattice const *)arg1)->getNearestReciprocalLatticeVectorCoordinates(arg2);
+  result = ((Lattice3D const *)arg1)->getNearestReciprocalLatticeVectorCoordinates(arg2);
   resultobj = SWIG_NewPointerObj((new ivector_t(static_cast< const ivector_t& >(result))), SWIGTYPE_p_BasicVector3DT_int_t, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
@@ -69105,9 +67855,9 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Lattice_reciprocalLatticeVectorsWithinRadius(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Lattice3D_reciprocalLatticeVectorsWithinRadius(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  Lattice *arg1 = (Lattice *) 0 ;
+  Lattice3D *arg1 = (Lattice3D *) 0 ;
   kvector_t arg2 ;
   double arg3 ;
   void *argp1 = 0 ;
@@ -69119,19 +67869,19 @@ SWIGINTERN PyObject *_wrap_Lattice_reciprocalLatticeVectorsWithinRadius(PyObject
   PyObject *swig_obj[3] ;
   std::vector< kvector_t,std::allocator< kvector_t > > result;
   
-  if (!SWIG_Python_UnpackTuple(args, "Lattice_reciprocalLatticeVectorsWithinRadius", 3, 3, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice, 0 |  0 );
+  if (!SWIG_Python_UnpackTuple(args, "Lattice3D_reciprocalLatticeVectorsWithinRadius", 3, 3, swig_obj)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice3D, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice_reciprocalLatticeVectorsWithinRadius" "', argument " "1"" of type '" "Lattice const *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice3D_reciprocalLatticeVectorsWithinRadius" "', argument " "1"" of type '" "Lattice3D const *""'"); 
   }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
+  arg1 = reinterpret_cast< Lattice3D * >(argp1);
   {
     res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_BasicVector3DT_double_t,  0  | 0);
     if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Lattice_reciprocalLatticeVectorsWithinRadius" "', argument " "2"" of type '" "kvector_t const""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Lattice3D_reciprocalLatticeVectorsWithinRadius" "', argument " "2"" of type '" "kvector_t const""'"); 
     }  
     if (!argp2) {
-      SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Lattice_reciprocalLatticeVectorsWithinRadius" "', argument " "2"" of type '" "kvector_t const""'");
+      SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Lattice3D_reciprocalLatticeVectorsWithinRadius" "', argument " "2"" of type '" "kvector_t const""'");
     } else {
       kvector_t * temp = reinterpret_cast< kvector_t * >(argp2);
       arg2 = *temp;
@@ -69140,10 +67890,10 @@ SWIGINTERN PyObject *_wrap_Lattice_reciprocalLatticeVectorsWithinRadius(PyObject
   }
   ecode3 = SWIG_AsVal_double(swig_obj[2], &val3);
   if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Lattice_reciprocalLatticeVectorsWithinRadius" "', argument " "3"" of type '" "double""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Lattice3D_reciprocalLatticeVectorsWithinRadius" "', argument " "3"" of type '" "double""'");
   } 
   arg3 = static_cast< double >(val3);
-  result = ((Lattice const *)arg1)->reciprocalLatticeVectorsWithinRadius(arg2,arg3);
+  result = ((Lattice3D const *)arg1)->reciprocalLatticeVectorsWithinRadius(arg2,arg3);
   resultobj = swig::from(static_cast< std::vector< BasicVector3D< double >,std::allocator< BasicVector3D< double > > > >(result));
   return resultobj;
 fail:
@@ -69151,9 +67901,9 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Lattice_setSelectionRule(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Lattice3D_setSelectionRule(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  Lattice *arg1 = (Lattice *) 0 ;
+  Lattice3D *arg1 = (Lattice3D *) 0 ;
   ISelectionRule *arg2 = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
@@ -69161,18 +67911,18 @@ SWIGINTERN PyObject *_wrap_Lattice_setSelectionRule(PyObject *SWIGUNUSEDPARM(sel
   int res2 = 0 ;
   PyObject *swig_obj[2] ;
   
-  if (!SWIG_Python_UnpackTuple(args, "Lattice_setSelectionRule", 2, 2, swig_obj)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice, 0 |  0 );
+  if (!SWIG_Python_UnpackTuple(args, "Lattice3D_setSelectionRule", 2, 2, swig_obj)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice3D, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice_setSelectionRule" "', argument " "1"" of type '" "Lattice *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice3D_setSelectionRule" "', argument " "1"" of type '" "Lattice3D *""'"); 
   }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
+  arg1 = reinterpret_cast< Lattice3D * >(argp1);
   res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_ISelectionRule,  0  | 0);
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Lattice_setSelectionRule" "', argument " "2"" of type '" "ISelectionRule const &""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Lattice3D_setSelectionRule" "', argument " "2"" of type '" "ISelectionRule const &""'"); 
   }
   if (!argp2) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Lattice_setSelectionRule" "', argument " "2"" of type '" "ISelectionRule const &""'"); 
+    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Lattice3D_setSelectionRule" "', argument " "2"" of type '" "ISelectionRule const &""'"); 
   }
   arg2 = reinterpret_cast< ISelectionRule * >(argp2);
   (arg1)->setSelectionRule((ISelectionRule const &)*arg2);
@@ -69183,202 +67933,14 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Lattice_createCubicLattice(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  double arg1 ;
-  double val1 ;
-  int ecode1 = 0 ;
-  PyObject *swig_obj[1] ;
-  SwigValueWrapper< Lattice > result;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
-  if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "Lattice_createCubicLattice" "', argument " "1"" of type '" "double""'");
-  } 
-  arg1 = static_cast< double >(val1);
-  result = Lattice::createCubicLattice(arg1);
-  resultobj = SWIG_NewPointerObj((new Lattice(static_cast< const Lattice& >(result))), SWIGTYPE_p_Lattice, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Lattice_createFCCLattice(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  double arg1 ;
-  double val1 ;
-  int ecode1 = 0 ;
-  PyObject *swig_obj[1] ;
-  SwigValueWrapper< Lattice > result;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
-  if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "Lattice_createFCCLattice" "', argument " "1"" of type '" "double""'");
-  } 
-  arg1 = static_cast< double >(val1);
-  result = Lattice::createFCCLattice(arg1);
-  resultobj = SWIG_NewPointerObj((new Lattice(static_cast< const Lattice& >(result))), SWIGTYPE_p_Lattice, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Lattice_createHexagonalLattice(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  double arg1 ;
-  double arg2 ;
-  double val1 ;
-  int ecode1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  PyObject *swig_obj[2] ;
-  SwigValueWrapper< Lattice > result;
-  
-  if (!SWIG_Python_UnpackTuple(args, "Lattice_createHexagonalLattice", 2, 2, swig_obj)) SWIG_fail;
-  ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
-  if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "Lattice_createHexagonalLattice" "', argument " "1"" of type '" "double""'");
-  } 
-  arg1 = static_cast< double >(val1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Lattice_createHexagonalLattice" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  result = Lattice::createHexagonalLattice(arg1,arg2);
-  resultobj = SWIG_NewPointerObj((new Lattice(static_cast< const Lattice& >(result))), SWIGTYPE_p_Lattice, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Lattice_createHCPLattice(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  double arg1 ;
-  double arg2 ;
-  double val1 ;
-  int ecode1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  PyObject *swig_obj[2] ;
-  SwigValueWrapper< Lattice > result;
-  
-  if (!SWIG_Python_UnpackTuple(args, "Lattice_createHCPLattice", 2, 2, swig_obj)) SWIG_fail;
-  ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
-  if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "Lattice_createHCPLattice" "', argument " "1"" of type '" "double""'");
-  } 
-  arg1 = static_cast< double >(val1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Lattice_createHCPLattice" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  result = Lattice::createHCPLattice(arg1,arg2);
-  resultobj = SWIG_NewPointerObj((new Lattice(static_cast< const Lattice& >(result))), SWIGTYPE_p_Lattice, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Lattice_createTetragonalLattice(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  double arg1 ;
-  double arg2 ;
-  double val1 ;
-  int ecode1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  PyObject *swig_obj[2] ;
-  SwigValueWrapper< Lattice > result;
-  
-  if (!SWIG_Python_UnpackTuple(args, "Lattice_createTetragonalLattice", 2, 2, swig_obj)) SWIG_fail;
-  ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
-  if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "Lattice_createTetragonalLattice" "', argument " "1"" of type '" "double""'");
-  } 
-  arg1 = static_cast< double >(val1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Lattice_createTetragonalLattice" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  result = Lattice::createTetragonalLattice(arg1,arg2);
-  resultobj = SWIG_NewPointerObj((new Lattice(static_cast< const Lattice& >(result))), SWIGTYPE_p_Lattice, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Lattice_createBCTLattice(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  double arg1 ;
-  double arg2 ;
-  double val1 ;
-  int ecode1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  PyObject *swig_obj[2] ;
-  SwigValueWrapper< Lattice > result;
-  
-  if (!SWIG_Python_UnpackTuple(args, "Lattice_createBCTLattice", 2, 2, swig_obj)) SWIG_fail;
-  ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
-  if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "Lattice_createBCTLattice" "', argument " "1"" of type '" "double""'");
-  } 
-  arg1 = static_cast< double >(val1);
-  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Lattice_createBCTLattice" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  result = Lattice::createBCTLattice(arg1,arg2);
-  resultobj = SWIG_NewPointerObj((new Lattice(static_cast< const Lattice& >(result))), SWIGTYPE_p_Lattice, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Lattice_onChange(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  Lattice *arg1 = (Lattice *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Lattice, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Lattice_onChange" "', argument " "1"" of type '" "Lattice *""'"); 
-  }
-  arg1 = reinterpret_cast< Lattice * >(argp1);
-  (arg1)->onChange();
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *Lattice_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *Lattice3D_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *obj;
   if (!SWIG_Python_UnpackTuple(args, "swigregister", 1, 1, &obj)) return NULL;
-  SWIG_TypeNewClientData(SWIGTYPE_p_Lattice, SWIG_NewClientData(obj));
+  SWIG_TypeNewClientData(SWIGTYPE_p_Lattice3D, SWIG_NewClientData(obj));
   return SWIG_Py_Void();
 }
 
-SWIGINTERN PyObject *Lattice_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *Lattice3D_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   return SWIG_Python_InitShadowInstance(args);
 }
 
@@ -70302,33 +68864,76 @@ SWIGINTERN PyObject *HexagonalLattice_swiginit(PyObject *SWIGUNUSEDPARM(self), P
   return SWIG_Python_InitShadowInstance(args);
 }
 
+SWIGINTERN PyObject *_wrap_createCubicLattice(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  double arg1 ;
+  double val1 ;
+  int ecode1 = 0 ;
+  PyObject *swig_obj[1] ;
+  SwigValueWrapper< Lattice3D > result;
+  
+  if (!args) SWIG_fail;
+  swig_obj[0] = args;
+  ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
+  if (!SWIG_IsOK(ecode1)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "createCubicLattice" "', argument " "1"" of type '" "double""'");
+  } 
+  arg1 = static_cast< double >(val1);
+  result = bake::createCubicLattice(arg1);
+  resultobj = SWIG_NewPointerObj((new Lattice3D(static_cast< const Lattice3D& >(result))), SWIGTYPE_p_Lattice3D, SWIG_POINTER_OWN |  0 );
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
 SWIGINTERN PyObject *_wrap_createFCCLattice(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   double arg1 ;
-  ILatticeOrientation *arg2 = 0 ;
   double val1 ;
   int ecode1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
-  PyObject *swig_obj[2] ;
-  SwigValueWrapper< Lattice > result;
+  PyObject *swig_obj[1] ;
+  SwigValueWrapper< Lattice3D > result;
   
-  if (!SWIG_Python_UnpackTuple(args, "createFCCLattice", 2, 2, swig_obj)) SWIG_fail;
+  if (!args) SWIG_fail;
+  swig_obj[0] = args;
   ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
   if (!SWIG_IsOK(ecode1)) {
     SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "createFCCLattice" "', argument " "1"" of type '" "double""'");
   } 
   arg1 = static_cast< double >(val1);
-  res2 = SWIG_ConvertPtr(swig_obj[1], &argp2, SWIGTYPE_p_ILatticeOrientation,  0  | 0);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "createFCCLattice" "', argument " "2"" of type '" "ILatticeOrientation const &""'"); 
-  }
-  if (!argp2) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "createFCCLattice" "', argument " "2"" of type '" "ILatticeOrientation const &""'"); 
-  }
-  arg2 = reinterpret_cast< ILatticeOrientation * >(argp2);
-  result = LatticeUtils::createFCCLattice(arg1,(ILatticeOrientation const &)*arg2);
-  resultobj = SWIG_NewPointerObj((new Lattice(static_cast< const Lattice& >(result))), SWIGTYPE_p_Lattice, SWIG_POINTER_OWN |  0 );
+  result = bake::createFCCLattice(arg1);
+  resultobj = SWIG_NewPointerObj((new Lattice3D(static_cast< const Lattice3D& >(result))), SWIGTYPE_p_Lattice3D, SWIG_POINTER_OWN |  0 );
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_createHexagonalLattice(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  double arg1 ;
+  double arg2 ;
+  double val1 ;
+  int ecode1 = 0 ;
+  double val2 ;
+  int ecode2 = 0 ;
+  PyObject *swig_obj[2] ;
+  SwigValueWrapper< Lattice3D > result;
+  
+  if (!SWIG_Python_UnpackTuple(args, "createHexagonalLattice", 2, 2, swig_obj)) SWIG_fail;
+  ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
+  if (!SWIG_IsOK(ecode1)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "createHexagonalLattice" "', argument " "1"" of type '" "double""'");
+  } 
+  arg1 = static_cast< double >(val1);
+  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "createHexagonalLattice" "', argument " "2"" of type '" "double""'");
+  } 
+  arg2 = static_cast< double >(val2);
+  result = bake::createHexagonalLattice(arg1,arg2);
+  resultobj = SWIG_NewPointerObj((new Lattice3D(static_cast< const Lattice3D& >(result))), SWIGTYPE_p_Lattice3D, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
@@ -70339,17 +68944,14 @@ SWIGINTERN PyObject *_wrap_createHCPLattice(PyObject *SWIGUNUSEDPARM(self), PyOb
   PyObject *resultobj = 0;
   double arg1 ;
   double arg2 ;
-  ILatticeOrientation *arg3 = 0 ;
   double val1 ;
   int ecode1 = 0 ;
   double val2 ;
   int ecode2 = 0 ;
-  void *argp3 = 0 ;
-  int res3 = 0 ;
-  PyObject *swig_obj[3] ;
-  SwigValueWrapper< Lattice > result;
+  PyObject *swig_obj[2] ;
+  SwigValueWrapper< Lattice3D > result;
   
-  if (!SWIG_Python_UnpackTuple(args, "createHCPLattice", 3, 3, swig_obj)) SWIG_fail;
+  if (!SWIG_Python_UnpackTuple(args, "createHCPLattice", 2, 2, swig_obj)) SWIG_fail;
   ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
   if (!SWIG_IsOK(ecode1)) {
     SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "createHCPLattice" "', argument " "1"" of type '" "double""'");
@@ -70360,16 +68962,38 @@ SWIGINTERN PyObject *_wrap_createHCPLattice(PyObject *SWIGUNUSEDPARM(self), PyOb
     SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "createHCPLattice" "', argument " "2"" of type '" "double""'");
   } 
   arg2 = static_cast< double >(val2);
-  res3 = SWIG_ConvertPtr(swig_obj[2], &argp3, SWIGTYPE_p_ILatticeOrientation,  0  | 0);
-  if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "createHCPLattice" "', argument " "3"" of type '" "ILatticeOrientation const &""'"); 
-  }
-  if (!argp3) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "createHCPLattice" "', argument " "3"" of type '" "ILatticeOrientation const &""'"); 
-  }
-  arg3 = reinterpret_cast< ILatticeOrientation * >(argp3);
-  result = LatticeUtils::createHCPLattice(arg1,arg2,(ILatticeOrientation const &)*arg3);
-  resultobj = SWIG_NewPointerObj((new Lattice(static_cast< const Lattice& >(result))), SWIGTYPE_p_Lattice, SWIG_POINTER_OWN |  0 );
+  result = bake::createHCPLattice(arg1,arg2);
+  resultobj = SWIG_NewPointerObj((new Lattice3D(static_cast< const Lattice3D& >(result))), SWIGTYPE_p_Lattice3D, SWIG_POINTER_OWN |  0 );
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_createTetragonalLattice(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  double arg1 ;
+  double arg2 ;
+  double val1 ;
+  int ecode1 = 0 ;
+  double val2 ;
+  int ecode2 = 0 ;
+  PyObject *swig_obj[2] ;
+  SwigValueWrapper< Lattice3D > result;
+  
+  if (!SWIG_Python_UnpackTuple(args, "createTetragonalLattice", 2, 2, swig_obj)) SWIG_fail;
+  ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
+  if (!SWIG_IsOK(ecode1)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "createTetragonalLattice" "', argument " "1"" of type '" "double""'");
+  } 
+  arg1 = static_cast< double >(val1);
+  ecode2 = SWIG_AsVal_double(swig_obj[1], &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "createTetragonalLattice" "', argument " "2"" of type '" "double""'");
+  } 
+  arg2 = static_cast< double >(val2);
+  result = bake::createTetragonalLattice(arg1,arg2);
+  resultobj = SWIG_NewPointerObj((new Lattice3D(static_cast< const Lattice3D& >(result))), SWIGTYPE_p_Lattice3D, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
@@ -70380,17 +69004,14 @@ SWIGINTERN PyObject *_wrap_createBCTLattice(PyObject *SWIGUNUSEDPARM(self), PyOb
   PyObject *resultobj = 0;
   double arg1 ;
   double arg2 ;
-  ILatticeOrientation *arg3 = 0 ;
   double val1 ;
   int ecode1 = 0 ;
   double val2 ;
   int ecode2 = 0 ;
-  void *argp3 = 0 ;
-  int res3 = 0 ;
-  PyObject *swig_obj[3] ;
-  SwigValueWrapper< Lattice > result;
+  PyObject *swig_obj[2] ;
+  SwigValueWrapper< Lattice3D > result;
   
-  if (!SWIG_Python_UnpackTuple(args, "createBCTLattice", 3, 3, swig_obj)) SWIG_fail;
+  if (!SWIG_Python_UnpackTuple(args, "createBCTLattice", 2, 2, swig_obj)) SWIG_fail;
   ecode1 = SWIG_AsVal_double(swig_obj[0], &val1);
   if (!SWIG_IsOK(ecode1)) {
     SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "createBCTLattice" "', argument " "1"" of type '" "double""'");
@@ -70401,16 +69022,8 @@ SWIGINTERN PyObject *_wrap_createBCTLattice(PyObject *SWIGUNUSEDPARM(self), PyOb
     SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "createBCTLattice" "', argument " "2"" of type '" "double""'");
   } 
   arg2 = static_cast< double >(val2);
-  res3 = SWIG_ConvertPtr(swig_obj[2], &argp3, SWIGTYPE_p_ILatticeOrientation,  0  | 0);
-  if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "createBCTLattice" "', argument " "3"" of type '" "ILatticeOrientation const &""'"); 
-  }
-  if (!argp3) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "createBCTLattice" "', argument " "3"" of type '" "ILatticeOrientation const &""'"); 
-  }
-  arg3 = reinterpret_cast< ILatticeOrientation * >(argp3);
-  result = LatticeUtils::createBCTLattice(arg1,arg2,(ILatticeOrientation const &)*arg3);
-  resultobj = SWIG_NewPointerObj((new Lattice(static_cast< const Lattice& >(result))), SWIGTYPE_p_Lattice, SWIG_POINTER_OWN |  0 );
+  result = bake::createBCTLattice(arg1,arg2);
+  resultobj = SWIG_NewPointerObj((new Lattice3D(static_cast< const Lattice3D& >(result))), SWIGTYPE_p_Lattice3D, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
@@ -72700,8 +71313,8 @@ static PyMethodDef SwigMethods[] = {
 	 { "RotationEuler_swigregister", RotationEuler_swigregister, METH_O, NULL},
 	 { "RotationEuler_swiginit", RotationEuler_swiginit, METH_VARARGS, NULL},
 	 { "new_FormFactorCrystal", _wrap_new_FormFactorCrystal, METH_VARARGS, "\n"
-		"FormFactorCrystal(Lattice lattice, IFormFactor basis_form_factor, IFormFactor meso_form_factor, double position_variance=0.0)\n"
-		"FormFactorCrystal::FormFactorCrystal(const Lattice &lattice, const IFormFactor &basis_form_factor, const IFormFactor &meso_form_factor, double position_variance=0.0)\n"
+		"FormFactorCrystal(Lattice3D lattice, IFormFactor basis_form_factor, IFormFactor meso_form_factor, double position_variance=0.0)\n"
+		"FormFactorCrystal::FormFactorCrystal(const Lattice3D &lattice, const IFormFactor &basis_form_factor, const IFormFactor &meso_form_factor, double position_variance=0.0)\n"
 		"\n"
 		""},
 	 { "delete_FormFactorCrystal", _wrap_delete_FormFactorCrystal, METH_O, "\n"
@@ -72879,32 +71492,9 @@ static PyMethodDef SwigMethods[] = {
 		"\n"
 		""},
 	 { "IAbstractParticle_swigregister", IAbstractParticle_swigregister, METH_O, NULL},
-	 { "IClusteredParticles_clone", _wrap_IClusteredParticles_clone, METH_O, "\n"
-		"IClusteredParticles_clone(IClusteredParticles self) -> IClusteredParticles\n"
-		"IClusteredParticles* IClusteredParticles::clone() const override=0\n"
-		"\n"
-		"Returns a clone of this  ISample object. \n"
-		"\n"
-		""},
-	 { "IClusteredParticles_createTotalFormFactor", _wrap_IClusteredParticles_createTotalFormFactor, METH_VARARGS, "\n"
-		"IClusteredParticles_createTotalFormFactor(IClusteredParticles self, IFormFactor arg2, IRotation arg3, kvector_t arg4) -> IFormFactor\n"
-		"virtual IFormFactor* IClusteredParticles::createTotalFormFactor(const IFormFactor &, const IRotation *, const kvector_t &) const =0\n"
-		"\n"
-		"Creates a total form factor for the mesocrystal with a specific shape and content The bulk content of the mesocrystal is encapsulated by the  IClusteredParticles object itself \n"
-		"\n"
-		""},
-	 { "IClusteredParticles_homogeneousRegions", _wrap_IClusteredParticles_homogeneousRegions, METH_O, "\n"
-		"IClusteredParticles_homogeneousRegions(IClusteredParticles self) -> std::vector< HomogeneousRegion,std::allocator< HomogeneousRegion > >\n"
-		"virtual std::vector<HomogeneousRegion> IClusteredParticles::homogeneousRegions() const =0\n"
-		"\n"
-		"Creates region information with volumetric densities instead of absolute volume These densities need to be multiplied by the total mesocrystal volume \n"
-		"\n"
-		""},
-	 { "delete_IClusteredParticles", _wrap_delete_IClusteredParticles, METH_O, "delete_IClusteredParticles(IClusteredParticles self)"},
-	 { "IClusteredParticles_swigregister", IClusteredParticles_swigregister, METH_O, NULL},
 	 { "new_Crystal", _wrap_new_Crystal, METH_VARARGS, "\n"
-		"new_Crystal(IParticle lattice_basis, Lattice lattice) -> Crystal\n"
-		"Crystal::Crystal(const IParticle &lattice_basis, const Lattice &lattice)\n"
+		"Crystal(IParticle basis, Lattice3D lattice, double position_variance=0)\n"
+		"Crystal::Crystal(const IParticle &basis, const Lattice3D &lattice, double position_variance=0)\n"
 		"\n"
 		""},
 	 { "delete_Crystal", _wrap_delete_Crystal, METH_O, "\n"
@@ -72926,26 +71516,17 @@ static PyMethodDef SwigMethods[] = {
 		""},
 	 { "Crystal_createTotalFormFactor", _wrap_Crystal_createTotalFormFactor, METH_VARARGS, "\n"
 		"Crystal_createTotalFormFactor(Crystal self, IFormFactor meso_crystal_form_factor, IRotation p_rotation, kvector_t translation) -> IFormFactor\n"
-		"IFormFactor * Crystal::createTotalFormFactor(const IFormFactor &meso_crystal_form_factor, const IRotation *p_rotation, const kvector_t &translation) const override final\n"
-		"\n"
-		"Creates a total form factor for the mesocrystal with a specific shape and content The bulk content of the mesocrystal is encapsulated by the  IClusteredParticles object itself \n"
+		"IFormFactor * Crystal::createTotalFormFactor(const IFormFactor &meso_crystal_form_factor, const IRotation *p_rotation, const kvector_t &translation) const\n"
 		"\n"
 		""},
 	 { "Crystal_homogeneousRegions", _wrap_Crystal_homogeneousRegions, METH_O, "\n"
 		"Crystal_homogeneousRegions(Crystal self) -> std::vector< HomogeneousRegion,std::allocator< HomogeneousRegion > >\n"
-		"std::vector< HomogeneousRegion > Crystal::homogeneousRegions() const override final\n"
-		"\n"
-		"Creates region information with volumetric densities instead of absolute volume These densities need to be multiplied by the total mesocrystal volume \n"
+		"std::vector< HomogeneousRegion > Crystal::homogeneousRegions() const\n"
 		"\n"
 		""},
 	 { "Crystal_transformedLattice", _wrap_Crystal_transformedLattice, METH_VARARGS, "\n"
-		"Crystal_transformedLattice(Crystal self, IRotation p_rotation=None) -> Lattice\n"
-		"Lattice Crystal::transformedLattice(const IRotation *p_rotation=nullptr) const\n"
-		"\n"
-		""},
-	 { "Crystal_setPositionVariance", _wrap_Crystal_setPositionVariance, METH_VARARGS, "\n"
-		"Crystal_setPositionVariance(Crystal self, double position_variance)\n"
-		"void Crystal::setPositionVariance(double position_variance)\n"
+		"Crystal_transformedLattice(Crystal self, IRotation p_rotation=None) -> Lattice3D\n"
+		"Lattice3D Crystal::transformedLattice(const IRotation *p_rotation=nullptr) const\n"
 		"\n"
 		""},
 	 { "Crystal_getChildren", _wrap_Crystal_getChildren, METH_O, "\n"
@@ -73069,8 +71650,8 @@ static PyMethodDef SwigMethods[] = {
 		""},
 	 { "IParticle_swigregister", IParticle_swigregister, METH_O, NULL},
 	 { "new_MesoCrystal", _wrap_new_MesoCrystal, METH_VARARGS, "\n"
-		"new_MesoCrystal(IClusteredParticles particle_structure, IFormFactor form_factor) -> MesoCrystal\n"
-		"MesoCrystal::MesoCrystal(const IClusteredParticles &particle_structure, const IFormFactor &form_factor)\n"
+		"new_MesoCrystal(Crystal particle_structure, IFormFactor form_factor) -> MesoCrystal\n"
+		"MesoCrystal::MesoCrystal(const Crystal &particle_structure, const IFormFactor &form_factor)\n"
 		"\n"
 		""},
 	 { "delete_MesoCrystal", _wrap_delete_MesoCrystal, METH_O, "\n"
@@ -73983,73 +72564,6 @@ static PyMethodDef SwigMethods[] = {
 	 { "delete_FTDistribution2DVoigt", _wrap_delete_FTDistribution2DVoigt, METH_O, "delete_FTDistribution2DVoigt(FTDistribution2DVoigt self)"},
 	 { "FTDistribution2DVoigt_swigregister", FTDistribution2DVoigt_swigregister, METH_O, NULL},
 	 { "FTDistribution2DVoigt_swiginit", FTDistribution2DVoigt_swiginit, METH_VARARGS, NULL},
-	 { "delete_ILayout", _wrap_delete_ILayout, METH_O, "\n"
-		"delete_ILayout(ILayout self)\n"
-		"ILayout::~ILayout()\n"
-		"\n"
-		""},
-	 { "ILayout_clone", _wrap_ILayout_clone, METH_O, "\n"
-		"ILayout_clone(ILayout self) -> ILayout\n"
-		"virtual ILayout* ILayout::clone() const =0\n"
-		"\n"
-		"Returns a clone of this  ISample object. \n"
-		"\n"
-		""},
-	 { "ILayout_accept", _wrap_ILayout_accept, METH_VARARGS, "\n"
-		"ILayout_accept(ILayout self, INodeVisitor * visitor)\n"
-		"virtual void ILayout::accept(INodeVisitor *visitor) const =0\n"
-		"\n"
-		""},
-	 { "ILayout_particles", _wrap_ILayout_particles, METH_O, "\n"
-		"ILayout_particles(ILayout self) -> SafePointerVector< IParticle >\n"
-		"virtual SafePointerVector<IParticle> ILayout::particles() const =0\n"
-		"\n"
-		"Returns information on all particles (type and abundance) and generates new particles if an  IAbstractParticle denotes a collection \n"
-		"\n"
-		""},
-	 { "ILayout_interferenceFunction", _wrap_ILayout_interferenceFunction, METH_O, "\n"
-		"ILayout_interferenceFunction(ILayout self) -> IInterferenceFunction\n"
-		"virtual const IInterferenceFunction* ILayout::interferenceFunction() const =0\n"
-		"\n"
-		"Returns the interference function. \n"
-		"\n"
-		""},
-	 { "ILayout_getTotalAbundance", _wrap_ILayout_getTotalAbundance, METH_O, "\n"
-		"ILayout_getTotalAbundance(ILayout self) -> double\n"
-		"virtual double ILayout::getTotalAbundance() const =0\n"
-		"\n"
-		"Get total abundance of all particles. \n"
-		"\n"
-		""},
-	 { "ILayout_totalParticleSurfaceDensity", _wrap_ILayout_totalParticleSurfaceDensity, METH_O, "\n"
-		"ILayout_totalParticleSurfaceDensity(ILayout self) -> double\n"
-		"virtual double ILayout::totalParticleSurfaceDensity() const =0\n"
-		"\n"
-		"Returns surface density of all particles. \n"
-		"\n"
-		""},
-	 { "ILayout_setTotalParticleSurfaceDensity", _wrap_ILayout_setTotalParticleSurfaceDensity, METH_VARARGS, "\n"
-		"ILayout_setTotalParticleSurfaceDensity(ILayout self, double particle_density)\n"
-		"virtual void ILayout::setTotalParticleSurfaceDensity(double particle_density)=0\n"
-		"\n"
-		"Sets surface density of all particles. \n"
-		"\n"
-		""},
-	 { "ILayout_weight", _wrap_ILayout_weight, METH_O, "\n"
-		"ILayout_weight(ILayout self) -> double\n"
-		"double ILayout::weight() const\n"
-		"\n"
-		"Returns the relative weight of this layout. \n"
-		"\n"
-		""},
-	 { "ILayout_setWeight", _wrap_ILayout_setWeight, METH_VARARGS, "\n"
-		"ILayout_setWeight(ILayout self, double weight)\n"
-		"void ILayout::setWeight(double weight)\n"
-		"\n"
-		"Sets the relative weight of this layout. \n"
-		"\n"
-		""},
-	 { "ILayout_swigregister", ILayout_swigregister, METH_O, NULL},
 	 { "delete_IPeakShape", _wrap_delete_IPeakShape, METH_O, "\n"
 		"delete_IPeakShape(IPeakShape self)\n"
 		"IPeakShape::~IPeakShape()\n"
@@ -74428,8 +72942,6 @@ static PyMethodDef SwigMethods[] = {
 		"void InterferenceFunction2DLattice::accept(INodeVisitor *visitor) const override final\n"
 		"\n"
 		""},
-	 { "InterferenceFunction2DLattice_createSquare", _wrap_InterferenceFunction2DLattice_createSquare, METH_VARARGS, "InterferenceFunction2DLattice_createSquare(double lattice_length, double xi) -> InterferenceFunction2DLattice"},
-	 { "InterferenceFunction2DLattice_createHexagonal", _wrap_InterferenceFunction2DLattice_createHexagonal, METH_VARARGS, "InterferenceFunction2DLattice_createHexagonal(double lattice_length, double xi) -> InterferenceFunction2DLattice"},
 	 { "InterferenceFunction2DLattice_setDecayFunction", _wrap_InterferenceFunction2DLattice_setDecayFunction, METH_VARARGS, "\n"
 		"InterferenceFunction2DLattice_setDecayFunction(InterferenceFunction2DLattice self, IFTDecayFunction2D decay)\n"
 		"void InterferenceFunction2DLattice::setDecayFunction(const IFTDecayFunction2D &decay)\n"
@@ -74520,8 +73032,6 @@ static PyMethodDef SwigMethods[] = {
 		"void InterferenceFunction2DParaCrystal::accept(INodeVisitor *visitor) const override final\n"
 		"\n"
 		""},
-	 { "InterferenceFunction2DParaCrystal_createSquare", _wrap_InterferenceFunction2DParaCrystal_createSquare, METH_VARARGS, "InterferenceFunction2DParaCrystal_createSquare(double lattice_length, double damping_length, double domain_size_1, double domain_size_2) -> InterferenceFunction2DParaCrystal"},
-	 { "InterferenceFunction2DParaCrystal_createHexagonal", _wrap_InterferenceFunction2DParaCrystal_createHexagonal, METH_VARARGS, "InterferenceFunction2DParaCrystal_createHexagonal(double lattice_length, double damping_length, double domain_size_1, double domain_size_2) -> InterferenceFunction2DParaCrystal"},
 	 { "InterferenceFunction2DParaCrystal_setDomainSizes", _wrap_InterferenceFunction2DParaCrystal_setDomainSizes, METH_VARARGS, "\n"
 		"InterferenceFunction2DParaCrystal_setDomainSizes(InterferenceFunction2DParaCrystal self, double size_1, double size_2)\n"
 		"void InterferenceFunction2DParaCrystal::setDomainSizes(double size_1, double size_2)\n"
@@ -74680,8 +73190,6 @@ static PyMethodDef SwigMethods[] = {
 		"const IInterferenceFunction & InterferenceFunction2DSuperLattice::substructureIFF() const\n"
 		"\n"
 		""},
-	 { "InterferenceFunction2DSuperLattice_createSquare", _wrap_InterferenceFunction2DSuperLattice_createSquare, METH_VARARGS, "InterferenceFunction2DSuperLattice_createSquare(double lattice_length, double xi, unsigned int size_1, unsigned int size_2) -> InterferenceFunction2DSuperLattice"},
-	 { "InterferenceFunction2DSuperLattice_createHexagonal", _wrap_InterferenceFunction2DSuperLattice_createHexagonal, METH_VARARGS, "InterferenceFunction2DSuperLattice_createHexagonal(double lattice_length, double xi, unsigned int size_1, unsigned int size_2) -> InterferenceFunction2DSuperLattice"},
 	 { "InterferenceFunction2DSuperLattice_evaluate", _wrap_InterferenceFunction2DSuperLattice_evaluate, METH_VARARGS, "\n"
 		"InterferenceFunction2DSuperLattice_evaluate(InterferenceFunction2DSuperLattice self, kvector_t q, double outer_iff=1.0) -> double\n"
 		"double InterferenceFunction2DSuperLattice::evaluate(const kvector_t q, double outer_iff=1.0) const override final\n"
@@ -74722,8 +73230,8 @@ static PyMethodDef SwigMethods[] = {
 	 { "InterferenceFunction2DSuperLattice_swigregister", InterferenceFunction2DSuperLattice_swigregister, METH_O, NULL},
 	 { "InterferenceFunction2DSuperLattice_swiginit", InterferenceFunction2DSuperLattice_swiginit, METH_VARARGS, NULL},
 	 { "new_InterferenceFunction3DLattice", _wrap_new_InterferenceFunction3DLattice, METH_O, "\n"
-		"new_InterferenceFunction3DLattice(Lattice lattice) -> InterferenceFunction3DLattice\n"
-		"InterferenceFunction3DLattice::InterferenceFunction3DLattice(const Lattice &lattice)\n"
+		"new_InterferenceFunction3DLattice(Lattice3D lattice) -> InterferenceFunction3DLattice\n"
+		"InterferenceFunction3DLattice::InterferenceFunction3DLattice(const Lattice3D &lattice)\n"
 		"\n"
 		""},
 	 { "delete_InterferenceFunction3DLattice", _wrap_delete_InterferenceFunction3DLattice, METH_O, "\n"
@@ -74749,8 +73257,8 @@ static PyMethodDef SwigMethods[] = {
 		"\n"
 		""},
 	 { "InterferenceFunction3DLattice_lattice", _wrap_InterferenceFunction3DLattice_lattice, METH_O, "\n"
-		"InterferenceFunction3DLattice_lattice(InterferenceFunction3DLattice self) -> Lattice\n"
-		"const Lattice & InterferenceFunction3DLattice::lattice() const\n"
+		"InterferenceFunction3DLattice_lattice(InterferenceFunction3DLattice self) -> Lattice3D\n"
+		"const Lattice3D & InterferenceFunction3DLattice::lattice() const\n"
 		"\n"
 		""},
 	 { "InterferenceFunction3DLattice_supportsMultilayer", _wrap_InterferenceFunction3DLattice_supportsMultilayer, METH_O, "\n"
@@ -74818,8 +73326,6 @@ static PyMethodDef SwigMethods[] = {
 		"void InterferenceFunctionFinite2DLattice::accept(INodeVisitor *visitor) const override final\n"
 		"\n"
 		""},
-	 { "InterferenceFunctionFinite2DLattice_createSquare", _wrap_InterferenceFunctionFinite2DLattice_createSquare, METH_VARARGS, "InterferenceFunctionFinite2DLattice_createSquare(double lattice_length, double xi, unsigned int N_1, unsigned int N_2) -> InterferenceFunctionFinite2DLattice"},
-	 { "InterferenceFunctionFinite2DLattice_createHexagonal", _wrap_InterferenceFunctionFinite2DLattice_createHexagonal, METH_VARARGS, "InterferenceFunctionFinite2DLattice_createHexagonal(double lattice_length, double xi, unsigned int N_1, unsigned int N_2) -> InterferenceFunctionFinite2DLattice"},
 	 { "InterferenceFunctionFinite2DLattice_numberUnitCells1", _wrap_InterferenceFunctionFinite2DLattice_numberUnitCells1, METH_O, "\n"
 		"InterferenceFunctionFinite2DLattice_numberUnitCells1(InterferenceFunctionFinite2DLattice self) -> unsigned int\n"
 		"unsigned InterferenceFunctionFinite2DLattice::numberUnitCells1() const\n"
@@ -74860,8 +73366,8 @@ static PyMethodDef SwigMethods[] = {
 	 { "InterferenceFunctionFinite2DLattice_swigregister", InterferenceFunctionFinite2DLattice_swigregister, METH_O, NULL},
 	 { "InterferenceFunctionFinite2DLattice_swiginit", InterferenceFunctionFinite2DLattice_swiginit, METH_VARARGS, NULL},
 	 { "new_InterferenceFunctionFinite3DLattice", _wrap_new_InterferenceFunctionFinite3DLattice, METH_VARARGS, "\n"
-		"new_InterferenceFunctionFinite3DLattice(Lattice lattice, unsigned int N_1, unsigned int N_2, unsigned int N_3) -> InterferenceFunctionFinite3DLattice\n"
-		"InterferenceFunctionFinite3DLattice::InterferenceFunctionFinite3DLattice(const Lattice &lattice, unsigned N_1, unsigned N_2, unsigned N_3)\n"
+		"new_InterferenceFunctionFinite3DLattice(Lattice3D lattice, unsigned int N_1, unsigned int N_2, unsigned int N_3) -> InterferenceFunctionFinite3DLattice\n"
+		"InterferenceFunctionFinite3DLattice::InterferenceFunctionFinite3DLattice(const Lattice3D &lattice, unsigned N_1, unsigned N_2, unsigned N_3)\n"
 		"\n"
 		""},
 	 { "delete_InterferenceFunctionFinite3DLattice", _wrap_delete_InterferenceFunctionFinite3DLattice, METH_O, "\n"
@@ -74897,8 +73403,8 @@ static PyMethodDef SwigMethods[] = {
 		"\n"
 		""},
 	 { "InterferenceFunctionFinite3DLattice_lattice", _wrap_InterferenceFunctionFinite3DLattice_lattice, METH_O, "\n"
-		"InterferenceFunctionFinite3DLattice_lattice(InterferenceFunctionFinite3DLattice self) -> Lattice\n"
-		"const Lattice & InterferenceFunctionFinite3DLattice::lattice() const\n"
+		"InterferenceFunctionFinite3DLattice_lattice(InterferenceFunctionFinite3DLattice self) -> Lattice3D\n"
+		"const Lattice3D & InterferenceFunctionFinite3DLattice::lattice() const\n"
 		"\n"
 		""},
 	 { "InterferenceFunctionFinite3DLattice_supportsMultilayer", _wrap_InterferenceFunctionFinite3DLattice_supportsMultilayer, METH_O, "\n"
@@ -75123,14 +73629,14 @@ static PyMethodDef SwigMethods[] = {
 		""},
 	 { "ParticleLayout_clone", _wrap_ParticleLayout_clone, METH_O, "\n"
 		"ParticleLayout_clone(ParticleLayout self) -> ParticleLayout\n"
-		"ParticleLayout * ParticleLayout::clone() const final override\n"
+		"ParticleLayout * ParticleLayout::clone() const override\n"
 		"\n"
 		"Returns a clone of this  ISample object. \n"
 		"\n"
 		""},
 	 { "ParticleLayout_accept", _wrap_ParticleLayout_accept, METH_VARARGS, "\n"
 		"ParticleLayout_accept(ParticleLayout self, INodeVisitor * visitor)\n"
-		"void ParticleLayout::accept(INodeVisitor *visitor) const final override\n"
+		"void ParticleLayout::accept(INodeVisitor *visitor) const override\n"
 		"\n"
 		""},
 	 { "ParticleLayout_addParticle", _wrap_ParticleLayout_addParticle, METH_VARARGS, "\n"
@@ -75157,23 +73663,19 @@ static PyMethodDef SwigMethods[] = {
 		""},
 	 { "ParticleLayout_particles", _wrap_ParticleLayout_particles, METH_O, "\n"
 		"ParticleLayout_particles(ParticleLayout self) -> SafePointerVector< IParticle >\n"
-		"SafePointerVector< IParticle > ParticleLayout::particles() const final override\n"
+		"SafePointerVector< IParticle > ParticleLayout::particles() const\n"
 		"\n"
 		"Returns information on all particles (type and abundance) and generates new particles if an  IAbstractParticle denotes a collection \n"
 		"\n"
 		""},
 	 { "ParticleLayout_interferenceFunction", _wrap_ParticleLayout_interferenceFunction, METH_O, "\n"
 		"ParticleLayout_interferenceFunction(ParticleLayout self) -> IInterferenceFunction\n"
-		"const IInterferenceFunction * ParticleLayout::interferenceFunction() const final override\n"
-		"\n"
-		"Returns the interference function. \n"
+		"const IInterferenceFunction * ParticleLayout::interferenceFunction() const\n"
 		"\n"
 		""},
 	 { "ParticleLayout_getTotalAbundance", _wrap_ParticleLayout_getTotalAbundance, METH_O, "\n"
 		"ParticleLayout_getTotalAbundance(ParticleLayout self) -> double\n"
-		"double ParticleLayout::getTotalAbundance() const final override\n"
-		"\n"
-		"Get total abundance of all particles. \n"
+		"double ParticleLayout::getTotalAbundance() const\n"
 		"\n"
 		""},
 	 { "ParticleLayout_setInterferenceFunction", _wrap_ParticleLayout_setInterferenceFunction, METH_VARARGS, "\n"
@@ -75185,14 +73687,12 @@ static PyMethodDef SwigMethods[] = {
 		""},
 	 { "ParticleLayout_totalParticleSurfaceDensity", _wrap_ParticleLayout_totalParticleSurfaceDensity, METH_O, "\n"
 		"ParticleLayout_totalParticleSurfaceDensity(ParticleLayout self) -> double\n"
-		"double ParticleLayout::totalParticleSurfaceDensity() const final override\n"
-		"\n"
-		"Returns surface density of all particles. \n"
+		"double ParticleLayout::totalParticleSurfaceDensity() const\n"
 		"\n"
 		""},
 	 { "ParticleLayout_setTotalParticleSurfaceDensity", _wrap_ParticleLayout_setTotalParticleSurfaceDensity, METH_VARARGS, "\n"
 		"ParticleLayout_setTotalParticleSurfaceDensity(ParticleLayout self, double particle_density)\n"
-		"void ParticleLayout::setTotalParticleSurfaceDensity(double particle_density) final override\n"
+		"void ParticleLayout::setTotalParticleSurfaceDensity(double particle_density)\n"
 		"\n"
 		"Sets total particle surface density.\n"
 		"\n"
@@ -75205,7 +73705,21 @@ static PyMethodDef SwigMethods[] = {
 		""},
 	 { "ParticleLayout_getChildren", _wrap_ParticleLayout_getChildren, METH_O, "\n"
 		"ParticleLayout_getChildren(ParticleLayout self) -> swig_dummy_type_const_inode_vector\n"
-		"std::vector< const INode * > ParticleLayout::getChildren() const final override\n"
+		"std::vector< const INode * > ParticleLayout::getChildren() const override\n"
+		"\n"
+		""},
+	 { "ParticleLayout_weight", _wrap_ParticleLayout_weight, METH_O, "\n"
+		"ParticleLayout_weight(ParticleLayout self) -> double\n"
+		"double ParticleLayout::weight() const\n"
+		"\n"
+		"Returns the relative weight of this layout. \n"
+		"\n"
+		""},
+	 { "ParticleLayout_setWeight", _wrap_ParticleLayout_setWeight, METH_VARARGS, "\n"
+		"ParticleLayout_setWeight(ParticleLayout self, double weight)\n"
+		"void ParticleLayout::setWeight(double weight)\n"
+		"\n"
+		"Sets the relative weight of this layout. \n"
 		"\n"
 		""},
 	 { "ParticleLayout_swigregister", ParticleLayout_swigregister, METH_O, NULL},
@@ -75268,8 +73782,8 @@ static PyMethodDef SwigMethods[] = {
 		"\n"
 		""},
 	 { "Layer_addLayout", _wrap_Layer_addLayout, METH_VARARGS, "\n"
-		"Layer_addLayout(Layer self, ILayout decoration)\n"
-		"void Layer::addLayout(const ILayout &decoration)\n"
+		"Layer_addLayout(Layer self, ParticleLayout decoration)\n"
+		"void Layer::addLayout(const ParticleLayout &decoration)\n"
 		"\n"
 		""},
 	 { "Layer_numberOfLayouts", _wrap_Layer_numberOfLayouts, METH_O, "\n"
@@ -75278,8 +73792,8 @@ static PyMethodDef SwigMethods[] = {
 		"\n"
 		""},
 	 { "Layer_layouts", _wrap_Layer_layouts, METH_O, "\n"
-		"Layer_layouts(Layer self) -> std::vector< ILayout const *,std::allocator< ILayout const * > >\n"
-		"std::vector< const ILayout * > Layer::layouts() const\n"
+		"Layer_layouts(Layer self) -> std::vector< ParticleLayout const *,std::allocator< ParticleLayout const * > >\n"
+		"std::vector< const ParticleLayout * > Layer::layouts() const\n"
 		"\n"
 		""},
 	 { "Layer_getChildren", _wrap_Layer_getChildren, METH_O, "\n"
@@ -76866,70 +75380,6 @@ static PyMethodDef SwigMethods[] = {
 	 { "delete_FormFactorSphereLogNormalRadius", _wrap_delete_FormFactorSphereLogNormalRadius, METH_O, "delete_FormFactorSphereLogNormalRadius(FormFactorSphereLogNormalRadius self)"},
 	 { "FormFactorSphereLogNormalRadius_swigregister", FormFactorSphereLogNormalRadius_swigregister, METH_O, NULL},
 	 { "FormFactorSphereLogNormalRadius_swiginit", FormFactorSphereLogNormalRadius_swiginit, METH_VARARGS, NULL},
-	 { "delete_ILatticeOrientation", _wrap_delete_ILatticeOrientation, METH_O, "\n"
-		"delete_ILatticeOrientation(ILatticeOrientation self)\n"
-		"ILatticeOrientation::~ILatticeOrientation()\n"
-		"\n"
-		""},
-	 { "ILatticeOrientation_clone", _wrap_ILatticeOrientation_clone, METH_O, "\n"
-		"ILatticeOrientation_clone(ILatticeOrientation self) -> ILatticeOrientation\n"
-		"virtual ILatticeOrientation* ILatticeOrientation::clone() const =0\n"
-		"\n"
-		""},
-	 { "ILatticeOrientation_usePrimitiveLattice", _wrap_ILatticeOrientation_usePrimitiveLattice, METH_VARARGS, "\n"
-		"ILatticeOrientation_usePrimitiveLattice(ILatticeOrientation self, Lattice lattice)\n"
-		"virtual void ILatticeOrientation::usePrimitiveLattice(const Lattice &lattice)=0\n"
-		"\n"
-		""},
-	 { "ILatticeOrientation_transformation", _wrap_ILatticeOrientation_transformation, METH_O, "\n"
-		"ILatticeOrientation_transformation(ILatticeOrientation self) -> Transform3D\n"
-		"virtual Transform3D ILatticeOrientation::transformation() const =0\n"
-		"\n"
-		""},
-	 { "ILatticeOrientation_swigregister", ILatticeOrientation_swigregister, METH_O, NULL},
-	 { "new_MillerIndex", _wrap_new_MillerIndex, METH_VARARGS, "\n"
-		"new_MillerIndex(double h_, double k_, double l_) -> MillerIndex\n"
-		"MillerIndex::MillerIndex(double h_, double k_, double l_)\n"
-		"\n"
-		""},
-	 { "MillerIndex_h_set", _wrap_MillerIndex_h_set, METH_VARARGS, "MillerIndex_h_set(MillerIndex self, double h)"},
-	 { "MillerIndex_h_get", _wrap_MillerIndex_h_get, METH_O, "MillerIndex_h_get(MillerIndex self) -> double"},
-	 { "MillerIndex_k_set", _wrap_MillerIndex_k_set, METH_VARARGS, "MillerIndex_k_set(MillerIndex self, double k)"},
-	 { "MillerIndex_k_get", _wrap_MillerIndex_k_get, METH_O, "MillerIndex_k_get(MillerIndex self) -> double"},
-	 { "MillerIndex_l_set", _wrap_MillerIndex_l_set, METH_VARARGS, "MillerIndex_l_set(MillerIndex self, double l)"},
-	 { "MillerIndex_l_get", _wrap_MillerIndex_l_get, METH_O, "MillerIndex_l_get(MillerIndex self) -> double"},
-	 { "delete_MillerIndex", _wrap_delete_MillerIndex, METH_O, "delete_MillerIndex(MillerIndex self)"},
-	 { "MillerIndex_swigregister", MillerIndex_swigregister, METH_O, NULL},
-	 { "MillerIndex_swiginit", MillerIndex_swiginit, METH_VARARGS, NULL},
-	 { "new_MillerIndexOrientation", _wrap_new_MillerIndexOrientation, METH_VARARGS, "\n"
-		"new_MillerIndexOrientation(MillerIndexOrientation::QComponent q1, MillerIndex index1, MillerIndexOrientation::QComponent q2, MillerIndex index2) -> MillerIndexOrientation\n"
-		"MillerIndexOrientation::MillerIndexOrientation(QComponent q1, MillerIndex index1, QComponent q2, MillerIndex index2)\n"
-		"\n"
-		"This constructor is best explained by an example. Arguments QX, (1,1,0), QY, (0,2,1) mean: Rotate the lattice such that the axis [110] points into x direction, and the axis [021], projected into the yz plane, points into z direction. \n"
-		"\n"
-		""},
-	 { "delete_MillerIndexOrientation", _wrap_delete_MillerIndexOrientation, METH_O, "\n"
-		"delete_MillerIndexOrientation(MillerIndexOrientation self)\n"
-		"MillerIndexOrientation::~MillerIndexOrientation() override\n"
-		"\n"
-		""},
-	 { "MillerIndexOrientation_clone", _wrap_MillerIndexOrientation_clone, METH_O, "\n"
-		"MillerIndexOrientation_clone(MillerIndexOrientation self) -> MillerIndexOrientation\n"
-		"MillerIndexOrientation * MillerIndexOrientation::clone() const override\n"
-		"\n"
-		""},
-	 { "MillerIndexOrientation_usePrimitiveLattice", _wrap_MillerIndexOrientation_usePrimitiveLattice, METH_VARARGS, "\n"
-		"MillerIndexOrientation_usePrimitiveLattice(MillerIndexOrientation self, Lattice lattice)\n"
-		"void MillerIndexOrientation::usePrimitiveLattice(const Lattice &lattice) override\n"
-		"\n"
-		""},
-	 { "MillerIndexOrientation_transformation", _wrap_MillerIndexOrientation_transformation, METH_O, "\n"
-		"MillerIndexOrientation_transformation(MillerIndexOrientation self) -> Transform3D\n"
-		"Transform3D MillerIndexOrientation::transformation() const override\n"
-		"\n"
-		""},
-	 { "MillerIndexOrientation_swigregister", MillerIndexOrientation_swigregister, METH_O, NULL},
-	 { "MillerIndexOrientation_swiginit", MillerIndexOrientation_swiginit, METH_VARARGS, NULL},
 	 { "delete_ISelectionRule", _wrap_delete_ISelectionRule, METH_O, "\n"
 		"delete_ISelectionRule(ISelectionRule self)\n"
 		"virtual ISelectionRule::~ISelectionRule()\n"
@@ -76968,127 +75418,105 @@ static PyMethodDef SwigMethods[] = {
 		""},
 	 { "SimpleSelectionRule_swigregister", SimpleSelectionRule_swigregister, METH_O, NULL},
 	 { "SimpleSelectionRule_swiginit", SimpleSelectionRule_swiginit, METH_VARARGS, NULL},
-	 { "new_Lattice", _wrap_new_Lattice, METH_VARARGS, "\n"
-		"Lattice()\n"
-		"Lattice(kvector_t a1, kvector_t a2, kvector_t a3)\n"
-		"new_Lattice(Lattice lattice) -> Lattice\n"
-		"Lattice::Lattice(const Lattice &lattice)\n"
+	 { "new_Lattice3D", _wrap_new_Lattice3D, METH_VARARGS, "\n"
+		"Lattice3D(kvector_t a, kvector_t b, kvector_t c)\n"
+		"new_Lattice3D(Lattice3D lattice) -> Lattice3D\n"
+		"Lattice3D::Lattice3D(const Lattice3D &lattice)\n"
 		"\n"
 		""},
-	 { "delete_Lattice", _wrap_delete_Lattice, METH_O, "\n"
-		"delete_Lattice(Lattice self)\n"
-		"Lattice::~Lattice() override\n"
+	 { "delete_Lattice3D", _wrap_delete_Lattice3D, METH_O, "\n"
+		"delete_Lattice3D(Lattice3D self)\n"
+		"Lattice3D::~Lattice3D() override\n"
 		"\n"
 		""},
-	 { "Lattice_accept", _wrap_Lattice_accept, METH_VARARGS, "\n"
-		"Lattice_accept(Lattice self, INodeVisitor * visitor)\n"
-		"void Lattice::accept(INodeVisitor *visitor) const override\n"
+	 { "Lattice3D_accept", _wrap_Lattice3D_accept, METH_VARARGS, "\n"
+		"Lattice3D_accept(Lattice3D self, INodeVisitor * visitor)\n"
+		"void Lattice3D::accept(INodeVisitor *visitor) const override\n"
 		"\n"
 		""},
-	 { "Lattice_transformed", _wrap_Lattice_transformed, METH_VARARGS, "\n"
-		"Lattice_transformed(Lattice self, Transform3D const & transform) -> Lattice\n"
-		"Lattice Lattice::transformed(const Transform3D &transform) const\n"
+	 { "Lattice3D_transformed", _wrap_Lattice3D_transformed, METH_VARARGS, "\n"
+		"Lattice3D_transformed(Lattice3D self, Transform3D const & transform) -> Lattice3D\n"
+		"Lattice3D Lattice3D::transformed(const Transform3D &transform) const\n"
 		"\n"
 		"Creates transformed lattice. \n"
 		"\n"
 		""},
-	 { "Lattice_initialize", _wrap_Lattice_initialize, METH_O, "\n"
-		"Lattice_initialize(Lattice self)\n"
-		"void Lattice::initialize() const\n"
+	 { "Lattice3D_initialize", _wrap_Lattice3D_initialize, METH_O, "\n"
+		"Lattice3D_initialize(Lattice3D self)\n"
+		"void Lattice3D::initialize()\n"
 		"\n"
 		"Initializes cached data. \n"
 		"\n"
 		""},
-	 { "Lattice_getBasisVectorA", _wrap_Lattice_getBasisVectorA, METH_O, "\n"
-		"Lattice_getBasisVectorA(Lattice self) -> kvector_t\n"
-		"kvector_t Lattice::getBasisVectorA() const\n"
+	 { "Lattice3D_getBasisVectorA", _wrap_Lattice3D_getBasisVectorA, METH_O, "\n"
+		"Lattice3D_getBasisVectorA(Lattice3D self) -> kvector_t\n"
+		"kvector_t Lattice3D::getBasisVectorA() const\n"
 		"\n"
 		"Returns basis vector a. \n"
 		"\n"
 		""},
-	 { "Lattice_getBasisVectorB", _wrap_Lattice_getBasisVectorB, METH_O, "\n"
-		"Lattice_getBasisVectorB(Lattice self) -> kvector_t\n"
-		"kvector_t Lattice::getBasisVectorB() const\n"
+	 { "Lattice3D_getBasisVectorB", _wrap_Lattice3D_getBasisVectorB, METH_O, "\n"
+		"Lattice3D_getBasisVectorB(Lattice3D self) -> kvector_t\n"
+		"kvector_t Lattice3D::getBasisVectorB() const\n"
 		"\n"
 		"Returns basis vector b. \n"
 		"\n"
 		""},
-	 { "Lattice_getBasisVectorC", _wrap_Lattice_getBasisVectorC, METH_O, "\n"
-		"Lattice_getBasisVectorC(Lattice self) -> kvector_t\n"
-		"kvector_t Lattice::getBasisVectorC() const\n"
+	 { "Lattice3D_getBasisVectorC", _wrap_Lattice3D_getBasisVectorC, METH_O, "\n"
+		"Lattice3D_getBasisVectorC(Lattice3D self) -> kvector_t\n"
+		"kvector_t Lattice3D::getBasisVectorC() const\n"
 		"\n"
 		"Returns basis vector c. \n"
 		"\n"
 		""},
-	 { "Lattice_resetBasis", _wrap_Lattice_resetBasis, METH_VARARGS, "\n"
-		"Lattice_resetBasis(Lattice self, kvector_t a1, kvector_t a2, kvector_t a3)\n"
-		"void Lattice::resetBasis(const kvector_t a1, const kvector_t a2, const kvector_t a3)\n"
-		"\n"
-		"Resets the basis vectors. \n"
+	 { "Lattice3D_getMillerDirection", _wrap_Lattice3D_getMillerDirection, METH_VARARGS, "\n"
+		"Lattice3D_getMillerDirection(Lattice3D self, double h, double k, double l) -> kvector_t\n"
+		"kvector_t Lattice3D::getMillerDirection(double h, double k, double l) const\n"
 		"\n"
-		""},
-	 { "Lattice_getMillerDirection", _wrap_Lattice_getMillerDirection, METH_VARARGS, "\n"
-		"Lattice_getMillerDirection(Lattice self, double h, double k, double l) -> kvector_t\n"
-		"kvector_t Lattice::getMillerDirection(double h, double k, double l) const\n"
+		"Returns normalized direction corresponding to the given Miller indices.\n"
 		"\n"
-		"Returns normalized direction corresponding to the given Miller indices. \n"
+		"Currently unused but may be useful for checks. \n"
 		"\n"
 		""},
-	 { "Lattice_volume", _wrap_Lattice_volume, METH_O, "\n"
-		"Lattice_volume(Lattice self) -> double\n"
-		"double Lattice::volume() const\n"
+	 { "Lattice3D_unitCellVolume", _wrap_Lattice3D_unitCellVolume, METH_O, "\n"
+		"Lattice3D_unitCellVolume(Lattice3D self) -> double\n"
+		"double Lattice3D::unitCellVolume() const\n"
 		"\n"
 		"Returns the volume of the unit cell. \n"
 		"\n"
 		""},
-	 { "Lattice_getReciprocalLatticeBasis", _wrap_Lattice_getReciprocalLatticeBasis, METH_VARARGS, "\n"
-		"Lattice_getReciprocalLatticeBasis(Lattice self, kvector_t b1, kvector_t b2, kvector_t b3)\n"
-		"void Lattice::getReciprocalLatticeBasis(kvector_t &b1, kvector_t &b2, kvector_t &b3) const\n"
-		"\n"
-		"Returns the reciprocal basis vectors. \n"
+	 { "Lattice3D_getReciprocalLatticeBasis", _wrap_Lattice3D_getReciprocalLatticeBasis, METH_VARARGS, "\n"
+		"Lattice3D_getReciprocalLatticeBasis(Lattice3D self, kvector_t ra, kvector_t rb, kvector_t rc)\n"
+		"void Lattice3D::getReciprocalLatticeBasis(kvector_t &ra, kvector_t &rb, kvector_t &rc) const\n"
 		"\n"
-		""},
-	 { "Lattice_getNearestLatticeVectorCoordinates", _wrap_Lattice_getNearestLatticeVectorCoordinates, METH_VARARGS, "\n"
-		"Lattice_getNearestLatticeVectorCoordinates(Lattice self, kvector_t vector_in) -> ivector_t\n"
-		"ivector_t Lattice::getNearestLatticeVectorCoordinates(const kvector_t vector_in) const\n"
+		"Returns the reciprocal basis vectors.\n"
 		"\n"
-		"Returns the nearest lattice point from a given vector. \n"
+		"Currently only used in tests. \n"
 		"\n"
 		""},
-	 { "Lattice_getNearestReciprocalLatticeVectorCoordinates", _wrap_Lattice_getNearestReciprocalLatticeVectorCoordinates, METH_VARARGS, "\n"
-		"Lattice_getNearestReciprocalLatticeVectorCoordinates(Lattice self, kvector_t vector_in) -> ivector_t\n"
-		"ivector_t Lattice::getNearestReciprocalLatticeVectorCoordinates(const kvector_t vector_in) const\n"
+	 { "Lattice3D_getNearestReciprocalLatticeVectorCoordinates", _wrap_Lattice3D_getNearestReciprocalLatticeVectorCoordinates, METH_VARARGS, "\n"
+		"Lattice3D_getNearestReciprocalLatticeVectorCoordinates(Lattice3D self, kvector_t q) -> ivector_t\n"
+		"ivector_t Lattice3D::getNearestReciprocalLatticeVectorCoordinates(const kvector_t q) const\n"
 		"\n"
 		"Returns the nearest reciprocal lattice point from a given vector. \n"
 		"\n"
 		""},
-	 { "Lattice_reciprocalLatticeVectorsWithinRadius", _wrap_Lattice_reciprocalLatticeVectorsWithinRadius, METH_VARARGS, "\n"
-		"Lattice_reciprocalLatticeVectorsWithinRadius(Lattice self, kvector_t input_vector, double radius) -> vector_kvector_t\n"
-		"std::vector< kvector_t > Lattice::reciprocalLatticeVectorsWithinRadius(const kvector_t input_vector, double radius) const\n"
+	 { "Lattice3D_reciprocalLatticeVectorsWithinRadius", _wrap_Lattice3D_reciprocalLatticeVectorsWithinRadius, METH_VARARGS, "\n"
+		"Lattice3D_reciprocalLatticeVectorsWithinRadius(Lattice3D self, kvector_t q, double dq) -> vector_kvector_t\n"
+		"std::vector< kvector_t > Lattice3D::reciprocalLatticeVectorsWithinRadius(const kvector_t q, double dq) const\n"
 		"\n"
-		"Computes a list of reciprocal lattice vectors within a specified distance of a given vector. \n"
+		"Returns a list of reciprocal lattice vectors within distance dq of a vector q. \n"
 		"\n"
 		""},
-	 { "Lattice_setSelectionRule", _wrap_Lattice_setSelectionRule, METH_VARARGS, "\n"
-		"Lattice_setSelectionRule(Lattice self, ISelectionRule p_selection_rule)\n"
-		"void Lattice::setSelectionRule(const ISelectionRule &p_selection_rule)\n"
+	 { "Lattice3D_setSelectionRule", _wrap_Lattice3D_setSelectionRule, METH_VARARGS, "\n"
+		"Lattice3D_setSelectionRule(Lattice3D self, ISelectionRule selection_rule)\n"
+		"void Lattice3D::setSelectionRule(const ISelectionRule &selection_rule)\n"
 		"\n"
 		"Sets a selection rule for the reciprocal vectors. \n"
 		"\n"
 		""},
-	 { "Lattice_createCubicLattice", _wrap_Lattice_createCubicLattice, METH_O, "Lattice_createCubicLattice(double a) -> Lattice"},
-	 { "Lattice_createFCCLattice", _wrap_Lattice_createFCCLattice, METH_O, "Lattice_createFCCLattice(double a) -> Lattice"},
-	 { "Lattice_createHexagonalLattice", _wrap_Lattice_createHexagonalLattice, METH_VARARGS, "Lattice_createHexagonalLattice(double a, double c) -> Lattice"},
-	 { "Lattice_createHCPLattice", _wrap_Lattice_createHCPLattice, METH_VARARGS, "Lattice_createHCPLattice(double a, double c) -> Lattice"},
-	 { "Lattice_createTetragonalLattice", _wrap_Lattice_createTetragonalLattice, METH_VARARGS, "Lattice_createTetragonalLattice(double a, double c) -> Lattice"},
-	 { "Lattice_createBCTLattice", _wrap_Lattice_createBCTLattice, METH_VARARGS, "Lattice_createBCTLattice(double a, double c) -> Lattice"},
-	 { "Lattice_onChange", _wrap_Lattice_onChange, METH_O, "\n"
-		"Lattice_onChange(Lattice self)\n"
-		"void Lattice::onChange() override\n"
-		"\n"
-		""},
-	 { "Lattice_swigregister", Lattice_swigregister, METH_O, NULL},
-	 { "Lattice_swiginit", Lattice_swiginit, METH_VARARGS, NULL},
+	 { "Lattice3D_swigregister", Lattice3D_swigregister, METH_O, NULL},
+	 { "Lattice3D_swiginit", Lattice3D_swiginit, METH_VARARGS, NULL},
 	 { "Lattice2D_clone", _wrap_Lattice2D_clone, METH_O, "\n"
 		"Lattice2D_clone(Lattice2D self) -> Lattice2D\n"
 		"virtual Lattice2D* Lattice2D::clone() const =0\n"
@@ -77245,19 +75673,46 @@ static PyMethodDef SwigMethods[] = {
 	 { "delete_HexagonalLattice", _wrap_delete_HexagonalLattice, METH_O, "delete_HexagonalLattice(HexagonalLattice self)"},
 	 { "HexagonalLattice_swigregister", HexagonalLattice_swigregister, METH_O, NULL},
 	 { "HexagonalLattice_swiginit", HexagonalLattice_swiginit, METH_VARARGS, NULL},
-	 { "createFCCLattice", _wrap_createFCCLattice, METH_VARARGS, "\n"
-		"createFCCLattice(double lattice_constant, ILatticeOrientation orientation) -> Lattice\n"
-		"Lattice LatticeUtils::createFCCLattice(double lattice_constant, const ILatticeOrientation &orientation)\n"
+	 { "createCubicLattice", _wrap_createCubicLattice, METH_O, "\n"
+		"createCubicLattice(double a) -> Lattice3D\n"
+		"Lattice3D bake::createCubicLattice(double a)\n"
+		"\n"
+		"Returns a primitive cubic (cP) lattice with edge length a. \n"
+		"\n"
+		""},
+	 { "createFCCLattice", _wrap_createFCCLattice, METH_O, "\n"
+		"createFCCLattice(double a) -> Lattice3D\n"
+		"Lattice3D bake::createFCCLattice(double a)\n"
+		"\n"
+		"Returns a face-centered cubic (cF) lattice with edge length a. \n"
+		"\n"
+		""},
+	 { "createHexagonalLattice", _wrap_createHexagonalLattice, METH_VARARGS, "\n"
+		"createHexagonalLattice(double a, double c) -> Lattice3D\n"
+		"Lattice3D bake::createHexagonalLattice(double a, double c)\n"
+		"\n"
+		"Returns a primitive hexagonal (hP) lattice with hexagonal edge a and height c. \n"
 		"\n"
 		""},
 	 { "createHCPLattice", _wrap_createHCPLattice, METH_VARARGS, "\n"
-		"createHCPLattice(double a, double c, ILatticeOrientation orientation) -> Lattice\n"
-		"Lattice LatticeUtils::createHCPLattice(double a, double c, const ILatticeOrientation &orientation)\n"
+		"createHCPLattice(double a, double c) -> Lattice3D\n"
+		"Lattice3D bake::createHCPLattice(double a, double c)\n"
+		"\n"
+		"TODO: Clarify how this is meant: HCP is not a Bravais lattice. \n"
+		"\n"
+		""},
+	 { "createTetragonalLattice", _wrap_createTetragonalLattice, METH_VARARGS, "\n"
+		"createTetragonalLattice(double a, double c) -> Lattice3D\n"
+		"Lattice3D bake::createTetragonalLattice(double a, double c)\n"
+		"\n"
+		"Returns a primitive tetragonal (tP) lattice with square base edge a and height c. \n"
 		"\n"
 		""},
 	 { "createBCTLattice", _wrap_createBCTLattice, METH_VARARGS, "\n"
-		"createBCTLattice(double a, double c, ILatticeOrientation orientation) -> Lattice\n"
-		"Lattice LatticeUtils::createBCTLattice(double a, double c, const ILatticeOrientation &orientation)\n"
+		"createBCTLattice(double a, double c) -> Lattice3D\n"
+		"Lattice3D bake::createBCTLattice(double a, double c)\n"
+		"\n"
+		"Returns a body-centered cubic (cI) lattice with edge length a. TODO: Clarify meaning of c \n"
 		"\n"
 		""},
 	 { "new_ISampleBuilder", _wrap_new_ISampleBuilder, METH_O, "\n"
@@ -77319,9 +75774,6 @@ static PyMethodDef SwigMethods_proxydocs[] = {
 
 /* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
 
-static void *_p_ParticleLayoutTo_p_ILayout(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((ILayout *)  ((ParticleLayout *) x));
-}
 static void *_p_RotationYTo_p_IRotation(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((IRotation *)  ((RotationY *) x));
 }
@@ -77529,20 +75981,17 @@ static void *_p_ParameterDistributionTo_p_IParameterized(void *x, int *SWIGUNUSE
 static void *_p_ParticleDistributionTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((IParameterized *) (INode *)(ISample *)(IAbstractParticle *) ((ParticleDistribution *) x));
 }
-static void *_p_FTDistribution1DGaussTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((IParameterized *) (INode *)(IFTDistribution1D *) ((FTDistribution1DGauss *) x));
-}
 static void *_p_FTDecayFunction1DGaussTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((IParameterized *) (INode *)(IFTDecayFunction1D *) ((FTDecayFunction1DGauss *) x));
 }
+static void *_p_FTDistribution1DGaussTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((IParameterized *) (INode *)(IFTDistribution1D *) ((FTDistribution1DGauss *) x));
+}
 static void *_p_InterferenceFunctionNoneTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((IParameterized *) (INode *)(ISample *)(IInterferenceFunction *) ((InterferenceFunctionNone *) x));
 }
 static void *_p_ParticleLayoutTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((IParameterized *) (INode *)(ISample *)(ILayout *) ((ParticleLayout *) x));
-}
-static void *_p_ILayoutTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((IParameterized *) (INode *)(ISample *) ((ILayout *) x));
+    return (void *)((IParameterized *) (INode *)(ISample *) ((ParticleLayout *) x));
 }
 static void *_p_FormFactorHemiEllipsoidTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((IParameterized *) (INode *)(ISample *)(IFormFactor *)(IFormFactorBorn *) ((FormFactorHemiEllipsoid *) x));
@@ -77601,12 +76050,12 @@ static void *_p_FTDistribution2DConeTo_p_IParameterized(void *x, int *SWIGUNUSED
 static void *_p_ParticleCoreShellTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((IParameterized *) (INode *)(ISample *)(IAbstractParticle *)(IParticle *) ((ParticleCoreShell *) x));
 }
-static void *_p_IProfileRectangularRippleTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((IParameterized *) (INode *)(ISample *)(IFormFactor *)(IFormFactorBorn *)(IProfileRipple *) ((IProfileRectangularRipple *) x));
-}
 static void *_p_ISawtoothRippleTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((IParameterized *) (INode *)(ISample *)(IFormFactor *)(IFormFactorBorn *)(IProfileRipple *) ((ISawtoothRipple *) x));
 }
+static void *_p_IProfileRectangularRippleTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((IParameterized *) (INode *)(ISample *)(IFormFactor *)(IFormFactorBorn *)(IProfileRipple *) ((IProfileRectangularRipple *) x));
+}
 static void *_p_FormFactorFullSphereTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((IParameterized *) (INode *)(ISample *)(IFormFactor *)(IFormFactorBorn *) ((FormFactorFullSphere *) x));
 }
@@ -77670,9 +76119,6 @@ static void *_p_RotationZTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmem
 static void *_p_IFormFactorBornTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((IParameterized *) (INode *)(ISample *)(IFormFactor *) ((IFormFactorBorn *) x));
 }
-static void *_p_IClusteredParticlesTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((IParameterized *) (INode *)(ISample *) ((IClusteredParticles *) x));
-}
 static void *_p_ISampleBuilderTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((IParameterized *)  ((ISampleBuilder *) x));
 }
@@ -77779,7 +76225,7 @@ static void *_p_FormFactorCrystalTo_p_IParameterized(void *x, int *SWIGUNUSEDPAR
     return (void *)((IParameterized *) (INode *)(ISample *)(IFormFactor *) ((FormFactorCrystal *) x));
 }
 static void *_p_CrystalTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((IParameterized *) (INode *)(ISample *)(IClusteredParticles *) ((Crystal *) x));
+    return (void *)((IParameterized *) (INode *)(ISample *) ((Crystal *) x));
 }
 static void *_p_MesoCrystalTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((IParameterized *) (INode *)(ISample *)(IAbstractParticle *)(IParticle *) ((MesoCrystal *) x));
@@ -77790,6 +76236,9 @@ static void *_p_ICosineRippleTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(ne
 static void *_p_IProfileRippleTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((IParameterized *) (INode *)(ISample *)(IFormFactor *)(IFormFactorBorn *) ((IProfileRipple *) x));
 }
+static void *_p_Lattice3DTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((IParameterized *) (INode *) ((Lattice3D *) x));
+}
 static void *_p_IFTDistribution2DTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((IParameterized *) (INode *) ((IFTDistribution2D *) x));
 }
@@ -77832,9 +76281,6 @@ static void *_p_FormFactorLongBoxLorentzTo_p_IParameterized(void *x, int *SWIGUN
 static void *_p_FormFactorSawtoothRippleLorentzTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((IParameterized *) (INode *)(ISample *)(IFormFactor *)(IFormFactorBorn *)(IProfileRipple *)(ISawtoothRipple *) ((FormFactorSawtoothRippleLorentz *) x));
 }
-static void *_p_LatticeTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((IParameterized *) (INode *) ((Lattice *) x));
-}
 static void *_p_BasicLatticeTo_p_IParameterized(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((IParameterized *) (INode *)(Lattice2D *) ((BasicLattice *) x));
 }
@@ -77892,9 +76338,6 @@ static void *_p_ParticleTo_p_IAbstractParticle(void *x, int *SWIGUNUSEDPARM(newm
 static void *_p_ParticleCoreShellTo_p_IAbstractParticle(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((IAbstractParticle *) (IParticle *) ((ParticleCoreShell *) x));
 }
-static void *_p_MillerIndexOrientationTo_p_ILatticeOrientation(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((ILatticeOrientation *)  ((MillerIndexOrientation *) x));
-}
 static void *_p_FormFactorPrism3To_p_IFormFactorPrism(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((IFormFactorPrism *)  ((FormFactorPrism3 *) x));
 }
@@ -77938,10 +76381,7 @@ static void *_p_InterferenceFunctionNoneTo_p_ICloneable(void *x, int *SWIGUNUSED
     return (void *)((ICloneable *) (ISample *)(IInterferenceFunction *) ((InterferenceFunctionNone *) x));
 }
 static void *_p_ParticleLayoutTo_p_ICloneable(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((ICloneable *) (ISample *)(ILayout *) ((ParticleLayout *) x));
-}
-static void *_p_ILayoutTo_p_ICloneable(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((ICloneable *) (ISample *) ((ILayout *) x));
+    return (void *)((ICloneable *) (ISample *) ((ParticleLayout *) x));
 }
 static void *_p_FormFactorHemiEllipsoidTo_p_ICloneable(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((ICloneable *) (ISample *)(IFormFactor *)(IFormFactorBorn *) ((FormFactorHemiEllipsoid *) x));
@@ -78066,9 +76506,6 @@ static void *_p_RotationZTo_p_ICloneable(void *x, int *SWIGUNUSEDPARM(newmemory)
 static void *_p_IFormFactorBornTo_p_ICloneable(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((ICloneable *) (ISample *)(IFormFactor *) ((IFormFactorBorn *) x));
 }
-static void *_p_IClusteredParticlesTo_p_ICloneable(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((ICloneable *) (ISample *) ((IClusteredParticles *) x));
-}
 static void *_p_IAbstractParticleTo_p_ICloneable(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((ICloneable *) (ISample *) ((IAbstractParticle *) x));
 }
@@ -78175,7 +76612,7 @@ static void *_p_FormFactorCrystalTo_p_ICloneable(void *x, int *SWIGUNUSEDPARM(ne
     return (void *)((ICloneable *) (ISample *)(IFormFactor *) ((FormFactorCrystal *) x));
 }
 static void *_p_CrystalTo_p_ICloneable(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((ICloneable *) (ISample *)(IClusteredParticles *) ((Crystal *) x));
+    return (void *)((ICloneable *) (ISample *) ((Crystal *) x));
 }
 static void *_p_MesoCrystalTo_p_ICloneable(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((ICloneable *) (ISample *)(IAbstractParticle *)(IParticle *) ((MesoCrystal *) x));
@@ -78282,9 +76719,6 @@ static void *_p_FormFactorCosineRippleGaussTo_p_IProfileRipple(void *x, int *SWI
 static void *_p_FormFactorSawtoothRippleGaussTo_p_IProfileRipple(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((IProfileRipple *) (ISawtoothRipple *) ((FormFactorSawtoothRippleGauss *) x));
 }
-static void *_p_CrystalTo_p_IClusteredParticles(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((IClusteredParticles *)  ((Crystal *) x));
-}
 static void *_p_SimpleSelectionRuleTo_p_ISelectionRule(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((ISelectionRule *)  ((SimpleSelectionRule *) x));
 }
@@ -78313,10 +76747,7 @@ static void *_p_InterferenceFunctionNoneTo_p_INode(void *x, int *SWIGUNUSEDPARM(
     return (void *)((INode *) (ISample *)(IInterferenceFunction *) ((InterferenceFunctionNone *) x));
 }
 static void *_p_ParticleLayoutTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((INode *) (ISample *)(ILayout *) ((ParticleLayout *) x));
-}
-static void *_p_ILayoutTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((INode *) (ISample *) ((ILayout *) x));
+    return (void *)((INode *) (ISample *) ((ParticleLayout *) x));
 }
 static void *_p_FormFactorHemiEllipsoidTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((INode *) (ISample *)(IFormFactor *)(IFormFactorBorn *) ((FormFactorHemiEllipsoid *) x));
@@ -78426,12 +76857,12 @@ static void *_p_FTDistribution2DGaussTo_p_INode(void *x, int *SWIGUNUSEDPARM(new
 static void *_p_FTDecayFunction2DGaussTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((INode *) (IFTDecayFunction2D *) ((FTDecayFunction2DGauss *) x));
 }
-static void *_p_RotationYTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((INode *) (IRotation *) ((RotationY *) x));
-}
 static void *_p_FormFactorCantellatedCubeTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((INode *) (ISample *)(IFormFactor *)(IFormFactorBorn *)(IFormFactorPolyhedron *) ((FormFactorCantellatedCube *) x));
 }
+static void *_p_RotationYTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((INode *) (IRotation *) ((RotationY *) x));
+}
 static void *_p_FormFactorTruncatedCubeTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((INode *) (ISample *)(IFormFactor *)(IFormFactorBorn *)(IFormFactorPolyhedron *) ((FormFactorTruncatedCube *) x));
 }
@@ -78441,9 +76872,6 @@ static void *_p_RotationZTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
 static void *_p_IFormFactorBornTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((INode *) (ISample *)(IFormFactor *) ((IFormFactorBorn *) x));
 }
-static void *_p_IClusteredParticlesTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((INode *) (ISample *) ((IClusteredParticles *) x));
-}
 static void *_p_IAbstractParticleTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((INode *) (ISample *) ((IAbstractParticle *) x));
 }
@@ -78543,12 +76971,12 @@ static void *_p_InterferenceFunctionRadialParaCrystalTo_p_INode(void *x, int *SW
 static void *_p_InterferenceFunction2DParaCrystalTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((INode *) (ISample *)(IInterferenceFunction *) ((InterferenceFunction2DParaCrystal *) x));
 }
+static void *_p_CrystalTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((INode *) (ISample *) ((Crystal *) x));
+}
 static void *_p_FormFactorCrystalTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((INode *) (ISample *)(IFormFactor *) ((FormFactorCrystal *) x));
 }
-static void *_p_CrystalTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((INode *) (ISample *)(IClusteredParticles *) ((Crystal *) x));
-}
 static void *_p_MesoCrystalTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((INode *) (ISample *)(IAbstractParticle *)(IParticle *) ((MesoCrystal *) x));
 }
@@ -78558,6 +76986,9 @@ static void *_p_ICosineRippleTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory))
 static void *_p_IProfileRippleTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((INode *) (ISample *)(IFormFactor *)(IFormFactorBorn *) ((IProfileRipple *) x));
 }
+static void *_p_Lattice3DTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((INode *)  ((Lattice3D *) x));
+}
 static void *_p_IFTDistribution2DTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((INode *)  ((IFTDistribution2D *) x));
 }
@@ -78600,9 +77031,6 @@ static void *_p_FormFactorLongBoxLorentzTo_p_INode(void *x, int *SWIGUNUSEDPARM(
 static void *_p_FormFactorSawtoothRippleLorentzTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((INode *) (ISample *)(IFormFactor *)(IFormFactorBorn *)(IProfileRipple *)(ISawtoothRipple *) ((FormFactorSawtoothRippleLorentz *) x));
 }
-static void *_p_LatticeTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((INode *)  ((Lattice *) x));
-}
 static void *_p_BasicLatticeTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((INode *) (Lattice2D *) ((BasicLattice *) x));
 }
@@ -78612,12 +77040,12 @@ static void *_p_SquareLatticeTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory))
 static void *_p_HexagonalLatticeTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((INode *) (Lattice2D *) ((HexagonalLattice *) x));
 }
-static void *_p_FTDistribution1DTriangleTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((INode *) (IFTDistribution1D *) ((FTDistribution1DTriangle *) x));
-}
 static void *_p_FTDecayFunction1DTriangleTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((INode *) (IFTDecayFunction1D *) ((FTDecayFunction1DTriangle *) x));
 }
+static void *_p_FTDistribution1DTriangleTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((INode *) (IFTDistribution1D *) ((FTDistribution1DTriangle *) x));
+}
 static void *_p_RotationEulerTo_p_INode(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((INode *) (IRotation *) ((RotationEuler *) x));
 }
@@ -78807,12 +77235,12 @@ static void *_p_SampleBuilderFactoryTo_p_IFactoryT_std__string_ISampleBuilder_t(
 static void *_p_FormFactorBoxTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((ISample *) (IFormFactor *)(IFormFactorBorn *)(IFormFactorPrism *) ((FormFactorBox *) x));
 }
-static void *_p_MultiLayerTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((ISample *)  ((MultiLayer *) x));
-}
 static void *_p_FormFactorSphereGaussianRadiusTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((ISample *) (IFormFactor *)(IFormFactorBorn *) ((FormFactorSphereGaussianRadius *) x));
 }
+static void *_p_MultiLayerTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((ISample *)  ((MultiLayer *) x));
+}
 static void *_p_FormFactorSphereLogNormalRadiusTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((ISample *) (IFormFactor *)(IFormFactorBorn *) ((FormFactorSphereLogNormalRadius *) x));
 }
@@ -78823,10 +77251,7 @@ static void *_p_InterferenceFunctionNoneTo_p_ISample(void *x, int *SWIGUNUSEDPAR
     return (void *)((ISample *) (IInterferenceFunction *) ((InterferenceFunctionNone *) x));
 }
 static void *_p_ParticleLayoutTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((ISample *) (ILayout *) ((ParticleLayout *) x));
-}
-static void *_p_ILayoutTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((ISample *)  ((ILayout *) x));
+    return (void *)((ISample *)  ((ParticleLayout *) x));
 }
 static void *_p_FormFactorHemiEllipsoidTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((ISample *) (IFormFactor *)(IFormFactorBorn *) ((FormFactorHemiEllipsoid *) x));
@@ -78915,9 +77340,6 @@ static void *_p_FormFactorCantellatedCubeTo_p_ISample(void *x, int *SWIGUNUSEDPA
 static void *_p_IFormFactorBornTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((ISample *) (IFormFactor *) ((IFormFactorBorn *) x));
 }
-static void *_p_IClusteredParticlesTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((ISample *)  ((IClusteredParticles *) x));
-}
 static void *_p_ParticleTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((ISample *) (IAbstractParticle *)(IParticle *) ((Particle *) x));
 }
@@ -78982,7 +77404,7 @@ static void *_p_MesoCrystalTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory))
     return (void *)((ISample *) (IAbstractParticle *)(IParticle *) ((MesoCrystal *) x));
 }
 static void *_p_CrystalTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((ISample *) (IClusteredParticles *) ((Crystal *) x));
+    return (void *)((ISample *)  ((Crystal *) x));
 }
 static void *_p_FormFactorCrystalTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((ISample *) (IFormFactor *) ((FormFactorCrystal *) x));
@@ -78999,12 +77421,12 @@ static void *_p_ICosineRippleTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory
 static void *_p_IProfileRippleTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((ISample *) (IFormFactor *)(IFormFactorBorn *) ((IProfileRipple *) x));
 }
-static void *_p_FormFactorHollowSphereTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory)) {
-    return (void *)((ISample *) (IFormFactor *)(IFormFactorBorn *) ((FormFactorHollowSphere *) x));
-}
 static void *_p_FormFactorGaussSphereTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((ISample *) (IFormFactor *)(IFormFactorBorn *) ((FormFactorGaussSphere *) x));
 }
+static void *_p_FormFactorHollowSphereTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((ISample *) (IFormFactor *)(IFormFactorBorn *) ((FormFactorHollowSphere *) x));
+}
 static void *_p_FormFactorWeightedTo_p_ISample(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((ISample *) (IFormFactor *) ((FormFactorWeighted *) x));
 }
@@ -79123,7 +77545,6 @@ static swig_type_info _swigt__p_GaussFisherPeakShape = {"_p_GaussFisherPeakShape
 static swig_type_info _swigt__p_HexagonalLattice = {"_p_HexagonalLattice", "HexagonalLattice *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_IAbstractParticle = {"_p_IAbstractParticle", "IAbstractParticle *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_ICloneable = {"_p_ICloneable", "ICloneable *", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_IClusteredParticles = {"_p_IClusteredParticles", "IClusteredParticles *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_ICosineRipple = {"_p_ICosineRipple", "ICosineRipple *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_IFTDecayFunction1D = {"_p_IFTDecayFunction1D", "IFTDecayFunction1D *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_IFTDecayFunction2D = {"_p_IFTDecayFunction2D", "IFTDecayFunction2D *", 0, 0, (void*)0, 0};
@@ -79136,8 +77557,6 @@ static swig_type_info _swigt__p_IFormFactorDecorator = {"_p_IFormFactorDecorator
 static swig_type_info _swigt__p_IFormFactorPolyhedron = {"_p_IFormFactorPolyhedron", "IFormFactorPolyhedron *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_IFormFactorPrism = {"_p_IFormFactorPrism", "IFormFactorPrism *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_IInterferenceFunction = {"_p_IInterferenceFunction", "IInterferenceFunction *", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_ILatticeOrientation = {"_p_ILatticeOrientation", "ILatticeOrientation *", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_ILayout = {"_p_ILayout", "ILayout *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_INode = {"_p_INode", "INode *|std::vector< INode * >::value_type|std::vector< INode const * >::value_type", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_INodeVisitor = {"_p_INodeVisitor", "INodeVisitor *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_IParameterized = {"_p_IParameterized", "IParameterized *", 0, 0, (void*)0, 0};
@@ -79164,17 +77583,15 @@ static swig_type_info _swigt__p_InterferenceFunctionRadialParaCrystal = {"_p_Int
 static swig_type_info _swigt__p_InterferenceFunctionTwin = {"_p_InterferenceFunctionTwin", "InterferenceFunctionTwin *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_IsotropicGaussPeakShape = {"_p_IsotropicGaussPeakShape", "IsotropicGaussPeakShape *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_IsotropicLorentzPeakShape = {"_p_IsotropicLorentzPeakShape", "IsotropicLorentzPeakShape *", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_Lattice = {"_p_Lattice", "Lattice *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_Lattice2D = {"_p_Lattice2D", "Lattice2D *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_Lattice2D__ReciprocalBases = {"_p_Lattice2D__ReciprocalBases", "Lattice2D::ReciprocalBases *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_Lattice3D = {"_p_Lattice3D", "Lattice3D *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_Layer = {"_p_Layer", "Layer *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_LayerInterface = {"_p_LayerInterface", "LayerInterface *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_LayerRoughness = {"_p_LayerRoughness", "LayerRoughness *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_LorentzFisherPeakShape = {"_p_LorentzFisherPeakShape", "LorentzFisherPeakShape *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_Material = {"_p_Material", "Material *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_MesoCrystal = {"_p_MesoCrystal", "MesoCrystal *", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_MillerIndex = {"_p_MillerIndex", "MillerIndex *", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_MillerIndexOrientation = {"_p_MillerIndexOrientation", "MillerIndexOrientation *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_MisesFisherGaussPeakShape = {"_p_MisesFisherGaussPeakShape", "MisesFisherGaussPeakShape *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_MisesGaussPeakShape = {"_p_MisesGaussPeakShape", "MisesGaussPeakShape *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_MultiLayer = {"_p_MultiLayer", "MultiLayer *", 0, 0, (void*)0, 0};
@@ -79243,10 +77660,10 @@ static swig_type_info _swigt__p_std__vectorT_BasicVector3DT_double_t_std__alloca
 static swig_type_info _swigt__p_std__vectorT_BasicVector3DT_std__complexT_double_t_t_std__allocatorT_BasicVector3DT_std__complexT_double_t_t_t_t = {"_p_std__vectorT_BasicVector3DT_std__complexT_double_t_t_std__allocatorT_BasicVector3DT_std__complexT_double_t_t_t_t", "std::vector< BasicVector3D< std::complex< double > > > *|std::vector< BasicVector3D< std::complex< double > >,std::allocator< BasicVector3D< std::complex< double > > > > *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_std__vectorT_HomogeneousRegion_std__allocatorT_HomogeneousRegion_t_t = {"_p_std__vectorT_HomogeneousRegion_std__allocatorT_HomogeneousRegion_t_t", "std::vector< HomogeneousRegion,std::allocator< HomogeneousRegion > > *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_std__vectorT_IFormFactor_p_std__allocatorT_IFormFactor_p_t_t = {"_p_std__vectorT_IFormFactor_p_std__allocatorT_IFormFactor_p_t_t", "std::vector< IFormFactor *,std::allocator< IFormFactor * > > *|std::vector< IFormFactor * > *", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_std__vectorT_ILayout_const_p_std__allocatorT_ILayout_const_p_t_t = {"_p_std__vectorT_ILayout_const_p_std__allocatorT_ILayout_const_p_t_t", "std::vector< ILayout const *,std::allocator< ILayout const * > > *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_std__vectorT_INode_const_p_std__allocatorT_INode_const_p_t_t = {"_p_std__vectorT_INode_const_p_std__allocatorT_INode_const_p_t_t", "std::vector< INode const *,std::allocator< INode const * > > *|std::vector< INode const * > *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_std__vectorT_INode_p_std__allocatorT_INode_p_t_t = {"_p_std__vectorT_INode_p_std__allocatorT_INode_p_t_t", "std::vector< INode *,std::allocator< INode * > > *|std::vector< INode * > *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_std__vectorT_Material_const_p_std__allocatorT_Material_const_p_t_t = {"_p_std__vectorT_Material_const_p_std__allocatorT_Material_const_p_t_t", "std::vector< Material const *,std::allocator< Material const * > > *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_std__vectorT_ParticleLayout_const_p_std__allocatorT_ParticleLayout_const_p_t_t = {"_p_std__vectorT_ParticleLayout_const_p_std__allocatorT_ParticleLayout_const_p_t_t", "std::vector< ParticleLayout const *,std::allocator< ParticleLayout const * > > *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_std__vectorT_double_std__allocatorT_double_t_t = {"_p_std__vectorT_double_std__allocatorT_double_t_t", "std::vector< double,std::allocator< double > > *|std::vector< double > *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_std__vectorT_int_std__allocatorT_int_t_t = {"_p_std__vectorT_int_std__allocatorT_int_t_t", "std::vector< int,std::allocator< int > > *|std::vector< int > *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_std__vectorT_std__complexT_double_t_std__allocatorT_std__complexT_double_t_t_t = {"_p_std__vectorT_std__complexT_double_t_std__allocatorT_std__complexT_double_t_t_t", "std::vector< std::complex< double > > *|std::vector< std::complex< double >,std::allocator< std::complex< double > > > *", 0, 0, (void*)0, 0};
@@ -79327,7 +77744,6 @@ static swig_type_info *swig_type_initial[] = {
   &_swigt__p_HexagonalLattice,
   &_swigt__p_IAbstractParticle,
   &_swigt__p_ICloneable,
-  &_swigt__p_IClusteredParticles,
   &_swigt__p_ICosineRipple,
   &_swigt__p_IFTDecayFunction1D,
   &_swigt__p_IFTDecayFunction2D,
@@ -79340,8 +77756,6 @@ static swig_type_info *swig_type_initial[] = {
   &_swigt__p_IFormFactorPolyhedron,
   &_swigt__p_IFormFactorPrism,
   &_swigt__p_IInterferenceFunction,
-  &_swigt__p_ILatticeOrientation,
-  &_swigt__p_ILayout,
   &_swigt__p_INode,
   &_swigt__p_INodeVisitor,
   &_swigt__p_IParameterized,
@@ -79368,17 +77782,15 @@ static swig_type_info *swig_type_initial[] = {
   &_swigt__p_InterferenceFunctionTwin,
   &_swigt__p_IsotropicGaussPeakShape,
   &_swigt__p_IsotropicLorentzPeakShape,
-  &_swigt__p_Lattice,
   &_swigt__p_Lattice2D,
   &_swigt__p_Lattice2D__ReciprocalBases,
+  &_swigt__p_Lattice3D,
   &_swigt__p_Layer,
   &_swigt__p_LayerInterface,
   &_swigt__p_LayerRoughness,
   &_swigt__p_LorentzFisherPeakShape,
   &_swigt__p_Material,
   &_swigt__p_MesoCrystal,
-  &_swigt__p_MillerIndex,
-  &_swigt__p_MillerIndexOrientation,
   &_swigt__p_MisesFisherGaussPeakShape,
   &_swigt__p_MisesGaussPeakShape,
   &_swigt__p_MultiLayer,
@@ -79447,10 +77859,10 @@ static swig_type_info *swig_type_initial[] = {
   &_swigt__p_std__vectorT_BasicVector3DT_std__complexT_double_t_t_std__allocatorT_BasicVector3DT_std__complexT_double_t_t_t_t,
   &_swigt__p_std__vectorT_HomogeneousRegion_std__allocatorT_HomogeneousRegion_t_t,
   &_swigt__p_std__vectorT_IFormFactor_p_std__allocatorT_IFormFactor_p_t_t,
-  &_swigt__p_std__vectorT_ILayout_const_p_std__allocatorT_ILayout_const_p_t_t,
   &_swigt__p_std__vectorT_INode_const_p_std__allocatorT_INode_const_p_t_t,
   &_swigt__p_std__vectorT_INode_p_std__allocatorT_INode_p_t_t,
   &_swigt__p_std__vectorT_Material_const_p_std__allocatorT_Material_const_p_t_t,
+  &_swigt__p_std__vectorT_ParticleLayout_const_p_std__allocatorT_ParticleLayout_const_p_t_t,
   &_swigt__p_std__vectorT_double_std__allocatorT_double_t_t,
   &_swigt__p_std__vectorT_int_std__allocatorT_int_t_t,
   &_swigt__p_std__vectorT_std__complexT_double_t_std__allocatorT_std__complexT_double_t_t_t,
@@ -79530,8 +77942,7 @@ static swig_cast_info _swigc__p_FormFactorWeighted[] = {  {&_swigt__p_FormFactor
 static swig_cast_info _swigc__p_GaussFisherPeakShape[] = {  {&_swigt__p_GaussFisherPeakShape, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_HexagonalLattice[] = {  {&_swigt__p_HexagonalLattice, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_IAbstractParticle[] = {  {&_swigt__p_ParticleComposition, _p_ParticleCompositionTo_p_IAbstractParticle, 0, 0},  {&_swigt__p_ParticleDistribution, _p_ParticleDistributionTo_p_IAbstractParticle, 0, 0},  {&_swigt__p_MesoCrystal, _p_MesoCrystalTo_p_IAbstractParticle, 0, 0},  {&_swigt__p_IAbstractParticle, 0, 0, 0},  {&_swigt__p_IParticle, _p_IParticleTo_p_IAbstractParticle, 0, 0},  {&_swigt__p_Particle, _p_ParticleTo_p_IAbstractParticle, 0, 0},  {&_swigt__p_ParticleCoreShell, _p_ParticleCoreShellTo_p_IAbstractParticle, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_ICloneable[] = {  {&_swigt__p_FormFactorBox, _p_FormFactorBoxTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorSphereGaussianRadius, _p_FormFactorSphereGaussianRadiusTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorSphereLogNormalRadius, _p_FormFactorSphereLogNormalRadiusTo_p_ICloneable, 0, 0},  {&_swigt__p_MultiLayer, _p_MultiLayerTo_p_ICloneable, 0, 0},  {&_swigt__p_ParticleDistribution, _p_ParticleDistributionTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDecayFunction1DGauss, _p_FTDecayFunction1DGaussTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution1DGauss, _p_FTDistribution1DGaussTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunctionNone, _p_InterferenceFunctionNoneTo_p_ICloneable, 0, 0},  {&_swigt__p_ParticleLayout, _p_ParticleLayoutTo_p_ICloneable, 0, 0},  {&_swigt__p_ILayout, _p_ILayoutTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorHemiEllipsoid, _p_FormFactorHemiEllipsoidTo_p_ICloneable, 0, 0},  {&_swigt__p_MisesGaussPeakShape, _p_MisesGaussPeakShapeTo_p_ICloneable, 0, 0},  {&_swigt__p_MisesFisherGaussPeakShape, _p_MisesFisherGaussPeakShapeTo_p_ICloneable, 0, 0},  {&_swigt__p_LorentzFisherPeakShape, _p_LorentzFisherPeakShapeTo_p_ICloneable, 0, 0},  {&_swigt__p_GaussFisherPeakShape, _p_GaussFisherPeakShapeTo_p_ICloneable, 0, 0},  {&_swigt__p_IsotropicLorentzPeakShape, _p_IsotropicLorentzPeakShapeTo_p_ICloneable, 0, 0},  {&_swigt__p_IsotropicGaussPeakShape, _p_IsotropicGaussPeakShapeTo_p_ICloneable, 0, 0},  {&_swigt__p_IPeakShape, _p_IPeakShapeTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorPrism3, _p_FormFactorPrism3To_p_ICloneable, 0, 0},  {&_swigt__p_IFormFactorPolyhedron, _p_IFormFactorPolyhedronTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorCuboctahedron, _p_FormFactorCuboctahedronTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorDodecahedron, _p_FormFactorDodecahedronTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorIcosahedron, _p_FormFactorIcosahedronTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorTetrahedron, _p_FormFactorTetrahedronTo_p_ICloneable, 0, 0},  {&_swigt__p_IFormFactorPrism, _p_IFormFactorPrismTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorPrism6, _p_FormFactorPrism6To_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution2DCone, _p_FTDistribution2DConeTo_p_ICloneable, 0, 0},  {&_swigt__p_ParticleCoreShell, _p_ParticleCoreShellTo_p_ICloneable, 0, 0},  {&_swigt__p_IProfileRectangularRipple, _p_IProfileRectangularRippleTo_p_ICloneable, 0, 0},  {&_swigt__p_ISawtoothRipple, _p_ISawtoothRippleTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorTruncatedSphere, _p_FormFactorTruncatedSphereTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorFullSphere, _p_FormFactorFullSphereTo_p_ICloneable, 0, 0},  {&_swigt__p_IFormFactor, _p_IFormFactorTo_p_ICloneable, 0, 0},  {&_swigt__p_ISample, _p_ISampleTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorLongBoxGauss, _p_FormFactorLongBoxGaussTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunctionHardDisk, _p_InterferenceFunctionHardDiskTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution2DGate, _p_FTDistribution2DGateTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDecayFunction1DVoigt, _p_FTDecayFunction1DVoigtTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution1DVoigt, _p_FTDistribution1DVoigtTo_p_ICloneable, 0, 0},  {&_swigt__p_IRotation, _p_IRotationTo_p_ICloneable, 0, 0},  {&_swigt__p_IdentityRotation, _p_IdentityRotationTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorTruncatedSpheroid, _p_FormFactorTruncatedSpheroidTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorFullSpheroid, _p_FormFactorFullSpheroidTo_p_ICloneable, 0, 0},  {&_swigt__p_RotationX, _p_RotationXTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorCantellatedCube, _p_FormFactorCantellatedCubeTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorTruncatedCube, _p_FormFactorTruncatedCubeTo_p_ICloneable, 0, 0},  {&_swigt__p_RotationY, _p_RotationYTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDecayFunction2DGauss, _p_FTDecayFunction2DGaussTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution2DGauss, _p_FTDistribution2DGaussTo_p_ICloneable, 0, 0},  {&_swigt__p_RotationZ, _p_RotationZTo_p_ICloneable, 0, 0},  {&_swigt__p_IFormFactorBorn, _p_IFormFactorBornTo_p_ICloneable, 0, 0},  {&_swigt__p_IClusteredParticles, _p_IClusteredParticlesTo_p_ICloneable, 0, 0},  {&_swigt__p_Particle, _p_ParticleTo_p_ICloneable, 0, 0},  {&_swigt__p_IParticle, _p_IParticleTo_p_ICloneable, 0, 0},  {&_swigt__p_IAbstractParticle, _p_IAbstractParticleTo_p_ICloneable, 0, 0},  {&_swigt__p_Lattice2D, _p_Lattice2DTo_p_ICloneable, 0, 0},  {&_swigt__p_IFTDistribution1D, _p_IFTDistribution1DTo_p_ICloneable, 0, 0},  {&_swigt__p_IFTDecayFunction1D, _p_IFTDecayFunction1DTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorCosineRippleBox, _p_FormFactorCosineRippleBoxTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleBox, _p_FormFactorSawtoothRippleBoxTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorCone, _p_FormFactorConeTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunctionTwin, _p_InterferenceFunctionTwinTo_p_ICloneable, 0, 0},  {&_swigt__p_Layer, _p_LayerTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorAnisoPyramid, _p_FormFactorAnisoPyramidTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorPyramid, _p_FormFactorPyramidTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorEllipsoidalCylinder, _p_FormFactorEllipsoidalCylinderTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorCylinder, _p_FormFactorCylinderTo_p_ICloneable, 0, 0},  {&_swigt__p_ParticleComposition, _p_ParticleCompositionTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution1DCosine, _p_FTDistribution1DCosineTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution1DGate, _p_FTDistribution1DGateTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorCosineRippleGauss, _p_FormFactorCosineRippleGaussTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleGauss, _p_FormFactorSawtoothRippleGaussTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDecayFunction2DVoigt, _p_FTDecayFunction2DVoigtTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution2DVoigt, _p_FTDistribution2DVoigtTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution1DCauchy, _p_FTDistribution1DCauchyTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDecayFunction1DCauchy, _p_FTDecayFunction1DCauchyTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution2DCauchy, _p_FTDistribution2DCauchyTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDecayFunction2DCauchy, _p_FTDecayFunction2DCauchyTo_p_ICloneable, 0, 0},  {&_swigt__p_IInterferenceFunction, _p_IInterferenceFunctionTo_p_ICloneable, 0, 0},  {&_swigt__p_ParameterPool, _p_ParameterPoolTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorCone6, _p_FormFactorCone6To_p_ICloneable, 0, 0},  {&_swigt__p_IFormFactorDecorator, _p_IFormFactorDecoratorTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorDot, _p_FormFactorDotTo_p_ICloneable, 0, 0},  {&_swigt__p_LayerRoughness, _p_LayerRoughnessTo_p_ICloneable, 0, 0},  {&_swigt__p_MesoCrystal, _p_MesoCrystalTo_p_ICloneable, 0, 0},  {&_swigt__p_Crystal, _p_CrystalTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorCrystal, _p_FormFactorCrystalTo_p_ICloneable, 0, 0},  {&_swigt__p_ICosineRipple, _p_ICosineRippleTo_p_ICloneable, 0, 0},  {&_swigt__p_IProfileRipple, _p_IProfileRippleTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunction2DParaCrystal, _p_InterferenceFunction2DParaCrystalTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunctionRadialParaCrystal, _p_InterferenceFunctionRadialParaCrystalTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorHollowSphere, _p_FormFactorHollowSphereTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorGaussSphere, _p_FormFactorGaussSphereTo_p_ICloneable, 0, 0},  {&_swigt__p_IFTDistribution2D, _p_IFTDistribution2DTo_p_ICloneable, 0, 0},  {&_swigt__p_IFTDecayFunction2D, _p_IFTDecayFunction2DTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorWeighted, _p_FormFactorWeightedTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorLongBoxLorentz, _p_FormFactorLongBoxLorentzTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorCosineRippleLorentz, _p_FormFactorCosineRippleLorentzTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleLorentz, _p_FormFactorSawtoothRippleLorentzTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunction1DLattice, _p_InterferenceFunction1DLatticeTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunction2DLattice, _p_InterferenceFunction2DLatticeTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunction2DSuperLattice, _p_InterferenceFunction2DSuperLatticeTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunction3DLattice, _p_InterferenceFunction3DLatticeTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunctionFinite2DLattice, _p_InterferenceFunctionFinite2DLatticeTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunctionFinite3DLattice, _p_InterferenceFunctionFinite3DLatticeTo_p_ICloneable, 0, 0},  {&_swigt__p_BasicLattice, _p_BasicLatticeTo_p_ICloneable, 0, 0},  {&_swigt__p_SquareLattice, _p_SquareLatticeTo_p_ICloneable, 0, 0},  {&_swigt__p_HexagonalLattice, _p_HexagonalLatticeTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution1DTriangle, _p_FTDistribution1DTriangleTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDecayFunction1DTriangle, _p_FTDecayFunction1DTriangleTo_p_ICloneable, 0, 0},  {&_swigt__p_ICloneable, 0, 0, 0},  {&_swigt__p_RotationEuler, _p_RotationEulerTo_p_ICloneable, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_IClusteredParticles[] = {  {&_swigt__p_IClusteredParticles, 0, 0, 0},  {&_swigt__p_Crystal, _p_CrystalTo_p_IClusteredParticles, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_ICloneable[] = {  {&_swigt__p_FormFactorBox, _p_FormFactorBoxTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorSphereGaussianRadius, _p_FormFactorSphereGaussianRadiusTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorSphereLogNormalRadius, _p_FormFactorSphereLogNormalRadiusTo_p_ICloneable, 0, 0},  {&_swigt__p_MultiLayer, _p_MultiLayerTo_p_ICloneable, 0, 0},  {&_swigt__p_ParticleDistribution, _p_ParticleDistributionTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDecayFunction1DGauss, _p_FTDecayFunction1DGaussTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution1DGauss, _p_FTDistribution1DGaussTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunctionNone, _p_InterferenceFunctionNoneTo_p_ICloneable, 0, 0},  {&_swigt__p_ParticleLayout, _p_ParticleLayoutTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorHemiEllipsoid, _p_FormFactorHemiEllipsoidTo_p_ICloneable, 0, 0},  {&_swigt__p_MisesGaussPeakShape, _p_MisesGaussPeakShapeTo_p_ICloneable, 0, 0},  {&_swigt__p_MisesFisherGaussPeakShape, _p_MisesFisherGaussPeakShapeTo_p_ICloneable, 0, 0},  {&_swigt__p_LorentzFisherPeakShape, _p_LorentzFisherPeakShapeTo_p_ICloneable, 0, 0},  {&_swigt__p_GaussFisherPeakShape, _p_GaussFisherPeakShapeTo_p_ICloneable, 0, 0},  {&_swigt__p_IsotropicLorentzPeakShape, _p_IsotropicLorentzPeakShapeTo_p_ICloneable, 0, 0},  {&_swigt__p_IsotropicGaussPeakShape, _p_IsotropicGaussPeakShapeTo_p_ICloneable, 0, 0},  {&_swigt__p_IPeakShape, _p_IPeakShapeTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorPrism3, _p_FormFactorPrism3To_p_ICloneable, 0, 0},  {&_swigt__p_IFormFactorPolyhedron, _p_IFormFactorPolyhedronTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorCuboctahedron, _p_FormFactorCuboctahedronTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorDodecahedron, _p_FormFactorDodecahedronTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorIcosahedron, _p_FormFactorIcosahedronTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorTetrahedron, _p_FormFactorTetrahedronTo_p_ICloneable, 0, 0},  {&_swigt__p_IFormFactorPrism, _p_IFormFactorPrismTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorPrism6, _p_FormFactorPrism6To_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution2DCone, _p_FTDistribution2DConeTo_p_ICloneable, 0, 0},  {&_swigt__p_ParticleCoreShell, _p_ParticleCoreShellTo_p_ICloneable, 0, 0},  {&_swigt__p_IProfileRectangularRipple, _p_IProfileRectangularRippleTo_p_ICloneable, 0, 0},  {&_swigt__p_ISawtoothRipple, _p_ISawtoothRippleTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorTruncatedSphere, _p_FormFactorTruncatedSphereTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorFullSphere, _p_FormFactorFullSphereTo_p_ICloneable, 0, 0},  {&_swigt__p_IFormFactor, _p_IFormFactorTo_p_ICloneable, 0, 0},  {&_swigt__p_ISample, _p_ISampleTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorLongBoxGauss, _p_FormFactorLongBoxGaussTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunctionHardDisk, _p_InterferenceFunctionHardDiskTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution2DGate, _p_FTDistribution2DGateTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDecayFunction1DVoigt, _p_FTDecayFunction1DVoigtTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution1DVoigt, _p_FTDistribution1DVoigtTo_p_ICloneable, 0, 0},  {&_swigt__p_IRotation, _p_IRotationTo_p_ICloneable, 0, 0},  {&_swigt__p_IdentityRotation, _p_IdentityRotationTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorTruncatedSpheroid, _p_FormFactorTruncatedSpheroidTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorFullSpheroid, _p_FormFactorFullSpheroidTo_p_ICloneable, 0, 0},  {&_swigt__p_RotationX, _p_RotationXTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorCantellatedCube, _p_FormFactorCantellatedCubeTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorTruncatedCube, _p_FormFactorTruncatedCubeTo_p_ICloneable, 0, 0},  {&_swigt__p_RotationY, _p_RotationYTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDecayFunction2DGauss, _p_FTDecayFunction2DGaussTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution2DGauss, _p_FTDistribution2DGaussTo_p_ICloneable, 0, 0},  {&_swigt__p_RotationZ, _p_RotationZTo_p_ICloneable, 0, 0},  {&_swigt__p_IFormFactorBorn, _p_IFormFactorBornTo_p_ICloneable, 0, 0},  {&_swigt__p_Particle, _p_ParticleTo_p_ICloneable, 0, 0},  {&_swigt__p_IParticle, _p_IParticleTo_p_ICloneable, 0, 0},  {&_swigt__p_IAbstractParticle, _p_IAbstractParticleTo_p_ICloneable, 0, 0},  {&_swigt__p_Lattice2D, _p_Lattice2DTo_p_ICloneable, 0, 0},  {&_swigt__p_IFTDistribution1D, _p_IFTDistribution1DTo_p_ICloneable, 0, 0},  {&_swigt__p_IFTDecayFunction1D, _p_IFTDecayFunction1DTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorCosineRippleBox, _p_FormFactorCosineRippleBoxTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleBox, _p_FormFactorSawtoothRippleBoxTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorCone, _p_FormFactorConeTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunctionTwin, _p_InterferenceFunctionTwinTo_p_ICloneable, 0, 0},  {&_swigt__p_Layer, _p_LayerTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorAnisoPyramid, _p_FormFactorAnisoPyramidTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorPyramid, _p_FormFactorPyramidTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorEllipsoidalCylinder, _p_FormFactorEllipsoidalCylinderTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorCylinder, _p_FormFactorCylinderTo_p_ICloneable, 0, 0},  {&_swigt__p_ParticleComposition, _p_ParticleCompositionTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution1DCosine, _p_FTDistribution1DCosineTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution1DGate, _p_FTDistribution1DGateTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorCosineRippleGauss, _p_FormFactorCosineRippleGaussTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleGauss, _p_FormFactorSawtoothRippleGaussTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDecayFunction2DVoigt, _p_FTDecayFunction2DVoigtTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution2DVoigt, _p_FTDistribution2DVoigtTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution1DCauchy, _p_FTDistribution1DCauchyTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDecayFunction1DCauchy, _p_FTDecayFunction1DCauchyTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution2DCauchy, _p_FTDistribution2DCauchyTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDecayFunction2DCauchy, _p_FTDecayFunction2DCauchyTo_p_ICloneable, 0, 0},  {&_swigt__p_IInterferenceFunction, _p_IInterferenceFunctionTo_p_ICloneable, 0, 0},  {&_swigt__p_ParameterPool, _p_ParameterPoolTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorCone6, _p_FormFactorCone6To_p_ICloneable, 0, 0},  {&_swigt__p_IFormFactorDecorator, _p_IFormFactorDecoratorTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorDot, _p_FormFactorDotTo_p_ICloneable, 0, 0},  {&_swigt__p_LayerRoughness, _p_LayerRoughnessTo_p_ICloneable, 0, 0},  {&_swigt__p_MesoCrystal, _p_MesoCrystalTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorCrystal, _p_FormFactorCrystalTo_p_ICloneable, 0, 0},  {&_swigt__p_ICosineRipple, _p_ICosineRippleTo_p_ICloneable, 0, 0},  {&_swigt__p_IProfileRipple, _p_IProfileRippleTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunction2DParaCrystal, _p_InterferenceFunction2DParaCrystalTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunctionRadialParaCrystal, _p_InterferenceFunctionRadialParaCrystalTo_p_ICloneable, 0, 0},  {&_swigt__p_Crystal, _p_CrystalTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorHollowSphere, _p_FormFactorHollowSphereTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorGaussSphere, _p_FormFactorGaussSphereTo_p_ICloneable, 0, 0},  {&_swigt__p_IFTDistribution2D, _p_IFTDistribution2DTo_p_ICloneable, 0, 0},  {&_swigt__p_IFTDecayFunction2D, _p_IFTDecayFunction2DTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorWeighted, _p_FormFactorWeightedTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorLongBoxLorentz, _p_FormFactorLongBoxLorentzTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorCosineRippleLorentz, _p_FormFactorCosineRippleLorentzTo_p_ICloneable, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleLorentz, _p_FormFactorSawtoothRippleLorentzTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunction3DLattice, _p_InterferenceFunction3DLatticeTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunction2DSuperLattice, _p_InterferenceFunction2DSuperLatticeTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunction2DLattice, _p_InterferenceFunction2DLatticeTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunction1DLattice, _p_InterferenceFunction1DLatticeTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunctionFinite2DLattice, _p_InterferenceFunctionFinite2DLatticeTo_p_ICloneable, 0, 0},  {&_swigt__p_InterferenceFunctionFinite3DLattice, _p_InterferenceFunctionFinite3DLatticeTo_p_ICloneable, 0, 0},  {&_swigt__p_BasicLattice, _p_BasicLatticeTo_p_ICloneable, 0, 0},  {&_swigt__p_SquareLattice, _p_SquareLatticeTo_p_ICloneable, 0, 0},  {&_swigt__p_HexagonalLattice, _p_HexagonalLatticeTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDistribution1DTriangle, _p_FTDistribution1DTriangleTo_p_ICloneable, 0, 0},  {&_swigt__p_FTDecayFunction1DTriangle, _p_FTDecayFunction1DTriangleTo_p_ICloneable, 0, 0},  {&_swigt__p_ICloneable, 0, 0, 0},  {&_swigt__p_RotationEuler, _p_RotationEulerTo_p_ICloneable, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_ICosineRipple[] = {  {&_swigt__p_FormFactorCosineRippleLorentz, _p_FormFactorCosineRippleLorentzTo_p_ICosineRipple, 0, 0},  {&_swigt__p_FormFactorCosineRippleBox, _p_FormFactorCosineRippleBoxTo_p_ICosineRipple, 0, 0},  {&_swigt__p_ICosineRipple, 0, 0, 0},  {&_swigt__p_FormFactorCosineRippleGauss, _p_FormFactorCosineRippleGaussTo_p_ICosineRipple, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_IFTDecayFunction1D[] = {  {&_swigt__p_FTDecayFunction1DCauchy, _p_FTDecayFunction1DCauchyTo_p_IFTDecayFunction1D, 0, 0},  {&_swigt__p_FTDecayFunction1DGauss, _p_FTDecayFunction1DGaussTo_p_IFTDecayFunction1D, 0, 0},  {&_swigt__p_FTDecayFunction1DTriangle, _p_FTDecayFunction1DTriangleTo_p_IFTDecayFunction1D, 0, 0},  {&_swigt__p_IFTDecayFunction1D, 0, 0, 0},  {&_swigt__p_FTDecayFunction1DVoigt, _p_FTDecayFunction1DVoigtTo_p_IFTDecayFunction1D, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_IFTDecayFunction2D[] = {  {&_swigt__p_FTDecayFunction2DCauchy, _p_FTDecayFunction2DCauchyTo_p_IFTDecayFunction2D, 0, 0},  {&_swigt__p_FTDecayFunction2DGauss, _p_FTDecayFunction2DGaussTo_p_IFTDecayFunction2D, 0, 0},  {&_swigt__p_IFTDecayFunction2D, 0, 0, 0},  {&_swigt__p_FTDecayFunction2DVoigt, _p_FTDecayFunction2DVoigtTo_p_IFTDecayFunction2D, 0, 0},{0, 0, 0, 0}};
@@ -79544,17 +77955,15 @@ static swig_cast_info _swigc__p_IFormFactorDecorator[] = {  {&_swigt__p_IFormFac
 static swig_cast_info _swigc__p_IFormFactorPolyhedron[] = {  {&_swigt__p_IFormFactorPolyhedron, 0, 0, 0},  {&_swigt__p_FormFactorCuboctahedron, _p_FormFactorCuboctahedronTo_p_IFormFactorPolyhedron, 0, 0},  {&_swigt__p_FormFactorDodecahedron, _p_FormFactorDodecahedronTo_p_IFormFactorPolyhedron, 0, 0},  {&_swigt__p_FormFactorIcosahedron, _p_FormFactorIcosahedronTo_p_IFormFactorPolyhedron, 0, 0},  {&_swigt__p_FormFactorTetrahedron, _p_FormFactorTetrahedronTo_p_IFormFactorPolyhedron, 0, 0},  {&_swigt__p_FormFactorCantellatedCube, _p_FormFactorCantellatedCubeTo_p_IFormFactorPolyhedron, 0, 0},  {&_swigt__p_FormFactorCone6, _p_FormFactorCone6To_p_IFormFactorPolyhedron, 0, 0},  {&_swigt__p_FormFactorTruncatedCube, _p_FormFactorTruncatedCubeTo_p_IFormFactorPolyhedron, 0, 0},  {&_swigt__p_FormFactorAnisoPyramid, _p_FormFactorAnisoPyramidTo_p_IFormFactorPolyhedron, 0, 0},  {&_swigt__p_FormFactorPyramid, _p_FormFactorPyramidTo_p_IFormFactorPolyhedron, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_IFormFactorPrism[] = {  {&_swigt__p_FormFactorPrism3, _p_FormFactorPrism3To_p_IFormFactorPrism, 0, 0},  {&_swigt__p_IFormFactorPrism, 0, 0, 0},  {&_swigt__p_FormFactorPrism6, _p_FormFactorPrism6To_p_IFormFactorPrism, 0, 0},  {&_swigt__p_FormFactorBox, _p_FormFactorBoxTo_p_IFormFactorPrism, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_IInterferenceFunction[] = {  {&_swigt__p_InterferenceFunctionHardDisk, _p_InterferenceFunctionHardDiskTo_p_IInterferenceFunction, 0, 0},  {&_swigt__p_IInterferenceFunction, 0, 0, 0},  {&_swigt__p_InterferenceFunction1DLattice, _p_InterferenceFunction1DLatticeTo_p_IInterferenceFunction, 0, 0},  {&_swigt__p_InterferenceFunction2DLattice, _p_InterferenceFunction2DLatticeTo_p_IInterferenceFunction, 0, 0},  {&_swigt__p_InterferenceFunction2DSuperLattice, _p_InterferenceFunction2DSuperLatticeTo_p_IInterferenceFunction, 0, 0},  {&_swigt__p_InterferenceFunction3DLattice, _p_InterferenceFunction3DLatticeTo_p_IInterferenceFunction, 0, 0},  {&_swigt__p_InterferenceFunctionFinite2DLattice, _p_InterferenceFunctionFinite2DLatticeTo_p_IInterferenceFunction, 0, 0},  {&_swigt__p_InterferenceFunctionFinite3DLattice, _p_InterferenceFunctionFinite3DLatticeTo_p_IInterferenceFunction, 0, 0},  {&_swigt__p_InterferenceFunctionNone, _p_InterferenceFunctionNoneTo_p_IInterferenceFunction, 0, 0},  {&_swigt__p_InterferenceFunction2DParaCrystal, _p_InterferenceFunction2DParaCrystalTo_p_IInterferenceFunction, 0, 0},  {&_swigt__p_InterferenceFunctionRadialParaCrystal, _p_InterferenceFunctionRadialParaCrystalTo_p_IInterferenceFunction, 0, 0},  {&_swigt__p_InterferenceFunctionTwin, _p_InterferenceFunctionTwinTo_p_IInterferenceFunction, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_ILatticeOrientation[] = {  {&_swigt__p_ILatticeOrientation, 0, 0, 0},  {&_swigt__p_MillerIndexOrientation, _p_MillerIndexOrientationTo_p_ILatticeOrientation, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_ILayout[] = {  {&_swigt__p_ILayout, 0, 0, 0},  {&_swigt__p_ParticleLayout, _p_ParticleLayoutTo_p_ILayout, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_INode[] = {  {&_swigt__p_FormFactorBox, _p_FormFactorBoxTo_p_INode, 0, 0},  {&_swigt__p_FormFactorSphereGaussianRadius, _p_FormFactorSphereGaussianRadiusTo_p_INode, 0, 0},  {&_swigt__p_FormFactorSphereLogNormalRadius, _p_FormFactorSphereLogNormalRadiusTo_p_INode, 0, 0},  {&_swigt__p_MultiLayer, _p_MultiLayerTo_p_INode, 0, 0},  {&_swigt__p_ParticleDistribution, _p_ParticleDistributionTo_p_INode, 0, 0},  {&_swigt__p_FTDecayFunction1DGauss, _p_FTDecayFunction1DGaussTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution1DGauss, _p_FTDistribution1DGaussTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunctionNone, _p_InterferenceFunctionNoneTo_p_INode, 0, 0},  {&_swigt__p_ParticleLayout, _p_ParticleLayoutTo_p_INode, 0, 0},  {&_swigt__p_ILayout, _p_ILayoutTo_p_INode, 0, 0},  {&_swigt__p_FormFactorHemiEllipsoid, _p_FormFactorHemiEllipsoidTo_p_INode, 0, 0},  {&_swigt__p_INode, 0, 0, 0},  {&_swigt__p_MisesGaussPeakShape, _p_MisesGaussPeakShapeTo_p_INode, 0, 0},  {&_swigt__p_MisesFisherGaussPeakShape, _p_MisesFisherGaussPeakShapeTo_p_INode, 0, 0},  {&_swigt__p_LorentzFisherPeakShape, _p_LorentzFisherPeakShapeTo_p_INode, 0, 0},  {&_swigt__p_GaussFisherPeakShape, _p_GaussFisherPeakShapeTo_p_INode, 0, 0},  {&_swigt__p_IsotropicLorentzPeakShape, _p_IsotropicLorentzPeakShapeTo_p_INode, 0, 0},  {&_swigt__p_IsotropicGaussPeakShape, _p_IsotropicGaussPeakShapeTo_p_INode, 0, 0},  {&_swigt__p_IPeakShape, _p_IPeakShapeTo_p_INode, 0, 0},  {&_swigt__p_FormFactorPrism3, _p_FormFactorPrism3To_p_INode, 0, 0},  {&_swigt__p_IFormFactorPolyhedron, _p_IFormFactorPolyhedronTo_p_INode, 0, 0},  {&_swigt__p_FormFactorCuboctahedron, _p_FormFactorCuboctahedronTo_p_INode, 0, 0},  {&_swigt__p_FormFactorDodecahedron, _p_FormFactorDodecahedronTo_p_INode, 0, 0},  {&_swigt__p_FormFactorIcosahedron, _p_FormFactorIcosahedronTo_p_INode, 0, 0},  {&_swigt__p_FormFactorTetrahedron, _p_FormFactorTetrahedronTo_p_INode, 0, 0},  {&_swigt__p_IFormFactorPrism, _p_IFormFactorPrismTo_p_INode, 0, 0},  {&_swigt__p_FormFactorPrism6, _p_FormFactorPrism6To_p_INode, 0, 0},  {&_swigt__p_FTDistribution2DCone, _p_FTDistribution2DConeTo_p_INode, 0, 0},  {&_swigt__p_ParticleCoreShell, _p_ParticleCoreShellTo_p_INode, 0, 0},  {&_swigt__p_IProfileRectangularRipple, _p_IProfileRectangularRippleTo_p_INode, 0, 0},  {&_swigt__p_ISawtoothRipple, _p_ISawtoothRippleTo_p_INode, 0, 0},  {&_swigt__p_FormFactorTruncatedSphere, _p_FormFactorTruncatedSphereTo_p_INode, 0, 0},  {&_swigt__p_FormFactorFullSphere, _p_FormFactorFullSphereTo_p_INode, 0, 0},  {&_swigt__p_IFormFactor, _p_IFormFactorTo_p_INode, 0, 0},  {&_swigt__p_ISample, _p_ISampleTo_p_INode, 0, 0},  {&_swigt__p_FormFactorLongBoxGauss, _p_FormFactorLongBoxGaussTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunctionHardDisk, _p_InterferenceFunctionHardDiskTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution2DGate, _p_FTDistribution2DGateTo_p_INode, 0, 0},  {&_swigt__p_FTDecayFunction1DVoigt, _p_FTDecayFunction1DVoigtTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution1DVoigt, _p_FTDistribution1DVoigtTo_p_INode, 0, 0},  {&_swigt__p_IRotation, _p_IRotationTo_p_INode, 0, 0},  {&_swigt__p_IdentityRotation, _p_IdentityRotationTo_p_INode, 0, 0},  {&_swigt__p_FormFactorTruncatedSpheroid, _p_FormFactorTruncatedSpheroidTo_p_INode, 0, 0},  {&_swigt__p_FormFactorFullSpheroid, _p_FormFactorFullSpheroidTo_p_INode, 0, 0},  {&_swigt__p_RotationX, _p_RotationXTo_p_INode, 0, 0},  {&_swigt__p_FormFactorCantellatedCube, _p_FormFactorCantellatedCubeTo_p_INode, 0, 0},  {&_swigt__p_FormFactorTruncatedCube, _p_FormFactorTruncatedCubeTo_p_INode, 0, 0},  {&_swigt__p_RotationY, _p_RotationYTo_p_INode, 0, 0},  {&_swigt__p_FTDecayFunction2DGauss, _p_FTDecayFunction2DGaussTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution2DGauss, _p_FTDistribution2DGaussTo_p_INode, 0, 0},  {&_swigt__p_RotationZ, _p_RotationZTo_p_INode, 0, 0},  {&_swigt__p_IFormFactorBorn, _p_IFormFactorBornTo_p_INode, 0, 0},  {&_swigt__p_IClusteredParticles, _p_IClusteredParticlesTo_p_INode, 0, 0},  {&_swigt__p_Particle, _p_ParticleTo_p_INode, 0, 0},  {&_swigt__p_IParticle, _p_IParticleTo_p_INode, 0, 0},  {&_swigt__p_IAbstractParticle, _p_IAbstractParticleTo_p_INode, 0, 0},  {&_swigt__p_Lattice2D, _p_Lattice2DTo_p_INode, 0, 0},  {&_swigt__p_IFTDistribution1D, _p_IFTDistribution1DTo_p_INode, 0, 0},  {&_swigt__p_IFTDecayFunction1D, _p_IFTDecayFunction1DTo_p_INode, 0, 0},  {&_swigt__p_FormFactorCosineRippleBox, _p_FormFactorCosineRippleBoxTo_p_INode, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleBox, _p_FormFactorSawtoothRippleBoxTo_p_INode, 0, 0},  {&_swigt__p_FormFactorCone, _p_FormFactorConeTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunctionTwin, _p_InterferenceFunctionTwinTo_p_INode, 0, 0},  {&_swigt__p_Layer, _p_LayerTo_p_INode, 0, 0},  {&_swigt__p_FormFactorAnisoPyramid, _p_FormFactorAnisoPyramidTo_p_INode, 0, 0},  {&_swigt__p_FormFactorPyramid, _p_FormFactorPyramidTo_p_INode, 0, 0},  {&_swigt__p_FormFactorEllipsoidalCylinder, _p_FormFactorEllipsoidalCylinderTo_p_INode, 0, 0},  {&_swigt__p_FormFactorCylinder, _p_FormFactorCylinderTo_p_INode, 0, 0},  {&_swigt__p_ParticleComposition, _p_ParticleCompositionTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution1DCosine, _p_FTDistribution1DCosineTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution1DGate, _p_FTDistribution1DGateTo_p_INode, 0, 0},  {&_swigt__p_FormFactorCosineRippleGauss, _p_FormFactorCosineRippleGaussTo_p_INode, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleGauss, _p_FormFactorSawtoothRippleGaussTo_p_INode, 0, 0},  {&_swigt__p_FTDecayFunction2DVoigt, _p_FTDecayFunction2DVoigtTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution2DVoigt, _p_FTDistribution2DVoigtTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution1DCauchy, _p_FTDistribution1DCauchyTo_p_INode, 0, 0},  {&_swigt__p_FTDecayFunction1DCauchy, _p_FTDecayFunction1DCauchyTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution2DCauchy, _p_FTDistribution2DCauchyTo_p_INode, 0, 0},  {&_swigt__p_FTDecayFunction2DCauchy, _p_FTDecayFunction2DCauchyTo_p_INode, 0, 0},  {&_swigt__p_IInterferenceFunction, _p_IInterferenceFunctionTo_p_INode, 0, 0},  {&_swigt__p_FormFactorCone6, _p_FormFactorCone6To_p_INode, 0, 0},  {&_swigt__p_IFormFactorDecorator, _p_IFormFactorDecoratorTo_p_INode, 0, 0},  {&_swigt__p_FormFactorDot, _p_FormFactorDotTo_p_INode, 0, 0},  {&_swigt__p_LayerRoughness, _p_LayerRoughnessTo_p_INode, 0, 0},  {&_swigt__p_MesoCrystal, _p_MesoCrystalTo_p_INode, 0, 0},  {&_swigt__p_Crystal, _p_CrystalTo_p_INode, 0, 0},  {&_swigt__p_FormFactorCrystal, _p_FormFactorCrystalTo_p_INode, 0, 0},  {&_swigt__p_ICosineRipple, _p_ICosineRippleTo_p_INode, 0, 0},  {&_swigt__p_IProfileRipple, _p_IProfileRippleTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunction2DParaCrystal, _p_InterferenceFunction2DParaCrystalTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunctionRadialParaCrystal, _p_InterferenceFunctionRadialParaCrystalTo_p_INode, 0, 0},  {&_swigt__p_FormFactorHollowSphere, _p_FormFactorHollowSphereTo_p_INode, 0, 0},  {&_swigt__p_FormFactorGaussSphere, _p_FormFactorGaussSphereTo_p_INode, 0, 0},  {&_swigt__p_IFTDistribution2D, _p_IFTDistribution2DTo_p_INode, 0, 0},  {&_swigt__p_IFTDecayFunction2D, _p_IFTDecayFunction2DTo_p_INode, 0, 0},  {&_swigt__p_FormFactorWeighted, _p_FormFactorWeightedTo_p_INode, 0, 0},  {&_swigt__p_FormFactorLongBoxLorentz, _p_FormFactorLongBoxLorentzTo_p_INode, 0, 0},  {&_swigt__p_FormFactorCosineRippleLorentz, _p_FormFactorCosineRippleLorentzTo_p_INode, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleLorentz, _p_FormFactorSawtoothRippleLorentzTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunction1DLattice, _p_InterferenceFunction1DLatticeTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunction2DLattice, _p_InterferenceFunction2DLatticeTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunction2DSuperLattice, _p_InterferenceFunction2DSuperLatticeTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunction3DLattice, _p_InterferenceFunction3DLatticeTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunctionFinite2DLattice, _p_InterferenceFunctionFinite2DLatticeTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunctionFinite3DLattice, _p_InterferenceFunctionFinite3DLatticeTo_p_INode, 0, 0},  {&_swigt__p_BasicLattice, _p_BasicLatticeTo_p_INode, 0, 0},  {&_swigt__p_SquareLattice, _p_SquareLatticeTo_p_INode, 0, 0},  {&_swigt__p_HexagonalLattice, _p_HexagonalLatticeTo_p_INode, 0, 0},  {&_swigt__p_Lattice, _p_LatticeTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution1DTriangle, _p_FTDistribution1DTriangleTo_p_INode, 0, 0},  {&_swigt__p_FTDecayFunction1DTriangle, _p_FTDecayFunction1DTriangleTo_p_INode, 0, 0},  {&_swigt__p_RotationEuler, _p_RotationEulerTo_p_INode, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_INode[] = {  {&_swigt__p_FormFactorBox, _p_FormFactorBoxTo_p_INode, 0, 0},  {&_swigt__p_FormFactorSphereGaussianRadius, _p_FormFactorSphereGaussianRadiusTo_p_INode, 0, 0},  {&_swigt__p_FormFactorSphereLogNormalRadius, _p_FormFactorSphereLogNormalRadiusTo_p_INode, 0, 0},  {&_swigt__p_MultiLayer, _p_MultiLayerTo_p_INode, 0, 0},  {&_swigt__p_ParticleDistribution, _p_ParticleDistributionTo_p_INode, 0, 0},  {&_swigt__p_FTDecayFunction1DGauss, _p_FTDecayFunction1DGaussTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution1DGauss, _p_FTDistribution1DGaussTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunctionNone, _p_InterferenceFunctionNoneTo_p_INode, 0, 0},  {&_swigt__p_ParticleLayout, _p_ParticleLayoutTo_p_INode, 0, 0},  {&_swigt__p_FormFactorHemiEllipsoid, _p_FormFactorHemiEllipsoidTo_p_INode, 0, 0},  {&_swigt__p_INode, 0, 0, 0},  {&_swigt__p_MisesGaussPeakShape, _p_MisesGaussPeakShapeTo_p_INode, 0, 0},  {&_swigt__p_MisesFisherGaussPeakShape, _p_MisesFisherGaussPeakShapeTo_p_INode, 0, 0},  {&_swigt__p_LorentzFisherPeakShape, _p_LorentzFisherPeakShapeTo_p_INode, 0, 0},  {&_swigt__p_GaussFisherPeakShape, _p_GaussFisherPeakShapeTo_p_INode, 0, 0},  {&_swigt__p_IsotropicLorentzPeakShape, _p_IsotropicLorentzPeakShapeTo_p_INode, 0, 0},  {&_swigt__p_IsotropicGaussPeakShape, _p_IsotropicGaussPeakShapeTo_p_INode, 0, 0},  {&_swigt__p_IPeakShape, _p_IPeakShapeTo_p_INode, 0, 0},  {&_swigt__p_FormFactorPrism3, _p_FormFactorPrism3To_p_INode, 0, 0},  {&_swigt__p_IFormFactorPolyhedron, _p_IFormFactorPolyhedronTo_p_INode, 0, 0},  {&_swigt__p_FormFactorCuboctahedron, _p_FormFactorCuboctahedronTo_p_INode, 0, 0},  {&_swigt__p_FormFactorDodecahedron, _p_FormFactorDodecahedronTo_p_INode, 0, 0},  {&_swigt__p_FormFactorIcosahedron, _p_FormFactorIcosahedronTo_p_INode, 0, 0},  {&_swigt__p_FormFactorTetrahedron, _p_FormFactorTetrahedronTo_p_INode, 0, 0},  {&_swigt__p_IFormFactorPrism, _p_IFormFactorPrismTo_p_INode, 0, 0},  {&_swigt__p_FormFactorPrism6, _p_FormFactorPrism6To_p_INode, 0, 0},  {&_swigt__p_FTDistribution2DCone, _p_FTDistribution2DConeTo_p_INode, 0, 0},  {&_swigt__p_ParticleCoreShell, _p_ParticleCoreShellTo_p_INode, 0, 0},  {&_swigt__p_IProfileRectangularRipple, _p_IProfileRectangularRippleTo_p_INode, 0, 0},  {&_swigt__p_ISawtoothRipple, _p_ISawtoothRippleTo_p_INode, 0, 0},  {&_swigt__p_FormFactorTruncatedSphere, _p_FormFactorTruncatedSphereTo_p_INode, 0, 0},  {&_swigt__p_FormFactorFullSphere, _p_FormFactorFullSphereTo_p_INode, 0, 0},  {&_swigt__p_IFormFactor, _p_IFormFactorTo_p_INode, 0, 0},  {&_swigt__p_ISample, _p_ISampleTo_p_INode, 0, 0},  {&_swigt__p_FormFactorLongBoxGauss, _p_FormFactorLongBoxGaussTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunctionHardDisk, _p_InterferenceFunctionHardDiskTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution2DGate, _p_FTDistribution2DGateTo_p_INode, 0, 0},  {&_swigt__p_FTDecayFunction1DVoigt, _p_FTDecayFunction1DVoigtTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution1DVoigt, _p_FTDistribution1DVoigtTo_p_INode, 0, 0},  {&_swigt__p_IRotation, _p_IRotationTo_p_INode, 0, 0},  {&_swigt__p_IdentityRotation, _p_IdentityRotationTo_p_INode, 0, 0},  {&_swigt__p_FormFactorTruncatedSpheroid, _p_FormFactorTruncatedSpheroidTo_p_INode, 0, 0},  {&_swigt__p_FormFactorFullSpheroid, _p_FormFactorFullSpheroidTo_p_INode, 0, 0},  {&_swigt__p_RotationX, _p_RotationXTo_p_INode, 0, 0},  {&_swigt__p_FormFactorCantellatedCube, _p_FormFactorCantellatedCubeTo_p_INode, 0, 0},  {&_swigt__p_FormFactorTruncatedCube, _p_FormFactorTruncatedCubeTo_p_INode, 0, 0},  {&_swigt__p_RotationY, _p_RotationYTo_p_INode, 0, 0},  {&_swigt__p_FTDecayFunction2DGauss, _p_FTDecayFunction2DGaussTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution2DGauss, _p_FTDistribution2DGaussTo_p_INode, 0, 0},  {&_swigt__p_RotationZ, _p_RotationZTo_p_INode, 0, 0},  {&_swigt__p_IFormFactorBorn, _p_IFormFactorBornTo_p_INode, 0, 0},  {&_swigt__p_Particle, _p_ParticleTo_p_INode, 0, 0},  {&_swigt__p_IParticle, _p_IParticleTo_p_INode, 0, 0},  {&_swigt__p_IAbstractParticle, _p_IAbstractParticleTo_p_INode, 0, 0},  {&_swigt__p_Lattice2D, _p_Lattice2DTo_p_INode, 0, 0},  {&_swigt__p_IFTDistribution1D, _p_IFTDistribution1DTo_p_INode, 0, 0},  {&_swigt__p_IFTDecayFunction1D, _p_IFTDecayFunction1DTo_p_INode, 0, 0},  {&_swigt__p_FormFactorCosineRippleBox, _p_FormFactorCosineRippleBoxTo_p_INode, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleBox, _p_FormFactorSawtoothRippleBoxTo_p_INode, 0, 0},  {&_swigt__p_FormFactorCone, _p_FormFactorConeTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunctionTwin, _p_InterferenceFunctionTwinTo_p_INode, 0, 0},  {&_swigt__p_Layer, _p_LayerTo_p_INode, 0, 0},  {&_swigt__p_FormFactorAnisoPyramid, _p_FormFactorAnisoPyramidTo_p_INode, 0, 0},  {&_swigt__p_FormFactorPyramid, _p_FormFactorPyramidTo_p_INode, 0, 0},  {&_swigt__p_FormFactorEllipsoidalCylinder, _p_FormFactorEllipsoidalCylinderTo_p_INode, 0, 0},  {&_swigt__p_FormFactorCylinder, _p_FormFactorCylinderTo_p_INode, 0, 0},  {&_swigt__p_ParticleComposition, _p_ParticleCompositionTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution1DCosine, _p_FTDistribution1DCosineTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution1DGate, _p_FTDistribution1DGateTo_p_INode, 0, 0},  {&_swigt__p_FormFactorCosineRippleGauss, _p_FormFactorCosineRippleGaussTo_p_INode, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleGauss, _p_FormFactorSawtoothRippleGaussTo_p_INode, 0, 0},  {&_swigt__p_FTDecayFunction2DVoigt, _p_FTDecayFunction2DVoigtTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution2DVoigt, _p_FTDistribution2DVoigtTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution1DCauchy, _p_FTDistribution1DCauchyTo_p_INode, 0, 0},  {&_swigt__p_FTDecayFunction1DCauchy, _p_FTDecayFunction1DCauchyTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution2DCauchy, _p_FTDistribution2DCauchyTo_p_INode, 0, 0},  {&_swigt__p_FTDecayFunction2DCauchy, _p_FTDecayFunction2DCauchyTo_p_INode, 0, 0},  {&_swigt__p_IInterferenceFunction, _p_IInterferenceFunctionTo_p_INode, 0, 0},  {&_swigt__p_FormFactorCone6, _p_FormFactorCone6To_p_INode, 0, 0},  {&_swigt__p_IFormFactorDecorator, _p_IFormFactorDecoratorTo_p_INode, 0, 0},  {&_swigt__p_FormFactorDot, _p_FormFactorDotTo_p_INode, 0, 0},  {&_swigt__p_LayerRoughness, _p_LayerRoughnessTo_p_INode, 0, 0},  {&_swigt__p_MesoCrystal, _p_MesoCrystalTo_p_INode, 0, 0},  {&_swigt__p_FormFactorCrystal, _p_FormFactorCrystalTo_p_INode, 0, 0},  {&_swigt__p_ICosineRipple, _p_ICosineRippleTo_p_INode, 0, 0},  {&_swigt__p_IProfileRipple, _p_IProfileRippleTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunction2DParaCrystal, _p_InterferenceFunction2DParaCrystalTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunctionRadialParaCrystal, _p_InterferenceFunctionRadialParaCrystalTo_p_INode, 0, 0},  {&_swigt__p_Crystal, _p_CrystalTo_p_INode, 0, 0},  {&_swigt__p_Lattice3D, _p_Lattice3DTo_p_INode, 0, 0},  {&_swigt__p_FormFactorHollowSphere, _p_FormFactorHollowSphereTo_p_INode, 0, 0},  {&_swigt__p_FormFactorGaussSphere, _p_FormFactorGaussSphereTo_p_INode, 0, 0},  {&_swigt__p_IFTDistribution2D, _p_IFTDistribution2DTo_p_INode, 0, 0},  {&_swigt__p_IFTDecayFunction2D, _p_IFTDecayFunction2DTo_p_INode, 0, 0},  {&_swigt__p_FormFactorWeighted, _p_FormFactorWeightedTo_p_INode, 0, 0},  {&_swigt__p_FormFactorLongBoxLorentz, _p_FormFactorLongBoxLorentzTo_p_INode, 0, 0},  {&_swigt__p_FormFactorCosineRippleLorentz, _p_FormFactorCosineRippleLorentzTo_p_INode, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleLorentz, _p_FormFactorSawtoothRippleLorentzTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunction3DLattice, _p_InterferenceFunction3DLatticeTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunction2DSuperLattice, _p_InterferenceFunction2DSuperLatticeTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunction2DLattice, _p_InterferenceFunction2DLatticeTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunction1DLattice, _p_InterferenceFunction1DLatticeTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunctionFinite2DLattice, _p_InterferenceFunctionFinite2DLatticeTo_p_INode, 0, 0},  {&_swigt__p_InterferenceFunctionFinite3DLattice, _p_InterferenceFunctionFinite3DLatticeTo_p_INode, 0, 0},  {&_swigt__p_BasicLattice, _p_BasicLatticeTo_p_INode, 0, 0},  {&_swigt__p_SquareLattice, _p_SquareLatticeTo_p_INode, 0, 0},  {&_swigt__p_HexagonalLattice, _p_HexagonalLatticeTo_p_INode, 0, 0},  {&_swigt__p_FTDistribution1DTriangle, _p_FTDistribution1DTriangleTo_p_INode, 0, 0},  {&_swigt__p_FTDecayFunction1DTriangle, _p_FTDecayFunction1DTriangleTo_p_INode, 0, 0},  {&_swigt__p_RotationEuler, _p_RotationEulerTo_p_INode, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_INodeVisitor[] = {  {&_swigt__p_INodeVisitor, 0, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_IParameterized[] = {  {&_swigt__p_FormFactorBox, _p_FormFactorBoxTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorSphereGaussianRadius, _p_FormFactorSphereGaussianRadiusTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorSphereLogNormalRadius, _p_FormFactorSphereLogNormalRadiusTo_p_IParameterized, 0, 0},  {&_swigt__p_MultiLayer, _p_MultiLayerTo_p_IParameterized, 0, 0},  {&_swigt__p_ParameterDistribution, _p_ParameterDistributionTo_p_IParameterized, 0, 0},  {&_swigt__p_ParticleDistribution, _p_ParticleDistributionTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution1DGauss, _p_FTDistribution1DGaussTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDecayFunction1DGauss, _p_FTDecayFunction1DGaussTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunctionNone, _p_InterferenceFunctionNoneTo_p_IParameterized, 0, 0},  {&_swigt__p_ParticleLayout, _p_ParticleLayoutTo_p_IParameterized, 0, 0},  {&_swigt__p_ILayout, _p_ILayoutTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorHemiEllipsoid, _p_FormFactorHemiEllipsoidTo_p_IParameterized, 0, 0},  {&_swigt__p_INode, _p_INodeTo_p_IParameterized, 0, 0},  {&_swigt__p_MisesFisherGaussPeakShape, _p_MisesFisherGaussPeakShapeTo_p_IParameterized, 0, 0},  {&_swigt__p_MisesGaussPeakShape, _p_MisesGaussPeakShapeTo_p_IParameterized, 0, 0},  {&_swigt__p_LorentzFisherPeakShape, _p_LorentzFisherPeakShapeTo_p_IParameterized, 0, 0},  {&_swigt__p_GaussFisherPeakShape, _p_GaussFisherPeakShapeTo_p_IParameterized, 0, 0},  {&_swigt__p_IsotropicLorentzPeakShape, _p_IsotropicLorentzPeakShapeTo_p_IParameterized, 0, 0},  {&_swigt__p_IsotropicGaussPeakShape, _p_IsotropicGaussPeakShapeTo_p_IParameterized, 0, 0},  {&_swigt__p_IPeakShape, _p_IPeakShapeTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorPrism3, _p_FormFactorPrism3To_p_IParameterized, 0, 0},  {&_swigt__p_IFormFactorPolyhedron, _p_IFormFactorPolyhedronTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorCuboctahedron, _p_FormFactorCuboctahedronTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorDodecahedron, _p_FormFactorDodecahedronTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorIcosahedron, _p_FormFactorIcosahedronTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorTetrahedron, _p_FormFactorTetrahedronTo_p_IParameterized, 0, 0},  {&_swigt__p_IFormFactorPrism, _p_IFormFactorPrismTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorPrism6, _p_FormFactorPrism6To_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution2DCone, _p_FTDistribution2DConeTo_p_IParameterized, 0, 0},  {&_swigt__p_ParticleCoreShell, _p_ParticleCoreShellTo_p_IParameterized, 0, 0},  {&_swigt__p_IProfileRectangularRipple, _p_IProfileRectangularRippleTo_p_IParameterized, 0, 0},  {&_swigt__p_ISawtoothRipple, _p_ISawtoothRippleTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorTruncatedSphere, _p_FormFactorTruncatedSphereTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorFullSphere, _p_FormFactorFullSphereTo_p_IParameterized, 0, 0},  {&_swigt__p_IFormFactor, _p_IFormFactorTo_p_IParameterized, 0, 0},  {&_swigt__p_ISample, _p_ISampleTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorLongBoxGauss, _p_FormFactorLongBoxGaussTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunctionHardDisk, _p_InterferenceFunctionHardDiskTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution2DGate, _p_FTDistribution2DGateTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDecayFunction1DVoigt, _p_FTDecayFunction1DVoigtTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution1DVoigt, _p_FTDistribution1DVoigtTo_p_IParameterized, 0, 0},  {&_swigt__p_IRotation, _p_IRotationTo_p_IParameterized, 0, 0},  {&_swigt__p_IdentityRotation, _p_IdentityRotationTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorTruncatedSpheroid, _p_FormFactorTruncatedSpheroidTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorFullSpheroid, _p_FormFactorFullSpheroidTo_p_IParameterized, 0, 0},  {&_swigt__p_RotationX, _p_RotationXTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorCantellatedCube, _p_FormFactorCantellatedCubeTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorTruncatedCube, _p_FormFactorTruncatedCubeTo_p_IParameterized, 0, 0},  {&_swigt__p_RotationY, _p_RotationYTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDecayFunction2DGauss, _p_FTDecayFunction2DGaussTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution2DGauss, _p_FTDistribution2DGaussTo_p_IParameterized, 0, 0},  {&_swigt__p_RotationZ, _p_RotationZTo_p_IParameterized, 0, 0},  {&_swigt__p_IFormFactorBorn, _p_IFormFactorBornTo_p_IParameterized, 0, 0},  {&_swigt__p_IClusteredParticles, _p_IClusteredParticlesTo_p_IParameterized, 0, 0},  {&_swigt__p_ISampleBuilder, _p_ISampleBuilderTo_p_IParameterized, 0, 0},  {&_swigt__p_Particle, _p_ParticleTo_p_IParameterized, 0, 0},  {&_swigt__p_IParticle, _p_IParticleTo_p_IParameterized, 0, 0},  {&_swigt__p_IAbstractParticle, _p_IAbstractParticleTo_p_IParameterized, 0, 0},  {&_swigt__p_Lattice2D, _p_Lattice2DTo_p_IParameterized, 0, 0},  {&_swigt__p_IFTDistribution1D, _p_IFTDistribution1DTo_p_IParameterized, 0, 0},  {&_swigt__p_IFTDecayFunction1D, _p_IFTDecayFunction1DTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorCosineRippleBox, _p_FormFactorCosineRippleBoxTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleBox, _p_FormFactorSawtoothRippleBoxTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorCone, _p_FormFactorConeTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunctionTwin, _p_InterferenceFunctionTwinTo_p_IParameterized, 0, 0},  {&_swigt__p_Layer, _p_LayerTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorAnisoPyramid, _p_FormFactorAnisoPyramidTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorPyramid, _p_FormFactorPyramidTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorEllipsoidalCylinder, _p_FormFactorEllipsoidalCylinderTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorCylinder, _p_FormFactorCylinderTo_p_IParameterized, 0, 0},  {&_swigt__p_ParticleComposition, _p_ParticleCompositionTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution1DCosine, _p_FTDistribution1DCosineTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution1DGate, _p_FTDistribution1DGateTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorCosineRippleGauss, _p_FormFactorCosineRippleGaussTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleGauss, _p_FormFactorSawtoothRippleGaussTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDecayFunction2DVoigt, _p_FTDecayFunction2DVoigtTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution2DVoigt, _p_FTDistribution2DVoigtTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution1DCauchy, _p_FTDistribution1DCauchyTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDecayFunction1DCauchy, _p_FTDecayFunction1DCauchyTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution2DCauchy, _p_FTDistribution2DCauchyTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDecayFunction2DCauchy, _p_FTDecayFunction2DCauchyTo_p_IParameterized, 0, 0},  {&_swigt__p_IInterferenceFunction, _p_IInterferenceFunctionTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorCone6, _p_FormFactorCone6To_p_IParameterized, 0, 0},  {&_swigt__p_IFormFactorDecorator, _p_IFormFactorDecoratorTo_p_IParameterized, 0, 0},  {&_swigt__p_IParameterized, 0, 0, 0},  {&_swigt__p_FormFactorDot, _p_FormFactorDotTo_p_IParameterized, 0, 0},  {&_swigt__p_LayerRoughness, _p_LayerRoughnessTo_p_IParameterized, 0, 0},  {&_swigt__p_MesoCrystal, _p_MesoCrystalTo_p_IParameterized, 0, 0},  {&_swigt__p_Crystal, _p_CrystalTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorCrystal, _p_FormFactorCrystalTo_p_IParameterized, 0, 0},  {&_swigt__p_ICosineRipple, _p_ICosineRippleTo_p_IParameterized, 0, 0},  {&_swigt__p_IProfileRipple, _p_IProfileRippleTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunction2DParaCrystal, _p_InterferenceFunction2DParaCrystalTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunctionRadialParaCrystal, _p_InterferenceFunctionRadialParaCrystalTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorHollowSphere, _p_FormFactorHollowSphereTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorGaussSphere, _p_FormFactorGaussSphereTo_p_IParameterized, 0, 0},  {&_swigt__p_IFTDistribution2D, _p_IFTDistribution2DTo_p_IParameterized, 0, 0},  {&_swigt__p_IFTDecayFunction2D, _p_IFTDecayFunction2DTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorWeighted, _p_FormFactorWeightedTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorLongBoxLorentz, _p_FormFactorLongBoxLorentzTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorCosineRippleLorentz, _p_FormFactorCosineRippleLorentzTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleLorentz, _p_FormFactorSawtoothRippleLorentzTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunction1DLattice, _p_InterferenceFunction1DLatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunction2DLattice, _p_InterferenceFunction2DLatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunction2DSuperLattice, _p_InterferenceFunction2DSuperLatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunction3DLattice, _p_InterferenceFunction3DLatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunctionFinite2DLattice, _p_InterferenceFunctionFinite2DLatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunctionFinite3DLattice, _p_InterferenceFunctionFinite3DLatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_BasicLattice, _p_BasicLatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_SquareLattice, _p_SquareLatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_HexagonalLattice, _p_HexagonalLatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_Lattice, _p_LatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution1DTriangle, _p_FTDistribution1DTriangleTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDecayFunction1DTriangle, _p_FTDecayFunction1DTriangleTo_p_IParameterized, 0, 0},  {&_swigt__p_RotationEuler, _p_RotationEulerTo_p_IParameterized, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_IParameterized[] = {  {&_swigt__p_FormFactorBox, _p_FormFactorBoxTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorSphereGaussianRadius, _p_FormFactorSphereGaussianRadiusTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorSphereLogNormalRadius, _p_FormFactorSphereLogNormalRadiusTo_p_IParameterized, 0, 0},  {&_swigt__p_MultiLayer, _p_MultiLayerTo_p_IParameterized, 0, 0},  {&_swigt__p_ParameterDistribution, _p_ParameterDistributionTo_p_IParameterized, 0, 0},  {&_swigt__p_ParticleDistribution, _p_ParticleDistributionTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDecayFunction1DGauss, _p_FTDecayFunction1DGaussTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution1DGauss, _p_FTDistribution1DGaussTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunctionNone, _p_InterferenceFunctionNoneTo_p_IParameterized, 0, 0},  {&_swigt__p_ParticleLayout, _p_ParticleLayoutTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorHemiEllipsoid, _p_FormFactorHemiEllipsoidTo_p_IParameterized, 0, 0},  {&_swigt__p_INode, _p_INodeTo_p_IParameterized, 0, 0},  {&_swigt__p_LorentzFisherPeakShape, _p_LorentzFisherPeakShapeTo_p_IParameterized, 0, 0},  {&_swigt__p_MisesFisherGaussPeakShape, _p_MisesFisherGaussPeakShapeTo_p_IParameterized, 0, 0},  {&_swigt__p_MisesGaussPeakShape, _p_MisesGaussPeakShapeTo_p_IParameterized, 0, 0},  {&_swigt__p_GaussFisherPeakShape, _p_GaussFisherPeakShapeTo_p_IParameterized, 0, 0},  {&_swigt__p_IsotropicLorentzPeakShape, _p_IsotropicLorentzPeakShapeTo_p_IParameterized, 0, 0},  {&_swigt__p_IsotropicGaussPeakShape, _p_IsotropicGaussPeakShapeTo_p_IParameterized, 0, 0},  {&_swigt__p_IPeakShape, _p_IPeakShapeTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorPrism3, _p_FormFactorPrism3To_p_IParameterized, 0, 0},  {&_swigt__p_IFormFactorPolyhedron, _p_IFormFactorPolyhedronTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorCuboctahedron, _p_FormFactorCuboctahedronTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorDodecahedron, _p_FormFactorDodecahedronTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorIcosahedron, _p_FormFactorIcosahedronTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorTetrahedron, _p_FormFactorTetrahedronTo_p_IParameterized, 0, 0},  {&_swigt__p_IFormFactorPrism, _p_IFormFactorPrismTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorPrism6, _p_FormFactorPrism6To_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution2DCone, _p_FTDistribution2DConeTo_p_IParameterized, 0, 0},  {&_swigt__p_ParticleCoreShell, _p_ParticleCoreShellTo_p_IParameterized, 0, 0},  {&_swigt__p_IProfileRectangularRipple, _p_IProfileRectangularRippleTo_p_IParameterized, 0, 0},  {&_swigt__p_ISawtoothRipple, _p_ISawtoothRippleTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorTruncatedSphere, _p_FormFactorTruncatedSphereTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorFullSphere, _p_FormFactorFullSphereTo_p_IParameterized, 0, 0},  {&_swigt__p_IFormFactor, _p_IFormFactorTo_p_IParameterized, 0, 0},  {&_swigt__p_ISample, _p_ISampleTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorLongBoxGauss, _p_FormFactorLongBoxGaussTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunctionHardDisk, _p_InterferenceFunctionHardDiskTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution2DGate, _p_FTDistribution2DGateTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDecayFunction1DVoigt, _p_FTDecayFunction1DVoigtTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution1DVoigt, _p_FTDistribution1DVoigtTo_p_IParameterized, 0, 0},  {&_swigt__p_IRotation, _p_IRotationTo_p_IParameterized, 0, 0},  {&_swigt__p_IdentityRotation, _p_IdentityRotationTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorTruncatedSpheroid, _p_FormFactorTruncatedSpheroidTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorFullSpheroid, _p_FormFactorFullSpheroidTo_p_IParameterized, 0, 0},  {&_swigt__p_RotationX, _p_RotationXTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorCantellatedCube, _p_FormFactorCantellatedCubeTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorTruncatedCube, _p_FormFactorTruncatedCubeTo_p_IParameterized, 0, 0},  {&_swigt__p_RotationY, _p_RotationYTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDecayFunction2DGauss, _p_FTDecayFunction2DGaussTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution2DGauss, _p_FTDistribution2DGaussTo_p_IParameterized, 0, 0},  {&_swigt__p_RotationZ, _p_RotationZTo_p_IParameterized, 0, 0},  {&_swigt__p_IFormFactorBorn, _p_IFormFactorBornTo_p_IParameterized, 0, 0},  {&_swigt__p_ISampleBuilder, _p_ISampleBuilderTo_p_IParameterized, 0, 0},  {&_swigt__p_Particle, _p_ParticleTo_p_IParameterized, 0, 0},  {&_swigt__p_IParticle, _p_IParticleTo_p_IParameterized, 0, 0},  {&_swigt__p_IAbstractParticle, _p_IAbstractParticleTo_p_IParameterized, 0, 0},  {&_swigt__p_Lattice2D, _p_Lattice2DTo_p_IParameterized, 0, 0},  {&_swigt__p_IFTDistribution1D, _p_IFTDistribution1DTo_p_IParameterized, 0, 0},  {&_swigt__p_IFTDecayFunction1D, _p_IFTDecayFunction1DTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorCosineRippleBox, _p_FormFactorCosineRippleBoxTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleBox, _p_FormFactorSawtoothRippleBoxTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorCone, _p_FormFactorConeTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunctionTwin, _p_InterferenceFunctionTwinTo_p_IParameterized, 0, 0},  {&_swigt__p_Layer, _p_LayerTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorAnisoPyramid, _p_FormFactorAnisoPyramidTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorPyramid, _p_FormFactorPyramidTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorEllipsoidalCylinder, _p_FormFactorEllipsoidalCylinderTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorCylinder, _p_FormFactorCylinderTo_p_IParameterized, 0, 0},  {&_swigt__p_ParticleComposition, _p_ParticleCompositionTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution1DCosine, _p_FTDistribution1DCosineTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution1DGate, _p_FTDistribution1DGateTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorCosineRippleGauss, _p_FormFactorCosineRippleGaussTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleGauss, _p_FormFactorSawtoothRippleGaussTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDecayFunction2DVoigt, _p_FTDecayFunction2DVoigtTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution2DVoigt, _p_FTDistribution2DVoigtTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution1DCauchy, _p_FTDistribution1DCauchyTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDecayFunction1DCauchy, _p_FTDecayFunction1DCauchyTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution2DCauchy, _p_FTDistribution2DCauchyTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDecayFunction2DCauchy, _p_FTDecayFunction2DCauchyTo_p_IParameterized, 0, 0},  {&_swigt__p_IInterferenceFunction, _p_IInterferenceFunctionTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorCone6, _p_FormFactorCone6To_p_IParameterized, 0, 0},  {&_swigt__p_IFormFactorDecorator, _p_IFormFactorDecoratorTo_p_IParameterized, 0, 0},  {&_swigt__p_IParameterized, 0, 0, 0},  {&_swigt__p_FormFactorDot, _p_FormFactorDotTo_p_IParameterized, 0, 0},  {&_swigt__p_LayerRoughness, _p_LayerRoughnessTo_p_IParameterized, 0, 0},  {&_swigt__p_MesoCrystal, _p_MesoCrystalTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorCrystal, _p_FormFactorCrystalTo_p_IParameterized, 0, 0},  {&_swigt__p_ICosineRipple, _p_ICosineRippleTo_p_IParameterized, 0, 0},  {&_swigt__p_IProfileRipple, _p_IProfileRippleTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunction2DParaCrystal, _p_InterferenceFunction2DParaCrystalTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunctionRadialParaCrystal, _p_InterferenceFunctionRadialParaCrystalTo_p_IParameterized, 0, 0},  {&_swigt__p_Crystal, _p_CrystalTo_p_IParameterized, 0, 0},  {&_swigt__p_Lattice3D, _p_Lattice3DTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorHollowSphere, _p_FormFactorHollowSphereTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorGaussSphere, _p_FormFactorGaussSphereTo_p_IParameterized, 0, 0},  {&_swigt__p_IFTDistribution2D, _p_IFTDistribution2DTo_p_IParameterized, 0, 0},  {&_swigt__p_IFTDecayFunction2D, _p_IFTDecayFunction2DTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorWeighted, _p_FormFactorWeightedTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorLongBoxLorentz, _p_FormFactorLongBoxLorentzTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorCosineRippleLorentz, _p_FormFactorCosineRippleLorentzTo_p_IParameterized, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleLorentz, _p_FormFactorSawtoothRippleLorentzTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunction2DLattice, _p_InterferenceFunction2DLatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunction1DLattice, _p_InterferenceFunction1DLatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunction2DSuperLattice, _p_InterferenceFunction2DSuperLatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunction3DLattice, _p_InterferenceFunction3DLatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunctionFinite2DLattice, _p_InterferenceFunctionFinite2DLatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_InterferenceFunctionFinite3DLattice, _p_InterferenceFunctionFinite3DLatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_BasicLattice, _p_BasicLatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_SquareLattice, _p_SquareLatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_HexagonalLattice, _p_HexagonalLatticeTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDistribution1DTriangle, _p_FTDistribution1DTriangleTo_p_IParameterized, 0, 0},  {&_swigt__p_FTDecayFunction1DTriangle, _p_FTDecayFunction1DTriangleTo_p_IParameterized, 0, 0},  {&_swigt__p_RotationEuler, _p_RotationEulerTo_p_IParameterized, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_IParticle[] = {  {&_swigt__p_ParticleComposition, _p_ParticleCompositionTo_p_IParticle, 0, 0},  {&_swigt__p_MesoCrystal, _p_MesoCrystalTo_p_IParticle, 0, 0},  {&_swigt__p_IParticle, 0, 0, 0},  {&_swigt__p_Particle, _p_ParticleTo_p_IParticle, 0, 0},  {&_swigt__p_ParticleCoreShell, _p_ParticleCoreShellTo_p_IParticle, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_IPeakShape[] = {  {&_swigt__p_IPeakShape, 0, 0, 0},  {&_swigt__p_IsotropicGaussPeakShape, _p_IsotropicGaussPeakShapeTo_p_IPeakShape, 0, 0},  {&_swigt__p_IsotropicLorentzPeakShape, _p_IsotropicLorentzPeakShapeTo_p_IPeakShape, 0, 0},  {&_swigt__p_GaussFisherPeakShape, _p_GaussFisherPeakShapeTo_p_IPeakShape, 0, 0},  {&_swigt__p_LorentzFisherPeakShape, _p_LorentzFisherPeakShapeTo_p_IPeakShape, 0, 0},  {&_swigt__p_MisesFisherGaussPeakShape, _p_MisesFisherGaussPeakShapeTo_p_IPeakShape, 0, 0},  {&_swigt__p_MisesGaussPeakShape, _p_MisesGaussPeakShapeTo_p_IPeakShape, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_IProfileRectangularRipple[] = {  {&_swigt__p_IProfileRectangularRipple, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_IProfileRipple[] = {  {&_swigt__p_FormFactorCosineRippleLorentz, _p_FormFactorCosineRippleLorentzTo_p_IProfileRipple, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleLorentz, _p_FormFactorSawtoothRippleLorentzTo_p_IProfileRipple, 0, 0},  {&_swigt__p_IProfileRectangularRipple, _p_IProfileRectangularRippleTo_p_IProfileRipple, 0, 0},  {&_swigt__p_ISawtoothRipple, _p_ISawtoothRippleTo_p_IProfileRipple, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleBox, _p_FormFactorSawtoothRippleBoxTo_p_IProfileRipple, 0, 0},  {&_swigt__p_FormFactorCosineRippleBox, _p_FormFactorCosineRippleBoxTo_p_IProfileRipple, 0, 0},  {&_swigt__p_IProfileRipple, 0, 0, 0},  {&_swigt__p_ICosineRipple, _p_ICosineRippleTo_p_IProfileRipple, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleGauss, _p_FormFactorSawtoothRippleGaussTo_p_IProfileRipple, 0, 0},  {&_swigt__p_FormFactorCosineRippleGauss, _p_FormFactorCosineRippleGaussTo_p_IProfileRipple, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_IRotation[] = {  {&_swigt__p_RotationY, _p_RotationYTo_p_IRotation, 0, 0},  {&_swigt__p_RotationEuler, _p_RotationEulerTo_p_IRotation, 0, 0},  {&_swigt__p_RotationZ, _p_RotationZTo_p_IRotation, 0, 0},  {&_swigt__p_IRotation, 0, 0, 0},  {&_swigt__p_IdentityRotation, _p_IdentityRotationTo_p_IRotation, 0, 0},  {&_swigt__p_RotationX, _p_RotationXTo_p_IRotation, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_ISample[] = {  {&_swigt__p_FormFactorBox, _p_FormFactorBoxTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorSphereGaussianRadius, _p_FormFactorSphereGaussianRadiusTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorSphereLogNormalRadius, _p_FormFactorSphereLogNormalRadiusTo_p_ISample, 0, 0},  {&_swigt__p_MultiLayer, _p_MultiLayerTo_p_ISample, 0, 0},  {&_swigt__p_ParticleDistribution, _p_ParticleDistributionTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunctionNone, _p_InterferenceFunctionNoneTo_p_ISample, 0, 0},  {&_swigt__p_ParticleLayout, _p_ParticleLayoutTo_p_ISample, 0, 0},  {&_swigt__p_ILayout, _p_ILayoutTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorHemiEllipsoid, _p_FormFactorHemiEllipsoidTo_p_ISample, 0, 0},  {&_swigt__p_IPeakShape, _p_IPeakShapeTo_p_ISample, 0, 0},  {&_swigt__p_IsotropicGaussPeakShape, _p_IsotropicGaussPeakShapeTo_p_ISample, 0, 0},  {&_swigt__p_IsotropicLorentzPeakShape, _p_IsotropicLorentzPeakShapeTo_p_ISample, 0, 0},  {&_swigt__p_GaussFisherPeakShape, _p_GaussFisherPeakShapeTo_p_ISample, 0, 0},  {&_swigt__p_LorentzFisherPeakShape, _p_LorentzFisherPeakShapeTo_p_ISample, 0, 0},  {&_swigt__p_MisesFisherGaussPeakShape, _p_MisesFisherGaussPeakShapeTo_p_ISample, 0, 0},  {&_swigt__p_MisesGaussPeakShape, _p_MisesGaussPeakShapeTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorPrism3, _p_FormFactorPrism3To_p_ISample, 0, 0},  {&_swigt__p_FormFactorTetrahedron, _p_FormFactorTetrahedronTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorIcosahedron, _p_FormFactorIcosahedronTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorDodecahedron, _p_FormFactorDodecahedronTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorCuboctahedron, _p_FormFactorCuboctahedronTo_p_ISample, 0, 0},  {&_swigt__p_IFormFactorPolyhedron, _p_IFormFactorPolyhedronTo_p_ISample, 0, 0},  {&_swigt__p_IFormFactorPrism, _p_IFormFactorPrismTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorPrism6, _p_FormFactorPrism6To_p_ISample, 0, 0},  {&_swigt__p_ParticleCoreShell, _p_ParticleCoreShellTo_p_ISample, 0, 0},  {&_swigt__p_IProfileRectangularRipple, _p_IProfileRectangularRippleTo_p_ISample, 0, 0},  {&_swigt__p_ISawtoothRipple, _p_ISawtoothRippleTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorFullSphere, _p_FormFactorFullSphereTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorTruncatedSphere, _p_FormFactorTruncatedSphereTo_p_ISample, 0, 0},  {&_swigt__p_IFormFactor, _p_IFormFactorTo_p_ISample, 0, 0},  {&_swigt__p_ISample, 0, 0, 0},  {&_swigt__p_FormFactorLongBoxGauss, _p_FormFactorLongBoxGaussTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunctionHardDisk, _p_InterferenceFunctionHardDiskTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorTruncatedSpheroid, _p_FormFactorTruncatedSpheroidTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorFullSpheroid, _p_FormFactorFullSpheroidTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorCantellatedCube, _p_FormFactorCantellatedCubeTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorTruncatedCube, _p_FormFactorTruncatedCubeTo_p_ISample, 0, 0},  {&_swigt__p_IFormFactorBorn, _p_IFormFactorBornTo_p_ISample, 0, 0},  {&_swigt__p_IClusteredParticles, _p_IClusteredParticlesTo_p_ISample, 0, 0},  {&_swigt__p_Particle, _p_ParticleTo_p_ISample, 0, 0},  {&_swigt__p_IParticle, _p_IParticleTo_p_ISample, 0, 0},  {&_swigt__p_IAbstractParticle, _p_IAbstractParticleTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorCosineRippleBox, _p_FormFactorCosineRippleBoxTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleBox, _p_FormFactorSawtoothRippleBoxTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorCone, _p_FormFactorConeTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunctionTwin, _p_InterferenceFunctionTwinTo_p_ISample, 0, 0},  {&_swigt__p_Layer, _p_LayerTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorAnisoPyramid, _p_FormFactorAnisoPyramidTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorPyramid, _p_FormFactorPyramidTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorEllipsoidalCylinder, _p_FormFactorEllipsoidalCylinderTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorCylinder, _p_FormFactorCylinderTo_p_ISample, 0, 0},  {&_swigt__p_ParticleComposition, _p_ParticleCompositionTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorCosineRippleGauss, _p_FormFactorCosineRippleGaussTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleGauss, _p_FormFactorSawtoothRippleGaussTo_p_ISample, 0, 0},  {&_swigt__p_IInterferenceFunction, _p_IInterferenceFunctionTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorCone6, _p_FormFactorCone6To_p_ISample, 0, 0},  {&_swigt__p_IFormFactorDecorator, _p_IFormFactorDecoratorTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorDot, _p_FormFactorDotTo_p_ISample, 0, 0},  {&_swigt__p_LayerRoughness, _p_LayerRoughnessTo_p_ISample, 0, 0},  {&_swigt__p_MesoCrystal, _p_MesoCrystalTo_p_ISample, 0, 0},  {&_swigt__p_Crystal, _p_CrystalTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorCrystal, _p_FormFactorCrystalTo_p_ISample, 0, 0},  {&_swigt__p_ICosineRipple, _p_ICosineRippleTo_p_ISample, 0, 0},  {&_swigt__p_IProfileRipple, _p_IProfileRippleTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunction2DParaCrystal, _p_InterferenceFunction2DParaCrystalTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunctionRadialParaCrystal, _p_InterferenceFunctionRadialParaCrystalTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorHollowSphere, _p_FormFactorHollowSphereTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorGaussSphere, _p_FormFactorGaussSphereTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorWeighted, _p_FormFactorWeightedTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorLongBoxLorentz, _p_FormFactorLongBoxLorentzTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorCosineRippleLorentz, _p_FormFactorCosineRippleLorentzTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleLorentz, _p_FormFactorSawtoothRippleLorentzTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunctionFinite2DLattice, _p_InterferenceFunctionFinite2DLatticeTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunction3DLattice, _p_InterferenceFunction3DLatticeTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunction2DSuperLattice, _p_InterferenceFunction2DSuperLatticeTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunction2DLattice, _p_InterferenceFunction2DLatticeTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunction1DLattice, _p_InterferenceFunction1DLatticeTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunctionFinite3DLattice, _p_InterferenceFunctionFinite3DLatticeTo_p_ISample, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_ISample[] = {  {&_swigt__p_FormFactorBox, _p_FormFactorBoxTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorSphereGaussianRadius, _p_FormFactorSphereGaussianRadiusTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorSphereLogNormalRadius, _p_FormFactorSphereLogNormalRadiusTo_p_ISample, 0, 0},  {&_swigt__p_MultiLayer, _p_MultiLayerTo_p_ISample, 0, 0},  {&_swigt__p_ParticleDistribution, _p_ParticleDistributionTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunctionNone, _p_InterferenceFunctionNoneTo_p_ISample, 0, 0},  {&_swigt__p_ParticleLayout, _p_ParticleLayoutTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorHemiEllipsoid, _p_FormFactorHemiEllipsoidTo_p_ISample, 0, 0},  {&_swigt__p_IPeakShape, _p_IPeakShapeTo_p_ISample, 0, 0},  {&_swigt__p_IsotropicGaussPeakShape, _p_IsotropicGaussPeakShapeTo_p_ISample, 0, 0},  {&_swigt__p_IsotropicLorentzPeakShape, _p_IsotropicLorentzPeakShapeTo_p_ISample, 0, 0},  {&_swigt__p_GaussFisherPeakShape, _p_GaussFisherPeakShapeTo_p_ISample, 0, 0},  {&_swigt__p_LorentzFisherPeakShape, _p_LorentzFisherPeakShapeTo_p_ISample, 0, 0},  {&_swigt__p_MisesFisherGaussPeakShape, _p_MisesFisherGaussPeakShapeTo_p_ISample, 0, 0},  {&_swigt__p_MisesGaussPeakShape, _p_MisesGaussPeakShapeTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorPrism3, _p_FormFactorPrism3To_p_ISample, 0, 0},  {&_swigt__p_FormFactorTetrahedron, _p_FormFactorTetrahedronTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorIcosahedron, _p_FormFactorIcosahedronTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorDodecahedron, _p_FormFactorDodecahedronTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorCuboctahedron, _p_FormFactorCuboctahedronTo_p_ISample, 0, 0},  {&_swigt__p_IFormFactorPolyhedron, _p_IFormFactorPolyhedronTo_p_ISample, 0, 0},  {&_swigt__p_IFormFactorPrism, _p_IFormFactorPrismTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorPrism6, _p_FormFactorPrism6To_p_ISample, 0, 0},  {&_swigt__p_ParticleCoreShell, _p_ParticleCoreShellTo_p_ISample, 0, 0},  {&_swigt__p_IProfileRectangularRipple, _p_IProfileRectangularRippleTo_p_ISample, 0, 0},  {&_swigt__p_ISawtoothRipple, _p_ISawtoothRippleTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorFullSphere, _p_FormFactorFullSphereTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorTruncatedSphere, _p_FormFactorTruncatedSphereTo_p_ISample, 0, 0},  {&_swigt__p_IFormFactor, _p_IFormFactorTo_p_ISample, 0, 0},  {&_swigt__p_ISample, 0, 0, 0},  {&_swigt__p_FormFactorLongBoxGauss, _p_FormFactorLongBoxGaussTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunctionHardDisk, _p_InterferenceFunctionHardDiskTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorTruncatedSpheroid, _p_FormFactorTruncatedSpheroidTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorFullSpheroid, _p_FormFactorFullSpheroidTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorCantellatedCube, _p_FormFactorCantellatedCubeTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorTruncatedCube, _p_FormFactorTruncatedCubeTo_p_ISample, 0, 0},  {&_swigt__p_IFormFactorBorn, _p_IFormFactorBornTo_p_ISample, 0, 0},  {&_swigt__p_Particle, _p_ParticleTo_p_ISample, 0, 0},  {&_swigt__p_IParticle, _p_IParticleTo_p_ISample, 0, 0},  {&_swigt__p_IAbstractParticle, _p_IAbstractParticleTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorCosineRippleBox, _p_FormFactorCosineRippleBoxTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleBox, _p_FormFactorSawtoothRippleBoxTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorCone, _p_FormFactorConeTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunctionTwin, _p_InterferenceFunctionTwinTo_p_ISample, 0, 0},  {&_swigt__p_Layer, _p_LayerTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorAnisoPyramid, _p_FormFactorAnisoPyramidTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorPyramid, _p_FormFactorPyramidTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorEllipsoidalCylinder, _p_FormFactorEllipsoidalCylinderTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorCylinder, _p_FormFactorCylinderTo_p_ISample, 0, 0},  {&_swigt__p_ParticleComposition, _p_ParticleCompositionTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorCosineRippleGauss, _p_FormFactorCosineRippleGaussTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleGauss, _p_FormFactorSawtoothRippleGaussTo_p_ISample, 0, 0},  {&_swigt__p_IInterferenceFunction, _p_IInterferenceFunctionTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorCone6, _p_FormFactorCone6To_p_ISample, 0, 0},  {&_swigt__p_IFormFactorDecorator, _p_IFormFactorDecoratorTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorDot, _p_FormFactorDotTo_p_ISample, 0, 0},  {&_swigt__p_LayerRoughness, _p_LayerRoughnessTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunctionRadialParaCrystal, _p_InterferenceFunctionRadialParaCrystalTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunction2DParaCrystal, _p_InterferenceFunction2DParaCrystalTo_p_ISample, 0, 0},  {&_swigt__p_MesoCrystal, _p_MesoCrystalTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorCrystal, _p_FormFactorCrystalTo_p_ISample, 0, 0},  {&_swigt__p_ICosineRipple, _p_ICosineRippleTo_p_ISample, 0, 0},  {&_swigt__p_IProfileRipple, _p_IProfileRippleTo_p_ISample, 0, 0},  {&_swigt__p_Crystal, _p_CrystalTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorHollowSphere, _p_FormFactorHollowSphereTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorGaussSphere, _p_FormFactorGaussSphereTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorWeighted, _p_FormFactorWeightedTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorLongBoxLorentz, _p_FormFactorLongBoxLorentzTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorCosineRippleLorentz, _p_FormFactorCosineRippleLorentzTo_p_ISample, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleLorentz, _p_FormFactorSawtoothRippleLorentzTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunctionFinite3DLattice, _p_InterferenceFunctionFinite3DLatticeTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunctionFinite2DLattice, _p_InterferenceFunctionFinite2DLatticeTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunction3DLattice, _p_InterferenceFunction3DLatticeTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunction2DSuperLattice, _p_InterferenceFunction2DSuperLatticeTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunction2DLattice, _p_InterferenceFunction2DLatticeTo_p_ISample, 0, 0},  {&_swigt__p_InterferenceFunction1DLattice, _p_InterferenceFunction1DLatticeTo_p_ISample, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_ISampleBuilder[] = {  {&_swigt__p_ISampleBuilder, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_ISawtoothRipple[] = {  {&_swigt__p_FormFactorSawtoothRippleLorentz, _p_FormFactorSawtoothRippleLorentzTo_p_ISawtoothRipple, 0, 0},  {&_swigt__p_ISawtoothRipple, 0, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleBox, _p_FormFactorSawtoothRippleBoxTo_p_ISawtoothRipple, 0, 0},  {&_swigt__p_FormFactorSawtoothRippleGauss, _p_FormFactorSawtoothRippleGaussTo_p_ISawtoothRipple, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_ISelectionRule[] = {  {&_swigt__p_ISelectionRule, 0, 0, 0},  {&_swigt__p_SimpleSelectionRule, _p_SimpleSelectionRuleTo_p_ISelectionRule, 0, 0},{0, 0, 0, 0}};
@@ -79572,17 +77981,15 @@ static swig_cast_info _swigc__p_InterferenceFunctionRadialParaCrystal[] = {  {&_
 static swig_cast_info _swigc__p_InterferenceFunctionTwin[] = {  {&_swigt__p_InterferenceFunctionTwin, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_IsotropicGaussPeakShape[] = {  {&_swigt__p_IsotropicGaussPeakShape, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_IsotropicLorentzPeakShape[] = {  {&_swigt__p_IsotropicLorentzPeakShape, 0, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_Lattice[] = {  {&_swigt__p_Lattice, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_Lattice2D[] = {  {&_swigt__p_Lattice2D, 0, 0, 0},  {&_swigt__p_BasicLattice, _p_BasicLatticeTo_p_Lattice2D, 0, 0},  {&_swigt__p_SquareLattice, _p_SquareLatticeTo_p_Lattice2D, 0, 0},  {&_swigt__p_HexagonalLattice, _p_HexagonalLatticeTo_p_Lattice2D, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_Lattice2D__ReciprocalBases[] = {  {&_swigt__p_Lattice2D__ReciprocalBases, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_Lattice3D[] = {  {&_swigt__p_Lattice3D, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_Layer[] = {  {&_swigt__p_Layer, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_LayerInterface[] = {  {&_swigt__p_LayerInterface, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_LayerRoughness[] = {  {&_swigt__p_LayerRoughness, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_LorentzFisherPeakShape[] = {  {&_swigt__p_LorentzFisherPeakShape, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_Material[] = {  {&_swigt__p_Material, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_MesoCrystal[] = {  {&_swigt__p_MesoCrystal, 0, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_MillerIndex[] = {  {&_swigt__p_MillerIndex, 0, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_MillerIndexOrientation[] = {  {&_swigt__p_MillerIndexOrientation, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_MisesFisherGaussPeakShape[] = {  {&_swigt__p_MisesFisherGaussPeakShape, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_MisesGaussPeakShape[] = {  {&_swigt__p_MisesGaussPeakShape, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_MultiLayer[] = {  {&_swigt__p_MultiLayer, 0, 0, 0},{0, 0, 0, 0}};
@@ -79651,10 +78058,10 @@ static swig_cast_info _swigc__p_std__vectorT_BasicVector3DT_double_t_std__alloca
 static swig_cast_info _swigc__p_std__vectorT_BasicVector3DT_std__complexT_double_t_t_std__allocatorT_BasicVector3DT_std__complexT_double_t_t_t_t[] = {  {&_swigt__p_std__vectorT_BasicVector3DT_std__complexT_double_t_t_std__allocatorT_BasicVector3DT_std__complexT_double_t_t_t_t, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_std__vectorT_HomogeneousRegion_std__allocatorT_HomogeneousRegion_t_t[] = {  {&_swigt__p_std__vectorT_HomogeneousRegion_std__allocatorT_HomogeneousRegion_t_t, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_std__vectorT_IFormFactor_p_std__allocatorT_IFormFactor_p_t_t[] = {  {&_swigt__p_std__vectorT_IFormFactor_p_std__allocatorT_IFormFactor_p_t_t, 0, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_std__vectorT_ILayout_const_p_std__allocatorT_ILayout_const_p_t_t[] = {  {&_swigt__p_std__vectorT_ILayout_const_p_std__allocatorT_ILayout_const_p_t_t, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_std__vectorT_INode_const_p_std__allocatorT_INode_const_p_t_t[] = {  {&_swigt__p_std__vectorT_INode_const_p_std__allocatorT_INode_const_p_t_t, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_std__vectorT_INode_p_std__allocatorT_INode_p_t_t[] = {  {&_swigt__p_std__vectorT_INode_p_std__allocatorT_INode_p_t_t, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_std__vectorT_Material_const_p_std__allocatorT_Material_const_p_t_t[] = {  {&_swigt__p_std__vectorT_Material_const_p_std__allocatorT_Material_const_p_t_t, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_std__vectorT_ParticleLayout_const_p_std__allocatorT_ParticleLayout_const_p_t_t[] = {  {&_swigt__p_std__vectorT_ParticleLayout_const_p_std__allocatorT_ParticleLayout_const_p_t_t, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_std__vectorT_double_std__allocatorT_double_t_t[] = {  {&_swigt__p_std__vectorT_double_std__allocatorT_double_t_t, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_std__vectorT_int_std__allocatorT_int_t_t[] = {  {&_swigt__p_std__vectorT_int_std__allocatorT_int_t_t, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_std__vectorT_std__complexT_double_t_std__allocatorT_std__complexT_double_t_t_t[] = {  {&_swigt__p_std__vectorT_std__complexT_double_t_std__allocatorT_std__complexT_double_t_t_t, 0, 0, 0},{0, 0, 0, 0}};
@@ -79735,7 +78142,6 @@ static swig_cast_info *swig_cast_initial[] = {
   _swigc__p_HexagonalLattice,
   _swigc__p_IAbstractParticle,
   _swigc__p_ICloneable,
-  _swigc__p_IClusteredParticles,
   _swigc__p_ICosineRipple,
   _swigc__p_IFTDecayFunction1D,
   _swigc__p_IFTDecayFunction2D,
@@ -79748,8 +78154,6 @@ static swig_cast_info *swig_cast_initial[] = {
   _swigc__p_IFormFactorPolyhedron,
   _swigc__p_IFormFactorPrism,
   _swigc__p_IInterferenceFunction,
-  _swigc__p_ILatticeOrientation,
-  _swigc__p_ILayout,
   _swigc__p_INode,
   _swigc__p_INodeVisitor,
   _swigc__p_IParameterized,
@@ -79776,17 +78180,15 @@ static swig_cast_info *swig_cast_initial[] = {
   _swigc__p_InterferenceFunctionTwin,
   _swigc__p_IsotropicGaussPeakShape,
   _swigc__p_IsotropicLorentzPeakShape,
-  _swigc__p_Lattice,
   _swigc__p_Lattice2D,
   _swigc__p_Lattice2D__ReciprocalBases,
+  _swigc__p_Lattice3D,
   _swigc__p_Layer,
   _swigc__p_LayerInterface,
   _swigc__p_LayerRoughness,
   _swigc__p_LorentzFisherPeakShape,
   _swigc__p_Material,
   _swigc__p_MesoCrystal,
-  _swigc__p_MillerIndex,
-  _swigc__p_MillerIndexOrientation,
   _swigc__p_MisesFisherGaussPeakShape,
   _swigc__p_MisesGaussPeakShape,
   _swigc__p_MultiLayer,
@@ -79855,10 +78257,10 @@ static swig_cast_info *swig_cast_initial[] = {
   _swigc__p_std__vectorT_BasicVector3DT_std__complexT_double_t_t_std__allocatorT_BasicVector3DT_std__complexT_double_t_t_t_t,
   _swigc__p_std__vectorT_HomogeneousRegion_std__allocatorT_HomogeneousRegion_t_t,
   _swigc__p_std__vectorT_IFormFactor_p_std__allocatorT_IFormFactor_p_t_t,
-  _swigc__p_std__vectorT_ILayout_const_p_std__allocatorT_ILayout_const_p_t_t,
   _swigc__p_std__vectorT_INode_const_p_std__allocatorT_INode_const_p_t_t,
   _swigc__p_std__vectorT_INode_p_std__allocatorT_INode_p_t_t,
   _swigc__p_std__vectorT_Material_const_p_std__allocatorT_Material_const_p_t_t,
+  _swigc__p_std__vectorT_ParticleLayout_const_p_std__allocatorT_ParticleLayout_const_p_t_t,
   _swigc__p_std__vectorT_double_std__allocatorT_double_t_t,
   _swigc__p_std__vectorT_int_std__allocatorT_int_t_t,
   _swigc__p_std__vectorT_std__complexT_double_t_std__allocatorT_std__complexT_double_t_t_t,
@@ -80619,9 +79021,6 @@ SWIG_init(void) {
   SWIG_Python_SetConstant(d, "RoughnessModel_DEFAULT",SWIG_From_int(static_cast< int >(RoughnessModelWrap::DEFAULT)));
   SWIG_Python_SetConstant(d, "RoughnessModel_TANH",SWIG_From_int(static_cast< int >(RoughnessModelWrap::TANH)));
   SWIG_Python_SetConstant(d, "RoughnessModel_NEVOT_CROCE",SWIG_From_int(static_cast< int >(RoughnessModelWrap::NEVOT_CROCE)));
-  SWIG_Python_SetConstant(d, "MillerIndexOrientation_QX",SWIG_From_int(static_cast< int >(MillerIndexOrientation::QX)));
-  SWIG_Python_SetConstant(d, "MillerIndexOrientation_QY",SWIG_From_int(static_cast< int >(MillerIndexOrientation::QY)));
-  SWIG_Python_SetConstant(d, "MillerIndexOrientation_QZ",SWIG_From_int(static_cast< int >(MillerIndexOrientation::QZ)));
 #if PY_VERSION_HEX >= 0x03000000
   return m;
 #else