diff --git a/GUI/Model/Sample/FTDecayFunctionItems.cpp b/GUI/Model/Sample/FTDecayFunctionItems.cpp
index fcf4001067f498ad7dfb2b4a8bc5ddea408b36cb..740aea9b4dc9bf81a82d327b47cccba8d7dca98a 100644
--- a/GUI/Model/Sample/FTDecayFunctionItems.cpp
+++ b/GUI/Model/Sample/FTDecayFunctionItems.cpp
@@ -14,6 +14,7 @@
 
 #include "GUI/Model/Sample/FTDecayFunctionItems.h"
 #include "Base/Const/Units.h"
+#include "GUI/Model/Session/Serializer.h"
 #include <QList>
 
 // --------------------------------------------------------------------------------------------- //
@@ -24,6 +25,12 @@ FTDecayFunction1DItem::FTDecayFunction1DItem()
                        Unit::nanometer, "decay");
 }
 
+void FTDecayFunction1DItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_decayLength);
+}
+
 DoubleDescriptor FTDecayFunction1DItem::decayLength() const
 {
     return m_decayLength;
@@ -68,6 +75,13 @@ std::unique_ptr<IFTDecayFunction1D> FTDecayFunction1DVoigtItem::createFTDecayFun
     return std::make_unique<FTDecayFunction1DVoigt>(decayLength(), m_eta);
 }
 
+void FTDecayFunction1DVoigtItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_decayLength);
+    s.rw(m_eta);
+}
+
 DoubleDescriptor FTDecayFunction1DVoigtItem::eta() const
 {
     return m_eta;
@@ -94,6 +108,14 @@ FTDecayFunction2DItem::FTDecayFunction2DItem()
                  Unit::degree, "gamma");
 }
 
+void FTDecayFunction2DItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_decayLengthX);
+    s.rw(m_decayLengthY);
+    s.rw(m_gamma);
+}
+
 DoubleDescriptor FTDecayFunction2DItem::decayLengthX() const
 {
     return m_decayLengthX;
@@ -159,6 +181,15 @@ std::unique_ptr<IFTDecayFunction2D> FTDecayFunction2DVoigtItem::createFTDecayFun
                                                     Units::deg2rad(gamma()));
 }
 
+void FTDecayFunction2DVoigtItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_decayLengthX);
+    s.rw(m_decayLengthY);
+    s.rw(m_gamma);
+    s.rw(m_eta);
+}
+
 void FTDecayFunction2DVoigtItem::setEta(const double eta)
 {
     m_eta.set(eta);
diff --git a/GUI/Model/Sample/FTDecayFunctionItems.h b/GUI/Model/Sample/FTDecayFunctionItems.h
index c7525cfec608e115fde6f516550a453a8385f0de..ab79420c147b87d08de9187ad39995b9b554e587 100644
--- a/GUI/Model/Sample/FTDecayFunctionItems.h
+++ b/GUI/Model/Sample/FTDecayFunctionItems.h
@@ -21,10 +21,13 @@
 #include "Sample/Correlations/FTDecay2D.h"
 #include <memory>
 
+class Serializer;
+
 class FTDecayFunction1DItem {
 public:
     virtual ~FTDecayFunction1DItem() = default;
     virtual std::unique_ptr<IFTDecayFunction1D> createFTDecayFunction() const = 0;
+    virtual void serialize(Serializer& s);
 
     DoubleDescriptor decayLength() const;
     virtual DoubleDescriptors valueDescriptors() const;
@@ -53,6 +56,7 @@ class FTDecayFunction1DVoigtItem : public FTDecayFunction1DItem {
 public:
     FTDecayFunction1DVoigtItem();
     std::unique_ptr<IFTDecayFunction1D> createFTDecayFunction() const override;
+    void serialize(Serializer& s) override;
 
     DoubleDescriptor eta() const;
     DoubleDescriptors valueDescriptors() const override;
@@ -67,6 +71,7 @@ class FTDecayFunction2DItem {
 public:
     virtual ~FTDecayFunction2DItem() = default;
     virtual std::unique_ptr<IFTDecayFunction2D> createFTDecayFunction() const = 0;
+    virtual void serialize(Serializer& s);
 
     DoubleDescriptor decayLengthX() const;
     void setDecayLengthX(double decay_length_x);
@@ -101,6 +106,7 @@ class FTDecayFunction2DVoigtItem : public FTDecayFunction2DItem {
 public:
     FTDecayFunction2DVoigtItem();
     std::unique_ptr<IFTDecayFunction2D> createFTDecayFunction() const override;
+    void serialize(Serializer& s) override;
 
     void setEta(double eta);
     DoubleDescriptor eta() const;
diff --git a/GUI/Model/Sample/FTDistributionItems.cpp b/GUI/Model/Sample/FTDistributionItems.cpp
index d92a9850e3ac5d9b4ee6d658602021aa82a031f2..6c3af282f83499e10d2cb67372dd349048e62905 100644
--- a/GUI/Model/Sample/FTDistributionItems.cpp
+++ b/GUI/Model/Sample/FTDistributionItems.cpp
@@ -14,12 +14,19 @@
 
 #include "GUI/Model/Sample/FTDistributionItems.h"
 #include "Base/Const/Units.h"
+#include "GUI/Model/Session/Serializer.h"
 
 FTDistribution1DItem::FTDistribution1DItem()
 {
     m_omega.init("Omega", "Half-width of the distribution", 1.0, Unit::nanometer, "omega");
 }
 
+void FTDistribution1DItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_omega);
+}
+
 DoubleDescriptor FTDistribution1DItem::omega() const
 {
     return m_omega;
@@ -78,6 +85,13 @@ std::unique_ptr<IFTDistribution1D> FTDistribution1DVoigtItem::createFTDistributi
     return std::make_unique<FTDistribution1DVoigt>(omega(), m_eta);
 }
 
+void FTDistribution1DVoigtItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_omega);
+    s.rw(m_eta);
+}
+
 DoubleDescriptor FTDistribution1DVoigtItem::eta() const
 {
     return m_eta;
@@ -102,6 +116,14 @@ FTDistribution2DItem::FTDistribution2DItem()
         Unit::degree, "gamma");
 }
 
+void FTDistribution2DItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_omegaX);
+    s.rw(m_omegaY);
+    s.rw(m_gamma);
+}
+
 DoubleDescriptor FTDistribution2DItem::omegaX() const
 {
     return m_omegaX;
@@ -179,6 +201,15 @@ std::unique_ptr<IFTDistribution2D> FTDistribution2DVoigtItem::createFTDistributi
                                                    m_eta);
 }
 
+void FTDistribution2DVoigtItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_omegaX);
+    s.rw(m_omegaY);
+    s.rw(m_gamma);
+    s.rw(m_eta);
+}
+
 DoubleDescriptor FTDistribution2DVoigtItem::eta() const
 {
     return m_eta;
diff --git a/GUI/Model/Sample/FTDistributionItems.h b/GUI/Model/Sample/FTDistributionItems.h
index 3c0ddbc6f359d02c6d7cfac44b5d2ea1da5b1603..2474757296862817cad643eb4c222881dd5a5464 100644
--- a/GUI/Model/Sample/FTDistributionItems.h
+++ b/GUI/Model/Sample/FTDistributionItems.h
@@ -21,6 +21,8 @@
 #include "Sample/Correlations/FTDistributions2D.h"
 #include <memory>
 
+class Serializer;
+
 class FTDistribution1DItem {
 private:
     static constexpr auto P_OMEGA{"Omega"};
@@ -28,6 +30,7 @@ private:
 public:
     virtual std::unique_ptr<IFTDistribution1D> createFTDistribution() const = 0;
     virtual ~FTDistribution1DItem() = default;
+    virtual void serialize(Serializer& s);
 
     DoubleDescriptor omega() const;
 
@@ -68,6 +71,7 @@ class FTDistribution1DVoigtItem : public FTDistribution1DItem {
 public:
     FTDistribution1DVoigtItem();
     std::unique_ptr<IFTDistribution1D> createFTDistribution() const override;
+    void serialize(Serializer& s) override;
 
     DoubleDescriptor eta() const;
     DoubleDescriptors valueDescriptors() const override;
@@ -82,6 +86,7 @@ class FTDistribution2DItem {
 public:
     virtual ~FTDistribution2DItem() = default;
     virtual std::unique_ptr<IFTDistribution2D> createFTDistribution() const = 0;
+    virtual void serialize(Serializer& s);
 
     DoubleDescriptor omegaX() const;
     void setOmegaX(double omega_x);
@@ -125,6 +130,7 @@ class FTDistribution2DVoigtItem : public FTDistribution2DItem {
 public:
     FTDistribution2DVoigtItem();
     std::unique_ptr<IFTDistribution2D> createFTDistribution() const override;
+    void serialize(Serializer& s) override;
 
     DoubleDescriptor eta() const;
     void setEta(double eta);
diff --git a/GUI/Model/Sample/FormFactorItems.cpp b/GUI/Model/Sample/FormFactorItems.cpp
index 86a6a96bd0b2c178df2b9d439ea3daefc895e8cb..ed7f8ef94eee2600c500f376f51a6d95e08b7d9b 100644
--- a/GUI/Model/Sample/FormFactorItems.cpp
+++ b/GUI/Model/Sample/FormFactorItems.cpp
@@ -417,3 +417,10 @@ std::unique_ptr<IBornFF> TruncatedSpheroidItem::createFormFactor() const
     return std::make_unique<FormFactorTruncatedSpheroid>(radius(), height(), heightFlattening(),
                                                          removedTop());
 }
+
+void FormFactorItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    for (auto* p : serializationProperties())
+        s.rw(*p);
+}
diff --git a/GUI/Model/Sample/FormFactorItems.h b/GUI/Model/Sample/FormFactorItems.h
index 613ab0fb6b75f47fbdb3773cc4e24d5540cf4580..9aeb84e7e0ede36627348610dd35e749ec6567a0 100644
--- a/GUI/Model/Sample/FormFactorItems.h
+++ b/GUI/Model/Sample/FormFactorItems.h
@@ -15,7 +15,9 @@
 #ifndef BORNAGAIN_GUI_MODEL_SAMPLE_FORMFACTORITEMS_H
 #define BORNAGAIN_GUI_MODEL_SAMPLE_FORMFACTORITEMS_H
 
+#include "GUI/Model/Session/Serializer.h"
 #include "GUI/Model/Types/DoubleProperty.h"
+#include <QVector>
 #include <memory>
 
 class IBornFF;
@@ -36,6 +38,8 @@ public:
 public:
     virtual std::unique_ptr<IBornFF> createFormFactor() const = 0;
     virtual DoubleDescriptors geometryValues() const = 0;
+    virtual QVector<DoubleProperty*> serializationProperties() = 0;
+    virtual void serialize(Serializer& s);
 };
 
 class AnisoPyramidItem : public FormFactorItem {
@@ -52,6 +56,10 @@ public:
     {
         return {length(), width(), height(), alpha()};
     }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_length, &m_width, &m_height, &m_alpha};
+    }
 };
 
 class BarGaussItem : public FormFactorItem {
@@ -64,6 +72,10 @@ public:
     FF_PROPERTY(height, Height)
 
     DoubleDescriptors geometryValues() const override { return {length(), width(), height()}; }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_length, &m_width, &m_height};
+    }
 };
 
 class BarLorentzItem : public FormFactorItem {
@@ -76,6 +88,10 @@ public:
     FF_PROPERTY(height, Height)
 
     DoubleDescriptors geometryValues() const override { return {length(), width(), height()}; }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_length, &m_width, &m_height};
+    }
 };
 
 class BoxItem : public FormFactorItem {
@@ -88,6 +104,10 @@ public:
     FF_PROPERTY(height, Height)
 
     DoubleDescriptors geometryValues() const override { return {length(), width(), height()}; }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_length, &m_width, &m_height};
+    }
 };
 
 class ConeItem : public FormFactorItem {
@@ -100,6 +120,10 @@ public:
     FF_PROPERTY(alpha, Alpha)
 
     DoubleDescriptors geometryValues() const override { return {radius(), height(), alpha()}; }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_radius, &m_height, &m_alpha};
+    }
 };
 
 class Cone6Item : public FormFactorItem {
@@ -112,6 +136,10 @@ public:
     FF_PROPERTY(alpha, Alpha)
 
     DoubleDescriptors geometryValues() const override { return {baseEdge(), height(), alpha()}; }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_baseEdge, &m_height, &m_alpha};
+    }
 };
 
 class CuboctahedronItem : public FormFactorItem {
@@ -128,6 +156,10 @@ public:
     {
         return {length(), height(), heightRatio(), alpha()};
     }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_length, &m_height, &m_heightRatio, &m_alpha};
+    }
 };
 
 class CylinderItem : public FormFactorItem {
@@ -139,6 +171,7 @@ public:
     FF_PROPERTY(height, Height)
 
     DoubleDescriptors geometryValues() const override { return {radius(), height()}; }
+    QVector<DoubleProperty*> serializationProperties() override { return {&m_radius, &m_height}; }
 };
 
 class DodecahedronItem : public FormFactorItem {
@@ -149,6 +182,7 @@ public:
     FF_PROPERTY(edge, Edge)
 
     DoubleDescriptors geometryValues() const override { return {edge()}; }
+    QVector<DoubleProperty*> serializationProperties() override { return {&m_edge}; }
 };
 
 class EllipsoidalCylinderItem : public FormFactorItem {
@@ -161,6 +195,10 @@ public:
     FF_PROPERTY(height, Height)
 
     DoubleDescriptors geometryValues() const override { return {radiusX(), radiusY(), height()}; }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_radiusX, &m_radiusY, &m_height};
+    }
 };
 
 class FullSphereItem : public FormFactorItem {
@@ -171,6 +209,7 @@ public:
     FF_PROPERTY(radius, Radius)
 
     DoubleDescriptors geometryValues() const override { return {radius()}; }
+    QVector<DoubleProperty*> serializationProperties() override { return {&m_radius}; }
 };
 
 class FullSpheroidItem : public FormFactorItem {
@@ -182,6 +221,7 @@ public:
     FF_PROPERTY(height, Height)
 
     DoubleDescriptors geometryValues() const override { return {radius(), height()}; }
+    QVector<DoubleProperty*> serializationProperties() override { return {&m_radius, &m_height}; }
 };
 
 class HemiEllipsoidItem : public FormFactorItem {
@@ -194,6 +234,10 @@ public:
     FF_PROPERTY(height, Height)
 
     DoubleDescriptors geometryValues() const override { return {radiusX(), radiusY(), height()}; }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_radiusX, &m_radiusY, &m_height};
+    }
 };
 
 class IcosahedronItem : public FormFactorItem {
@@ -204,6 +248,7 @@ public:
     FF_PROPERTY(edge, Edge)
 
     DoubleDescriptors geometryValues() const override { return {edge()}; }
+    QVector<DoubleProperty*> serializationProperties() override { return {&m_edge}; }
 };
 
 class Prism3Item : public FormFactorItem {
@@ -215,6 +260,7 @@ public:
     FF_PROPERTY(height, Height)
 
     DoubleDescriptors geometryValues() const override { return {baseEdge(), height()}; }
+    QVector<DoubleProperty*> serializationProperties() override { return {&m_baseEdge, &m_height}; }
 };
 
 class Prism6Item : public FormFactorItem {
@@ -226,6 +272,7 @@ public:
     FF_PROPERTY(height, Height)
 
     DoubleDescriptors geometryValues() const override { return {baseEdge(), height()}; }
+    QVector<DoubleProperty*> serializationProperties() override { return {&m_baseEdge, &m_height}; }
 };
 
 class PyramidItem : public FormFactorItem {
@@ -238,6 +285,10 @@ public:
     FF_PROPERTY(alpha, Alpha)
 
     DoubleDescriptors geometryValues() const override { return {baseEdge(), height(), alpha()}; }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_baseEdge, &m_height, &m_alpha};
+    }
 };
 
 class CosineRippleBoxItem : public FormFactorItem {
@@ -250,6 +301,10 @@ public:
     FF_PROPERTY(height, Height)
 
     DoubleDescriptors geometryValues() const override { return {length(), width(), height()}; }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_length, &m_width, &m_height};
+    }
 };
 
 class CosineRippleGaussItem : public FormFactorItem {
@@ -262,6 +317,10 @@ public:
     FF_PROPERTY(height, Height)
 
     DoubleDescriptors geometryValues() const override { return {length(), width(), height()}; }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_length, &m_width, &m_height};
+    }
 };
 
 class CosineRippleLorentzItem : public FormFactorItem {
@@ -274,6 +333,10 @@ public:
     FF_PROPERTY(height, Height)
 
     DoubleDescriptors geometryValues() const override { return {length(), width(), height()}; }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_length, &m_width, &m_height};
+    }
 };
 
 class SawtoothRippleBoxItem : public FormFactorItem {
@@ -290,6 +353,10 @@ public:
     {
         return {length(), width(), height(), asymmetry()};
     }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_length, &m_width, &m_height, &m_asymmetry};
+    }
 };
 
 class SawtoothRippleGaussItem : public FormFactorItem {
@@ -306,6 +373,10 @@ public:
     {
         return {length(), width(), height(), asymmetry()};
     }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_length, &m_width, &m_height, &m_asymmetry};
+    }
 };
 
 class SawtoothRippleLorentzItem : public FormFactorItem {
@@ -322,6 +393,10 @@ public:
     {
         return {length(), width(), height(), asymmetry()};
     }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_length, &m_width, &m_height, &m_asymmetry};
+    }
 };
 
 class TetrahedronItem : public FormFactorItem {
@@ -334,6 +409,10 @@ public:
     FF_PROPERTY(alpha, Alpha)
 
     DoubleDescriptors geometryValues() const override { return {baseEdge(), height(), alpha()}; }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_baseEdge, &m_height, &m_alpha};
+    }
 };
 
 class TruncatedCubeItem : public FormFactorItem {
@@ -345,6 +424,10 @@ public:
     FF_PROPERTY(removedLength, RemovedLength)
 
     DoubleDescriptors geometryValues() const override { return {length(), removedLength()}; }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_length, &m_removedLength};
+    }
 };
 
 class TruncatedSphereItem : public FormFactorItem {
@@ -357,6 +440,10 @@ public:
     FF_PROPERTY(removedTop, RemovedTop)
 
     DoubleDescriptors geometryValues() const override { return {radius(), height(), removedTop()}; }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_radius, &m_height, &m_removedTop};
+    }
 };
 
 class TruncatedSpheroidItem : public FormFactorItem {
@@ -373,6 +460,10 @@ public:
     {
         return {radius(), height(), heightFlattening(), removedTop()};
     }
+    QVector<DoubleProperty*> serializationProperties() override
+    {
+        return {&m_radius, &m_height, &m_heightFlattening, &m_removedTop};
+    }
 };
 
 #endif // BORNAGAIN_GUI_MODEL_SAMPLE_FORMFACTORITEMS_H
diff --git a/GUI/Model/Sample/InterferenceItems.cpp b/GUI/Model/Sample/InterferenceItems.cpp
index 284aa1caebe918240d99e99dc021ed32b8e904ba..48909fb543449beefbeb41af5477b69b35530f7a 100644
--- a/GUI/Model/Sample/InterferenceItems.cpp
+++ b/GUI/Model/Sample/InterferenceItems.cpp
@@ -82,6 +82,15 @@ SelectionDescriptor<FTDecayFunction1DItem*> Interference1DLatticeItem::decayFunc
     return m_decayFunction;
 }
 
+void Interference1DLatticeItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_positionVariance);
+    s.rw(m_length);
+    s.rw(m_rotationAngle);
+    s.rw<FTDecayFunction1DItemCatalog>(m_decayFunction);
+}
+
 // --------------------------------------------------------------------------------------------- //
 
 SelectionDescriptor<Lattice2DItem*> Interference2DAbstractLatticeItem::latticeType() const
@@ -132,6 +141,15 @@ std::unique_ptr<IInterference> Interference2DLatticeItem::createInterference() c
     return std::unique_ptr<IInterference>(result.release());
 }
 
+void Interference2DLatticeItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_positionVariance);
+    s.rw("integrate", m_xiIntegration);
+    s.rw<Lattice2DItemCatalog>(m_latticeType);
+    s.rw<FTDecayFunction2DItemCatalog>(m_decayFunction);
+}
+
 void Interference2DLatticeItem::setDecayFunctionType(FTDecayFunction2DItem* p)
 {
     m_decayFunction.set(p);
@@ -175,6 +193,19 @@ std::unique_ptr<IInterference> Interference2DParaCrystalItem::createInterference
     return std::unique_ptr<IInterference>(result.release());
 }
 
+void Interference2DParaCrystalItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_positionVariance);
+    s.rw("integrate", m_xiIntegration);
+    s.rw<Lattice2DItemCatalog>(m_latticeType);
+    s.rw(m_dampingLength);
+    s.rw(m_domainSize1);
+    s.rw(m_domainSize2);
+    s.rw<FTDistribution2DItemCatalog>(m_pdf1);
+    s.rw<FTDistribution2DItemCatalog>(m_pdf2);
+}
+
 DoubleDescriptor Interference2DParaCrystalItem::dampingLength() const
 {
     return m_dampingLength;
@@ -250,6 +281,16 @@ std::unique_ptr<IInterference> InterferenceFinite2DLatticeItem::createInterferen
     return std::unique_ptr<IInterference>(result.release());
 }
 
+void InterferenceFinite2DLatticeItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_positionVariance);
+    s.rw("integrate", m_xiIntegration);
+    s.rw<Lattice2DItemCatalog>(m_latticeType);
+    s.rw(m_domainSize1);
+    s.rw(m_domainSize2);
+}
+
 UIntDescriptor InterferenceFinite2DLatticeItem::domainSize1()
 {
     return m_domainSize1;
@@ -286,6 +327,14 @@ std::unique_ptr<IInterference> InterferenceHardDiskItem::createInterference() co
     return std::unique_ptr<IInterference>(result.release());
 }
 
+void InterferenceHardDiskItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_positionVariance);
+    s.rw(m_radius);
+    s.rw(m_density);
+}
+
 DoubleDescriptor InterferenceHardDiskItem::density() const
 {
     return m_density;
@@ -324,6 +373,17 @@ std::unique_ptr<IInterference> InterferenceRadialParaCrystalItem::createInterfer
     return std::unique_ptr<IInterference>(result.release());
 }
 
+void InterferenceRadialParaCrystalItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_positionVariance);
+    s.rw(m_peakDistance);
+    s.rw(m_dampingLength);
+    s.rw(m_domainSize);
+    s.rw(m_kappa);
+    s.rw<FTDistribution1DItemCatalog>(m_pdf);
+}
+
 DoubleDescriptor InterferenceRadialParaCrystalItem::peakDistance() const
 {
     return m_peakDistance;
diff --git a/GUI/Model/Sample/InterferenceItems.h b/GUI/Model/Sample/InterferenceItems.h
index d11fa0fadde636092a900a12e3a607ec1dcb552e..4c0496440a44b1cf91d369afa094b47a88930611 100644
--- a/GUI/Model/Sample/InterferenceItems.h
+++ b/GUI/Model/Sample/InterferenceItems.h
@@ -30,23 +30,24 @@ class InterferenceItem {
 public:
     virtual ~InterferenceItem() = default;
     virtual std::unique_ptr<IInterference> createInterference() const = 0;
+    virtual void serialize(Serializer& s) = 0;
 
     DoubleDescriptor positionVariance() const;
 
-    virtual void serialize(Serializer& s);
-
 protected:
     InterferenceItem();
 
-private:
     DoubleProperty m_positionVariance;
 };
 
+// ------------------------------------------------------------------------------------------------
+
 class Interference1DLatticeItem : public InterferenceItem {
 public:
     Interference1DLatticeItem();
 
     std::unique_ptr<IInterference> createInterference() const override;
+    void serialize(Serializer& s) override;
 
     DoubleDescriptor length() const;
     DoubleDescriptor rotationAngle() const;
@@ -60,6 +61,8 @@ private:
     SelectionProperty<FTDecayFunction1DItem*> m_decayFunction;
 };
 
+// ------------------------------------------------------------------------------------------------
+
 class Interference2DAbstractLatticeItem : public InterferenceItem {
 public:
     SelectionDescriptor<Lattice2DItem*> latticeType() const;
@@ -71,14 +74,17 @@ public:
 protected:
     explicit Interference2DAbstractLatticeItem(bool xiIntegration);
 
-    bool m_xiIntegration; // #baMigration serialize
+    bool m_xiIntegration;
     SelectionProperty<Lattice2DItem*> m_latticeType;
 };
 
+// ------------------------------------------------------------------------------------------------
+
 class Interference2DLatticeItem : public Interference2DAbstractLatticeItem {
 public:
     Interference2DLatticeItem();
     std::unique_ptr<IInterference> createInterference() const override;
+    void serialize(Serializer& s) override;
 
     void setDecayFunctionType(FTDecayFunction2DItem* p);
     SelectionDescriptor<FTDecayFunction2DItem*> decayFunction() const;
@@ -87,10 +93,13 @@ protected:
     SelectionProperty<FTDecayFunction2DItem*> m_decayFunction;
 };
 
+// ------------------------------------------------------------------------------------------------
+
 class Interference2DParaCrystalItem : public Interference2DAbstractLatticeItem {
 public:
     Interference2DParaCrystalItem();
     std::unique_ptr<IInterference> createInterference() const override;
+    void serialize(Serializer& s) override;
 
     DoubleDescriptor dampingLength() const;
     void setDampingLength(double dampingLength);
@@ -114,10 +123,13 @@ private:
     SelectionProperty<FTDistribution2DItem*> m_pdf2;
 };
 
+// ------------------------------------------------------------------------------------------------
+
 class InterferenceFinite2DLatticeItem : public Interference2DAbstractLatticeItem {
 public:
     InterferenceFinite2DLatticeItem();
     std::unique_ptr<IInterference> createInterference() const override;
+    void serialize(Serializer& s) override;
 
     UIntDescriptor domainSize1();
     void setDomainSize1(unsigned int domain_size1);
@@ -129,10 +141,13 @@ private:
     UIntProperty m_domainSize2;
 };
 
+// ------------------------------------------------------------------------------------------------
+
 class InterferenceHardDiskItem : public InterferenceItem {
 public:
     InterferenceHardDiskItem();
     std::unique_ptr<IInterference> createInterference() const override;
+    void serialize(Serializer& s) override;
 
     DoubleDescriptor radius() const;
     DoubleDescriptor density() const;
@@ -142,10 +157,13 @@ private:
     DoubleProperty m_density;
 };
 
+// ------------------------------------------------------------------------------------------------
+
 class InterferenceRadialParaCrystalItem : public InterferenceItem {
 public:
     InterferenceRadialParaCrystalItem();
     std::unique_ptr<IInterference> createInterference() const override;
+    void serialize(Serializer& s) override;
 
     DoubleDescriptor peakDistance() const;
     DoubleDescriptor dampingLength() const;
diff --git a/GUI/Model/Sample/ItemWithParticles.cpp b/GUI/Model/Sample/ItemWithParticles.cpp
index 5491bd3fdf1dcc69900133da615a502ea7eed288..aec3f8a40ecc38c3c788cf7d383e09aeb8732d0a 100644
--- a/GUI/Model/Sample/ItemWithParticles.cpp
+++ b/GUI/Model/Sample/ItemWithParticles.cpp
@@ -73,11 +73,3 @@ void ItemWithParticles::setTransformationInfo(IParticle* result) const
         result->setRotation(*rotation);
     }
 }
-
-void ItemWithParticles::serialize(Serializer& s)
-{
-    s.assertVersion(0);
-    s.rw(m_abundance);
-    s.rw(m_position);
-    s.rw<RotationItemCatalog>(m_rotation);
-}
diff --git a/GUI/Model/Sample/ItemWithParticles.h b/GUI/Model/Sample/ItemWithParticles.h
index 164714e3536f4c71dab474cede91a12e6349a348..d71beaf2f77796cd748f014d59ef8d9ee4617245 100644
--- a/GUI/Model/Sample/ItemWithParticles.h
+++ b/GUI/Model/Sample/ItemWithParticles.h
@@ -48,16 +48,11 @@ public:
     //! For example ParticleCompositionItem contains other items, ParticleItem doesn't.
     virtual QVector<ItemWithParticles*> containedItemsWithParticles() const = 0;
 
-    virtual void serialize(Serializer& s);
+    virtual void serialize(Serializer& s) = 0;
 
 protected:
     ItemWithParticles(const QString& abundanceTooltip, const QString& positionTooltip);
 
-private:
-    //! Convenience method to return a rotation item from the contained transformation item.
-    //! nullptr, if no transformation item defined.
-    RotationItem* rotationItem() const;
-
     DoubleProperty m_abundance;
     VectorProperty m_position;
     SelectionProperty<RotationItem*> m_rotation;
diff --git a/GUI/Model/Sample/Lattice2DItems.cpp b/GUI/Model/Sample/Lattice2DItems.cpp
index 2f7c4b5f59003a7d34b619c0ef102b809a29b6a2..6526d6717b5294cd31446edc8f4ad285a4d7cddc 100644
--- a/GUI/Model/Sample/Lattice2DItems.cpp
+++ b/GUI/Model/Sample/Lattice2DItems.cpp
@@ -15,6 +15,7 @@
 #include "GUI/Model/Sample/Lattice2DItems.h"
 #include "Base/Const/Units.h"
 #include "Base/Util/Assert.h"
+#include "GUI/Model/Session/Serializer.h"
 #include "Sample/Lattice/Lattice2D.h"
 
 Lattice2DItem::Lattice2DItem()
@@ -56,6 +57,15 @@ std::unique_ptr<Lattice2D> BasicLattice2DItem::createLattice() const
                                             Units::deg2rad(latticeRotationAngle()));
 }
 
+void BasicLattice2DItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_latticeRotationAngle);
+    s.rw(m_length1);
+    s.rw(m_length2);
+    s.rw(m_angle);
+}
+
 DoubleDescriptor BasicLattice2DItem::latticeLength1() const
 {
     return m_length1;
@@ -99,6 +109,13 @@ std::unique_ptr<Lattice2D> SquareLattice2DItem::createLattice() const
     return std::make_unique<SquareLattice2D>(m_length, Units::deg2rad(latticeRotationAngle()));
 }
 
+void SquareLattice2DItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_latticeRotationAngle);
+    s.rw(m_length);
+}
+
 DoubleDescriptor SquareLattice2DItem::latticeLength() const
 {
     return m_length;
@@ -122,6 +139,13 @@ std::unique_ptr<Lattice2D> HexagonalLattice2DItem::createLattice() const
     return std::make_unique<HexagonalLattice2D>(m_length, Units::deg2rad(latticeRotationAngle()));
 }
 
+void HexagonalLattice2DItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_latticeRotationAngle);
+    s.rw(m_length);
+}
+
 DoubleDescriptor HexagonalLattice2DItem::latticeLength() const
 {
     return m_length;
diff --git a/GUI/Model/Sample/Lattice2DItems.h b/GUI/Model/Sample/Lattice2DItems.h
index bd18d691e13b12e356a82c620f89e76e4f03eb6e..c11f0ecab67acb94f6e4569e7dbd163f3e283a85 100644
--- a/GUI/Model/Sample/Lattice2DItems.h
+++ b/GUI/Model/Sample/Lattice2DItems.h
@@ -21,6 +21,7 @@
 
 class Lattice2D;
 class DoubleDescriptor;
+class Serializer;
 
 class Lattice2DItem {
 protected:
@@ -29,19 +30,23 @@ protected:
 public:
     virtual ~Lattice2DItem() = default;
     virtual std::unique_ptr<Lattice2D> createLattice() const = 0;
+    virtual void serialize(Serializer& s) = 0;
     double unitCellArea() const;
 
     DoubleDescriptor latticeRotationAngle() const;
     void setLatticeRotationAngle(double angle);
 
-private:
+protected:
     DoubleProperty m_latticeRotationAngle;
 };
 
+// -------------------------------------------------------------------------------------
+
 class BasicLattice2DItem : public Lattice2DItem {
 public:
     BasicLattice2DItem();
     std::unique_ptr<Lattice2D> createLattice() const override;
+    void serialize(Serializer& s) override;
 
     DoubleDescriptor latticeLength1() const;
     void setLatticeLength1(double length1);
@@ -58,10 +63,13 @@ private:
     DoubleProperty m_angle;
 };
 
+// -------------------------------------------------------------------------------------
+
 class SquareLattice2DItem : public Lattice2DItem {
 public:
     SquareLattice2DItem();
     std::unique_ptr<Lattice2D> createLattice() const override;
+    void serialize(Serializer& s) override;
 
     DoubleDescriptor latticeLength() const;
     void setLatticeLength(double length);
@@ -70,10 +78,13 @@ private:
     DoubleProperty m_length;
 };
 
+// -------------------------------------------------------------------------------------
+
 class HexagonalLattice2DItem : public Lattice2DItem {
 public:
     HexagonalLattice2DItem();
     std::unique_ptr<Lattice2D> createLattice() const override;
+    void serialize(Serializer& s) override;
 
     DoubleDescriptor latticeLength() const;
     void setLatticeLength(double length);
diff --git a/GUI/Model/Sample/LayerItem.cpp b/GUI/Model/Sample/LayerItem.cpp
index fac9bc161c7d4addf9e079f140d4c0043c4e1a30..0fb9b82941e4d21397712f6cad5f23fbba5ef28d 100644
--- a/GUI/Model/Sample/LayerItem.cpp
+++ b/GUI/Model/Sample/LayerItem.cpp
@@ -191,13 +191,6 @@ void LayerItem::serialize(Serializer& s)
     s.rw("MaterialIdentifier", m_materialIdentifier);
     s.rw(m_numSlices);
     s.rw(m_thickness);
-    // #baSerialize ++ implement
-
-    //     if (m_topRoughness) {
-    //         writer->writeStartElement(Tags::TopRoughness);
-    //         m_topRoughness->writeContentTo(writer);
-    //         writer->writeEndElement();
-    //     }
-
+    s.rw("Roughness", m_topRoughness);
     s.rw("Layouts", m_layouts);
 }
diff --git a/GUI/Model/Sample/MesoCrystalItem.cpp b/GUI/Model/Sample/MesoCrystalItem.cpp
index b96e2b9d12c2b4419e972b47de7f24f5b1c42bb3..200ab4b6e8aaa1e8b9c06574c5f8f681b7a786cc 100644
--- a/GUI/Model/Sample/MesoCrystalItem.cpp
+++ b/GUI/Model/Sample/MesoCrystalItem.cpp
@@ -15,9 +15,12 @@
 #include "GUI/Model/Sample/MesoCrystalItem.h"
 #include "GUI/Model/Sample/FormFactorItemCatalog.h"
 #include "GUI/Model/Sample/FormFactorItems.h"
+#include "GUI/Model/Sample/ItemWithParticlesCatalog.h"
 #include "GUI/Model/Sample/ParticleCompositionItem.h"
 #include "GUI/Model/Sample/ParticleCoreShellItem.h"
 #include "GUI/Model/Sample/ParticleItem.h"
+#include "GUI/Model/Sample/RotationItemCatalog.h"
+#include "GUI/Model/Session/Serializer.h"
 #include "GUI/Util/Error.h"
 #include "Sample/Particle/Crystal.h"
 #include "Sample/Particle/IBornFF.h"
@@ -45,6 +48,20 @@ MesoCrystalItem::MesoCrystalItem() : ItemWithParticles(abundance_tooltip, positi
                    Unit::nanometer, "vectorC");
 
     m_outerShape.init<FormFactorItemCatalog>("Outer Shape", "", "outerShape");
+    m_basisParticle.init<ItemWithParticlesCatalog>("Basis", "", "basis");
+}
+
+void MesoCrystalItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_abundance);
+    s.rw(m_position);
+    s.rw<RotationItemCatalog>(m_rotation);
+    s.rw(m_vectorA);
+    s.rw(m_vectorB);
+    s.rw(m_vectorC);
+    s.rw<FormFactorItemCatalog>(m_outerShape);
+    s.rw<ItemWithParticlesCatalog>(m_basisParticle);
 }
 
 std::unique_ptr<MesoCrystal> MesoCrystalItem::createMesoCrystal() const
@@ -114,7 +131,7 @@ ItemWithParticles* MesoCrystalItem::basisParticle() const
 
 void MesoCrystalItem::setBasis(ItemWithParticles* basis)
 {
-    m_basisParticle.reset(basis);
+    m_basisParticle.set(basis);
 }
 
 void MesoCrystalItem::setVectorA(const R3& v)
diff --git a/GUI/Model/Sample/MesoCrystalItem.h b/GUI/Model/Sample/MesoCrystalItem.h
index 170682c4189a0a1606cae35fd6c819bb1e8d4395..9e1c89f22bcf71583fb9d716a91f0f7de7a7292f 100644
--- a/GUI/Model/Sample/MesoCrystalItem.h
+++ b/GUI/Model/Sample/MesoCrystalItem.h
@@ -29,6 +29,7 @@ class MesoCrystal;
 class MesoCrystalItem : public ItemWithParticles {
 public:
     MesoCrystalItem();
+    void serialize(Serializer& s) override;
 
     std::unique_ptr<MesoCrystal> createMesoCrystal() const;
 
@@ -60,7 +61,7 @@ private:
     VectorProperty m_vectorB;
     VectorProperty m_vectorC;
     SelectionProperty<FormFactorItem*> m_outerShape;
-    std::unique_ptr<ItemWithParticles> m_basisParticle;
+    SelectionProperty<ItemWithParticles*> m_basisParticle;
 };
 
 template <typename T> T* MesoCrystalItem::setOuterShapeType()
diff --git a/GUI/Model/Sample/ParticleCompositionItem.cpp b/GUI/Model/Sample/ParticleCompositionItem.cpp
index 40159e6dc663f55407081fde2c18dad281c5a9fb..0281e24241b425265bafe6b3b9e18926d021c46a 100644
--- a/GUI/Model/Sample/ParticleCompositionItem.cpp
+++ b/GUI/Model/Sample/ParticleCompositionItem.cpp
@@ -13,12 +13,12 @@
 //  ************************************************************************************************
 
 #include "GUI/Model/Sample/ParticleCompositionItem.h"
+#include "GUI/Model/Sample/ItemWithParticlesCatalog.h"
 #include "GUI/Model/Sample/MesoCrystalItem.h"
 #include "GUI/Model/Sample/ParticleCoreShellItem.h"
 #include "GUI/Model/Sample/ParticleItem.h"
-#include "GUI/Model/Session/SessionItemUtils.h"
-#include "GUI/Model/Types/DoubleDescriptor.h"
-#include "GUI/Model/Types/VectorItem.h"
+#include "GUI/Model/Sample/RotationItemCatalog.h"
+#include "GUI/Model/Session/Serializer.h"
 #include "Sample/Particle/MesoCrystal.h"
 #include "Sample/Particle/Particle.h"
 #include "Sample/Particle/ParticleCoreShell.h"
@@ -39,6 +39,15 @@ ParticleCompositionItem::ParticleCompositionItem()
 {
 }
 
+void ParticleCompositionItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_abundance);
+    s.rw(m_position);
+    s.rw<RotationItemCatalog>(m_rotation);
+    s.rw<ItemWithParticlesCatalog>("Particles", m_particles);
+}
+
 std::unique_ptr<ParticleComposition> ParticleCompositionItem::createParticleComposition() const
 {
     auto P_composition = std::make_unique<ParticleComposition>();
diff --git a/GUI/Model/Sample/ParticleCompositionItem.h b/GUI/Model/Sample/ParticleCompositionItem.h
index b5232119c000c7e8ad037de7949934f279bc1c45..937ed92b0242c435649687fdd494be9ec9664278 100644
--- a/GUI/Model/Sample/ParticleCompositionItem.h
+++ b/GUI/Model/Sample/ParticleCompositionItem.h
@@ -22,6 +22,7 @@
 class ParticleCompositionItem : public ItemWithParticles {
 public:
     ParticleCompositionItem();
+    void serialize(Serializer& s) override;
 
     std::unique_ptr<ParticleComposition> createParticleComposition() const;
 
diff --git a/GUI/Model/Sample/ParticleCoreShellItem.cpp b/GUI/Model/Sample/ParticleCoreShellItem.cpp
index d2e95ac2690c9d3962bca4f452b239a71facbdb9..0cdd60bbe3c307bed99742042e8c4beaab6853b0 100644
--- a/GUI/Model/Sample/ParticleCoreShellItem.cpp
+++ b/GUI/Model/Sample/ParticleCoreShellItem.cpp
@@ -38,6 +38,15 @@ ParticleCoreShellItem::ParticleCoreShellItem()
 {
 }
 
+void ParticleCoreShellItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_abundance);
+    s.rw(m_position);
+    s.rw("core", m_core);
+    s.rw("shell", m_shell);
+}
+
 std::unique_ptr<ParticleCoreShell> ParticleCoreShellItem::createParticleCoreShell() const
 {
     std::unique_ptr<Particle> P_core{};
diff --git a/GUI/Model/Sample/ParticleCoreShellItem.h b/GUI/Model/Sample/ParticleCoreShellItem.h
index 612601ec3bf2643243bd06ad3d3968c27ba1fde1..e2986b4ac3f11e1625d4cb9fc45e2dd0f63b5b5d 100644
--- a/GUI/Model/Sample/ParticleCoreShellItem.h
+++ b/GUI/Model/Sample/ParticleCoreShellItem.h
@@ -26,6 +26,7 @@ class MaterialModel;
 class ParticleCoreShellItem : public ItemWithParticles {
 public:
     ParticleCoreShellItem();
+    void serialize(Serializer& s) override;
 
     std::unique_ptr<ParticleCoreShell> createParticleCoreShell() const;
 
diff --git a/GUI/Model/Sample/ParticleItem.cpp b/GUI/Model/Sample/ParticleItem.cpp
index 1e730bebcd89bc63623716d29c7a2993f6b63cd3..380bd82e1a0f9cd2044a33243f5cac48088f23b8 100644
--- a/GUI/Model/Sample/ParticleItem.cpp
+++ b/GUI/Model/Sample/ParticleItem.cpp
@@ -13,16 +13,13 @@
 //  ************************************************************************************************
 
 #include "GUI/Model/Sample/ParticleItem.h"
-#include "GUI/Model/Group/GroupItem.h"
 #include "GUI/Model/Job/JobItem.h"
-#include "GUI/Model/Job/JobModelFunctions.h"
 #include "GUI/Model/Material/MaterialItem.h"
 #include "GUI/Model/Sample/FormFactorItemCatalog.h"
 #include "GUI/Model/Sample/FormFactorItems.h"
 #include "GUI/Model/Sample/ParticleCoreShellItem.h"
-#include "GUI/Model/Sample/ParticleLayoutItem.h"
-#include "GUI/Model/Session/SessionItemUtils.h"
-#include "GUI/Model/Types/VectorItem.h"
+#include "GUI/Model/Sample/RotationItemCatalog.h"
+#include "GUI/Model/Session/Serializer.h"
 #include "Sample/Particle/Particle.h"
 
 namespace {
@@ -41,6 +38,15 @@ ParticleItem::ParticleItem() : ItemWithParticles(abundance_tooltip, position_too
     m_formFactor.set(new CylinderItem());
 }
 
+void ParticleItem::serialize(Serializer& s)
+{
+    s.assertVersion(0);
+    s.rw(m_abundance);
+    s.rw(m_position);
+    s.rw<RotationItemCatalog>(m_rotation);
+    s.rw<FormFactorItemCatalog>(m_formFactor);
+}
+
 std::unique_ptr<Particle> ParticleItem::createParticle() const
 {
     auto domainMaterial = materialItem()->createMaterial();
diff --git a/GUI/Model/Sample/ParticleItem.h b/GUI/Model/Sample/ParticleItem.h
index 29b6e19d92e500e5ea8db2180d7374137b74706b..5eafe2ee8295e6483c241e1e5df69540b25d0658 100644
--- a/GUI/Model/Sample/ParticleItem.h
+++ b/GUI/Model/Sample/ParticleItem.h
@@ -28,6 +28,7 @@ class VectorItem;
 class ParticleItem : public ItemWithMaterial, public ItemWithParticles {
 public:
     ParticleItem();
+    void serialize(Serializer& s) override;
 
     std::unique_ptr<Particle> createParticle() const;
 
diff --git a/GUI/Model/Session/Serializer.h b/GUI/Model/Session/Serializer.h
index b2716c72d9f677bac39f2e1506f7cfa7d3b1a533..9b7502484398d44572325f95c5fe3bffaa124977 100644
--- a/GUI/Model/Session/Serializer.h
+++ b/GUI/Model/Session/Serializer.h
@@ -106,6 +106,46 @@ public:
         }
     }
 
+    //! serialize item which has only one exact class, and can be present or not
+    template <typename ItemClass> void rw(const QString& tag, ItemClass*& p)
+    {
+        if (m_w) {
+            m_w->writeStartElement(tag);
+            m_w->writeAttribute("valid", p ? "1" : "0");
+            if (p != nullptr)
+                p->serialize(*this);
+            m_w->writeEndElement();
+        } else {
+            goToStartElementOfTag(tag);
+            const bool valid = m_r->attributes().value("valid").toUInt() > 0;
+            p = valid ? new ItemClass() : nullptr;
+            if (p != nullptr)
+                p->serialize(*this);
+            goToEndElementOfTag(tag);
+        }
+    }
+
+    //! serialize item which has only one exact class, and can be present or not
+    template <typename ItemClass> void rw(const QString& tag, std::unique_ptr<ItemClass>& up)
+    {
+        if (m_w) {
+            m_w->writeStartElement(tag);
+            m_w->writeAttribute("valid", up ? "1" : "0");
+            if (up)
+                up->serialize(*this);
+            m_w->writeEndElement();
+        } else {
+            goToStartElementOfTag(tag);
+            const bool valid = m_r->attributes().value("valid").toUInt() > 0;
+            if (valid) {
+                up.reset(new ItemClass());
+                up->serialize(*this);
+            } else
+                up.reset();
+            goToEndElementOfTag(tag);
+        }
+    }
+
     template <typename Catalog> void write(const QString& tag, typename Catalog::CatalogedType*& p)
     {
         ASSERT(m_w);