diff --git a/.appveyor.yml b/.appveyor.yml
index 092087f36dc94ad16e45d11baa722f1e84c56ef0..3345b083125930ba9868c088e5adf7da6e58a9dd 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -1,4 +1,4 @@
-image: Previous Visual Studio 2015
+image: Visual Studio 2017
 
 matrix:
   fast_finish: true
@@ -8,12 +8,9 @@ platform:
 
 # http://www.appveyor.com/docs/installed-software
 environment:
-  QTDIR: "C:\\Qt\\5.7\\msvc2015_64"
+  QTDIR: "C:\\Qt\\5.9.1\\msvc2017_64"
   MYCONDA: "C:\\Miniconda-x64;C:\\Miniconda-x64\\Scripts;C:\\Miniconda-x64\\Library\\bin"
-  MYGIT: "C:\\Program Files\\Git\\cmd;C:\\Program Files\\Git\\usr\\bin;"
-  MYOTHER: "C:\\Program Files (x86)\\CMake\\bin;C:\\Program Files\\7-Zip"
-  MYMSVC: "C:\\Program Files (x86)\\MSBuild\\14.0\\Bin;"
-  PATH: "%QTDIR%\\bin;C:\\opt\\local_x64\\lib;%MYCONDA%;%MYGIT%;%MYOTHER%"
+  PATH: "%QTDIR%\\bin;C:\\opt\\local_x64\\lib;%MYCONDA%;%PATH%"
   PYTHONPATH: "C:\\Miniconda-x64;C:\\Miniconda-x64\\Lib;C:\\Miniconda-x64\\Lib\\site-packages;C:\\Miniconda-x64\\DLLs"
 build:
   parallel: true
@@ -36,7 +33,7 @@ before_build:
 build_script:
 - mkdir build
 - cd build
-- cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_INCLUDE_PATH=C:/opt/local_x64/include -DCMAKE_LIBRARY_PATH=C:/opt/local_x64/lib ..
+- cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_INCLUDE_PATH=C:/opt/local_x64/include -DCMAKE_LIBRARY_PATH=C:/opt/local_x64/lib ..
 - cmake --build . --config Release
 
 test_script:
diff --git a/Core/Computation/MainComputation.cpp b/Core/Computation/MainComputation.cpp
index 49ebaa14025c819e1449682d1c28dc76abe524f4..f033a58e02db23721b6598425909f2f82ad00a0f 100644
--- a/Core/Computation/MainComputation.cpp
+++ b/Core/Computation/MainComputation.cpp
@@ -17,6 +17,7 @@
 #include "ParticleLayoutComputation.h"
 #include "Layer.h"
 #include "IFresnelMap.h"
+#include "Instrument.h"
 #include "MatrixFresnelMap.h"
 #include "MultiLayer.h"
 #include "RoughMultiLayerComputation.h"
@@ -28,16 +29,19 @@
 namespace
 {
 HomogeneousMaterial CalculateAverageMaterial(const HomogeneousMaterial& layer_mat,
+                                             double wavelength,
                                              const std::vector<HomogeneousRegion>& regions);
 }
 
 MainComputation::MainComputation(
     const MultiLayer& multilayer,
+    const Instrument& instrument,
     const SimulationOptions& options,
     ProgressHandler& progress,
     const std::vector<SimulationElement>::iterator& begin_it,
     const std::vector<SimulationElement>::iterator& end_it)
     : mP_multi_layer(multilayer.cloneSliced(options.useAvgMaterials()))
+    , m_instrument(instrument)
     , m_sim_options(options)
     , m_progress(&progress)
     , m_begin_it(begin_it)
@@ -125,7 +129,8 @@ std::unique_ptr<MultiLayer> MainComputation::getAveragedMultilayer() const
         if (!checkRegions(entry.second))
             throw std::runtime_error("MainComputation::getAveragedMultilayer: "
                                      "total volumetric fraction of particles exceeds 1!");
-        auto new_mat = CalculateAverageMaterial(layer_mat, entry.second);
+        double beam_wavelength = m_instrument.getBeam().getWavelength();
+        auto new_mat = CalculateAverageMaterial(layer_mat, beam_wavelength, entry.second);
         P_result->setLayerMaterial(i_layer, new_mat);
     }
     return P_result;
@@ -157,16 +162,17 @@ bool MainComputation::checkRegions(const std::vector<HomogeneousRegion>& regions
 namespace
 {
 HomogeneousMaterial CalculateAverageMaterial(const HomogeneousMaterial& layer_mat,
+                                             double wavelength,
                                              const std::vector<HomogeneousRegion>& regions)
 {
     kvector_t magnetization_layer = layer_mat.magnetization();
-    complex_t refr_index2_layer = layer_mat.refractiveIndex2();
+    complex_t refr_index2_layer = layer_mat.refractiveIndex2(wavelength);
     kvector_t magnetization_avg = magnetization_layer;
     complex_t refr_index2_avg = refr_index2_layer;
     for (auto& region : regions)
     {
         kvector_t magnetization_region = region.m_material.magnetization();
-        complex_t refr_index2_region = region.m_material.refractiveIndex2();
+        complex_t refr_index2_region = region.m_material.refractiveIndex2(wavelength);
         magnetization_avg += region.m_volume*(magnetization_region - magnetization_layer);
         refr_index2_avg += region.m_volume*(refr_index2_region - refr_index2_layer);
     }
diff --git a/Core/Computation/MainComputation.h b/Core/Computation/MainComputation.h
index 373b3e2dc4c113426e9a55444820b4b55559eed8..76b5a551cbaa8558c76f85b9350eb1d087a6ced2 100644
--- a/Core/Computation/MainComputation.h
+++ b/Core/Computation/MainComputation.h
@@ -25,6 +25,7 @@
 
 class IFresnelMap;
 class MultiLayer;
+class Instrument;
 struct HomogeneousRegion;
 class IComputationTerm;
 class ProgressHandler;
@@ -42,6 +43,7 @@ class MainComputation final : public INoncopyable
 public:
     MainComputation(
         const MultiLayer& multilayer,
+        const Instrument& instrument,
         const SimulationOptions& options,
         ProgressHandler& progress,
         const std::vector<SimulationElement>::iterator& begin_it,
@@ -66,6 +68,7 @@ private:
     bool checkRegions(const std::vector<HomogeneousRegion>& regions) const;
 
     std::unique_ptr<MultiLayer> mP_multi_layer;
+    const Instrument& m_instrument;
     SimulationOptions m_sim_options;
     ProgressHandler* m_progress;
     //! these iterators define the span of detector bins this simulation will work on
diff --git a/Core/Computation/RoughMultiLayerComputation.cpp b/Core/Computation/RoughMultiLayerComputation.cpp
index 8e1c71d5242c15e43a7f63186b06bf4ca87f55c1..681880e63022c43d902bc6700b64e443c51482ba 100644
--- a/Core/Computation/RoughMultiLayerComputation.cpp
+++ b/Core/Computation/RoughMultiLayerComputation.cpp
@@ -77,7 +77,7 @@ double RoughMultiLayerComputation::evaluate(const SimulationElement& sim_element
     std::vector<complex_t > sterm( mp_multilayer->numberOfLayers()-1 );
 
     for (size_t i=0; i<mp_multilayer->numberOfLayers()-1; i++){
-        rterm[i] = get_refractive_term(i);
+        rterm[i] = get_refractive_term(i, wavelength);
         sterm[i] = get_sum8terms(i, sim_element);
     }
 
@@ -104,10 +104,10 @@ double RoughMultiLayerComputation::evaluate(const SimulationElement& sim_element
     return (autocorr+crosscorr.real())*M_PI/4./wavelength/wavelength;
 }
 
-complex_t RoughMultiLayerComputation::get_refractive_term(size_t ilayer) const
+complex_t RoughMultiLayerComputation::get_refractive_term(size_t ilayer, double wavelength) const
 {
-    return mp_multilayer->layer(ilayer  )->refractiveIndex2() -
-           mp_multilayer->layer(ilayer+1)->refractiveIndex2();
+    return mp_multilayer->layer(ilayer  )->material()->refractiveIndex2(wavelength) -
+           mp_multilayer->layer(ilayer+1)->material()->refractiveIndex2(wavelength);
 }
 
 complex_t RoughMultiLayerComputation::get_sum8terms(
diff --git a/Core/Computation/RoughMultiLayerComputation.h b/Core/Computation/RoughMultiLayerComputation.h
index d2223ea0ec4bbd6dfb7e7cfc692cc663c941cd8d..3d869ce3d36175424cfa6ba1545e5ec44091545d 100644
--- a/Core/Computation/RoughMultiLayerComputation.h
+++ b/Core/Computation/RoughMultiLayerComputation.h
@@ -40,7 +40,7 @@ public:
 
 private:
     double evaluate(const SimulationElement& sim_element) const;
-    complex_t get_refractive_term(size_t ilayer) const;
+    complex_t get_refractive_term(size_t ilayer, double wavelength) const;
     complex_t get_sum8terms(size_t ilayer, const SimulationElement& sim_element) const;
 };
 
diff --git a/Core/DecoratedFormFactor/FormFactorDecoratorMaterial.cpp b/Core/DecoratedFormFactor/FormFactorDecoratorMaterial.cpp
index 32192510567cf1dbf5461c83f1e0e0499c70b16c..c6f17f92c5296d3f4288db7a785490e4e30041e8 100644
--- a/Core/DecoratedFormFactor/FormFactorDecoratorMaterial.cpp
+++ b/Core/DecoratedFormFactor/FormFactorDecoratorMaterial.cpp
@@ -47,11 +47,6 @@ void FormFactorDecoratorMaterial::setAmbientMaterial(HomogeneousMaterial materia
     m_ambient_material = std::move(material);
 }
 
-complex_t FormFactorDecoratorMaterial::getAmbientRefractiveIndex() const
-{
-    return m_ambient_material.refractiveIndex();
-}
-
 complex_t FormFactorDecoratorMaterial::evaluate(const WavevectorInfo& wavevectors) const
 {
     return getRefractiveIndexFactor(wavevectors)*mp_form_factor->evaluate(wavevectors);
@@ -66,13 +61,13 @@ Eigen::Matrix2cd FormFactorDecoratorMaterial::evaluatePol(const WavevectorInfo&
     time_reverse_conj(1, 0) = -1.0;
     // the interaction and time reversal taken together:
     Eigen::Matrix2cd V_eff = time_reverse_conj
-                             * (  m_material.polarizedSLD(wavevectors)
-                                - m_ambient_material.polarizedSLD(wavevectors) );
+                             * (  m_material.polarizedSubtrSLD(wavevectors)
+                                - m_ambient_material.polarizedSubtrSLD(wavevectors) );
     return mp_form_factor->evaluate(wavevectors) * V_eff;
 }
 
 complex_t FormFactorDecoratorMaterial::getRefractiveIndexFactor(
         const WavevectorInfo& wavevectors) const
 {
-    return m_material.scalarSLD(wavevectors) - m_ambient_material.scalarSLD(wavevectors);
+    return m_material.scalarSubtrSLD(wavevectors) - m_ambient_material.scalarSubtrSLD(wavevectors);
 }
diff --git a/Core/DecoratedFormFactor/FormFactorDecoratorMaterial.h b/Core/DecoratedFormFactor/FormFactorDecoratorMaterial.h
index b65cc9843802aa3dfb0661170c75393c7862201b..030261128004d25c26259b51a729058b9d777b70 100644
--- a/Core/DecoratedFormFactor/FormFactorDecoratorMaterial.h
+++ b/Core/DecoratedFormFactor/FormFactorDecoratorMaterial.h
@@ -41,8 +41,6 @@ public:
     //! Sets the ambient material
     void setAmbientMaterial(HomogeneousMaterial material) override;
 
-    complex_t getAmbientRefractiveIndex() const;
-
     complex_t evaluate(const WavevectorInfo& wavevectors) const override;
 #ifndef SWIG
     //! Returns scattering amplitude for matrix interactions
diff --git a/Core/Export/ExportToPython.cpp b/Core/Export/ExportToPython.cpp
index 4e82e5a5e61cee3800f64249db9f1b1980db4ebd..f60b81dede67395704c9ac4c84d5b99785cfefa4 100644
--- a/Core/Export/ExportToPython.cpp
+++ b/Core/Export/ExportToPython.cpp
@@ -200,14 +200,14 @@ std::string ExportToPython::defineMaterials() const
             continue;
         visitedMaterials.insert(it->second);
         const HomogeneousMaterial* p_material = it->first;
-        complex_t ri = p_material->refractiveIndex();
-        double delta = 1.0 - std::real(ri);
-        double beta = std::imag(ri);
+        complex_t material_data = p_material->materialData();
+        double real = std::real(material_data);
+        double imag = std::imag(material_data);
         if (p_material->isScalarMaterial()) {
             result << indent() << m_label->labelMaterial(p_material)
                    << " = ba.HomogeneousMaterial(\"" << p_material->getName()
-                   << "\", " << printDouble(delta) << ", "
-                   << printDouble(beta) << ")\n";
+                   << "\", " << printDouble(real) << ", "
+                   << printDouble(imag) << ")\n";
         } else {
             kvector_t magnetic_field = p_material->magnetization();
             result << indent() << "magnetic_field = kvector_t(" << magnetic_field.x() << ", "
@@ -215,8 +215,8 @@ std::string ExportToPython::defineMaterials() const
                    << ")\n";
             result << indent() << m_label->labelMaterial(p_material)
                    << " = ba.HomogeneousMaterial(\"" << p_material->getName();
-            result << "\", " << printDouble(delta) << ", "
-                   << printDouble(beta) << ", "
+            result << "\", " << printDouble(real) << ", "
+                   << printDouble(imag) << ", "
                    << "magnetic_field)\n";
         }
     }
diff --git a/Core/HardParticle/FormFactorPolyhedron.cpp b/Core/HardParticle/FormFactorPolyhedron.cpp
index fa4d03547e987c516079026e18d415f5ec3d3698..ad14bd70bf306a9cf0386ce1a2a64a919eaa1ecf 100644
--- a/Core/HardParticle/FormFactorPolyhedron.cpp
+++ b/Core/HardParticle/FormFactorPolyhedron.cpp
@@ -27,6 +27,7 @@
 namespace {
     const complex_t I = {0.,1.};
     const double eps = 2e-16;
+    constexpr auto ReciprocalFactorialArray = Precomputed::GenerateReciprocalFactorialArray<171>();
 }
 
 double PolyhedralFace::qpa_limit_series = 3e-2;
@@ -60,25 +61,24 @@ complex_t PolyhedralEdge::contrib(int M, cvector_t qpa, complex_t qrperp) const
         std::cout<<std::scientific<<std::showpos<<std::setprecision(16)<<"contrib: u="<<u<<
             " v1="<<v1<<" v2="<<v2<<"\n";
 #endif
-    static auto& precomputed = Precomputed::instance();
     if( v==0. ) { // only 2l=M contributes
         if( M&1 ) // M is odd
             return 0.;
         else
-            return precomputed.reciprocal_factorial[M] * ( pow(u, M)/(M+1.) - pow(v1, M) );
+            return ReciprocalFactorialArray[M] * ( pow(u, M)/(M+1.) - pow(v1, M) );
     }
     complex_t ret = 0;
     // the l=0 term, minus (qperp.R)^M, which cancels under the sum over E*contrib()
     if        ( v1==0. ) {
-        ret = precomputed.reciprocal_factorial[M] * pow(v2, M);
+        ret = ReciprocalFactorialArray[M] * pow(v2, M);
     } else if ( v2==0. ) {
         ; // leave ret=0
     } else {
         // binomial expansion
         for( int mm=1; mm<=M; ++mm ) {
             complex_t term =
-                precomputed.reciprocal_factorial[mm] *
-                precomputed.reciprocal_factorial[M-mm] *
+                ReciprocalFactorialArray[mm] *
+                ReciprocalFactorialArray[M-mm] *
                 pow(v2, mm) * pow(v1, M-mm);
             ret += term;
 #ifdef POLYHEDRAL_DIAGNOSTIC
@@ -91,8 +91,8 @@ complex_t PolyhedralEdge::contrib(int M, cvector_t qpa, complex_t qrperp) const
         return ret;
     for( int l=1; l<=M/2; ++l ) {
         complex_t term =
-            precomputed.reciprocal_factorial[M-2*l] *
-            precomputed.reciprocal_factorial[2*l+1] *
+            ReciprocalFactorialArray[M-2*l] *
+            ReciprocalFactorialArray[2*l+1] *
             pow(u, 2*l) * pow(v, M-2*l);
         ret += term;
 #ifdef POLYHEDRAL_DIAGNOSTIC
@@ -250,9 +250,8 @@ complex_t PolyhedralFace::ff_n( int n, cvector_t q ) const
     cvector_t qpa;
     decompose_q( q, qperp, qpa );
     double qpa_mag2 = qpa.mag2();
-    static auto& precomputed = Precomputed::instance();
     if ( qpa_mag2==0. ) {
-        return qn * pow(qperp*m_rperp, n) * m_area / precomputed.factorial[n];
+        return qn * pow(qperp*m_rperp, n) * m_area * ReciprocalFactorialArray[n];
     } else if ( sym_S2 ) {
         return qn * ( ff_n_core( n, qpa, qperp ) + ff_n_core( n, -qpa, qperp ) ) / qpa_mag2;
     } else {
diff --git a/Core/Instrument/Beam.cpp b/Core/Instrument/Beam.cpp
index a13b7ca05a65683f8ed15e545f3e704b93dcc2a8..a906568f0cd8fd46e83f05e0a91c02e92df1cae7 100644
--- a/Core/Instrument/Beam.cpp
+++ b/Core/Instrument/Beam.cpp
@@ -82,6 +82,14 @@ void Beam::setPolarization(const kvector_t bloch_vector)
     m_polarization = calculatePolarization(bloch_vector);
 }
 
+kvector_t Beam::getBlochVector() const
+{
+    double x = 2.0*m_polarization(0, 1).real();
+    double y = 2.0*m_polarization(1, 0).imag();
+    double z = (m_polarization(0, 0) - m_polarization(1, 1)).real();
+    return { x, y, z };
+}
+
 Eigen::Matrix2cd Beam::calculatePolarization(const kvector_t bloch_vector) const
 {
     Eigen::Matrix2cd result;
diff --git a/Core/Instrument/Beam.h b/Core/Instrument/Beam.h
index da0f57a68156f3f4733c4bcc9e55b35b48607696..a52d5bbb36926f8679dea7835ce885023ef7fe2e 100644
--- a/Core/Instrument/Beam.h
+++ b/Core/Instrument/Beam.h
@@ -47,6 +47,8 @@ public:
     //! Sets the polarization density matrix according to the given Bloch vector
     void setPolarization(const kvector_t bloch_vector);
 
+    kvector_t getBlochVector() const;
+
 #ifndef SWIG
     //! Returns the polarization density matrix (in spin basis along z-axis)
     Eigen::Matrix2cd getPolarization() const  { return m_polarization; }
diff --git a/Core/Instrument/DetectionProperties.cpp b/Core/Instrument/DetectionProperties.cpp
index 23e3c5430920490b7991d4ad11ef3aef07646ca1..e01b3048ae3c5852eb73ba340aa3e7ced721d15a 100644
--- a/Core/Instrument/DetectionProperties.cpp
+++ b/Core/Instrument/DetectionProperties.cpp
@@ -18,9 +18,10 @@
 #include "Complex.h"
 
 DetectionProperties::DetectionProperties()
-{
-    initPolarizationOperator();
-}
+    : m_direction {}
+    , m_efficiency {}
+    , m_total_transmission { 1.0 }
+{}
 
 void DetectionProperties::setAnalyzerProperties(const kvector_t direction, double efficiency,
                                                double total_transmission)
@@ -28,18 +29,47 @@ void DetectionProperties::setAnalyzerProperties(const kvector_t direction, doubl
     if (!checkAnalyzerProperties(direction, efficiency, total_transmission))
         throw Exceptions::ClassInitializationException("IDetector2D::setAnalyzerProperties: the "
                                                        "given properties are not physical");
-
-    m_analyzer_operator = calculateAnalyzerOperator(direction, efficiency, total_transmission);
+    if (efficiency==0.0 || total_transmission==0.0 || direction.mag()==0.0) {
+        m_direction = kvector_t {};
+        m_efficiency = 0.0;
+    } else {
+        m_direction = direction.unit();
+        m_efficiency = efficiency;
+    }
+    m_total_transmission = total_transmission;
 }
 
 Eigen::Matrix2cd DetectionProperties::analyzerOperator() const
 {
-    return m_analyzer_operator;
+    if (m_direction.mag()==0.0 || m_efficiency==0.0)
+        return m_total_transmission*Eigen::Matrix2cd::Identity();
+    Eigen::Matrix2cd result;
+    double x = m_direction.x()/m_direction.mag();
+    double y = m_direction.y()/m_direction.mag();
+    double z = m_direction.z()/m_direction.mag();
+    double sum = m_total_transmission * 2.0;
+    double diff = m_total_transmission * m_efficiency * 2.0;
+    complex_t im(0.0, 1.0);
+    result(0, 0) = (sum + diff*z) / 2.0;
+    result(0, 1) = diff*(x - im * y) / 2.0;
+    result(1, 0) = diff*(x + im * y) / 2.0;
+    result(1, 1) = (sum - diff*z) / 2.0;
+    return result;
+}
+
+kvector_t DetectionProperties::analyzerDirection() const
+{
+    return m_direction;
 }
 
-void DetectionProperties::initPolarizationOperator()
+double DetectionProperties::analyzerEfficiency() const
 {
-    m_analyzer_operator = Eigen::Matrix2cd::Identity();
+    return m_efficiency;
+}
+
+double DetectionProperties::analyzerTotalTransmission() const
+{
+    return m_total_transmission;
 }
 
 bool DetectionProperties::checkAnalyzerProperties(
@@ -55,20 +85,3 @@ bool DetectionProperties::checkAnalyzerProperties(
         return false;
     return true;
 }
-
-Eigen::Matrix2cd DetectionProperties::calculateAnalyzerOperator(
-    const kvector_t direction, double efficiency, double total_transmission) const
-{
-    Eigen::Matrix2cd result;
-    double x = direction.x()/direction.mag();
-    double y = direction.y()/direction.mag();
-    double z = direction.z()/direction.mag();
-    double sum = total_transmission * 2.0;
-    double diff = total_transmission * efficiency * 2.0;
-    complex_t im(0.0, 1.0);
-    result(0, 0) = (sum + diff*z) / 2.0;
-    result(0, 1) = diff*(x - im * y) / 2.0;
-    result(1, 0) = diff*(x + im * y) / 2.0;
-    result(1, 1) = (sum - diff*z) / 2.0;
-    return result;
-}
diff --git a/Core/Instrument/DetectionProperties.h b/Core/Instrument/DetectionProperties.h
index d2c07f1a2f83c29c335fd26659bfd0b2b1be5584..96239c267c212dd22fcf66d88183baf59de5e98f 100644
--- a/Core/Instrument/DetectionProperties.h
+++ b/Core/Instrument/DetectionProperties.h
@@ -31,21 +31,21 @@ public:
     void setAnalyzerProperties(const kvector_t direction, double efficiency,
                                double total_transmission);
 
-    //! Gets the polarization density matrix (in spin basis along z-axis)
+    //! Return the polarization density matrix (in spin basis along z-axis)
     Eigen::Matrix2cd analyzerOperator() const;
 
+    //! Retrieve the analyzer characteristics
+    kvector_t analyzerDirection() const;
+    double analyzerEfficiency() const;
+    double analyzerTotalTransmission() const;
 private:
-    //! Initialize polarization
-    void initPolarizationOperator();
-
-    Eigen::Matrix2cd calculateAnalyzerOperator(
-        const kvector_t direction, double efficiency, double total_transmission = 1.0) const;
-
     //! Verify if the given analyzer properties are physical
     bool checkAnalyzerProperties(const kvector_t direction, double efficiency,
                                  double total_transmission) const;
 
-    Eigen::Matrix2cd m_analyzer_operator; //!< polarization analyzer operator
+    kvector_t m_direction;  //!< direction of polarization analysis
+    double m_efficiency;  //!< efficiency of polarization analysis
+    double m_total_transmission;  //!< total transmission of polarization analysis
 };
 
 #endif // DETECTIONPROPERTIES_H
diff --git a/Core/Instrument/IDetector2D.cpp b/Core/Instrument/IDetector2D.cpp
index ea90b341959a7256b571270a40da94e985b76345..c2bf0681d0bebf5c5bda16344064e6e81e80f3b3 100644
--- a/Core/Instrument/IDetector2D.cpp
+++ b/Core/Instrument/IDetector2D.cpp
@@ -84,6 +84,21 @@ void IDetector2D::setAnalyzerProperties(const kvector_t direction, double effici
     m_detection_properties.setAnalyzerProperties(direction, efficiency, total_transmission);
 }
 
+kvector_t IDetector2D::analyzerDirection() const
+{
+    return m_detection_properties.analyzerDirection();
+}
+
+double IDetector2D::analyzerEfficiency() const
+{
+    return m_detection_properties.analyzerEfficiency();
+}
+
+double IDetector2D::analyzerTotalTransmission() const
+{
+    return m_detection_properties.analyzerTotalTransmission();
+}
+
 OutputData<double> *IDetector2D::createDetectorIntensity(
         const std::vector<SimulationElement> &elements,
         const Beam &beam, IDetector2D::EAxesUnits units_type) const
@@ -233,7 +248,7 @@ size_t IDetector2D::getAxisBinIndex(size_t index, size_t selected_axis) const
     for (size_t i=0; i<getDimension(); ++i)
     {
         size_t i_axis = getDimension()-1-i;
-		size_t result = remainder % m_axes[i_axis]->size();
+        size_t result = remainder % m_axes[i_axis]->size();
         if(selected_axis == i_axis ) return result;
         remainder /= m_axes[i_axis]->size();
     }
diff --git a/Core/Instrument/IDetector2D.h b/Core/Instrument/IDetector2D.h
index 31bb286d84a8bf26fbf84b9ba39ada1655384c5b..9d12ff833499df275428d498ea4f354e760d4c28 100644
--- a/Core/Instrument/IDetector2D.h
+++ b/Core/Instrument/IDetector2D.h
@@ -83,6 +83,11 @@ public:
     void setAnalyzerProperties(const kvector_t direction, double efficiency,
                                double total_transmission);
 
+    //! Get analyzer properties
+    kvector_t analyzerDirection() const;
+    double analyzerEfficiency() const;  //!< will always return a positive number
+    double analyzerTotalTransmission() const;
+
     //! Removes all masks from the detector
     void removeMasks();
 
diff --git a/Core/Material/HomogeneousMaterial.cpp b/Core/Material/HomogeneousMaterial.cpp
index 152ddfb7d35efc21c52ca73b783cdfbb9fe4a342..6c3e436c2c9e6490b8caea73c7f6040d87c191ab 100644
--- a/Core/Material/HomogeneousMaterial.cpp
+++ b/Core/Material/HomogeneousMaterial.cpp
@@ -68,25 +68,21 @@ HomogeneousMaterial HomogeneousMaterial::inverted() const
 {
     std::string name = isScalarMaterial() ? getName()
                                           : getName()+"_inv";
-    HomogeneousMaterial result(name, refractiveIndex(), -magnetization());
+    complex_t material_data = materialData();
+    HomogeneousMaterial result(name, material_data.real(), material_data.imag(), -magnetization());
     return result;
 }
 
-complex_t HomogeneousMaterial::refractiveIndex() const
+complex_t HomogeneousMaterial::refractiveIndex(double) const
 {
     return m_refractive_index;
 }
 
-complex_t HomogeneousMaterial::refractiveIndex2() const
+complex_t HomogeneousMaterial::refractiveIndex2(double) const
 {
     return m_refractive_index*m_refractive_index;
 }
 
-void HomogeneousMaterial::setRefractiveIndex(const complex_t refractive_index)
-{
-    m_refractive_index = refractive_index;
-}
-
 bool HomogeneousMaterial::isScalarMaterial() const
 {
     return m_magnetization == kvector_t {};
@@ -97,23 +93,22 @@ kvector_t HomogeneousMaterial::magnetization() const
     return m_magnetization;
 }
 
-void HomogeneousMaterial::setMagnetization(const kvector_t magnetic_field)
+complex_t HomogeneousMaterial::materialData() const
 {
-    m_magnetization = magnetic_field;
+    return complex_t(1.0 - m_refractive_index.real(), m_refractive_index.imag());
 }
 
-complex_t HomogeneousMaterial::scalarSLD(const WavevectorInfo& wavevectors) const
+complex_t HomogeneousMaterial::scalarSubtrSLD(const WavevectorInfo& wavevectors) const
 {
     double wavelength = wavevectors.getWavelength();
     double prefactor = M_PI/wavelength/wavelength;
-    complex_t refractive_index = refractiveIndex();
-    return prefactor * refractive_index * refractive_index;
+    return prefactor * refractiveIndex2(wavelength);
 }
 
-Eigen::Matrix2cd HomogeneousMaterial::polarizedSLD(const WavevectorInfo& wavevectors) const
+Eigen::Matrix2cd HomogeneousMaterial::polarizedSubtrSLD(const WavevectorInfo& wavevectors) const
 {
     cvector_t mag_ortho = OrthogonalToBaseVector(wavevectors.getQ(), m_magnetization);
-    complex_t unit_factor = scalarSLD(wavevectors);
+    complex_t unit_factor = scalarSubtrSLD(wavevectors);
     Eigen::Matrix2cd result;
     result = unit_factor*Unit_Matrix
             + Magnetization_Prefactor*Pauli_X*mag_ortho[0]
@@ -125,7 +120,8 @@ Eigen::Matrix2cd HomogeneousMaterial::polarizedSLD(const WavevectorInfo& wavevec
 HomogeneousMaterial HomogeneousMaterial::transformedMaterial(const Transform3D& transform) const
 {
     kvector_t transformed_field = transform.transformed(m_magnetization);
-    return HomogeneousMaterial(getName(), refractiveIndex(), transformed_field);
+    complex_t material_data = materialData();
+    return HomogeneousMaterial(getName(), material_data.real(), material_data.imag(), transformed_field);
 }
 
 void HomogeneousMaterial::print(std::ostream& ostr) const
@@ -161,8 +157,8 @@ Eigen::Matrix2cd PolarizedReducedPotential(complex_t n, kvector_t b_field,
 bool operator==(const HomogeneousMaterial& left, const HomogeneousMaterial& right)
 {
     if (left.getName() != right.getName()) return false;
-    if (left.refractiveIndex() != right.refractiveIndex()) return false;
     if (left.magnetization() != right.magnetization()) return false;
+    if (left.materialData() != right.materialData()) return false;
     return true;
 }
 
diff --git a/Core/Material/HomogeneousMaterial.h b/Core/Material/HomogeneousMaterial.h
index bf54256623e7ad7ccfb5693b5b52eb12b4fa6ba2..b4b642ac8df0e0e552035d3405a6c7a14570de5a 100644
--- a/Core/Material/HomogeneousMaterial.h
+++ b/Core/Material/HomogeneousMaterial.h
@@ -47,9 +47,8 @@ public:
     //! Constructs a material with inverted magnetization
     HomogeneousMaterial inverted() const;
 
-    complex_t refractiveIndex() const;
-    complex_t refractiveIndex2() const;
-    void setRefractiveIndex(const complex_t refractive_index);
+    complex_t refractiveIndex(double wavelength) const;
+    complex_t refractiveIndex2(double wavelength) const;
 
     //! Indicates whether the interaction with the material is scalar.
     //! This means that different polarization states will be diffracted equally
@@ -60,14 +59,15 @@ public:
     //! Get the magnetization (in A/m)
     kvector_t magnetization() const;
 
-    //! Set the magnetizationd (in A/m)
-    void setMagnetization(const kvector_t magnetization);
+    //! Returns underlying material data
+    complex_t materialData() const;
 
-    complex_t scalarSLD(const WavevectorInfo& wavevectors) const;
+    //! Returns \pi/(wl*wl) - sld, with wl being the wavelength
+    complex_t scalarSubtrSLD(const WavevectorInfo& wavevectors) const;
 
 #ifndef SWIG
-    //! Get the scattering matrix for a material defined by its magnetization
-    Eigen::Matrix2cd polarizedSLD(const WavevectorInfo& wavevectors) const;
+    //! Returns \pi/(wl*wl) - sld matrix with magnetization corrections. wl denotes the wavelength
+    Eigen::Matrix2cd polarizedSubtrSLD(const WavevectorInfo& wavevectors) const;
 #endif
 
     HomogeneousMaterial transformedMaterial(const Transform3D& transform) const;
diff --git a/Core/Multilayer/Layer.cpp b/Core/Multilayer/Layer.cpp
index f3c8acf9ee734205ca115e17133623e30f376193..2369397c5c2c39dee081515cb6f9a1c7e201a06f 100644
--- a/Core/Multilayer/Layer.cpp
+++ b/Core/Multilayer/Layer.cpp
@@ -65,16 +65,6 @@ void Layer::setMaterial(HomogeneousMaterial material)
     m_material = std::move(material);
 }
 
-complex_t Layer::refractiveIndex() const
-{
-    return m_material.refractiveIndex();
-}
-
-complex_t Layer::refractiveIndex2() const
-{
-    return m_material.refractiveIndex2();
-}
-
 void Layer::addLayout(const ILayout& layout)
 {
     ILayout* clone = layout.clone();
@@ -153,13 +143,13 @@ SafePointerVector<Layer> Layer::slice(ZLimits limits, Layer::ELayerType layer_ty
 
 complex_t Layer::scalarReducedPotential(kvector_t k, double n_ref) const
 {
-    complex_t n = m_material.refractiveIndex();
+    complex_t n = m_material.refractiveIndex(2.0 * M_PI / k.mag());
     return ScalarReducedPotential(n, k, n_ref);
 }
 
 Eigen::Matrix2cd Layer::polarizedReducedPotential(kvector_t k, double n_ref) const
 {
-    complex_t n = m_material.refractiveIndex();
+    complex_t n = m_material.refractiveIndex(2.0 * M_PI / k.mag());
     kvector_t b_field = bField();
     return PolarizedReducedPotential(n, b_field, k, n_ref);
 }
diff --git a/Core/Multilayer/Layer.h b/Core/Multilayer/Layer.h
index 153e9f370191491650127b0912f43b6b87fb392a..d2c5fdfada2ffc2139fd51896b126288ad9d0540 100644
--- a/Core/Multilayer/Layer.h
+++ b/Core/Multilayer/Layer.h
@@ -51,9 +51,6 @@ public:
     const HomogeneousMaterial* material() const override final { return &m_material; }
     void setMaterial(HomogeneousMaterial material);
 
-    complex_t refractiveIndex() const;
-    complex_t refractiveIndex2() const; //!< squared refractive index
-
     void addLayout(const ILayout& decoration);
     size_t numberOfLayouts() const { return m_layouts.size(); }
     std::vector<const ILayout*> layouts() const;
diff --git a/Core/Multilayer/SpecularMagnetic.cpp b/Core/Multilayer/SpecularMagnetic.cpp
index 74733e328e7750fceb75bd06951691ee6f44af76..a7c34dc402e78cc26434eda789c090b5c01b17c5 100644
--- a/Core/Multilayer/SpecularMagnetic.cpp
+++ b/Core/Multilayer/SpecularMagnetic.cpp
@@ -40,7 +40,7 @@ void SpecularMagnetic::calculateEigenvalues(
     const MultiLayer& sample, const kvector_t k, std::vector<MatrixRTCoefficients>& coeff)
 {
     double mag_k = k.mag();
-    double n_ref = sample.layer(0)->refractiveIndex().real();
+    double n_ref = sample.layer(0)->material()->refractiveIndex(2 * M_PI / mag_k).real();
     double sign_kz = k.z() > 0.0 ? -1.0 : 1.0;
     for(size_t i=0; i<coeff.size(); ++i) {
         coeff[i].m_scatt_matrix = sample.layer(i)->polarizedReducedPotential(k, n_ref);
diff --git a/Core/Multilayer/SpecularMatrix.cpp b/Core/Multilayer/SpecularMatrix.cpp
index d28508fc1d9371ae48e3fdbda2c1887e4ac6fb8a..66c881077740c81aa074f0ef5a9bec92760ad24e 100644
--- a/Core/Multilayer/SpecularMatrix.cpp
+++ b/Core/Multilayer/SpecularMatrix.cpp
@@ -49,7 +49,7 @@ void SpecularMatrix::execute(const MultiLayer& sample, const kvector_t k,
     coeff.clear();
     coeff.resize(N);
 
-    double n_ref = sample.layer(0)->refractiveIndex().real();
+    double n_ref = sample.layer(0)->material()->refractiveIndex(2 * M_PI / k.mag()).real();
 
     // Calculate refraction angle, expressed as lambda or k_z, for each layer.
     double sign_kz_out = k.z() > 0.0 ? -1.0 : 1.0;
diff --git a/Core/Particle/Particle.cpp b/Core/Particle/Particle.cpp
index 859c98e8db86921fb2d5c97d00feb7d4db783682..017434b55d820cbd606ed054aa8a62ed2280d194 100644
--- a/Core/Particle/Particle.cpp
+++ b/Core/Particle/Particle.cpp
@@ -85,11 +85,6 @@ void Particle::setMaterial(HomogeneousMaterial material)
     m_material = std::move(material);
 }
 
-complex_t Particle::refractiveIndex() const
-{
-    return m_material.refractiveIndex();
-}
-
 void Particle::setFormFactor(const IFormFactor& form_factor)
 {
     if (&form_factor != mP_form_factor.get()) {
diff --git a/Core/Particle/Particle.h b/Core/Particle/Particle.h
index 59bb2e165f9212bb9632d99811bd78be67fe6d7e..467f39ae0c46b681a34bfc39a133c5b707faf7ee 100644
--- a/Core/Particle/Particle.h
+++ b/Core/Particle/Particle.h
@@ -42,8 +42,6 @@ public:
     void setMaterial(HomogeneousMaterial material);
     const HomogeneousMaterial* material() const override final { return &m_material; }
 
-    complex_t refractiveIndex() const;
-
     void setFormFactor(const IFormFactor& form_factor);
 
     std::vector<const INode*> getChildren() const override final;
diff --git a/Core/Simulation/Simulation.cpp b/Core/Simulation/Simulation.cpp
index 67f83bc2041ead0c58747cde1689b1525438dbaf..189e980b7703411259c1980d1f85bf915a143327 100644
--- a/Core/Simulation/Simulation.cpp
+++ b/Core/Simulation/Simulation.cpp
@@ -215,7 +215,7 @@ void Simulation::runSingleSimulation()
     if (m_options.getNumberOfThreads() == 1) {
         // Single thread.
         std::unique_ptr<MainComputation> P_computation(
-            new MainComputation(*sample(), m_options, m_progress, batch_start, batch_end));
+            new MainComputation(*sample(), m_instrument, m_options, m_progress, batch_start, batch_end));
         P_computation->run(); // the work is done here
         if (!P_computation->isCompleted()) {
             std::string message = P_computation->errorMessage();
@@ -246,7 +246,7 @@ void Simulation::runSingleSimulation()
             else
                 end_it = batch_start + end_thread_index;
             computations.emplace_back(
-                new MainComputation(*sample(), m_options, m_progress, begin_it, end_it));
+                new MainComputation(*sample(), m_instrument, m_options, m_progress, begin_it, end_it));
         }
 
         // Run simulations in n threads.
diff --git a/Core/Tools/Precomputed.cpp b/Core/Tools/Precomputed.cpp
deleted file mode 100644
index 2668158387481ac47f58a1d6550aa109f059647f..0000000000000000000000000000000000000000
--- a/Core/Tools/Precomputed.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-// ************************************************************************** //
-//
-//  BornAgain: simulate and fit scattering at grazing incidence
-//
-//! @file      Core/Tools/Precomputed.cpp
-//! @brief     Implements class Precomputed, providing precomputed constants
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2016
-//! @authors   Scientific Computing Group at MLZ Garching
-//! @authors   J. Fisher, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke
-//
-// ************************************************************************** //
-
-#include "Precomputed.h"
-#include <cmath>
-
-//! Precompute things upon class instantiation.
-
-Precomputed::Precomputed()
-{
-    // Precompute the factorial: factorial[k] = k!
-    double fac = 1;
-    for( int k=1; std::isfinite(fac); ++k ){
-        factorial.push_back( fac );
-        fac *= k;
-    }
-    // Precompute the reciprocal factorial: reciprocal_factorial[k] = 1/k!
-    for( size_t k=0; k<factorial.size(); ++k ){
-        reciprocal_factorial.push_back( 1/factorial[k] );
-    }
-}
diff --git a/Core/Tools/Precomputed.h b/Core/Tools/Precomputed.h
index 7ae087265a612ff2c52e2006a68b6d89acf1bc05..ee498060e8d498bf9eefbdd5ac34650c16ffe2c5 100644
--- a/Core/Tools/Precomputed.h
+++ b/Core/Tools/Precomputed.h
@@ -18,18 +18,36 @@
 
 #include "WinDllMacros.h"
 #include "ISingleton.h"
+#include <array>
+#include <utility>
 #include <vector>
 
-//! This class contains precomputed constants.
+//! Compile-time generated std::array of reciprocal factorials
+namespace Precomputed
+{
+template<size_t N>
+struct ReciprocalFactorial
+{
+    static constexpr double value = ReciprocalFactorial<N-1>::value/N;
+};
+
+template<>
+struct ReciprocalFactorial<0>
+{
+    static constexpr double value = 1.0;
+};
+
+template<template<size_t> class F, size_t... I>
+constexpr std::array<double, sizeof...(I)> GenerateArrayHelper(std::index_sequence<I...>)
+{
+    return { F<I>::value... };
+};
 
-class BA_CORE_API_ Precomputed : public ISingleton<Precomputed>
+template<size_t N, typename Indices = std::make_index_sequence<N>>
+constexpr std::array<double, N> GenerateReciprocalFactorialArray()
 {
-    friend class ISingleton<Precomputed>;
-public:
-    std::vector<double> factorial; //!< factorial[k] = k! for k=0,1,...,170 (for IEEE double).
-    std::vector<double> reciprocal_factorial; //!< 1/k!
-private:
-    Precomputed(); //!< Constructor, precomputes everything.
+    return GenerateArrayHelper<ReciprocalFactorial>(Indices{});
 };
+}  // namespace Precomputed
 
 #endif // PRECOMPUTED_H
diff --git a/GUI/coregui/Models/BeamItem.cpp b/GUI/coregui/Models/BeamItem.cpp
index 3a06699bcba052343002afee11d6e314f0d76316..162b6ce08b27284383ea7d5fafe9d5e496ef1bed 100644
--- a/GUI/coregui/Models/BeamItem.cpp
+++ b/GUI/coregui/Models/BeamItem.cpp
@@ -125,5 +125,7 @@ std::unique_ptr<Beam> BeamItem::createBeam() const
     double azimuthal_angle = Units::deg2rad(getAzimuthalAngle());
     result->setCentralK(lambda, inclination_angle, azimuthal_angle);
 
+    result->setPolarization(getVectorItem(P_POLARIZATION));
+
     return result;
 }
diff --git a/GUI/coregui/Models/DetectorItems.cpp b/GUI/coregui/Models/DetectorItems.cpp
index 7b55b29deab6881f0c0f23c0789e8cc2b64cd968..817ea8a0fcd4af5fa3adb32c1c473582c9ba5a56 100644
--- a/GUI/coregui/Models/DetectorItems.cpp
+++ b/GUI/coregui/Models/DetectorItems.cpp
@@ -30,7 +30,7 @@ const QString analyzer_transmission_tooltip = "Total transmission of the polariz
 }
 
 const QString DetectorItem::T_MASKS = "Masks";
-const QString DetectorItem::P_RESOLUTION_FUNCTION = "ResolutionFunctions";
+const QString DetectorItem::P_RESOLUTION_FUNCTION = "Resolution function";
 const QString DetectorItem::P_ANALYZER_DIRECTION = "Analyzer direction";
 const QString DetectorItem::P_ANALYZER_EFFICIENCY = "Analyzer efficiency";
 const QString DetectorItem::P_ANALYZER_TOTAL_TRANSMISSION = "Total transmission";
@@ -59,6 +59,12 @@ std::unique_ptr<IDetector2D> DetectorItem::createDetector() const
     if (auto resFunc = createResolutionFunction())
         result->setResolutionFunction(*resFunc);
 
+    kvector_t analyzer_dir = getVectorItem(P_ANALYZER_DIRECTION);
+    double analyzer_eff = getItemValue(P_ANALYZER_EFFICIENCY).toDouble();
+    double analyzer_total_trans = getItemValue(P_ANALYZER_TOTAL_TRANSMISSION).toDouble();
+    if (analyzer_dir.mag() > 0.0)
+        result->setAnalyzerProperties(analyzer_dir, analyzer_eff, analyzer_total_trans);
+
     return result;
 }
 
diff --git a/GUI/coregui/Models/GUIObjectBuilder.cpp b/GUI/coregui/Models/GUIObjectBuilder.cpp
index b76898e67463141fd37e4f0ca897dee168444441..77660561dfe9ba68c021694c15fdda621b19c3ec 100644
--- a/GUI/coregui/Models/GUIObjectBuilder.cpp
+++ b/GUI/coregui/Models/GUIObjectBuilder.cpp
@@ -130,7 +130,8 @@ SessionItem* GUIObjectBuilder::populateDocumentModel(DocumentModel* p_document_m
     Q_ASSERT(p_options_item);
     if (simulation.getOptions().isIntegrate()) {
         p_options_item->setComputationMethod(Constants::SIMULATION_MONTECARLO);
-        p_options_item->setNumberOfMonteCarloPoints(static_cast<int>(simulation.getOptions().getMcPoints()));
+        p_options_item->setNumberOfMonteCarloPoints(
+                    static_cast<int>(simulation.getOptions().getMcPoints()));
     }
     if (simulation.getOptions().useAvgMaterials()) {
         p_options_item->setFresnelMaterialMethod(Constants::AVERAGE_LAYER_MATERIAL);
@@ -196,7 +197,10 @@ void GUIObjectBuilder::visit(const MultiLayer* p_sample)
     SessionItem* p_multilayer_item =
             m_sampleModel->insertNewItem(Constants::MultiLayerType);
     p_multilayer_item->setItemName(p_sample->getName().c_str());
-    p_multilayer_item->setItemValue(MultiLayerItem::P_CROSS_CORR_LENGTH, p_sample->crossCorrLength());
+    p_multilayer_item->setItemValue(MultiLayerItem::P_CROSS_CORR_LENGTH,
+                                    p_sample->crossCorrLength());
+    p_multilayer_item->setVectorItem(MultiLayerItem::P_EXTERNAL_FIELD,
+                                     p_sample->externalField());
     m_levelToParentItem[depth()] = p_multilayer_item;
     m_itemToSample[p_multilayer_item] = p_sample;
 }
@@ -251,21 +255,9 @@ void GUIObjectBuilder::visit(const Crystal* p_sample)
     auto vector_b = lattice.getBasisVectorB();
     auto vector_c = lattice.getBasisVectorC();
 
-    SessionItem* p_vector_a_item = p_mesocrystal_item->getItem(MesoCrystalItem::P_VECTOR_A);
-    SessionItem* p_vector_b_item = p_mesocrystal_item->getItem(MesoCrystalItem::P_VECTOR_B);
-    SessionItem* p_vector_c_item = p_mesocrystal_item->getItem(MesoCrystalItem::P_VECTOR_C);
-    Q_ASSERT(p_vector_a_item);
-    Q_ASSERT(p_vector_b_item);
-    Q_ASSERT(p_vector_c_item);
-    p_vector_a_item->setItemValue(VectorItem::P_X, vector_a.x());
-    p_vector_a_item->setItemValue(VectorItem::P_Y, vector_a.y());
-    p_vector_a_item->setItemValue(VectorItem::P_Z, vector_a.z());
-    p_vector_b_item->setItemValue(VectorItem::P_X, vector_b.x());
-    p_vector_b_item->setItemValue(VectorItem::P_Y, vector_b.y());
-    p_vector_b_item->setItemValue(VectorItem::P_Z, vector_b.z());
-    p_vector_c_item->setItemValue(VectorItem::P_X, vector_c.x());
-    p_vector_c_item->setItemValue(VectorItem::P_Y, vector_c.y());
-    p_vector_c_item->setItemValue(VectorItem::P_Z, vector_c.z());
+    p_mesocrystal_item->setVectorItem(MesoCrystalItem::P_VECTOR_A, vector_a);
+    p_mesocrystal_item->setVectorItem(MesoCrystalItem::P_VECTOR_B, vector_b);
+    p_mesocrystal_item->setVectorItem(MesoCrystalItem::P_VECTOR_C, vector_c);
 
     // Since there is no CrystalItem, set the parent map to the MesoCrystalItem
     m_levelToParentItem[depth()] = p_mesocrystal_item;
@@ -583,7 +575,7 @@ void GUIObjectBuilder::visit(const RotationEuler* p_sample)
     Q_ASSERT(transformation_item);
     SessionItem* p_rotationItem = transformation_item->setGroupProperty(
                 TransformationItem::P_ROT, Constants::EulerRotationType);
-    p_rotationItem->setItemValue(EulerRotationItem::P_ALPHA,  Units::rad2deg(p_sample->getAlpha()) );
+    p_rotationItem->setItemValue(EulerRotationItem::P_ALPHA, Units::rad2deg(p_sample->getAlpha()) );
     p_rotationItem->setItemValue(EulerRotationItem::P_BETA, Units::rad2deg(p_sample->getBeta()) );
     p_rotationItem->setItemValue(EulerRotationItem::P_GAMMA, Units::rad2deg(p_sample->getGamma()) );
     m_levelToParentItem[depth()] = transformation_item;
@@ -592,11 +584,7 @@ void GUIObjectBuilder::visit(const RotationEuler* p_sample)
 void GUIObjectBuilder::buildPositionInfo(SessionItem* p_particle_item, const IParticle* p_sample)
 {
     kvector_t position = p_sample->position();
-    SessionItem* positionItem = p_particle_item->getItem(ParticleItem::P_POSITION);
-    Q_ASSERT(positionItem);
-    positionItem->setItemValue(VectorItem::P_X, position.x());
-    positionItem->setItemValue(VectorItem::P_Y, position.y());
-    positionItem->setItemValue(VectorItem::P_Z, position.z());
+    p_particle_item->setVectorItem(ParticleItem::P_POSITION, position);
 }
 
 MaterialProperty GUIObjectBuilder::createMaterialFromDomain(
@@ -609,15 +597,11 @@ MaterialProperty GUIObjectBuilder::createMaterialFromDomain(
 
     MaterialModel* model = MaterialSvc::getMaterialModel();
 
-    if(material->isScalarMaterial()) {
-        complex_t rindex = material->refractiveIndex();
-        MaterialItem* materialItem  =
-            model->addMaterial(materialName, 1-rindex.real(),rindex.imag());
-        return MaterialProperty(materialItem->getIdentifier());
-    } else {
-        throw GUIHelpers::Error("GUIObjectBuilder::createMaterialFromDomain()"
-                                " -> Not implemented.");
-    }
+    complex_t material_data = material->materialData();
+    MaterialItem* materialItem  =
+            model->addMaterial(materialName, material_data.real(),material_data.imag());
+    materialItem->setVectorItem(MaterialItem::P_MAGNETIZATION, material->magnetization());
+    return MaterialProperty(materialItem->getIdentifier());
 }
 
 SessionItem* GUIObjectBuilder::InsertIParticle(const IParticle* p_particle, QString model_type)
diff --git a/GUI/coregui/Models/ItemFactory.cpp b/GUI/coregui/Models/ItemFactory.cpp
index 3be70463ea4579c13ebf7f8521976217f98dfbfd..1ee580d1ab2f49f890dfeae5928ec7f2b58b40ab 100644
--- a/GUI/coregui/Models/ItemFactory.cpp
+++ b/GUI/coregui/Models/ItemFactory.cpp
@@ -36,7 +36,6 @@
 #include "Lattice2DItems.h"
 #include "LayerItem.h"
 #include "LayerRoughnessItems.h"
-#include "MagneticFieldItem.h"
 #include "MaskItems.h"
 #include "MaterialItem.h"
 #include "MesoCrystalItem.h"
@@ -50,13 +49,13 @@
 #include "ParticleLayoutItem.h"
 #include "PropertyItem.h"
 #include "RealDataItem.h"
-#include "RefractiveIndexItem.h"
 #include "ResolutionFunctionItems.h"
 #include "RotationItems.h"
 #include "SimulationOptionsItem.h"
 #include "TransformationItem.h"
 #include "VectorItem.h"
 #include "LinkInstrumentItem.h"
+#include "MaterialDataItem.h"
 #include "RealLimitsItems.h"
 #include "ProjectionItems.h"
 
@@ -154,9 +153,7 @@ ItemFactory::ItemMap_t initializeItemMap() {
 
     result[Constants::HomogeneousMaterialType] = &createInstance<MaterialItem>;
 
-    result[Constants::RefractiveIndexType] = &createInstance<RefractiveIndexItem>;
-
-    result[Constants::MagneticFieldType] = &createInstance<MagneticFieldItem>;
+    result[Constants::MaterialDataType] = &createInstance<MaterialDataItem>;
 
     result[Constants::JobItemType] = &createInstance<JobItem>;
 
diff --git a/GUI/coregui/Models/MagneticFieldItem.cpp b/GUI/coregui/Models/MagneticFieldItem.cpp
deleted file mode 100644
index 7408cd565a6aa0f24bcf78359a75a3f934bc463e..0000000000000000000000000000000000000000
--- a/GUI/coregui/Models/MagneticFieldItem.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-// ************************************************************************** //
-//
-//  BornAgain: simulate and fit scattering at grazing incidence
-//
-//! @file      GUI/coregui/Models/MagneticFieldItem.cpp
-//! @brief     Implements class MagneticFieldItem
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2016
-//! @authors   Scientific Computing Group at MLZ Garching
-//! @authors   Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov
-//! @authors   Walter Van Herck, Joachim Wuttke
-//
-// ************************************************************************** //
-
-#include "MagneticFieldItem.h"
-
-const QString MagneticFieldItem::P_BX = "Bx";
-const QString MagneticFieldItem::P_BY = "By";
-const QString MagneticFieldItem::P_BZ = "Bz";
-
-MagneticFieldItem::MagneticFieldItem()
-    : SessionItem(Constants::MagneticFieldType)
-{
-    addProperty(P_BX, 0.0);
-    addProperty(P_BY, 0.0);
-    addProperty(P_BZ, 0.0);
-}
-
-QString MagneticFieldItem::itemLabel() const
-{
-    return QString("(%1, %2, %3)").arg(getItemValue(P_BX).toDouble())
-                                  .arg(getItemValue(P_BY).toDouble())
-                                  .arg(getItemValue(P_BZ).toDouble());
-}
diff --git a/GUI/coregui/Models/MagneticFieldItem.h b/GUI/coregui/Models/MagneticFieldItem.h
deleted file mode 100644
index 9146ab8210856c0187b3bf866ec119db2d27aa7d..0000000000000000000000000000000000000000
--- a/GUI/coregui/Models/MagneticFieldItem.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// ************************************************************************** //
-//
-//  BornAgain: simulate and fit scattering at grazing incidence
-//
-//! @file      GUI/coregui/Models/MagneticFieldItem.h
-//! @brief     Defines class MagneticFieldItem
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2016
-//! @authors   Scientific Computing Group at MLZ Garching
-//! @authors   Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov
-//! @authors   Walter Van Herck, Joachim Wuttke
-//
-// ************************************************************************** //
-
-#ifndef MAGNETICFIELDITEM_H
-#define MAGNETICFIELDITEM_H
-
-
-#include "SessionItem.h"
-
-class BA_CORE_API_ MagneticFieldItem : public SessionItem
-{
-
-public:
-    static const QString P_BX;
-    static const QString P_BY;
-    static const QString P_BZ;
-    explicit MagneticFieldItem();
-    virtual ~MagneticFieldItem() {}
-    virtual QString itemLabel() const;
-};
-
-
-
-#endif // MAGNETICFIELDITEM_H
-
diff --git a/GUI/coregui/Models/MaterialDataItem.cpp b/GUI/coregui/Models/MaterialDataItem.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f310c61a95f12e516e6e5ee6fc1efcfd775e88a4
--- /dev/null
+++ b/GUI/coregui/Models/MaterialDataItem.cpp
@@ -0,0 +1,72 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      GUI/coregui/Models/RefractiveIndexItem.cpp
+//! @brief     Implements class RefractiveIndexItem
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2016
+//! @authors   Scientific Computing Group at MLZ Garching
+//! @authors   Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov
+//! @authors   Walter Van Herck, Joachim Wuttke
+//
+// ************************************************************************** //
+
+#include "MaterialDataItem.h"
+
+#include "ScientificDoubleProperty.h"
+
+
+const QString MaterialDataItem::P_REAL = "real";
+const QString MaterialDataItem::P_IMAG = "imag";
+
+
+MaterialDataItem::MaterialDataItem()
+    : SessionItem(Constants::MaterialDataType)
+{
+    ScientificDoubleProperty real(0.0);
+    addProperty(P_REAL, real.getVariant());
+
+    ScientificDoubleProperty imag(0.0);
+    addProperty(P_IMAG, imag.getVariant());
+
+    mapper()->setOnPropertyChange(
+        [this](const QString &){
+            setValue(itemLabel());
+        }
+    );
+
+    setValue(itemLabel());
+    setEditable(false);
+}
+
+QString MaterialDataItem::itemLabel() const
+{
+    return QString("(1 - %1, %2)").arg(getReal()).arg(getImag());
+}
+
+double MaterialDataItem::getReal() const
+{
+    return getItemValue(P_REAL).value<ScientificDoubleProperty>().getValue();
+}
+
+void MaterialDataItem::setReal(double real)
+{
+    ScientificDoubleProperty property = getItemValue(P_REAL).value<ScientificDoubleProperty>();
+    property.setValue(real);
+    setItemValue(P_REAL, property.getVariant());
+}
+
+double MaterialDataItem::getImag() const
+{
+    return getItemValue(P_IMAG).value<ScientificDoubleProperty>().getValue();
+}
+
+void MaterialDataItem::setImag(double imag)
+{
+    ScientificDoubleProperty property = getItemValue(P_IMAG).value<ScientificDoubleProperty>();
+    property.setValue(imag);
+    setItemValue(P_IMAG, property.getVariant());
+}
diff --git a/GUI/coregui/Models/RefractiveIndexItem.h b/GUI/coregui/Models/MaterialDataItem.h
similarity index 65%
rename from GUI/coregui/Models/RefractiveIndexItem.h
rename to GUI/coregui/Models/MaterialDataItem.h
index 13a02f98c0c97b616e8644f436f95c68c362d0c1..218667fcebef950be2ede4ff2ac4ee098742211d 100644
--- a/GUI/coregui/Models/RefractiveIndexItem.h
+++ b/GUI/coregui/Models/MaterialDataItem.h
@@ -14,26 +14,26 @@
 //
 // ************************************************************************** //
 
-#ifndef REFRACTIVEINDEXITEM_H
-#define REFRACTIVEINDEXITEM_H
+#ifndef MATERIALDATAITEM_H
+#define MATERIALDATAITEM_H
 
 #include "SessionItem.h"
 
-class BA_CORE_API_ RefractiveIndexItem : public SessionItem
+class BA_CORE_API_ MaterialDataItem : public SessionItem
 {
 
 public:
-    static const QString P_DELTA;
-    static const QString P_BETA;
-    explicit RefractiveIndexItem();
-    virtual ~RefractiveIndexItem(){}
+    static const QString P_REAL;
+    static const QString P_IMAG;
+    explicit MaterialDataItem();
+    virtual ~MaterialDataItem(){}
     virtual QString itemLabel() const;
 
-    double getDelta() const;
-    void setDelta(double delta);
+    double getReal() const;
+    void setReal(double real);
 
-    double getBeta() const;
-    void setBeta(double beta);
+    double getImag() const;
+    void setImag(double imag);
 };
 
-#endif // REFRACTIVEINDEXITEM_H
+#endif // MATERIALDATAITEM_H
diff --git a/GUI/coregui/Models/MaterialItem.cpp b/GUI/coregui/Models/MaterialItem.cpp
index d6c5cfb10172491d3aea27739df3bb9d18a88299..ea85ac6c4afbb91c9813ceb5cca720c256efeed3 100644
--- a/GUI/coregui/Models/MaterialItem.cpp
+++ b/GUI/coregui/Models/MaterialItem.cpp
@@ -17,8 +17,8 @@
 #include "MaterialItem.h"
 #include "GUIHelpers.h"
 #include "HomogeneousMaterial.h"
+#include "MaterialDataItem.h"
 #include "MaterialUtils.h"
-#include "RefractiveIndexItem.h"
 
 
 namespace {
@@ -27,7 +27,7 @@ const QString magnetization_tooltip =
 }
 
 const QString MaterialItem::P_COLOR = "Color";
-const QString MaterialItem::P_REFRACTIVE_INDEX = "Refractive index";
+const QString MaterialItem::P_MATERIAL_DATA = "Material data";
 const QString MaterialItem::P_MAGNETIZATION = "Magnetization";
 const QString MaterialItem::P_IDENTIFIER = "Identifier";
 
@@ -38,7 +38,7 @@ MaterialItem::MaterialItem()
 
     ColorProperty color;
     addProperty(P_COLOR, color.getVariant());
-    addGroupProperty(P_REFRACTIVE_INDEX, Constants::RefractiveIndexType);
+    addGroupProperty(P_MATERIAL_DATA, Constants::MaterialDataType);
     addGroupProperty(P_MAGNETIZATION, Constants::VectorType)->setToolTip(magnetization_tooltip);
     addProperty(P_IDENTIFIER, GUIHelpers::createUuid());
     getItem(P_IDENTIFIER)->setVisible(false);
@@ -57,15 +57,16 @@ QColor MaterialItem::getColor() const
 
 std::unique_ptr<HomogeneousMaterial> MaterialItem::createMaterial() const
 {
-    const RefractiveIndexItem *refractiveIndexItem
-        = dynamic_cast<const RefractiveIndexItem *>(
-            getItem(MaterialItem::P_REFRACTIVE_INDEX));
+    const MaterialDataItem* materialDataItem
+        = dynamic_cast<const MaterialDataItem*>(getItem(MaterialItem::P_MATERIAL_DATA));
 
-    Q_ASSERT(refractiveIndexItem);
+    Q_ASSERT(materialDataItem);
 
-    double delta = refractiveIndexItem->getDelta();
-    double beta = refractiveIndexItem->getBeta();
+    double real = materialDataItem->getReal();
+    double imag = materialDataItem->getImag();
 
-    return std::make_unique<HomogeneousMaterial>(
-                itemName().toStdString(), delta, beta);
+    auto magnetization = getVectorItem(P_MAGNETIZATION);
+
+    return std::make_unique<HomogeneousMaterial>(itemName().toStdString(), real, imag,
+                                                 magnetization);
 }
diff --git a/GUI/coregui/Models/MaterialItem.h b/GUI/coregui/Models/MaterialItem.h
index 12d4f0f8e3c1efee78d362c8504f2c758d13ad73..517b530c1a53accbc2287ab7174618b7c0aefbc2 100644
--- a/GUI/coregui/Models/MaterialItem.h
+++ b/GUI/coregui/Models/MaterialItem.h
@@ -25,7 +25,7 @@ class BA_CORE_API_ MaterialItem : public SessionItem
 {
 public:
     static const QString P_COLOR;
-    static const QString P_REFRACTIVE_INDEX;
+    static const QString P_MATERIAL_DATA;
     static const QString P_MAGNETIZATION;
     static const QString P_IDENTIFIER;
     explicit MaterialItem();
diff --git a/GUI/coregui/Models/MaterialModel.cpp b/GUI/coregui/Models/MaterialModel.cpp
index 7af9a064679a393c5da485563e151372d4c53c61..45fed4afe18e322aa8781e3ae6d9088b771023b8 100644
--- a/GUI/coregui/Models/MaterialModel.cpp
+++ b/GUI/coregui/Models/MaterialModel.cpp
@@ -16,8 +16,8 @@
 
 #include "MaterialModel.h"
 #include "MaterialUtils.h"
-#include "RefractiveIndexItem.h"
 #include "GUIHelpers.h"
+#include "MaterialDataItem.h"
 
 MaterialModel::MaterialModel(QObject* parent) : SessionModel(SessionXML::MaterialModelTag, parent)
 {
@@ -31,18 +31,18 @@ MaterialModel* MaterialModel::createCopy(SessionItem* parent)
     return result;
 }
 
-MaterialItem* MaterialModel::addMaterial(const QString& name, double delta, double beta)
+MaterialItem* MaterialModel::addMaterial(const QString& name, double material_data_real, double material_data_imag)
 {
     MaterialItem* materialItem
         = dynamic_cast<MaterialItem*>(insertNewItem(Constants::HomogeneousMaterialType));
     materialItem->setItemName(name);
 
-    RefractiveIndexItem* refractiveIndexItem = dynamic_cast<RefractiveIndexItem*>(
-        materialItem->getItem(MaterialItem::P_REFRACTIVE_INDEX));
-    Q_ASSERT(refractiveIndexItem);
+    MaterialDataItem* materialDataItem = dynamic_cast<MaterialDataItem*>(
+        materialItem->getItem(MaterialItem::P_MATERIAL_DATA));
+    Q_ASSERT(materialDataItem);
 
-    refractiveIndexItem->setDelta(delta);
-    refractiveIndexItem->setBeta(beta);
+    materialDataItem->setReal(material_data_real);
+    materialDataItem->setImag(material_data_imag);
 
     materialItem->setItemValue(MaterialItem::P_COLOR,
                                MaterialUtils::suggestMaterialColorProperty(name).getVariant());
diff --git a/GUI/coregui/Models/MaterialModel.h b/GUI/coregui/Models/MaterialModel.h
index 4f248cc7f92eee88a1e5609943f8499d6cfc5db3..50ba0ad69dd9ec959cef29f25fe4743886a8e59a 100644
--- a/GUI/coregui/Models/MaterialModel.h
+++ b/GUI/coregui/Models/MaterialModel.h
@@ -32,7 +32,7 @@ public:
 
     virtual MaterialModel* createCopy(SessionItem* parent = 0);
 
-    MaterialItem* addMaterial(const QString& name, double delta = 0.0, double beta = 0.0);
+    MaterialItem* addMaterial(const QString& name, double material_data_real = 0.0, double material_data_imag = 0.0);
     void removeMaterial(MaterialItem*);
 
     MaterialItem* getMaterial(const QModelIndex& index);
diff --git a/GUI/coregui/Models/MesoCrystalItem.cpp b/GUI/coregui/Models/MesoCrystalItem.cpp
index bfd2138baa104f3aed2d26214bf83803e7500141..fef3b6b1cc091593d3658d9346add1932f1fff48 100644
--- a/GUI/coregui/Models/MesoCrystalItem.cpp
+++ b/GUI/coregui/Models/MesoCrystalItem.cpp
@@ -140,18 +140,9 @@ QStringList MesoCrystalItem::translateList(const QStringList& list) const
 
 Lattice MesoCrystalItem::getLattice() const
 {
-    SessionItem* lattice_vector1_item = getItem(P_VECTOR_A);
-    SessionItem* lattice_vector2_item = getItem(P_VECTOR_B);
-    SessionItem* lattice_vector3_item = getItem(P_VECTOR_C);
-    kvector_t a1(lattice_vector1_item->getItemValue(VectorItem::P_X).toDouble(),
-                 lattice_vector1_item->getItemValue(VectorItem::P_Y).toDouble(),
-                 lattice_vector1_item->getItemValue(VectorItem::P_Z).toDouble());
-    kvector_t a2(lattice_vector2_item->getItemValue(VectorItem::P_X).toDouble(),
-                 lattice_vector2_item->getItemValue(VectorItem::P_Y).toDouble(),
-                 lattice_vector2_item->getItemValue(VectorItem::P_Z).toDouble());
-    kvector_t a3(lattice_vector3_item->getItemValue(VectorItem::P_X).toDouble(),
-                 lattice_vector3_item->getItemValue(VectorItem::P_Y).toDouble(),
-                 lattice_vector3_item->getItemValue(VectorItem::P_Z).toDouble());
+    kvector_t a1 = getVectorItem(P_VECTOR_A);
+    kvector_t a2 = getVectorItem(P_VECTOR_B);
+    kvector_t a3 = getVectorItem(P_VECTOR_C);
     return Lattice(a1, a2, a3);
 }
 
diff --git a/GUI/coregui/Models/ParticleItem.cpp b/GUI/coregui/Models/ParticleItem.cpp
index 2c1ba14e8b05bbd02f1cbb7d0bf90ac15f46bbdb..d08859f48415795c9937778cd57dad128cdd7994 100644
--- a/GUI/coregui/Models/ParticleItem.cpp
+++ b/GUI/coregui/Models/ParticleItem.cpp
@@ -86,10 +86,9 @@ void ParticleItem::updatePropertiesAppearance(SessionItem* newParent)
         setItemValue(ParticleItem::P_ABUNDANCE, 1.0);
         getItem(ParticleItem::P_ABUNDANCE)->setEnabled(false);
         if (isShellParticle()) {
+            kvector_t zero_vector;
+            setVectorItem(ParticleItem::P_POSITION, zero_vector);
             SessionItem *positionItem = getItem(ParticleItem::P_POSITION);
-            positionItem->setItemValue(VectorItem::P_X, 0.0);
-            positionItem->setItemValue(VectorItem::P_Y, 0.0);
-            positionItem->setItemValue(VectorItem::P_Z, 0.0);
             positionItem->setEnabled(false);
         }
     } else {
diff --git a/GUI/coregui/Models/RefractiveIndexItem.cpp b/GUI/coregui/Models/RefractiveIndexItem.cpp
deleted file mode 100644
index 7f8d7cedd40f26bc90a5b0ee388f49c721d6c698..0000000000000000000000000000000000000000
--- a/GUI/coregui/Models/RefractiveIndexItem.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-// ************************************************************************** //
-//
-//  BornAgain: simulate and fit scattering at grazing incidence
-//
-//! @file      GUI/coregui/Models/RefractiveIndexItem.cpp
-//! @brief     Implements class RefractiveIndexItem
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2016
-//! @authors   Scientific Computing Group at MLZ Garching
-//! @authors   Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov
-//! @authors   Walter Van Herck, Joachim Wuttke
-//
-// ************************************************************************** //
-
-#include "RefractiveIndexItem.h"
-#include "ScientificDoubleProperty.h"
-
-
-const QString RefractiveIndexItem::P_DELTA = "delta";
-const QString RefractiveIndexItem::P_BETA = "beta";
-
-
-RefractiveIndexItem::RefractiveIndexItem()
-    : SessionItem(Constants::RefractiveIndexType)
-{
-    ScientificDoubleProperty delta(0.0);
-    addProperty(P_DELTA, delta.getVariant());
-
-    ScientificDoubleProperty beta(0.0);
-    addProperty(P_BETA, beta.getVariant());
-
-    mapper()->setOnPropertyChange(
-        [this](const QString &){
-            setValue(itemLabel());
-        }
-    );
-
-    setValue(itemLabel());
-    setEditable(false);
-}
-
-QString RefractiveIndexItem::itemLabel() const
-{
-    return QString("(1 - %1, %2)").arg(getDelta()).arg(getBeta());
-}
-
-double RefractiveIndexItem::getDelta() const
-{
-    return getItemValue(P_DELTA).value<ScientificDoubleProperty>().getValue();
-}
-
-void RefractiveIndexItem::setDelta(double delta)
-{
-    ScientificDoubleProperty property = getItemValue(P_DELTA).value<ScientificDoubleProperty>();
-    property.setValue(delta);
-    setItemValue(P_DELTA, property.getVariant());
-}
-
-double RefractiveIndexItem::getBeta() const
-{
-    return getItemValue(P_BETA).value<ScientificDoubleProperty>().getValue();
-}
-
-void RefractiveIndexItem::setBeta(double beta)
-{
-    ScientificDoubleProperty property = getItemValue(P_BETA).value<ScientificDoubleProperty>();
-    property.setValue(beta);
-    setItemValue(P_BETA, property.getVariant());
-}
diff --git a/GUI/coregui/Models/SessionItem.cpp b/GUI/coregui/Models/SessionItem.cpp
index 940aec854de71c3dfe076593aa29f4d05de7376d..3f037754e3a5a3c6505a9dfc9f69ae5d84c380fc 100644
--- a/GUI/coregui/Models/SessionItem.cpp
+++ b/GUI/coregui/Models/SessionItem.cpp
@@ -18,17 +18,18 @@
 #include "GroupItem.h"
 #include "GroupPropertyRegistry.h"
 #include "ItemFactory.h"
-#include "SessionModel.h"
 #include "ParameterTranslators.h"
+#include "SessionModel.h"
+#include "VectorItem.h"
 
 class SessionItemData
 {
 public:
     inline SessionItemData() : role(-1) {}
-    inline SessionItemData(int r, const QVariant &v) : role(r), value(v) {}
+    inline SessionItemData(int r, const QVariant& v) : role(r), value(v) {}
     int role;
     QVariant value;
-    inline bool operator==(const SessionItemData &other) const {
+    inline bool operator==(const SessionItemData& other) const {
         return role == other.role && value == other.value;
     }
 };
@@ -37,7 +38,7 @@ const QString SessionItem::P_NAME = "Name";
 
 //! Constructs new item with given model type. The type must be defined.
 
-SessionItem::SessionItem(const QString &modelType)
+SessionItem::SessionItem(const QString& modelType)
     : m_parent(nullptr)
     , m_model(nullptr)
 {
@@ -58,7 +59,7 @@ SessionItem::~SessionItem()
 
     QVector<SessionItem*>::const_iterator it;
     for (it = m_children.constBegin(); it != m_children.constEnd(); ++it) {
-        SessionItem *child = *it;
+        SessionItem* child = *it;
         if (child)
             child->setModel(nullptr);
         delete child;
@@ -72,7 +73,7 @@ SessionItem::~SessionItem()
 }
 
 //! internal
-void SessionItem::childDeleted(SessionItem *child)
+void SessionItem::childDeleted(SessionItem* child)
 {
     int index = rowOfChild(child);
     Q_ASSERT(index != -1);
@@ -80,21 +81,21 @@ void SessionItem::childDeleted(SessionItem *child)
 }
 
 //! internal
-void SessionItem::setParentAndModel(SessionItem *parent, SessionModel *model)
+void SessionItem::setParentAndModel(SessionItem* parent, SessionModel* model)
 {
     setModel(model);
     m_parent = parent;
 }
 
 //! internal
-void SessionItem::setModel(SessionModel *model)
+void SessionItem::setModel(SessionModel* model)
 {
     m_model = model;
     if (m_mapper) {
         m_mapper->setItem(this);
     }
     // process children as well
-    for (auto &child : m_children) {
+    for (auto& child : m_children) {
         child->setModel(model);
     }
 }
@@ -103,14 +104,14 @@ void SessionItem::setModel(SessionModel *model)
 
 //! Returns model of this item.
 
-SessionModel *SessionItem::model() const
+SessionModel* SessionItem::model() const
 {
     return m_model;
 }
 
 //! Returns parent of this item.
 
-SessionItem *SessionItem::parent() const
+SessionItem* SessionItem::parent() const
 {
     return m_parent;
 }
@@ -141,7 +142,7 @@ int SessionItem::rowCount() const
 
 //! Returns vector of all children.
 
-QVector<SessionItem *> SessionItem::childItems() const
+QVector<SessionItem*> SessionItem::childItems() const
 {
     return m_children;
 }
@@ -149,14 +150,14 @@ QVector<SessionItem *> SessionItem::childItems() const
 
 //! Returns the child at the given row.
 
-SessionItem *SessionItem::childAt(int row) const
+SessionItem* SessionItem::childAt(int row) const
 {
     return m_children.value(row, nullptr);
 }
 
 //! Returns row index of given child.
 
-int SessionItem::rowOfChild(SessionItem *child) const
+int SessionItem::rowOfChild(SessionItem* child) const
 {
     return m_children.indexOf(child);
 }
@@ -172,7 +173,7 @@ int SessionItem::parentRow() const
 }
 
 //! Returns the first child with the given name.
-SessionItem *SessionItem::getChildByName(const QString &name) const
+SessionItem* SessionItem::getChildByName(const QString& name) const
 {
     for (auto child : m_children) {
         if (child->itemName() == name) return child;
@@ -182,7 +183,7 @@ SessionItem *SessionItem::getChildByName(const QString &name) const
 
 //! Returns the first child of the given type.
 
-SessionItem *SessionItem::getChildOfType(const QString &type) const
+SessionItem* SessionItem::getChildOfType(const QString& type) const
 {
     for (auto child : m_children) {
         if (child->modelType() == type) return child;
@@ -192,9 +193,9 @@ SessionItem *SessionItem::getChildOfType(const QString &type) const
 
 //! Returns a vector of all children of the given type.
 
-QVector<SessionItem *> SessionItem::getChildrenOfType(const QString &model_type) const
+QVector<SessionItem*> SessionItem::getChildrenOfType(const QString& model_type) const
 {
-    QVector<SessionItem *> result;
+    QVector<SessionItem*> result;
     for (auto child : m_children) {
         if (child->modelType() == model_type)
             result.append(child);
@@ -204,9 +205,9 @@ QVector<SessionItem *> SessionItem::getChildrenOfType(const QString &model_type)
 
 //! Removes row from item and returns the item.
 
-SessionItem *SessionItem::takeRow(int row)
+SessionItem* SessionItem::takeRow(int row)
 {
-    SessionItem *item = childAt(row);
+    SessionItem* item = childAt(row);
     QString tag = tagFromItem(item);
     auto items = getItems(tag);
     return takeItem(items.indexOf(item), tag);
@@ -215,7 +216,7 @@ SessionItem *SessionItem::takeRow(int row)
 //! Add new tag to this item with given name, min, max and types.
 //! max = -1 -> unlimited, modelTypes empty -> all types allowed
 
-bool SessionItem::registerTag(const QString &name, int min, int max, QStringList modelTypes)
+bool SessionItem::registerTag(const QString& name, int min, int max, QStringList modelTypes)
 {
     if (min < 0 || (min > max && max >= 0))
         return false;
@@ -227,14 +228,14 @@ bool SessionItem::registerTag(const QString &name, int min, int max, QStringList
 
 //! Returns true if tag is available.
 
-bool SessionItem::isTag(const QString &name) const
+bool SessionItem::isTag(const QString& name) const
 {
     return getTagInfo(name).isValid();
 }
 
 //! Returns the tag name of given item when existing.
 
-QString SessionItem::tagFromItem(const SessionItem *item) const
+QString SessionItem::tagFromItem(const SessionItem* item) const
 {
     int index = m_children.indexOf(const_cast<SessionItem*>(item));
     if (index == -1)
@@ -253,7 +254,7 @@ QString SessionItem::tagFromItem(const SessionItem *item) const
 
 //! Returns corresponding tag info.
 
-SessionTagInfo SessionItem::getTagInfo(const QString &tag) const
+SessionTagInfo SessionItem::getTagInfo(const QString& tag) const
 {
     QString tagName = tag.isEmpty() ? defaultTag() : tag;
     QVector<SessionTagInfo>::const_iterator it;
@@ -267,7 +268,7 @@ SessionTagInfo SessionItem::getTagInfo(const QString &tag) const
 
 //! Returns true if model type can be added to default tag.
 
-bool SessionItem::acceptsAsDefaultItem(const QString &item_name) const
+bool SessionItem::acceptsAsDefaultItem(const QString& item_name) const
 {
     return getTagInfo(defaultTag()).modelTypes.contains(item_name);
 }
@@ -280,7 +281,7 @@ QVector<QString> SessionItem::acceptableDefaultItemTypes() const
 }
 
 //! internal
-int SessionItem::tagStartIndex(const QString &name) const
+int SessionItem::tagStartIndex(const QString& name) const
 {
     int index = 0;
     QVector<SessionTagInfo>::const_iterator it;
@@ -297,7 +298,7 @@ int SessionItem::tagStartIndex(const QString &name) const
 
 //! Returns item in given row of given tag.
 
-SessionItem *SessionItem::getItem(const QString &tag, int row) const
+SessionItem* SessionItem::getItem(const QString& tag, int row) const
 {
     const QString tagName = tag.isEmpty() ? defaultTag() : tag;
     SessionTagInfo tagInfo = getTagInfo(tagName);
@@ -314,7 +315,7 @@ SessionItem *SessionItem::getItem(const QString &tag, int row) const
 
 //! Returns vector of all items of given tag.
 
-QVector<SessionItem *> SessionItem::getItems(const QString &tag) const
+QVector<SessionItem*> SessionItem::getItems(const QString& tag) const
 {
     const QString tagName = tag.isEmpty() ? defaultTag() : tag;
     SessionTagInfo tagInfo = getTagInfo(tagName);
@@ -327,7 +328,7 @@ QVector<SessionItem *> SessionItem::getItems(const QString &tag) const
 
 //! Insert item into given tag into given row.
 
-bool SessionItem::insertItem(int row, SessionItem *item, const QString &tag)
+bool SessionItem::insertItem(int row, SessionItem* item, const QString& tag)
 {
     if (!item)
         return false;
@@ -373,7 +374,7 @@ bool SessionItem::insertItem(int row, SessionItem *item, const QString &tag)
 
 //! Remove item from given row from given tag.
 
-SessionItem *SessionItem::takeItem(int row, const QString &tag)
+SessionItem* SessionItem::takeItem(int row, const QString& tag)
 {
     const QString tagName = tag.isEmpty() ? defaultTag() : tag;
     SessionTagInfo tagInfo = getTagInfo(tagName);
@@ -387,7 +388,7 @@ SessionItem *SessionItem::takeItem(int row, const QString &tag)
     Q_ASSERT(index >= 0 && index <= m_children.size());
     if (m_model)
             m_model->beginRemoveRows(this->index(),index, index);
-    SessionItem *result = m_children.takeAt(index);
+    SessionItem* result = m_children.takeAt(index);
     result->setParentAndModel(nullptr, nullptr);
 
     QVector<SessionTagInfo>::iterator it;
@@ -405,14 +406,14 @@ SessionItem *SessionItem::takeItem(int row, const QString &tag)
 
 //! Add new property item and register new tag.
 
-SessionItem *SessionItem::addProperty(const QString &name, const QVariant &variant)
+SessionItem* SessionItem::addProperty(const QString& name, const QVariant& variant)
 {
     if (isTag(name))
         throw GUIHelpers::Error(
             "ParameterizedItem::registerProperty() -> Error. Already existing property " + name);
 
     const QString property_type = Constants::PropertyType;
-    SessionItem *property = ItemFactory::createItem(property_type);
+    SessionItem* property = ItemFactory::createItem(property_type);
     property->setDisplayName(name);
     registerTag(name, 1, 1, QStringList() << property_type);
     if(!insertItem(0, property, name)) {
@@ -424,7 +425,7 @@ SessionItem *SessionItem::addProperty(const QString &name, const QVariant &varia
 
 //! Directly access value of item under given tag.
 
-QVariant SessionItem::getItemValue(const QString &tag) const
+QVariant SessionItem::getItemValue(const QString& tag) const
 {
     if (!isTag(tag))
         throw GUIHelpers::Error(
@@ -434,26 +435,44 @@ QVariant SessionItem::getItemValue(const QString &tag) const
     return getItem(tag)->value();
 }
 
+kvector_t SessionItem::getVectorItem(const QString& name) const
+{
+    SessionItem* vectorItem = getItem(name);
+    Q_ASSERT(vectorItem);
+    double x = vectorItem->getItemValue(VectorItem::P_X).toDouble();
+    double y = vectorItem->getItemValue(VectorItem::P_Y).toDouble();
+    double z = vectorItem->getItemValue(VectorItem::P_Z).toDouble();
+    return { x, y, z };
+}
+
 //! Directly set value of item under given tag.
 
-void SessionItem::setItemValue(const QString &tag, const QVariant &variant)
+void SessionItem::setItemValue(const QString& tag, const QVariant& variant)
 {
     if (!isTag(tag))
         throw GUIHelpers::Error("Property not existing!");
 
-     getItem(tag)->setValue(variant);
+    getItem(tag)->setValue(variant);
+}
+
+void SessionItem::setVectorItem(const QString& name, kvector_t value)
+{
+    auto p_vector_item = getItem(name);
+    p_vector_item->setItemValue(VectorItem::P_X, value.x());
+    p_vector_item->setItemValue(VectorItem::P_Y, value.y());
+    p_vector_item->setItemValue(VectorItem::P_Z, value.z());
 }
 
 //! Creates new group item and register new tag, returns GroupItem.
 
-SessionItem *SessionItem::addGroupProperty(const QString &groupName, const QString &groupType)
+SessionItem* SessionItem::addGroupProperty(const QString& groupName, const QString& groupType)
 {
-    SessionItem *result(0);
+    SessionItem* result(0);
 
     if(GroupPropertyRegistry::isValidGroup(groupType)) {
         // create group item
         GroupProperty_t group_property = GroupPropertyRegistry::createGroupProperty(groupType);
-        GroupItem *groupItem = dynamic_cast<GroupItem *>(
+        GroupItem* groupItem = dynamic_cast<GroupItem*>(
                     ItemFactory::createItem(Constants::GroupItemType));
         Q_ASSERT(groupItem);
         groupItem->setGroup(group_property);
@@ -478,14 +497,14 @@ SessionItem *SessionItem::addGroupProperty(const QString &groupName, const QStri
 
 //! Access subitem of group item.
 
-SessionItem *SessionItem::getGroupItem(const QString &groupName) const
+SessionItem* SessionItem::getGroupItem(const QString& groupName) const
 {
     return item<GroupItem>(groupName).currentItem();
 }
 
 //! Set the current type of group item.
 
-SessionItem *SessionItem::setGroupProperty(const QString &groupName, const QString &value) const
+SessionItem* SessionItem::setGroupProperty(const QString& groupName, const QString& value) const
 {
     return item<GroupItem>(groupName).setCurrentType(value);
 }
@@ -505,7 +524,7 @@ QVariant SessionItem::data(int role) const
 
 //! Set variant to role, create role if not present yet.
 
-bool SessionItem::setData(int role, const QVariant &value)
+bool SessionItem::setData(int role, const QVariant& value)
 {
     role = (role == Qt::EditRole) ? Qt::DisplayRole : role;
     QVector<SessionItemData>::iterator it;
@@ -615,7 +634,7 @@ QString SessionItem::defaultTag() const
 
 //! Set default tag
 
-void SessionItem::setDefaultTag(const QString &tag)
+void SessionItem::setDefaultTag(const QString& tag)
 {
     setData(SessionModel::DefaultTagRole, tag);
 }
@@ -650,13 +669,13 @@ QString SessionItem::displayName() const
 
 //! Set display name
 
-void SessionItem::setDisplayName(const QString &display_name)
+void SessionItem::setDisplayName(const QString& display_name)
 {
     setData(SessionModel::DisplayNameRole, display_name);
 }
 
 //! internal
-int SessionItem::getCopyNumberOfChild(const SessionItem *item) const
+int SessionItem::getCopyNumberOfChild(const SessionItem* item) const
 {
     if (!item) return -1;
     int result = -1;
@@ -689,7 +708,7 @@ QString SessionItem::itemName() const
 
 //! Set item name, add property if necessary.
 
-void SessionItem::setItemName(const QString &name)
+void SessionItem::setItemName(const QString& name)
 {
     if (isTag(P_NAME)) {
         setItemValue(P_NAME, name);
@@ -697,7 +716,7 @@ void SessionItem::setItemName(const QString &name)
         addProperty(P_NAME, name);
         // when name changes, than parent should be notified about it
         mapper()->setOnPropertyChange(
-                    [this] (const QString &name)
+                    [this] (const QString& name)
         {
             if (name == P_NAME)
                 emitDataChanged();
@@ -746,7 +765,7 @@ RealLimits SessionItem::limits() const
     return data(SessionModel::LimitsRole).value<RealLimits>();
 }
 
-SessionItem& SessionItem::setLimits(const RealLimits &value)
+SessionItem& SessionItem::setLimits(const RealLimits& value)
 {
     this->setData(SessionModel::LimitsRole, QVariant::fromValue<RealLimits>(value));
     return *this;
@@ -768,7 +787,7 @@ QString SessionItem::toolTip() const
     return data(Qt::ToolTipRole).toString();
 }
 
-SessionItem& SessionItem::setToolTip(const QString &tooltip)
+SessionItem& SessionItem::setToolTip(const QString& tooltip)
 {
     setData(Qt::ToolTipRole, tooltip);
     return *this;
@@ -783,7 +802,7 @@ QString SessionItem::itemLabel() const
 
 //! Returns the current model mapper of this item. Creates new one if necessary.
 
-ModelMapper *SessionItem::mapper()
+ModelMapper* SessionItem::mapper()
 {
     if (!m_mapper) {
         m_mapper = std::unique_ptr<ModelMapper>(new ModelMapper);
diff --git a/GUI/coregui/Models/SessionItem.h b/GUI/coregui/Models/SessionItem.h
index cc1decc3b2b2e56c9914b834ccb84e41871d4075..505c027953a8572cfac581f753433465f9b6b4ee 100644
--- a/GUI/coregui/Models/SessionItem.h
+++ b/GUI/coregui/Models/SessionItem.h
@@ -20,6 +20,7 @@
 #include "RealLimits.h"
 #include "ModelMapper.h"
 #include "item_constants.h"
+#include "Vectors3D.h"
 #include <QStringList>
 #include <memory>
 
@@ -54,54 +55,56 @@ class BA_CORE_API_ SessionItem
 public:
     static const QString P_NAME;
 
-    explicit SessionItem(const QString &modelType = QString());
+    explicit SessionItem(const QString& modelType = QString());
     virtual ~SessionItem();
-    SessionModel *model() const;
-    SessionItem *parent() const;
+    SessionModel* model() const;
+    SessionItem* parent() const;
 
     // these functions work without tags and operate on all children
     QModelIndex index() const;
     bool hasChildren() const;
     int rowCount() const;
-    QVector<SessionItem *> childItems() const;
-    SessionItem *childAt(int row) const;
-    int rowOfChild(SessionItem *child) const;
+    QVector<SessionItem*> childItems() const;
+    SessionItem* childAt(int row) const;
+    int rowOfChild(SessionItem* child) const;
     int parentRow() const;
-    SessionItem* getChildByName(const QString &name) const;
-    SessionItem *getChildOfType(const QString &type) const;
-    QVector<SessionItem *> getChildrenOfType(const QString &model_type) const;
-    SessionItem *takeRow(int row);
+    SessionItem* getChildByName(const QString& name) const;
+    SessionItem* getChildOfType(const QString& type) const;
+    QVector<SessionItem*> getChildrenOfType(const QString& model_type) const;
+    SessionItem* takeRow(int row);
 
     // manage and check tags
-    bool registerTag(const QString &name, int min = 0, int max = -1,
+    bool registerTag(const QString& name, int min = 0, int max = -1,
                      QStringList modelTypes = QStringList());
-    bool isTag(const QString &name) const;
-    QString tagFromItem(const SessionItem *item) const;
-    SessionTagInfo getTagInfo(const QString &name = QString()) const;
-    bool acceptsAsDefaultItem(const QString &item_name) const;
+    bool isTag(const QString& name) const;
+    QString tagFromItem(const SessionItem* item) const;
+    SessionTagInfo getTagInfo(const QString& name = QString()) const;
+    bool acceptsAsDefaultItem(const QString& item_name) const;
     QVector<QString> acceptableDefaultItemTypes() const;
 
     // access tagged items
-    SessionItem *getItem(const QString &tag = QString(), int row = 0) const;
-    template<typename T> T& item(const QString &tag) const;
+    SessionItem* getItem(const QString& tag = QString(), int row = 0) const;
+    template<typename T> T& item(const QString& tag) const;
 
-    QVector<SessionItem *> getItems(const QString &tag = QString()) const;
-    bool insertItem(int row, SessionItem *item, const QString &tag = QString());
-    SessionItem *takeItem(int row, const QString &tag);
+    QVector<SessionItem*> getItems(const QString& tag = QString()) const;
+    bool insertItem(int row, SessionItem* item, const QString& tag = QString());
+    SessionItem* takeItem(int row, const QString& tag);
 
     // convenience functions for properties and groups
-    SessionItem *addProperty(const QString &name, const QVariant &variant);
-    QVariant getItemValue(const QString &tag) const;
-    void setItemValue(const QString &tag, const QVariant &variant);
-    SessionItem *addGroupProperty(const QString &groupName, const QString &groupType);
+    SessionItem* addProperty(const QString& name, const QVariant& variant);
+    QVariant getItemValue(const QString& tag) const;
+    kvector_t getVectorItem(const QString& name) const;
+    void setItemValue(const QString& tag, const QVariant& variant);
+    void setVectorItem(const QString& name, kvector_t value);
+    SessionItem* addGroupProperty(const QString& groupName, const QString& groupType);
 
-    SessionItem *setGroupProperty(const QString &name, const QString &value) const;
-    SessionItem *getGroupItem(const QString &groupName) const;
-    template<typename T> T& groupItem(const QString &groupName) const;
+    SessionItem* setGroupProperty(const QString& name, const QString& value) const;
+    SessionItem* getGroupItem(const QString& groupName) const;
+    template<typename T> T& groupItem(const QString& groupName) const;
 
     // access data stored in roles
     virtual QVariant data(int role) const;
-    virtual bool setData(int role, const QVariant &value);
+    virtual bool setData(int role, const QVariant& value);
     QVector<int> getRoles() const;
     void emitDataChanged(int role = Qt::DisplayRole);
 
@@ -112,13 +115,13 @@ public:
     bool setValue(QVariant value);
 
     QString defaultTag() const;
-    void setDefaultTag(const QString &tag);
+    void setDefaultTag(const QString& tag);
 
     QString displayName() const;
-    void setDisplayName(const QString &display_name);
+    void setDisplayName(const QString& display_name);
 
     QString itemName() const;
-    void setItemName(const QString &name);
+    void setItemName(const QString& name);
 
     void setVisible(bool enabled);
     void setEnabled(bool enabled);
@@ -128,34 +131,34 @@ public:
     bool isEditable() const;
 
     RealLimits limits() const;
-    SessionItem& setLimits(const RealLimits &value);
+    SessionItem& setLimits(const RealLimits& value);
 
     int decimals() const;
     SessionItem& setDecimals(int n);
 
     QString toolTip() const;
-    SessionItem& setToolTip(const QString &tooltip);
+    SessionItem& setToolTip(const QString& tooltip);
 
 
     // helper functions
     virtual QString itemLabel() const;
-    ModelMapper *mapper();
+    ModelMapper* mapper();
 
     virtual QStringList translateList(const QStringList& list) const;
     void addTranslator(const IPathTranslator& translator);
 
 private:
-    void childDeleted(SessionItem *child);
-    void setParentAndModel(SessionItem *parent, SessionModel *model);
-    void setModel(SessionModel *model);
-    int tagStartIndex(const QString &name) const;
+    void childDeleted(SessionItem* child);
+    void setParentAndModel(SessionItem* parent, SessionModel* model);
+    void setModel(SessionModel* model);
+    int tagStartIndex(const QString& name) const;
     int flags() const;
     void changeFlags(bool enabled, int flag);
-    int getCopyNumberOfChild(const SessionItem *item) const;
+    int getCopyNumberOfChild(const SessionItem* item) const;
 
-    SessionItem *m_parent;
-    SessionModel *m_model;
-    QVector<SessionItem *> m_children;
+    SessionItem* m_parent;
+    SessionModel* m_model;
+    QVector<SessionItem*> m_children;
     QVector<SessionItemData> m_values;
     QVector<SessionTagInfo> m_tags;
     std::unique_ptr<ModelMapper> m_mapper;
diff --git a/GUI/coregui/Models/TransformFromDomain.cpp b/GUI/coregui/Models/TransformFromDomain.cpp
index f6b3cdf5c0adae3a816b0df8791ab177741db19e..76827074d1c1291ddddfe51b324ebd224ca1e48a 100644
--- a/GUI/coregui/Models/TransformFromDomain.cpp
+++ b/GUI/coregui/Models/TransformFromDomain.cpp
@@ -235,35 +235,75 @@ void TransformFromDomain::setItemFromSample(BeamItem* beamItem, const GISASSimul
             setItemFromSample(azimuthalAngle, distributions[i]);
         }
     }
+
+    // polarization parameters
+    beamItem->setVectorItem(BeamItem::P_POLARIZATION, beam.getBlochVector());
 }
 
 void TransformFromDomain::setInstrumentDetectorFromSample(InstrumentItem* instrumentItem,
                                             const GISASSimulation& simulation)
 {
-    const IDetector2D* iDetector = simulation.getInstrument().getDetector();
+    const IDetector2D* p_detector = simulation.getInstrument().getDetector();
+    DetectorItem* detector_item;
 
-    if(auto detector = dynamic_cast<const SphericalDetector*>(iDetector)) {
+    if(auto detector = dynamic_cast<const SphericalDetector*>(p_detector)) {
         instrumentItem->setDetectorGroup(Constants::SphericalDetectorType);
-        auto item = dynamic_cast<SphericalDetectorItem*> (instrumentItem->detectorItem());
+        detector_item = instrumentItem->detectorItem();
+        auto item = dynamic_cast<SphericalDetectorItem*>(detector_item);
         setItemFromSample(item, *detector);
     }
-
-    else if(auto detector = dynamic_cast<const RectangularDetector*>(iDetector)) {
+    else if(auto detector = dynamic_cast<const RectangularDetector*>(p_detector)) {
         instrumentItem->setDetectorGroup(Constants::RectangularDetectorType);
-        auto item = dynamic_cast<RectangularDetectorItem*> (instrumentItem->detectorItem());
+        detector_item = instrumentItem->detectorItem();
+        auto item = dynamic_cast<RectangularDetectorItem*>(detector_item);
         setItemFromSample(item, *detector);
-
-        Q_ASSERT(item);
-        setItemFromSample(item,* detector);
     }
-
     else {
         throw GUIHelpers::Error(
             "TransformFromDomain::setInstrumentDetectorFromSample(DetectorItem*) -> Unknown detector type.");
     }
+    // detector resolution
+    if (const IDetectorResolution* p_resfunc = p_detector->detectorResolution()) {
+        if (const ConvolutionDetectorResolution* p_convfunc
+            = dynamic_cast<const ConvolutionDetectorResolution*>(p_resfunc)) {
+            if (const ResolutionFunction2DGaussian* resfunc
+                = dynamic_cast<const ResolutionFunction2DGaussian*>(
+                    p_convfunc->getResolutionFunction2D())) {
+                SessionItem* item
+                    = detector_item->setGroupProperty(DetectorItem::P_RESOLUTION_FUNCTION,
+                                                     Constants::ResolutionFunction2DGaussianType);
+                double scale(1.0);
+                if(detector_item->modelType() == Constants::SphericalDetectorType)
+                    scale = 1./Units::degree;
+                item->setItemValue(ResolutionFunction2DGaussianItem::P_SIGMA_X,
+                                   scale*resfunc->getSigmaX());
+                item->setItemValue(ResolutionFunction2DGaussianItem::P_SIGMA_Y,
+                                   scale*resfunc->getSigmaY());
+            } else {
+                throw GUIHelpers::Error("TransformFromDomain::setInstrumentDetectorFromSample("
+                                        "InstrumentItem* instrumentItem, const GISASSimulation& "
+                                        "simulation) -> Error, unknown detector resolution "
+                                        "function");
+            }
+        } else {
+            throw GUIHelpers::Error(
+                "TransformFromDomain::setInstrumentDetectorFromSample(InstrumentItem* "
+                "instrumentItem, const GISASSimulation& simulation) -> Error, not a "
+                "ConvolutionDetectorResolution function");
+        }
+    }
+    // polarization analysis parameters
+    double total_transmission = p_detector->analyzerTotalTransmission();
+    if (total_transmission>0.0) {
+        kvector_t analyzer_dir = p_detector->analyzerDirection();
+        double efficiency = p_detector->analyzerEfficiency();
+        detector_item->setVectorItem(DetectorItem::P_ANALYZER_DIRECTION, analyzer_dir);
+        detector_item->setItemValue(DetectorItem::P_ANALYZER_EFFICIENCY, efficiency);
+        detector_item->setItemValue(DetectorItem::P_ANALYZER_TOTAL_TRANSMISSION,
+                                    total_transmission);
+    }
 }
 
-
 void TransformFromDomain::setItemFromSample(SphericalDetectorItem* detectorItem,
                                             const SphericalDetector& detector)
 {
@@ -284,34 +324,6 @@ void TransformFromDomain::setItemFromSample(SphericalDetectorItem* detectorItem,
     alphaAxisItem->setItemValue(BasicAxisItem::P_NBINS, (int)alpha_axis.size());
     alphaAxisItem->setItemValue(BasicAxisItem::P_MIN, Units::rad2deg(alpha_axis.getMin()));
     alphaAxisItem->setItemValue(BasicAxisItem::P_MAX, Units::rad2deg(alpha_axis.getMax()));
-
-    // detector resolution
-    if (const IDetectorResolution* p_resfunc = detector.detectorResolution()) {
-        if (const ConvolutionDetectorResolution* p_convfunc
-            = dynamic_cast<const ConvolutionDetectorResolution*>(p_resfunc)) {
-            if (const ResolutionFunction2DGaussian* resfunc
-                = dynamic_cast<const ResolutionFunction2DGaussian*>(
-                    p_convfunc->getResolutionFunction2D())) {
-                SessionItem* item
-                    = detectorItem->setGroupProperty(SphericalDetectorItem::P_RESOLUTION_FUNCTION,
-                                                     Constants::ResolutionFunction2DGaussianType);
-                item->setItemValue(ResolutionFunction2DGaussianItem::P_SIGMA_X,
-                                            Units::rad2deg(resfunc->getSigmaX()));
-                item->setItemValue(ResolutionFunction2DGaussianItem::P_SIGMA_Y,
-                                            Units::rad2deg(resfunc->getSigmaY()));
-            } else {
-                throw GUIHelpers::Error("TransformFromDomain::setItemFromSample("
-                                        "SphericalDetectorItem* detectorItem, const GISASSimulation "
-                                        "&simulation) -> Error, unknown detector resolution "
-                                        "function");
-            }
-        } else {
-            throw GUIHelpers::Error(
-                "TransformFromDomain::setItemFromSample(SphericalDetectorItem "
-                "*detectorItem, const GISASSimulation& simulation) -> Error, not a "
-                "ConvolutionDetectorResolution function");
-        }
-    }
 }
 
 
@@ -335,20 +347,10 @@ void TransformFromDomain::setItemFromSample(RectangularDetectorItem* detectorIte
         detectorItem->setDetectorAlignment(Constants::ALIGNMENT_GENERIC);
 
         kvector_t normal = detector.getNormalVector();
-        detectorItem->getItem(RectangularDetectorItem::P_NORMAL)->setItemValue(
-            VectorItem::P_X, normal.x());
-        detectorItem->getItem(RectangularDetectorItem::P_NORMAL)->setItemValue(
-            VectorItem::P_Y, normal.y());
-        detectorItem->getItem(RectangularDetectorItem::P_NORMAL)->setItemValue(
-            VectorItem::P_Z, normal.z());
+        detectorItem->setVectorItem(RectangularDetectorItem::P_NORMAL, normal);
 
         kvector_t direction = detector.getDirectionVector();
-        detectorItem->getItem(RectangularDetectorItem::P_DIRECTION)->setItemValue(
-            VectorItem::P_X, direction.x());
-        detectorItem->getItem(RectangularDetectorItem::P_DIRECTION)->setItemValue(
-            VectorItem::P_Y, direction.y());
-        detectorItem->getItem(RectangularDetectorItem::P_DIRECTION)->setItemValue(
-            VectorItem::P_Z, direction.z());
+        detectorItem->setVectorItem(RectangularDetectorItem::P_DIRECTION, direction);
 
         detectorItem->setItemValue(RectangularDetectorItem::P_U0, detector.getU0());
         detectorItem->setItemValue(RectangularDetectorItem::P_V0, detector.getV0());
@@ -392,37 +394,10 @@ void TransformFromDomain::setItemFromSample(RectangularDetectorItem* detectorIte
             "TransformFromDomain::setItemFromSample(RectangularDetectorItem* detectorItem "
             "Error. Unknown detector arrangement");
     }
-
-    // detector resolution
-    if (const IDetectorResolution* p_resfunc = detector.detectorResolution()) {
-        if (const ConvolutionDetectorResolution* p_convfunc
-            = dynamic_cast<const ConvolutionDetectorResolution*>(p_resfunc)) {
-            if (const ResolutionFunction2DGaussian* resfunc
-                = dynamic_cast<const ResolutionFunction2DGaussian*>(
-                    p_convfunc->getResolutionFunction2D())) {
-                SessionItem* item
-                    = detectorItem->setGroupProperty(RectangularDetectorItem::P_RESOLUTION_FUNCTION,
-                                                     Constants::ResolutionFunction2DGaussianType);
-                item->setItemValue(ResolutionFunction2DGaussianItem::P_SIGMA_X,
-                                            resfunc->getSigmaX());
-                item->setItemValue(ResolutionFunction2DGaussianItem::P_SIGMA_Y,
-                                            resfunc->getSigmaY());
-            } else {
-                throw GUIHelpers::Error("TransformFromDomain::setItemFromSample("
-                                        "RectangularDetectorItem* detectorItem, const GISASSimulation "
-                                        "&simulation) -> Error, unknown detector resolution "
-                                        "function");
-            }
-        } else {
-            throw GUIHelpers::Error(
-                "TransformFromDomain::setItemFromSample(RectangularDetectorItem "
-                "*detectorItem, const GISASSimulation& simulation) -> Error, not a "
-                "ConvolutionDetectorResolution function");
-        }
-    }
 }
 
-void TransformFromDomain::setDetectorMasks(DetectorItem* detectorItem, const GISASSimulation& simulation)
+void TransformFromDomain::setDetectorMasks(DetectorItem* detectorItem,
+                                           const GISASSimulation& simulation)
 {
     const IDetector2D* detector = simulation.getInstrument().getDetector();
     if( (detector->getDetectorMask() && detector->getDetectorMask()->numberOfMasks()) ||
diff --git a/GUI/coregui/Models/TransformToDomain.cpp b/GUI/coregui/Models/TransformToDomain.cpp
index cf1bdd48e61218a5d21a0038472bc338395317fc..5f833f2c75493e1c676360061ef6d26efb2c7ebb 100644
--- a/GUI/coregui/Models/TransformToDomain.cpp
+++ b/GUI/coregui/Models/TransformToDomain.cpp
@@ -80,6 +80,8 @@ std::unique_ptr<MultiLayer> TransformToDomain::createMultiLayer(const SessionIte
         = item.getItemValue(MultiLayerItem::P_CROSS_CORR_LENGTH).toDouble();
     if (cross_corr_length > 0)
         P_multilayer->setCrossCorrLength(cross_corr_length);
+    auto external_field = item.getVectorItem(MultiLayerItem::P_EXTERNAL_FIELD);
+    P_multilayer->setExternalField(external_field);
     return P_multilayer;
 }
 
@@ -213,12 +215,8 @@ void TransformToDomain::setTransformationInfo(IParticle* result, const SessionIt
 
 void TransformToDomain::setPositionInfo(IParticle* result, const SessionItem& item)
 {
-    SessionItem* positionItem = item.getItem(ParticleItem::P_POSITION);
-    Q_ASSERT(positionItem);
-    double pos_x = positionItem->getItemValue(VectorItem::P_X).toDouble();
-    double pos_y = positionItem->getItemValue(VectorItem::P_Y).toDouble();
-    double pos_z = positionItem->getItemValue(VectorItem::P_Z).toDouble();
-    result->setPosition(pos_x, pos_y, pos_z);
+    kvector_t pos = item.getVectorItem(ParticleItem::P_POSITION);
+    result->setPosition(pos.x(), pos.y(), pos.z());
 }
 
 void TransformToDomain::setRotationInfo(IParticle* result, const SessionItem& item)
diff --git a/GUI/coregui/Models/item_constants.h b/GUI/coregui/Models/item_constants.h
index b48528d0983a34e5cc90d559a7363a8d214e2340..68ece4d2b831ab772718fb389e5515ae22e6e890 100644
--- a/GUI/coregui/Models/item_constants.h
+++ b/GUI/coregui/Models/item_constants.h
@@ -120,7 +120,7 @@ const ModelType HexagonalLatticeType = "HexagonalLattice";
 
 const ModelType HomogeneousMaterialType = "HomogeneousMaterial";
 
-const ModelType RefractiveIndexType = "RefractiveIndex";
+const ModelType MaterialDataType = "MaterialData";
 
 const ModelType MagneticFieldType = "MagneticField";
 
diff --git a/GUI/coregui/Views/MaterialEditor/MaterialUtils.cpp b/GUI/coregui/Views/MaterialEditor/MaterialUtils.cpp
index 3b38b083f68a18ca2661cdee26aa92bdd30256c2..39093564eadf94f3e71ee929124311d612a97a86 100644
--- a/GUI/coregui/Views/MaterialEditor/MaterialUtils.cpp
+++ b/GUI/coregui/Views/MaterialEditor/MaterialUtils.cpp
@@ -15,14 +15,14 @@
 // ************************************************************************** //
 
 #include "MaterialUtils.h"
+
+#include "MaterialDataItem.h"
 #include "ComboProperty.h"
 #include "DesignerHelper.h"
 #include "GUIHelpers.h"
 #include "HomogeneousMaterial.h"
-#include "MagneticFieldItem.h"
 #include "MaterialModel.h"
 #include "MaterialSvc.h"
-#include "RefractiveIndexItem.h"
 #include "ParticleItem.h"
 #include "LayerItem.h"
 
diff --git a/GUI/coregui/Views/PropertyEditor/ComponentEditor.cpp b/GUI/coregui/Views/PropertyEditor/ComponentEditor.cpp
index 5811295139ff4a648fb02d030687ed161182d49b..8b0f76bf986fd5a5287c6ba769e7851b778ea139 100644
--- a/GUI/coregui/Views/PropertyEditor/ComponentEditor.cpp
+++ b/GUI/coregui/Views/PropertyEditor/ComponentEditor.cpp
@@ -193,7 +193,7 @@ ComponentEditor::componentItems(SessionItem *item) const
             result.append(child);
         }
 
-        else if (child->modelType() == Constants::RefractiveIndexType) {
+        else if (child->modelType() == Constants::MaterialDataType) {
             result.append(child);
         }
 
diff --git a/Tests/UnitTests/Core/Detector/PrecomputedTest.h b/Tests/UnitTests/Core/Detector/PrecomputedTest.h
index c9bc60c0896c61bb1bdf9beb2304b35c5fcb1aa0..ec5be695daab38b28bb8829b0e8855d1295cca61 100644
--- a/Tests/UnitTests/Core/Detector/PrecomputedTest.h
+++ b/Tests/UnitTests/Core/Detector/PrecomputedTest.h
@@ -1,24 +1,28 @@
 #include "Precomputed.h"
 #include <memory>
 
+namespace {
+    constexpr auto ReciprocalFactorialArray = Precomputed::GenerateReciprocalFactorialArray<171>();
+}
+
 class PrecomputedTest : public ::testing::Test
 {
 public:
 };
 
-TEST_F(PrecomputedTest, Factorial)
+TEST_F(PrecomputedTest, ReciprocalFactorial)
 {
     const double eps = 2.3e-16; // about the machine precision
-    auto& precomputed = Precomputed::instance();
-    EXPECT_TRUE(precomputed.factorial.size()>150);
-    EXPECT_DOUBLE_EQ(precomputed.factorial[0], 1.);
-    EXPECT_DOUBLE_EQ(precomputed.factorial[1], 1.);
-    EXPECT_DOUBLE_EQ(precomputed.factorial[2], 2.);
-    EXPECT_DOUBLE_EQ(precomputed.factorial[3], 6.);
+    EXPECT_TRUE(ReciprocalFactorialArray.size()>150);
+    EXPECT_DOUBLE_EQ(ReciprocalFactorialArray[0], 1.);
+    EXPECT_DOUBLE_EQ(ReciprocalFactorialArray[1], 1.);
+    EXPECT_DOUBLE_EQ(ReciprocalFactorialArray[2], 0.5);
+    EXPECT_DOUBLE_EQ(ReciprocalFactorialArray[3], 1.0/6);
     /* the following disabled because tgamma is too unprecise under
        old versions of glibc (at leat up to 2.12, but less than 2.22)
     for( size_t k=4; k<precomputed.factorial.size(); ++k )
         EXPECT_NEAR(precomputed.factorial[k], tgamma(k+1.), 12*eps*tgamma(k+1.) );
     */
-    EXPECT_NEAR(precomputed.factorial[150], 5.71338395644585459e262, 4*eps*precomputed.factorial[150]);
+    EXPECT_NEAR(ReciprocalFactorialArray[150], 1.75027620692601519e-263,
+                4*eps*ReciprocalFactorialArray[150]);
 }
diff --git a/Tests/UnitTests/Core/Detector/RectangularDetectorTest.h b/Tests/UnitTests/Core/Detector/RectangularDetectorTest.h
index 9ff14c490f817fcb51f573dccb1331861f4d7200..0acc70d387f5c666579fed172b82d9a6a2815aba 100644
--- a/Tests/UnitTests/Core/Detector/RectangularDetectorTest.h
+++ b/Tests/UnitTests/Core/Detector/RectangularDetectorTest.h
@@ -258,3 +258,82 @@ TEST_F(RectangularDetectorTest, PerpToReflectedBeamDpos)
     EXPECT_DOUBLE_EQ(phi(k), phi(element));
     EXPECT_NEAR(alpha(k), alpha(element), 1e-10*std::abs(alpha(k)));
 }
+
+// Test retrieval of analyzer properties
+TEST_F(RectangularDetectorTest, AnalyzerProperties)
+{
+    RectangularDetector detector(50, 10.0, 60, 20.0);
+
+    kvector_t direction;
+    double efficiency = 0.0;
+    double total_transmission = 1.0;
+    kvector_t unit_direction;
+
+    // if direction is the zero vector, an exception is thrown
+    EXPECT_THROW(detector.setAnalyzerProperties(direction, efficiency, total_transmission),
+                 Exceptions::ClassInitializationException);
+
+    // zero efficiency
+    direction = kvector_t(1.0, 0.0, 0.0);
+    unit_direction = direction.unit();
+    detector.setAnalyzerProperties(direction, efficiency, total_transmission);
+
+    EXPECT_NEAR(detector.analyzerEfficiency(), efficiency, 1e-8);
+    EXPECT_NEAR(detector.analyzerTotalTransmission(), total_transmission, 1e-8);
+    // direction vector returned is zero vector because efficiency is zero
+    EXPECT_NEAR(detector.analyzerDirection().x(), 0.0, 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().y(), 0.0, 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().z(), 0.0, 1e-8);
+
+    // intermediate efficiency
+    direction = kvector_t(1.0, 0.0, 0.0);
+    efficiency = 0.5;
+    total_transmission = 0.6;
+    unit_direction = direction.unit();
+    detector.setAnalyzerProperties(direction, efficiency, total_transmission);
+
+    EXPECT_NEAR(detector.analyzerEfficiency(), efficiency, 1e-8);
+    EXPECT_NEAR(detector.analyzerTotalTransmission(), total_transmission, 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().x(), unit_direction.x(), 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().y(), unit_direction.y(), 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().z(), unit_direction.z(), 1e-8);
+
+    // maximum efficiency
+    direction = kvector_t(1.0, 0.0, 0.0);
+    efficiency = 1.0;
+    total_transmission = 0.5;
+    unit_direction = direction.unit();
+    detector.setAnalyzerProperties(direction, efficiency, total_transmission);
+
+    EXPECT_NEAR(detector.analyzerEfficiency(), efficiency, 1e-8);
+    EXPECT_NEAR(detector.analyzerTotalTransmission(), total_transmission, 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().x(), unit_direction.x(), 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().y(), unit_direction.y(), 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().z(), unit_direction.z(), 1e-8);
+
+    // non-axis direction
+    direction = kvector_t(1.0, 2.0, 3.0);
+    efficiency = 1.0;
+    total_transmission = 0.5;
+    unit_direction = direction.unit();
+    detector.setAnalyzerProperties(direction, efficiency, total_transmission);
+
+    EXPECT_NEAR(detector.analyzerEfficiency(), efficiency, 1e-8);
+    EXPECT_NEAR(detector.analyzerTotalTransmission(), total_transmission, 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().x(), unit_direction.x(), 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().y(), unit_direction.y(), 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().z(), unit_direction.z(), 1e-8);
+
+    // maximum efficiency and negative efficiency
+    direction = kvector_t(0.0, -1.0, -1.0);
+    efficiency = -1.0;
+    total_transmission = 0.5;
+    unit_direction = direction.unit();
+    detector.setAnalyzerProperties(direction, efficiency, total_transmission);
+
+    EXPECT_NEAR(detector.analyzerEfficiency(), efficiency, 1e-8);
+    EXPECT_NEAR(detector.analyzerTotalTransmission(), total_transmission, 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().x(), unit_direction.x(), 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().y(), unit_direction.y(), 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().z(), unit_direction.z(), 1e-8);
+}
diff --git a/Tests/UnitTests/Core/Detector/SphericalDetectorTest.h b/Tests/UnitTests/Core/Detector/SphericalDetectorTest.h
index c0c8a4ca583d1349b3ca26624474cad83d6d6a80..4bcbf60fcd34dfe3331deaeb915dd1b1ed6a159c 100644
--- a/Tests/UnitTests/Core/Detector/SphericalDetectorTest.h
+++ b/Tests/UnitTests/Core/Detector/SphericalDetectorTest.h
@@ -21,8 +21,7 @@ class SphericalDetectorTest : public ::testing::Test
     virtual ~SphericalDetectorTest(){}
 };
 
-//! Default detector construction
-
+// Default detector construction
 TEST_F(SphericalDetectorTest, initialState)
 {
     SphericalDetector detector;
@@ -53,8 +52,7 @@ TEST_F(SphericalDetectorTest, initialState)
                  Exceptions::NullPointerException);
 }
 
-//! Construction of the detector with axes.
-
+// Construction of the detector with axes.
 TEST_F(SphericalDetectorTest, constructionWithAxes)
 {
     SphericalDetector detector;
@@ -77,8 +75,7 @@ TEST_F(SphericalDetectorTest, constructionWithAxes)
     EXPECT_EQ(0u, detector.getDimension());
 }
 
-//! Construction of the detector via classical constructor.
-
+// Construction of the detector via classical constructor.
 TEST_F(SphericalDetectorTest, constructionWithParameters)
 {
     SphericalDetector detector(10, -1.0, 1.0, 20, 0.0, 2.0);
@@ -92,8 +89,7 @@ TEST_F(SphericalDetectorTest, constructionWithParameters)
     EXPECT_EQ(BornAgain::ALPHA_AXIS_NAME, detector.getAxis(1).getName());
 }
 
-//! Init external data with detector axes.
-
+// Init external data with detector axes.
 TEST_F(SphericalDetectorTest, initOutputData)
 {
     SphericalDetector detector(10, -1.0, 1.0, 20, 0.0, 2.0);
@@ -112,8 +108,7 @@ TEST_F(SphericalDetectorTest, initOutputData)
     EXPECT_EQ(BornAgain::ALPHA_AXIS_NAME, data.getAxis(1).getName());
 }
 
-//! Creation of the detector map with axes in given units
-
+// Creation of the detector map with axes in given units
 TEST_F(SphericalDetectorTest, createDetectorMap)
 {
     SphericalDetector detector(10, -1.0*Units::deg, 1.0*Units::deg,
@@ -135,24 +130,23 @@ TEST_F(SphericalDetectorTest, createDetectorMap)
     // creating map in degrees and checking axes
     data.reset(detector.createDetectorMap(beam, IDetector2D::DEGREES));
     EXPECT_EQ(data->getAxis(0).size(), 10u);
-	EXPECT_DOUBLE_EQ(data->getAxis(0).getMin(), -1.0);
-	EXPECT_DOUBLE_EQ(data->getAxis(0).getMax(), 1.0);
+    EXPECT_DOUBLE_EQ(data->getAxis(0).getMin(), -1.0);
+    EXPECT_DOUBLE_EQ(data->getAxis(0).getMax(), 1.0);
     EXPECT_EQ(data->getAxis(1).size(), 20u);
-	EXPECT_DOUBLE_EQ(data->getAxis(1).getMin(), 0.0);
-	EXPECT_DOUBLE_EQ(data->getAxis(1).getMax(), 2.0);
+    EXPECT_DOUBLE_EQ(data->getAxis(1).getMin(), 0.0);
+    EXPECT_DOUBLE_EQ(data->getAxis(1).getMax(), 2.0);
 
     // creating map in nbins and checking axes
     data.reset(detector.createDetectorMap(beam, IDetector2D::NBINS));
     EXPECT_EQ(data->getAxis(0).size(), 10u);
-	EXPECT_DOUBLE_EQ(data->getAxis(0).getMin(), 0.0);
-	EXPECT_DOUBLE_EQ(data->getAxis(0).getMax(), 10.0);
+    EXPECT_DOUBLE_EQ(data->getAxis(0).getMin(), 0.0);
+    EXPECT_DOUBLE_EQ(data->getAxis(0).getMax(), 10.0);
     EXPECT_EQ(data->getAxis(1).size(), 20u);
-	EXPECT_DOUBLE_EQ(data->getAxis(1).getMin(), 0.0);
-	EXPECT_DOUBLE_EQ(data->getAxis(1).getMax(), 20.0);
+    EXPECT_DOUBLE_EQ(data->getAxis(1).getMin(), 0.0);
+    EXPECT_DOUBLE_EQ(data->getAxis(1).getMax(), 20.0);
 }
 
-//! Testing region of interest.
-
+// Testing region of interest.
 TEST_F(SphericalDetectorTest, regionOfInterest)
 {
     SphericalDetector detector;
@@ -181,8 +175,7 @@ TEST_F(SphericalDetectorTest, regionOfInterest)
     EXPECT_TRUE(nullptr == detector.regionOfInterest());
 }
 
-//! Init external data with detector axes when region of interest is present.
-
+// Init external data with detector axes when region of interest is present.
 TEST_F(SphericalDetectorTest, regionOfInterestAndData)
 {
     SphericalDetector detector;
@@ -205,8 +198,7 @@ TEST_F(SphericalDetectorTest, regionOfInterestAndData)
     EXPECT_EQ(data.getAxis(1).getMax(), 4.0);
 }
 
-//! Create detector map in the presence of region of interest.
-
+// Create detector map in the presence of region of interest.
 TEST_F(SphericalDetectorTest, regionOfInterestAndDetectorMap)
 {
     SphericalDetector detector(6, -1.0*Units::deg, 5.0*Units::deg,
@@ -237,8 +229,7 @@ TEST_F(SphericalDetectorTest, regionOfInterestAndDetectorMap)
     EXPECT_EQ(data->getAxis(1).getMax(), 3.0);
 }
 
-//! Checking IDetector2D::getIntensityData in the presence of region of interest.
-
+// Checking IDetector2D::getIntensityData in the presence of region of interest.
 TEST_F(SphericalDetectorTest, getIntensityData)
 {
     SphericalDetector detector(6, -1.0*Units::deg, 5.0*Units::deg,
@@ -320,8 +311,7 @@ TEST_F(SphericalDetectorTest, MaskOfDetector)
     }
 }
 
-//! Checking clone in the presence of ROI and masks.
-
+// Checking clone in the presence of ROI and masks.
 TEST_F(SphericalDetectorTest, Clone)
 {
     Beam beam;
@@ -379,3 +369,82 @@ TEST_F(SphericalDetectorTest, nameToUnitTranslation)
     EXPECT_THROW(DetectorFunctions::detectorUnits("xxx"), std::runtime_error);
 }
 
+// Test retrieval of analyzer properties
+TEST_F(SphericalDetectorTest, AnalyzerProperties)
+{
+    SphericalDetector detector(6, -1.0*Units::deg, 5.0*Units::deg,
+                               4, 0.0*Units::deg, 4.0*Units::deg);
+
+    kvector_t direction;
+    double efficiency = 0.0;
+    double total_transmission = 1.0;
+    kvector_t unit_direction;
+
+    // if direction is the zero vector, an exception is thrown
+    EXPECT_THROW(detector.setAnalyzerProperties(direction, efficiency, total_transmission),
+                 Exceptions::ClassInitializationException);
+
+    // zero efficiency
+    direction = kvector_t(1.0, 0.0, 0.0);
+    unit_direction = direction.unit();
+    detector.setAnalyzerProperties(direction, efficiency, total_transmission);
+
+    EXPECT_NEAR(detector.analyzerEfficiency(), efficiency, 1e-8);
+    EXPECT_NEAR(detector.analyzerTotalTransmission(), total_transmission, 1e-8);
+    // direction vector returned is zero vector because efficiency is zero
+    EXPECT_NEAR(detector.analyzerDirection().x(), 0.0, 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().y(), 0.0, 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().z(), 0.0, 1e-8);
+
+    // intermediate efficiency
+    direction = kvector_t(1.0, 0.0, 0.0);
+    efficiency = 0.5;
+    total_transmission = 0.6;
+    unit_direction = direction.unit();
+    detector.setAnalyzerProperties(direction, efficiency, total_transmission);
+
+    EXPECT_NEAR(detector.analyzerEfficiency(), efficiency, 1e-8);
+    EXPECT_NEAR(detector.analyzerTotalTransmission(), total_transmission, 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().x(), unit_direction.x(), 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().y(), unit_direction.y(), 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().z(), unit_direction.z(), 1e-8);
+
+    // maximum efficiency
+    direction = kvector_t(1.0, 0.0, 0.0);
+    efficiency = 1.0;
+    total_transmission = 0.5;
+    unit_direction = direction.unit();
+    detector.setAnalyzerProperties(direction, efficiency, total_transmission);
+
+    EXPECT_NEAR(detector.analyzerEfficiency(), efficiency, 1e-8);
+    EXPECT_NEAR(detector.analyzerTotalTransmission(), total_transmission, 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().x(), unit_direction.x(), 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().y(), unit_direction.y(), 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().z(), unit_direction.z(), 1e-8);
+
+    // non-axis direction
+    direction = kvector_t(1.0, 2.0, 3.0);
+    efficiency = 1.0;
+    total_transmission = 0.5;
+    unit_direction = direction.unit();
+    detector.setAnalyzerProperties(direction, efficiency, total_transmission);
+
+    EXPECT_NEAR(detector.analyzerEfficiency(), efficiency, 1e-8);
+    EXPECT_NEAR(detector.analyzerTotalTransmission(), total_transmission, 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().x(), unit_direction.x(), 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().y(), unit_direction.y(), 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().z(), unit_direction.z(), 1e-8);
+
+    // maximum efficiency and negative efficiency
+    direction = kvector_t(0.0, -1.0, -1.0);
+    efficiency = -1.0;
+    total_transmission = 0.5;
+    unit_direction = direction.unit();
+    detector.setAnalyzerProperties(direction, efficiency, total_transmission);
+
+    EXPECT_NEAR(detector.analyzerEfficiency(), efficiency, 1e-8);
+    EXPECT_NEAR(detector.analyzerTotalTransmission(), total_transmission, 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().x(), unit_direction.x(), 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().y(), unit_direction.y(), 1e-8);
+    EXPECT_NEAR(detector.analyzerDirection().z(), unit_direction.z(), 1e-8);
+}
diff --git a/Tests/UnitTests/Core/Other/BeamTest.h b/Tests/UnitTests/Core/Other/BeamTest.h
index 76fe61b83d2204dfbd6ba81a58f656915e921825..2cbc6c710a4b7998d55f2bf40acf2ed8eba846ce 100644
--- a/Tests/UnitTests/Core/Other/BeamTest.h
+++ b/Tests/UnitTests/Core/Other/BeamTest.h
@@ -20,7 +20,7 @@ TEST_F(BeamTest, BeamInitialState)
     EXPECT_EQ(0.0, m_empty_beam.getCentralK()[1]);
     EXPECT_EQ(0.0, m_empty_beam.getCentralK()[2]);
     EXPECT_EQ(0.0, m_empty_beam.getIntensity());
-    /* TEMPORARILY DISABLED getParameterPool() 
+    /* TEMPORARILY DISABLED getParameterPool()
     EXPECT_EQ(size_t(4), m_empty_beam.getParameterPool()->size());
     EXPECT_EQ(0.0, m_empty_beam.getParameterPool()->getParameter(BornAgain::Intensity).getValue());
     EXPECT_EQ(1.0, m_empty_beam.getParameterPool()->getParameter(BornAgain::Wavelength).getValue());
@@ -46,7 +46,7 @@ TEST_F(BeamTest, BeamAssignment)
     EXPECT_NEAR(-2.85664, beam_copy.getCentralK()[1], 0.00001);
     EXPECT_NEAR(-5.28712, beam_copy.getCentralK()[2], 0.00001);
     EXPECT_EQ(double(2.0), beam_copy.getIntensity());
-    /* TEMPORARILY DISABLED getParameterPool() 
+    /* TEMPORARILY DISABLED getParameterPool()
     EXPECT_EQ(size_t(4), beam_copy.getParameterPool()->size());
     EXPECT_EQ(double(2.0),
               beam_copy.getParameterPool()->getParameter(BornAgain::Intensity).getValue());
@@ -54,3 +54,15 @@ TEST_F(BeamTest, BeamAssignment)
     EXPECT_EQ(complex_t(0.4, 0.0), beam_copy.getPolarization()(1, 1));
     */
 }
+
+TEST_F(BeamTest, BeamPolarization)
+{
+    Beam beam;
+    kvector_t polarization(0.1, -0.2, 0.4);
+    beam.setPolarization(polarization);
+
+    kvector_t bloch_vector = beam.getBlochVector();
+    EXPECT_NEAR(0.1, bloch_vector.x(), 1e-8);
+    EXPECT_NEAR(-0.2, bloch_vector.y(), 1e-8);
+    EXPECT_NEAR(0.4, bloch_vector.z(), 1e-8);
+}
diff --git a/Tests/UnitTests/Core/Other/HomogeneousMaterialTest.h b/Tests/UnitTests/Core/Other/HomogeneousMaterialTest.h
index d47ff58b77db8ec14a3401532d8cfa190145fe1f..74a37106576575544366528a2c17889c531c37dd 100644
--- a/Tests/UnitTests/Core/Other/HomogeneousMaterialTest.h
+++ b/Tests/UnitTests/Core/Other/HomogeneousMaterialTest.h
@@ -9,44 +9,30 @@ public:
     virtual ~HomogeneousMaterialTest() {}
 };
 
-TEST_F(HomogeneousMaterialTest, HomogeneousMaterialWithRefIndex)
-{
-    complex_t refIndex = complex_t(1.0, 2.0);
-    kvector_t magnetism = kvector_t(3.0, 4.0, 5.0);
-    HomogeneousMaterial material("MagMaterial", refIndex, magnetism);
-    EXPECT_EQ("MagMaterial", material.getName());
-    EXPECT_EQ(refIndex, material.refractiveIndex());
-    EXPECT_EQ(magnetism, material.magnetization());
-
-    complex_t refIndex2 = complex_t(2.0, 3.0);
-    material.setRefractiveIndex(refIndex2);
-    EXPECT_EQ(refIndex2, material.refractiveIndex());
-
-    kvector_t magnetism2 = kvector_t(5.0, 6.0, 7.0);
-    material.setMagnetization(magnetism2);
-    EXPECT_EQ(magnetism2, material.magnetization());
-}
-
 TEST_F(HomogeneousMaterialTest, HomogeneousMaterialWithRefIndexAndMagField)
 {
+    complex_t material_data = complex_t(0.0, 2.0);
+    complex_t refIndex = complex_t(1.0 - material_data.real(), material_data.imag());
     kvector_t magnetism = kvector_t(3.0, 4.0, 5.0);
-    HomogeneousMaterial material("MagMaterial", 2.0, 2.0, magnetism);
+    HomogeneousMaterial material("MagMaterial", refIndex, magnetism);
     EXPECT_EQ("MagMaterial", material.getName());
-    EXPECT_EQ(complex_t(-1.0, 2.0), material.refractiveIndex());
+    EXPECT_EQ(material_data, material.materialData());
     EXPECT_EQ(magnetism, material.magnetization());
 
-    complex_t refIndex2 = complex_t(2.0, 3.0);
-    material.setRefractiveIndex(refIndex2);
-    EXPECT_EQ(refIndex2, material.refractiveIndex());
+    complex_t material_data2 = complex_t(-1.0, 2.0);
+    complex_t refIndex2 = complex_t(1.0 - material_data2.real(), material_data2.imag());
+    HomogeneousMaterial material2("MagMaterial", refIndex2, magnetism);
+    EXPECT_EQ(material_data2, material2.materialData());
 
     kvector_t magnetism2 = kvector_t(5.0, 6.0, 7.0);
-    material.setMagnetization(magnetism2);
-    EXPECT_EQ(magnetism2, material.magnetization());
+    HomogeneousMaterial material3("MagMaterial", refIndex2, magnetism2);
+    EXPECT_EQ(magnetism2, material3.magnetization());
 }
 
 TEST_F(HomogeneousMaterialTest, HomogeneousMaterialTransform)
 {
-    complex_t refIndex = complex_t(0.0, 0.0);
+    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(0.0, 0.0, 0.0);
     HomogeneousMaterial material("MagMaterial", refIndex, magnetism);
 
@@ -54,32 +40,25 @@ TEST_F(HomogeneousMaterialTest, HomogeneousMaterialTransform)
     HomogeneousMaterial material2 = material.transformedMaterial(transform.getTransform3D());
 
     EXPECT_EQ("MagMaterial", material2.getName());
-    EXPECT_EQ(refIndex, material2.refractiveIndex());
+    EXPECT_EQ(material_data, material2.materialData());
 }
 
 TEST_F(HomogeneousMaterialTest, HomogeneousMaterialCopy)
 {
-    complex_t refIndex = complex_t(1.0, 2.0);
+    complex_t material_data = complex_t(0.0, 2.0);
+    complex_t refIndex = complex_t(1.0 - material_data.real(), material_data.imag());
     kvector_t magnetism = kvector_t(3.0, 4.0, 5.0);
     HomogeneousMaterial material("MagMaterial", refIndex, magnetism);
 
     HomogeneousMaterial copy = material;
 
     EXPECT_EQ("MagMaterial", copy.getName());
-    EXPECT_EQ(refIndex, copy.refractiveIndex());
+    EXPECT_EQ(material_data, copy.materialData());
     EXPECT_EQ(magnetism, copy.magnetization());
 
-    complex_t refIndex2 = complex_t(2.0, 3.0);
-    copy.setRefractiveIndex(refIndex2);
-    EXPECT_EQ(refIndex2, copy.refractiveIndex());
-
-    kvector_t magnetism2 = kvector_t(5.0, 6.0, 7.0);
-    copy.setMagnetization(magnetism2);
-    EXPECT_EQ(magnetism2, copy.magnetization());
-
     RotationZ transform(45.*Units::degree);
     HomogeneousMaterial material2 = copy.transformedMaterial(transform.getTransform3D());
 
     EXPECT_EQ("MagMaterial", material2.getName());
-    EXPECT_EQ(refIndex2, material2.refractiveIndex());
+    EXPECT_EQ(material_data, material2.materialData());
 }
diff --git a/Tests/UnitTests/Core/Sample/LayerTest.h b/Tests/UnitTests/Core/Sample/LayerTest.h
index 2f1973bb723976db60da50b3259d0d9375318334..5779f8fa9c48e88802250ac21ac0f9b32bfbf7fb 100644
--- a/Tests/UnitTests/Core/Sample/LayerTest.h
+++ b/Tests/UnitTests/Core/Sample/LayerTest.h
@@ -13,26 +13,23 @@ class LayerTest : public ::testing::Test
 TEST_F(LayerTest, LayerGetAndSet)
 {
     HomogeneousMaterial air("air",0,0);
-
     Layer layer(air, 10*Units::nanometer);
-    EXPECT_EQ(air.getName(), layer.material()->getName());
+    EXPECT_EQ(air, *layer.material());
     EXPECT_EQ(0u, layer.layouts().size());
     EXPECT_EQ(10, layer.thickness());
     EXPECT_EQ(layer.numberOfLayouts(), 0u);
-    EXPECT_EQ(complex_t(1, 0), layer.refractiveIndex());
     EXPECT_EQ(BornAgain::LayerType, layer.getName());
 
     layer.setThickness(20.0);
+    EXPECT_EQ(air, *layer.material());
     EXPECT_EQ(20, layer.thickness());
     EXPECT_EQ(BornAgain::LayerType, layer.getName());
-    EXPECT_EQ(complex_t(1, 0), layer.refractiveIndex());
 
     std::unique_ptr<Layer> clone(layer.clone());
-    EXPECT_EQ(air.getName(), clone->material()->getName());
+    EXPECT_EQ(air, *clone->material());
     EXPECT_EQ(0u, clone->layouts().size());
     EXPECT_EQ(20, clone->thickness());
     EXPECT_EQ(clone->numberOfLayouts(), 0u);
-    EXPECT_EQ(complex_t(1, 0), clone->refractiveIndex());
     EXPECT_EQ(BornAgain::LayerType, clone->getName());
 }
 
diff --git a/Tests/UnitTests/Core/Sample/ParticleTest.h b/Tests/UnitTests/Core/Sample/ParticleTest.h
index 5097510986457ee5c90a72e0ab90b508cf9fe8ad..00f0fe599724af9c11b8b755ac182f43356e707c 100644
--- a/Tests/UnitTests/Core/Sample/ParticleTest.h
+++ b/Tests/UnitTests/Core/Sample/ParticleTest.h
@@ -17,7 +17,6 @@ TEST_F(ParticleTest, InitialState)
     Particle particle;
     HomogeneousMaterial vacuum;
     EXPECT_EQ(vacuum, *particle.material());
-    EXPECT_EQ(complex_t(1,0), particle.refractiveIndex());
     EXPECT_EQ(nullptr, particle.createFormFactor());
     EXPECT_EQ(nullptr, particle.rotation());
     EXPECT_EQ(BornAgain::ParticleType, particle.getName());
@@ -29,7 +28,6 @@ TEST_F(ParticleTest, Clone)
     HomogeneousMaterial vacuum;
     std::unique_ptr<Particle> clone(particle.clone());
     EXPECT_EQ(vacuum, *clone->material());
-    EXPECT_EQ(complex_t(1,0), clone->refractiveIndex());
     EXPECT_EQ(nullptr, clone->createFormFactor());
     EXPECT_EQ(nullptr, clone->rotation());
     EXPECT_EQ(BornAgain::ParticleType, clone->getName());
@@ -43,27 +41,20 @@ TEST_F(ParticleTest, Constructors)
 
     // construction with material
     std::unique_ptr<Particle> p1(new Particle(mat));
-    EXPECT_EQ("Air", p1->material()->getName());
-    EXPECT_EQ(complex_t(1,0), p1->refractiveIndex());
+    EXPECT_EQ(mat, *p1->material());
     EXPECT_EQ(nullptr, p1->createFormFactor());
     EXPECT_EQ( nullptr, p1->rotation());
 
     // construction with formfactor
     std::unique_ptr<Particle> p2(new Particle(mat, sphere));
-    EXPECT_EQ("Air", p2->material()->getName());
-    EXPECT_EQ(complex_t(1,0), p2->refractiveIndex());
+    EXPECT_EQ(mat, *p2->material());
     EXPECT_TRUE(dynamic_cast<FormFactorDecoratorMaterial *>(p2->createFormFactor()));
-    EXPECT_EQ(complex_t(1,0), dynamic_cast<FormFactorDecoratorMaterial *>(
-                      p2->createFormFactor())->getAmbientRefractiveIndex());
     EXPECT_EQ( nullptr, p2->rotation());
 
     // construction with transformation
     std::unique_ptr<Particle> p3(new Particle(mat, sphere, transform));
-    EXPECT_EQ("Air", p3->material()->getName());
-    EXPECT_EQ(complex_t(1,0), p3->refractiveIndex());
+    EXPECT_EQ(mat, *p3->material());
     EXPECT_TRUE(dynamic_cast<FormFactorDecoratorMaterial *>(p3->createFormFactor()));
-    EXPECT_EQ(complex_t(1,0), dynamic_cast<FormFactorDecoratorMaterial *>(
-                      p3->createFormFactor())->getAmbientRefractiveIndex());
     EXPECT_EQ(BornAgain::ZRotationType, p3->rotation()->getName());
 }
 
@@ -83,8 +74,7 @@ TEST_F(ParticleTest, setters)
 
     std::unique_ptr<Particle> particle2(particle.clone());
     EXPECT_EQ(BornAgain::ParticleType, particle2->getName());
-    EXPECT_EQ(vacuum.getName(), particle2->material()->getName());
-    EXPECT_EQ(complex_t(1.0), particle2->refractiveIndex());
+    EXPECT_EQ(vacuum, *particle2->material());
     EXPECT_TRUE(nullptr != particle2->rotation());
 }
 
diff --git a/Tests/UnitTests/GUI/TestMaterialModel.h b/Tests/UnitTests/GUI/TestMaterialModel.h
index 90a4c5164185f87b4cfdbc923212f043e9507ea1..c641c36b7aaf102944733d5a6e525a54e3231f57 100644
--- a/Tests/UnitTests/GUI/TestMaterialModel.h
+++ b/Tests/UnitTests/GUI/TestMaterialModel.h
@@ -1,6 +1,6 @@
 #include "MaterialModel.h"
 #include "MaterialItem.h"
-#include "RefractiveIndexItem.h"
+#include "MaterialDataItem.h"
 #include <QtTest>
 #include <memory>
 
@@ -27,10 +27,10 @@ inline void TestMaterialModel::test_addMaterial()
     QCOMPARE(model->rowCount(QModelIndex()), 1);
 
     QCOMPARE(item->itemName(), name);
-    const RefractiveIndexItem *refIndex = dynamic_cast<const RefractiveIndexItem *>(
-        item->getItem(MaterialItem::P_REFRACTIVE_INDEX));
-    QCOMPARE(refIndex->getDelta(), delta);
-    QCOMPARE(refIndex->getBeta(), beta);
+    const MaterialDataItem *refIndex = dynamic_cast<const MaterialDataItem *>(
+        item->getItem(MaterialItem::P_MATERIAL_DATA));
+    QCOMPARE(refIndex->getReal(), delta);
+    QCOMPARE(refIndex->getImag(), beta);
 
 }
 
@@ -57,10 +57,10 @@ inline void TestMaterialModel::test_cloneMaterial()
     // checking name of cloned material
     QCOMPARE(item->itemName()+" (clone)", clonedMaterial->itemName());
 
-    const RefractiveIndexItem *refIndex = dynamic_cast<const RefractiveIndexItem *>(
-        clonedMaterial->getItem(MaterialItem::P_REFRACTIVE_INDEX));
-    QCOMPARE(refIndex->getDelta(), delta);
-    QCOMPARE(refIndex->getBeta(), beta);
+    const MaterialDataItem *refIndex = dynamic_cast<const MaterialDataItem *>(
+        clonedMaterial->getItem(MaterialItem::P_MATERIAL_DATA));
+    QCOMPARE(refIndex->getReal(), delta);
+    QCOMPARE(refIndex->getImag(), beta);
 
 
 }
diff --git a/Tests/UnitTests/GUI/TestParticleCoreShell.h b/Tests/UnitTests/GUI/TestParticleCoreShell.h
index f432e0848c7c1ed289f9aa1345b5200bb607e6ea..2d62dffff54ebaf88be61bf95f5d25cfbe7b86ad 100644
--- a/Tests/UnitTests/GUI/TestParticleCoreShell.h
+++ b/Tests/UnitTests/GUI/TestParticleCoreShell.h
@@ -27,10 +27,10 @@ inline void TestParticleCoreShell::test_propertyAppearance()
     QVERIFY(coreshell->getItem(ParticleItem::P_ABUNDANCE)->isEnabled() == true);
     QCOMPARE(coreshell->getItemValue(ParticleItem::P_ABUNDANCE).toDouble(), 1.0);
     QVERIFY(coreshell->getItem(ParticleItem::P_POSITION)->isEnabled() == true);
-    SessionItem* positionItem = coreshell->getItem(ParticleItem::P_POSITION);
-    QCOMPARE(positionItem->getItemValue(VectorItem::P_X).toDouble(), 0.0);
-    QCOMPARE(positionItem->getItemValue(VectorItem::P_Y).toDouble(), 0.0);
-    QCOMPARE(positionItem->getItemValue(VectorItem::P_Z).toDouble(), 0.0);
+    kvector_t pos = coreshell->getVectorItem(ParticleItem::P_POSITION);
+    QCOMPARE(pos.x(), 0.0);
+    QCOMPARE(pos.y(), 0.0);
+    QCOMPARE(pos.z(), 0.0);
 
     // adding core, and checking that abundance is disabled
     SessionItem* core = model.insertNewItem(Constants::ParticleType, coreshell->index(), -1,
@@ -46,7 +46,7 @@ inline void TestParticleCoreShell::test_propertyAppearance()
 
     // creating shell (not yet attached to the coreshell)
     SessionItem* shell = model.insertNewItem(Constants::ParticleType);
-    positionItem = shell->getItem(ParticleItem::P_POSITION);
+    SessionItem* positionItem = shell->getItem(ParticleItem::P_POSITION);
     // putting some values to position and abundance
     shell->setItemValue(ParticleItem::P_ABUNDANCE, 0.2);
     positionItem->setItemValue(VectorItem::P_X, 1.0);
diff --git a/auto/Wrap/libBornAgainCore.py b/auto/Wrap/libBornAgainCore.py
index 085bfceb01f0426d9b140d1acd220a795b1382f7..a78b841f06e428b2f5780af58d90de90ad466577 100644
--- a/auto/Wrap/libBornAgainCore.py
+++ b/auto/Wrap/libBornAgainCore.py
@@ -3774,6 +3774,11 @@ class Beam(INode):
         return _libBornAgainCore.Beam_setPolarization(self, bloch_vector)
 
 
+    def getBlochVector(self):
+        """getBlochVector(Beam self) -> kvector_t"""
+        return _libBornAgainCore.Beam_getBlochVector(self)
+
+
     def getWavelength(self):
         """
         getWavelength(Beam self) -> double
@@ -17824,34 +17829,24 @@ class HomogeneousMaterial(INamed):
         return _libBornAgainCore.HomogeneousMaterial_inverted(self)
 
 
-    def refractiveIndex(self):
+    def refractiveIndex(self, wavelength):
         """
-        refractiveIndex(HomogeneousMaterial self) -> complex_t
+        refractiveIndex(HomogeneousMaterial self, double wavelength) -> complex_t
 
         complex_t HomogeneousMaterial::refractiveIndex() const 
 
         """
-        return _libBornAgainCore.HomogeneousMaterial_refractiveIndex(self)
+        return _libBornAgainCore.HomogeneousMaterial_refractiveIndex(self, wavelength)
 
 
-    def refractiveIndex2(self):
+    def refractiveIndex2(self, wavelength):
         """
-        refractiveIndex2(HomogeneousMaterial self) -> complex_t
+        refractiveIndex2(HomogeneousMaterial self, double wavelength) -> complex_t
 
         complex_t HomogeneousMaterial::refractiveIndex2() const 
 
         """
-        return _libBornAgainCore.HomogeneousMaterial_refractiveIndex2(self)
-
-
-    def setRefractiveIndex(self, refractive_index):
-        """
-        setRefractiveIndex(HomogeneousMaterial self, complex_t const refractive_index)
-
-        void HomogeneousMaterial::setRefractiveIndex(const complex_t refractive_index)
-
-        """
-        return _libBornAgainCore.HomogeneousMaterial_setRefractiveIndex(self, refractive_index)
+        return _libBornAgainCore.HomogeneousMaterial_refractiveIndex2(self, wavelength)
 
 
     def isScalarMaterial(self):
@@ -17888,26 +17883,14 @@ class HomogeneousMaterial(INamed):
         return _libBornAgainCore.HomogeneousMaterial_magnetization(self)
 
 
-    def setMagnetization(self, magnetization):
-        """
-        setMagnetization(HomogeneousMaterial self, kvector_t magnetization)
+    def materialData(self):
+        """materialData(HomogeneousMaterial self) -> complex_t"""
+        return _libBornAgainCore.HomogeneousMaterial_materialData(self)
 
-        void HomogeneousMaterial::setMagnetization(const kvector_t magnetization)
 
-        Set the magnetizationd (in A/m) 
-
-        """
-        return _libBornAgainCore.HomogeneousMaterial_setMagnetization(self, magnetization)
-
-
-    def scalarSLD(self, wavevectors):
-        """
-        scalarSLD(HomogeneousMaterial self, WavevectorInfo wavevectors) -> complex_t
-
-        complex_t HomogeneousMaterial::scalarSLD(const WavevectorInfo &wavevectors) const 
-
-        """
-        return _libBornAgainCore.HomogeneousMaterial_scalarSLD(self, wavevectors)
+    def scalarSubtrSLD(self, wavevectors):
+        """scalarSubtrSLD(HomogeneousMaterial self, WavevectorInfo wavevectors) -> complex_t"""
+        return _libBornAgainCore.HomogeneousMaterial_scalarSubtrSLD(self, wavevectors)
 
 
     def transformedMaterial(self, transform):
@@ -18116,6 +18099,21 @@ class IDetector2D(ICloneable, INode):
         return _libBornAgainCore.IDetector2D_setAnalyzerProperties(self, direction, efficiency, total_transmission)
 
 
+    def analyzerDirection(self):
+        """analyzerDirection(IDetector2D self) -> kvector_t"""
+        return _libBornAgainCore.IDetector2D_analyzerDirection(self)
+
+
+    def analyzerEfficiency(self):
+        """analyzerEfficiency(IDetector2D self) -> double"""
+        return _libBornAgainCore.IDetector2D_analyzerEfficiency(self)
+
+
+    def analyzerTotalTransmission(self):
+        """analyzerTotalTransmission(IDetector2D self) -> double"""
+        return _libBornAgainCore.IDetector2D_analyzerTotalTransmission(self)
+
+
     def removeMasks(self):
         """
         removeMasks(IDetector2D self)
@@ -22191,28 +22189,6 @@ class Layer(ISample):
         return _libBornAgainCore.Layer_setMaterial(self, material)
 
 
-    def refractiveIndex(self):
-        """
-        refractiveIndex(Layer self) -> complex_t
-
-        complex_t Layer::refractiveIndex() const 
-
-        """
-        return _libBornAgainCore.Layer_refractiveIndex(self)
-
-
-    def refractiveIndex2(self):
-        """
-        refractiveIndex2(Layer self) -> complex_t
-
-        complex_t Layer::refractiveIndex2() const
-
-        squared refractive index 
-
-        """
-        return _libBornAgainCore.Layer_refractiveIndex2(self)
-
-
     def addLayout(self, decoration):
         """
         addLayout(Layer self, ILayout decoration)
@@ -24534,16 +24510,6 @@ class Particle(IParticle):
         return _libBornAgainCore.Particle_material(self)
 
 
-    def refractiveIndex(self):
-        """
-        refractiveIndex(Particle self) -> complex_t
-
-        complex_t Particle::refractiveIndex() const 
-
-        """
-        return _libBornAgainCore.Particle_refractiveIndex(self)
-
-
     def setFormFactor(self, form_factor):
         """
         setFormFactor(Particle self, IFormFactor form_factor)
diff --git a/auto/Wrap/libBornAgainCore_wrap.cpp b/auto/Wrap/libBornAgainCore_wrap.cpp
index 8bc628bea1e83951b93c8f01934f2f0ba800c586..32b8b4d05ab20d12e296d1d1e1b1bc14ccb8022f 100644
--- a/auto/Wrap/libBornAgainCore_wrap.cpp
+++ b/auto/Wrap/libBornAgainCore_wrap.cpp
@@ -35214,6 +35214,28 @@ fail:
 }
 
 
+SWIGINTERN PyObject *_wrap_Beam_getBlochVector(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  Beam *arg1 = (Beam *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  kvector_t result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:Beam_getBlochVector",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_Beam, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Beam_getBlochVector" "', argument " "1"" of type '" "Beam const *""'"); 
+  }
+  arg1 = reinterpret_cast< Beam * >(argp1);
+  result = ((Beam const *)arg1)->getBlochVector();
+  resultobj = SWIG_NewPointerObj((new kvector_t(static_cast< const kvector_t& >(result))), SWIGTYPE_p_BasicVector3DT_double_t, SWIG_POINTER_OWN |  0 );
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
 SWIGINTERN PyObject *_wrap_Beam_getWavelength(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   Beam *arg1 = (Beam *) 0 ;
@@ -81679,18 +81701,27 @@ fail:
 SWIGINTERN PyObject *_wrap_HomogeneousMaterial_refractiveIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   HomogeneousMaterial *arg1 = (HomogeneousMaterial *) 0 ;
+  double arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  double val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
   complex_t result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:HomogeneousMaterial_refractiveIndex",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:HomogeneousMaterial_refractiveIndex",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_HomogeneousMaterial, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
     SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "HomogeneousMaterial_refractiveIndex" "', argument " "1"" of type '" "HomogeneousMaterial const *""'"); 
   }
   arg1 = reinterpret_cast< HomogeneousMaterial * >(argp1);
-  result = ((HomogeneousMaterial const *)arg1)->refractiveIndex();
+  ecode2 = SWIG_AsVal_double(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "HomogeneousMaterial_refractiveIndex" "', argument " "2"" of type '" "double""'");
+  } 
+  arg2 = static_cast< double >(val2);
+  result = ((HomogeneousMaterial const *)arg1)->refractiveIndex(arg2);
   resultobj = SWIG_From_std_complex_Sl_double_Sg_(static_cast< std::complex<double> >(result));
   return resultobj;
 fail:
@@ -81701,49 +81732,28 @@ fail:
 SWIGINTERN PyObject *_wrap_HomogeneousMaterial_refractiveIndex2(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   HomogeneousMaterial *arg1 = (HomogeneousMaterial *) 0 ;
+  double arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  complex_t result;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:HomogeneousMaterial_refractiveIndex2",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_HomogeneousMaterial, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "HomogeneousMaterial_refractiveIndex2" "', argument " "1"" of type '" "HomogeneousMaterial const *""'"); 
-  }
-  arg1 = reinterpret_cast< HomogeneousMaterial * >(argp1);
-  result = ((HomogeneousMaterial const *)arg1)->refractiveIndex2();
-  resultobj = SWIG_From_std_complex_Sl_double_Sg_(static_cast< std::complex<double> >(result));
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_HomogeneousMaterial_setRefractiveIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  HomogeneousMaterial *arg1 = (HomogeneousMaterial *) 0 ;
-  complex_t arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  std::complex< double > val2 ;
+  double val2 ;
   int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
+  complex_t result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:HomogeneousMaterial_setRefractiveIndex",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:HomogeneousMaterial_refractiveIndex2",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_HomogeneousMaterial, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "HomogeneousMaterial_setRefractiveIndex" "', argument " "1"" of type '" "HomogeneousMaterial *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "HomogeneousMaterial_refractiveIndex2" "', argument " "1"" of type '" "HomogeneousMaterial const *""'"); 
   }
   arg1 = reinterpret_cast< HomogeneousMaterial * >(argp1);
-  ecode2 = SWIG_AsVal_std_complex_Sl_double_Sg_(obj1, &val2);
+  ecode2 = SWIG_AsVal_double(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "HomogeneousMaterial_setRefractiveIndex" "', argument " "2"" of type '" "complex_t""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "HomogeneousMaterial_refractiveIndex2" "', argument " "2"" of type '" "double""'");
   } 
-  arg2 = static_cast< complex_t >(val2);
-  (arg1)->setRefractiveIndex(arg2);
-  resultobj = SWIG_Py_Void();
+  arg2 = static_cast< double >(val2);
+  result = ((HomogeneousMaterial const *)arg1)->refractiveIndex2(arg2);
+  resultobj = SWIG_From_std_complex_Sl_double_Sg_(static_cast< std::complex<double> >(result));
   return resultobj;
 fail:
   return NULL;
@@ -81816,45 +81826,29 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_HomogeneousMaterial_setMagnetization(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_HomogeneousMaterial_materialData(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   HomogeneousMaterial *arg1 = (HomogeneousMaterial *) 0 ;
-  kvector_t arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 ;
-  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
+  complex_t result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:HomogeneousMaterial_setMagnetization",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:HomogeneousMaterial_materialData",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_HomogeneousMaterial, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "HomogeneousMaterial_setMagnetization" "', argument " "1"" of type '" "HomogeneousMaterial *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "HomogeneousMaterial_materialData" "', argument " "1"" of type '" "HomogeneousMaterial const *""'"); 
   }
   arg1 = reinterpret_cast< HomogeneousMaterial * >(argp1);
-  {
-    res2 = SWIG_ConvertPtr(obj1, &argp2, SWIGTYPE_p_BasicVector3DT_double_t,  0  | 0);
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "HomogeneousMaterial_setMagnetization" "', argument " "2"" of type '" "kvector_t const""'"); 
-    }  
-    if (!argp2) {
-      SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "HomogeneousMaterial_setMagnetization" "', argument " "2"" of type '" "kvector_t const""'");
-    } else {
-      kvector_t * temp = reinterpret_cast< kvector_t * >(argp2);
-      arg2 = *temp;
-      if (SWIG_IsNewObj(res2)) delete temp;
-    }
-  }
-  (arg1)->setMagnetization(arg2);
-  resultobj = SWIG_Py_Void();
+  result = ((HomogeneousMaterial const *)arg1)->materialData();
+  resultobj = SWIG_From_std_complex_Sl_double_Sg_(static_cast< std::complex<double> >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_HomogeneousMaterial_scalarSLD(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_HomogeneousMaterial_scalarSubtrSLD(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   HomogeneousMaterial *arg1 = (HomogeneousMaterial *) 0 ;
   WavevectorInfo *arg2 = 0 ;
@@ -81866,21 +81860,21 @@ SWIGINTERN PyObject *_wrap_HomogeneousMaterial_scalarSLD(PyObject *SWIGUNUSEDPAR
   PyObject * obj1 = 0 ;
   complex_t result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:HomogeneousMaterial_scalarSLD",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:HomogeneousMaterial_scalarSubtrSLD",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_HomogeneousMaterial, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "HomogeneousMaterial_scalarSLD" "', argument " "1"" of type '" "HomogeneousMaterial const *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "HomogeneousMaterial_scalarSubtrSLD" "', argument " "1"" of type '" "HomogeneousMaterial const *""'"); 
   }
   arg1 = reinterpret_cast< HomogeneousMaterial * >(argp1);
   res2 = SWIG_ConvertPtr(obj1, &argp2, SWIGTYPE_p_WavevectorInfo,  0  | 0);
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "HomogeneousMaterial_scalarSLD" "', argument " "2"" of type '" "WavevectorInfo const &""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "HomogeneousMaterial_scalarSubtrSLD" "', argument " "2"" of type '" "WavevectorInfo const &""'"); 
   }
   if (!argp2) {
-    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "HomogeneousMaterial_scalarSLD" "', argument " "2"" of type '" "WavevectorInfo const &""'"); 
+    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "HomogeneousMaterial_scalarSubtrSLD" "', argument " "2"" of type '" "WavevectorInfo const &""'"); 
   }
   arg2 = reinterpret_cast< WavevectorInfo * >(argp2);
-  result = ((HomogeneousMaterial const *)arg1)->scalarSLD((WavevectorInfo const &)*arg2);
+  result = ((HomogeneousMaterial const *)arg1)->scalarSubtrSLD((WavevectorInfo const &)*arg2);
   resultobj = SWIG_From_std_complex_Sl_double_Sg_(static_cast< std::complex<double> >(result));
   return resultobj;
 fail:
@@ -82475,6 +82469,72 @@ fail:
 }
 
 
+SWIGINTERN PyObject *_wrap_IDetector2D_analyzerDirection(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  IDetector2D *arg1 = (IDetector2D *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  kvector_t result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:IDetector2D_analyzerDirection",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_IDetector2D, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "IDetector2D_analyzerDirection" "', argument " "1"" of type '" "IDetector2D const *""'"); 
+  }
+  arg1 = reinterpret_cast< IDetector2D * >(argp1);
+  result = ((IDetector2D const *)arg1)->analyzerDirection();
+  resultobj = SWIG_NewPointerObj((new kvector_t(static_cast< const kvector_t& >(result))), SWIGTYPE_p_BasicVector3DT_double_t, SWIG_POINTER_OWN |  0 );
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_IDetector2D_analyzerEfficiency(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  IDetector2D *arg1 = (IDetector2D *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  double result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:IDetector2D_analyzerEfficiency",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_IDetector2D, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "IDetector2D_analyzerEfficiency" "', argument " "1"" of type '" "IDetector2D const *""'"); 
+  }
+  arg1 = reinterpret_cast< IDetector2D * >(argp1);
+  result = (double)((IDetector2D const *)arg1)->analyzerEfficiency();
+  resultobj = SWIG_From_double(static_cast< double >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_IDetector2D_analyzerTotalTransmission(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  IDetector2D *arg1 = (IDetector2D *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  double result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:IDetector2D_analyzerTotalTransmission",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_IDetector2D, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "IDetector2D_analyzerTotalTransmission" "', argument " "1"" of type '" "IDetector2D const *""'"); 
+  }
+  arg1 = reinterpret_cast< IDetector2D * >(argp1);
+  result = (double)((IDetector2D const *)arg1)->analyzerTotalTransmission();
+  resultobj = SWIG_From_double(static_cast< double >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
 SWIGINTERN PyObject *_wrap_IDetector2D_removeMasks(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   IDetector2D *arg1 = (IDetector2D *) 0 ;
@@ -94531,50 +94591,6 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_refractiveIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  Layer *arg1 = (Layer *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  complex_t result;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:Layer_refractiveIndex",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_Layer, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_refractiveIndex" "', argument " "1"" of type '" "Layer const *""'"); 
-  }
-  arg1 = reinterpret_cast< Layer * >(argp1);
-  result = ((Layer const *)arg1)->refractiveIndex();
-  resultobj = SWIG_From_std_complex_Sl_double_Sg_(static_cast< std::complex<double> >(result));
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Layer_refractiveIndex2(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  Layer *arg1 = (Layer *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  complex_t result;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:Layer_refractiveIndex2",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_Layer, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_refractiveIndex2" "', argument " "1"" of type '" "Layer const *""'"); 
-  }
-  arg1 = reinterpret_cast< Layer * >(argp1);
-  result = ((Layer const *)arg1)->refractiveIndex2();
-  resultobj = SWIG_From_std_complex_Sl_double_Sg_(static_cast< std::complex<double> >(result));
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
 SWIGINTERN PyObject *_wrap_Layer_addLayout(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   Layer *arg1 = (Layer *) 0 ;
@@ -103389,28 +103405,6 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Particle_refractiveIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  Particle *arg1 = (Particle *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  complex_t result;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:Particle_refractiveIndex",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_Particle, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Particle_refractiveIndex" "', argument " "1"" of type '" "Particle const *""'"); 
-  }
-  arg1 = reinterpret_cast< Particle * >(argp1);
-  result = ((Particle const *)arg1)->refractiveIndex();
-  resultobj = SWIG_From_std_complex_Sl_double_Sg_(static_cast< std::complex<double> >(result));
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
 SWIGINTERN PyObject *_wrap_Particle_setFormFactor(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   Particle *arg1 = (Particle *) 0 ;
@@ -111538,6 +111532,7 @@ static PyMethodDef SwigMethods[] = {
 		"Sets the polarization density matrix according to the given Bloch vector. \n"
 		"\n"
 		""},
+	 { (char *)"Beam_getBlochVector", _wrap_Beam_getBlochVector, METH_VARARGS, (char *)"Beam_getBlochVector(Beam self) -> kvector_t"},
 	 { (char *)"Beam_getWavelength", _wrap_Beam_getWavelength, METH_VARARGS, (char *)"\n"
 		"Beam_getWavelength(Beam self) -> double\n"
 		"\n"
@@ -119081,23 +119076,17 @@ static PyMethodDef SwigMethods[] = {
 		"\n"
 		""},
 	 { (char *)"HomogeneousMaterial_refractiveIndex", _wrap_HomogeneousMaterial_refractiveIndex, METH_VARARGS, (char *)"\n"
-		"HomogeneousMaterial_refractiveIndex(HomogeneousMaterial self) -> complex_t\n"
+		"HomogeneousMaterial_refractiveIndex(HomogeneousMaterial self, double wavelength) -> complex_t\n"
 		"\n"
 		"complex_t HomogeneousMaterial::refractiveIndex() const \n"
 		"\n"
 		""},
 	 { (char *)"HomogeneousMaterial_refractiveIndex2", _wrap_HomogeneousMaterial_refractiveIndex2, METH_VARARGS, (char *)"\n"
-		"HomogeneousMaterial_refractiveIndex2(HomogeneousMaterial self) -> complex_t\n"
+		"HomogeneousMaterial_refractiveIndex2(HomogeneousMaterial self, double wavelength) -> complex_t\n"
 		"\n"
 		"complex_t HomogeneousMaterial::refractiveIndex2() const \n"
 		"\n"
 		""},
-	 { (char *)"HomogeneousMaterial_setRefractiveIndex", _wrap_HomogeneousMaterial_setRefractiveIndex, METH_VARARGS, (char *)"\n"
-		"HomogeneousMaterial_setRefractiveIndex(HomogeneousMaterial self, complex_t const refractive_index)\n"
-		"\n"
-		"void HomogeneousMaterial::setRefractiveIndex(const complex_t refractive_index)\n"
-		"\n"
-		""},
 	 { (char *)"HomogeneousMaterial_isScalarMaterial", _wrap_HomogeneousMaterial_isScalarMaterial, METH_VARARGS, (char *)"\n"
 		"HomogeneousMaterial_isScalarMaterial(HomogeneousMaterial self) -> bool\n"
 		"\n"
@@ -119120,20 +119109,8 @@ static PyMethodDef SwigMethods[] = {
 		"Get the magnetization (in A/m) \n"
 		"\n"
 		""},
-	 { (char *)"HomogeneousMaterial_setMagnetization", _wrap_HomogeneousMaterial_setMagnetization, METH_VARARGS, (char *)"\n"
-		"HomogeneousMaterial_setMagnetization(HomogeneousMaterial self, kvector_t magnetization)\n"
-		"\n"
-		"void HomogeneousMaterial::setMagnetization(const kvector_t magnetization)\n"
-		"\n"
-		"Set the magnetizationd (in A/m) \n"
-		"\n"
-		""},
-	 { (char *)"HomogeneousMaterial_scalarSLD", _wrap_HomogeneousMaterial_scalarSLD, METH_VARARGS, (char *)"\n"
-		"HomogeneousMaterial_scalarSLD(HomogeneousMaterial self, WavevectorInfo wavevectors) -> complex_t\n"
-		"\n"
-		"complex_t HomogeneousMaterial::scalarSLD(const WavevectorInfo &wavevectors) const \n"
-		"\n"
-		""},
+	 { (char *)"HomogeneousMaterial_materialData", _wrap_HomogeneousMaterial_materialData, METH_VARARGS, (char *)"HomogeneousMaterial_materialData(HomogeneousMaterial self) -> complex_t"},
+	 { (char *)"HomogeneousMaterial_scalarSubtrSLD", _wrap_HomogeneousMaterial_scalarSubtrSLD, METH_VARARGS, (char *)"HomogeneousMaterial_scalarSubtrSLD(HomogeneousMaterial self, WavevectorInfo wavevectors) -> complex_t"},
 	 { (char *)"HomogeneousMaterial_transformedMaterial", _wrap_HomogeneousMaterial_transformedMaterial, METH_VARARGS, (char *)"\n"
 		"HomogeneousMaterial_transformedMaterial(HomogeneousMaterial self, Transform3D const & transform) -> HomogeneousMaterial\n"
 		"\n"
@@ -119251,6 +119228,9 @@ static PyMethodDef SwigMethods[] = {
 		"Sets the polarization analyzer characteristics of the detector. \n"
 		"\n"
 		""},
+	 { (char *)"IDetector2D_analyzerDirection", _wrap_IDetector2D_analyzerDirection, METH_VARARGS, (char *)"IDetector2D_analyzerDirection(IDetector2D self) -> kvector_t"},
+	 { (char *)"IDetector2D_analyzerEfficiency", _wrap_IDetector2D_analyzerEfficiency, METH_VARARGS, (char *)"IDetector2D_analyzerEfficiency(IDetector2D self) -> double"},
+	 { (char *)"IDetector2D_analyzerTotalTransmission", _wrap_IDetector2D_analyzerTotalTransmission, METH_VARARGS, (char *)"IDetector2D_analyzerTotalTransmission(IDetector2D self) -> double"},
 	 { (char *)"IDetector2D_removeMasks", _wrap_IDetector2D_removeMasks, METH_VARARGS, (char *)"\n"
 		"IDetector2D_removeMasks(IDetector2D self)\n"
 		"\n"
@@ -121506,20 +121486,6 @@ static PyMethodDef SwigMethods[] = {
 		"void Layer::setMaterial(HomogeneousMaterial material)\n"
 		"\n"
 		""},
-	 { (char *)"Layer_refractiveIndex", _wrap_Layer_refractiveIndex, METH_VARARGS, (char *)"\n"
-		"Layer_refractiveIndex(Layer self) -> complex_t\n"
-		"\n"
-		"complex_t Layer::refractiveIndex() const \n"
-		"\n"
-		""},
-	 { (char *)"Layer_refractiveIndex2", _wrap_Layer_refractiveIndex2, METH_VARARGS, (char *)"\n"
-		"Layer_refractiveIndex2(Layer self) -> complex_t\n"
-		"\n"
-		"complex_t Layer::refractiveIndex2() const\n"
-		"\n"
-		"squared refractive index \n"
-		"\n"
-		""},
 	 { (char *)"Layer_addLayout", _wrap_Layer_addLayout, METH_VARARGS, (char *)"\n"
 		"Layer_addLayout(Layer self, ILayout decoration)\n"
 		"\n"
@@ -122834,12 +122800,6 @@ static PyMethodDef SwigMethods[] = {
 		"Returns nullptr, unless overwritten to return a specific material. \n"
 		"\n"
 		""},
-	 { (char *)"Particle_refractiveIndex", _wrap_Particle_refractiveIndex, METH_VARARGS, (char *)"\n"
-		"Particle_refractiveIndex(Particle self) -> complex_t\n"
-		"\n"
-		"complex_t Particle::refractiveIndex() const \n"
-		"\n"
-		""},
 	 { (char *)"Particle_setFormFactor", _wrap_Particle_setFormFactor, METH_VARARGS, (char *)"\n"
 		"Particle_setFormFactor(Particle self, IFormFactor form_factor)\n"
 		"\n"