diff --git a/Core/Instrument/Instrument.cpp b/Core/Instrument/Instrument.cpp
index 42d843e14deb575123485130be5088a9050a8bb5..88e4714a3c986300b3f9f4b7a8a252e9ed3057df 100644
--- a/Core/Instrument/Instrument.cpp
+++ b/Core/Instrument/Instrument.cpp
@@ -35,7 +35,7 @@ Instrument::Instrument(const Instrument& other) : m_beam(other.m_beam)
     setName(other.getName());
 }
 
-Instrument::~Instrument() {}
+Instrument::~Instrument() = default;
 
 Instrument& Instrument::operator=(const Instrument& other)
 {
@@ -137,6 +137,12 @@ IDetector* Instrument::getDetector()
     return mP_detector.get();
 }
 
+IDetector2D& Instrument::detector2D()
+{
+    check2D();
+    return *dynamic_cast<IDetector2D*>(mP_detector.get());
+}
+
 const IAxis& Instrument::getDetectorAxis(size_t index) const
 {
     return mP_detector->getAxis(index);
@@ -152,3 +158,9 @@ void Instrument::setAnalyzerProperties(const kvector_t direction, double efficie
 {
     mP_detector->setAnalyzerProperties(direction, efficiency, total_transmission);
 }
+
+void Instrument::check2D()
+{
+    if (!dynamic_cast<IDetector2D*>(mP_detector.get()))
+        throw std::runtime_error("Error: Detector is not twodimensional");
+}
diff --git a/Core/Instrument/Instrument.h b/Core/Instrument/Instrument.h
index 06be562b182e8adb0b641a904eed7456a8927519..8d028011c84aa2af6e30c361f8a56deb73c08e3b 100644
--- a/Core/Instrument/Instrument.h
+++ b/Core/Instrument/Instrument.h
@@ -61,6 +61,7 @@ public:
     //! Returns the detector data
     const IDetector* getDetector() const;
     IDetector* getDetector();
+    IDetector2D& detector2D();
 
     const DetectorMask* getDetectorMask() const;
 
@@ -98,6 +99,9 @@ public:
 protected:
     std::unique_ptr<IDetector> mP_detector;
     Beam m_beam;
+
+private:
+    void check2D();
 };
 
 #endif // BORNAGAIN_CORE_INSTRUMENT_INSTRUMENT_H
diff --git a/Core/Simulation/Simulation2D.cpp b/Core/Simulation/Simulation2D.cpp
index abb0b2bfc50968c5e85b2deadeb03805da44c90c..9726d631d01abf56a30db8c42fa0e32ca725ed08 100644
--- a/Core/Simulation/Simulation2D.cpp
+++ b/Core/Simulation/Simulation2D.cpp
@@ -20,11 +20,6 @@
 #include "Core/Intensity/Histogram2D.h"
 #include "Core/SimulationElement/SimulationElement.h"
 
-namespace
-{
-IDetector2D* Detector2D(Instrument& instrument);
-}
-
 Simulation2D::Simulation2D() = default;
 
 Simulation2D::Simulation2D(const MultiLayer& p_sample) : Simulation(p_sample) {}
@@ -39,27 +34,27 @@ Simulation2D::~Simulation2D() = default;
 void Simulation2D::prepareSimulation()
 {
     Simulation::prepareSimulation();
-    detector_context = Detector2D(m_instrument)->createContext();
+    detector_context = m_instrument.detector2D().createContext();
 }
 
 void Simulation2D::removeMasks()
 {
-    Detector2D(m_instrument)->removeMasks();
+    m_instrument.detector2D().removeMasks();
 }
 
 void Simulation2D::addMask(const IShape2D& shape, bool mask_value)
 {
-    Detector2D(m_instrument)->addMask(shape, mask_value);
+    m_instrument.detector2D().addMask(shape, mask_value);
 }
 
 void Simulation2D::maskAll()
 {
-    Detector2D(m_instrument)->maskAll();
+    m_instrument.detector2D().maskAll();
 }
 
 void Simulation2D::setRegionOfInterest(double xlow, double ylow, double xup, double yup)
 {
-    Detector2D(m_instrument)->setRegionOfInterest(xlow, ylow, xup, yup);
+    m_instrument.detector2D().setRegionOfInterest(xlow, ylow, xup, yup);
 }
 
 Simulation2D::Simulation2D(const Simulation2D& other)
@@ -77,11 +72,7 @@ size_t Simulation2D::numberOfSimulationElements() const
 void Simulation2D::setDetectorParameters(size_t n_x, double x_min, double x_max, size_t n_y,
                                          double y_min, double y_max)
 {
-    if (auto detector = Detector2D(m_instrument))
-        detector->setDetectorParameters(n_x, x_min, x_max, n_y, y_min, y_max);
-    else
-        throw std::runtime_error(
-            "Error in Simulation2D::setDetectorParameters: wrong detector type");
+    m_instrument.detector2D().setDetectorParameters(n_x, x_min, x_max, n_y, y_min, y_max);
     updateIntensityMap();
 }
 
@@ -108,11 +99,11 @@ std::vector<SimulationElement> Simulation2D::generateSimulationElements(const Be
     const double alpha_i = -beam.getAlpha(); // Defined to be always positive in Beam
     const double phi_i = beam.getPhi();
 
-    auto detector = Detector2D(m_instrument);
+    const IDetector2D& detector = m_instrument.detector2D();
 
     const Eigen::Matrix2cd beam_polarization = beam.getPolarization();
-    const Eigen::Matrix2cd analyzer_operator = detector->detectionProperties().analyzerOperator();
-    size_t spec_index = detector->getIndexOfSpecular(beam);
+    const Eigen::Matrix2cd analyzer_operator = detector.detectionProperties().analyzerOperator();
+    const size_t spec_index = detector.getIndexOfSpecular(beam);
 
     result.reserve(detector_context->numberOfSimulationElements());
     for (size_t element_index = 0; element_index < detector_context->numberOfSimulationElements();
@@ -158,18 +149,16 @@ void Simulation2D::addDataToCache(double weight)
     if (m_sim_elements.size() != m_cache.size())
         throw std::runtime_error("Error in Simulation2D::addDataToCache(double): cache size"
                                  " not the same as element size");
-    for (unsigned i = 0; i < m_sim_elements.size(); i++) {
+    for (unsigned i = 0; i < m_sim_elements.size(); i++)
         m_cache[i] += m_sim_elements[i].getIntensity() * weight;
-    }
 }
 
 void Simulation2D::moveDataFromCache()
 {
     ASSERT(!m_cache.empty());
     if (!m_cache.empty()) {
-        for (unsigned i = 0; i < m_sim_elements.size(); i++) {
+        for (unsigned i = 0; i < m_sim_elements.size(); i++)
             m_sim_elements[i].setIntensity(m_cache[i]);
-        }
         m_cache.clear();
     }
 }
@@ -178,9 +167,8 @@ std::vector<double> Simulation2D::rawResults() const
 {
     std::vector<double> result;
     result.resize(m_sim_elements.size());
-    for (unsigned i = 0; i < m_sim_elements.size(); ++i) {
+    for (unsigned i = 0; i < m_sim_elements.size(); ++i)
         result[i] = m_sim_elements[i].getIntensity();
-    }
     return result;
 }
 
@@ -190,19 +178,7 @@ void Simulation2D::setRawResults(const std::vector<double>& raw_data)
     if (raw_data.size() != m_sim_elements.size())
         throw std::runtime_error("Simulation2D::setRawResults: size of vector passed as "
                                  "argument doesn't match number of elements in this simulation");
-    for (unsigned i = 0; i < raw_data.size(); i++) {
+    for (unsigned i = 0; i < raw_data.size(); i++)
         m_sim_elements[i].setIntensity(raw_data[i]);
-    }
     transferResultsToIntensityMap();
 }
-
-namespace
-{
-IDetector2D* Detector2D(Instrument& instrument)
-{
-    IDetector2D* p_detector = dynamic_cast<IDetector2D*>(instrument.getDetector());
-    if (!p_detector)
-        throw std::runtime_error("Error in Simulation2D: wrong detector type");
-    return p_detector;
-}
-} // namespace
diff --git a/Core/SimulationElement/SimulationElement.cpp b/Core/SimulationElement/SimulationElement.cpp
index a3647e769bf4c79cc450f8f0f72ed0cd03e261e6..48e99e32b439e2d8eeb0440c9e92793f3f01c0da 100644
--- a/Core/SimulationElement/SimulationElement.cpp
+++ b/Core/SimulationElement/SimulationElement.cpp
@@ -49,7 +49,7 @@ SimulationElement::SimulationElement(SimulationElement&& other) noexcept
 {
 }
 
-SimulationElement::~SimulationElement() = default;
+SimulationElement::~SimulationElement() = default; // here because of forward declared members
 
 SimulationElement& SimulationElement::operator=(const SimulationElement& other)
 {
diff --git a/auto/Wrap/doxygen_core.i b/auto/Wrap/doxygen_core.i
index 44d390cef7d400e53118bf2e675577dabffb233d..fe0328fde4570d56d63ee32e69160641803b72ff 100644
--- a/auto/Wrap/doxygen_core.i
+++ b/auto/Wrap/doxygen_core.i
@@ -7648,6 +7648,9 @@ Scalar value getters; these throw errors by default as they should only be used
 %feature("docstring")  ILayerRTCoefficients::getScalarKz "virtual complex_t ILayerRTCoefficients::getScalarKz() const
 ";
 
+%feature("docstring")  ILayerRTCoefficients::getReflectionMatrix "virtual Eigen::Matrix2cd ILayerRTCoefficients::getReflectionMatrix() const
+";
+
 
 // File: classILayout.xml
 %feature("docstring") ILayout "
@@ -8286,6 +8289,9 @@ Returns the detector data.
 %feature("docstring")  Instrument::getDetector "IDetector * Instrument::getDetector()
 ";
 
+%feature("docstring")  Instrument::detector2D "IDetector2D & Instrument::detector2D()
+";
+
 %feature("docstring")  Instrument::getDetectorMask "const DetectorMask * Instrument::getDetectorMask() const
 ";
 
@@ -9862,6 +9868,12 @@ C++ includes: ISpecularStrategy.h
 %feature("docstring")  ISpecularStrategy::~ISpecularStrategy "virtual ISpecularStrategy::~ISpecularStrategy()=default
 ";
 
+%feature("docstring")  ISpecularStrategy::ISpecularStrategy "ISpecularStrategy::ISpecularStrategy()=default
+";
+
+%feature("docstring")  ISpecularStrategy::ISpecularStrategy "ISpecularStrategy::ISpecularStrategy(const ISpecularStrategy &other)=delete
+";
+
 %feature("docstring")  ISpecularStrategy::Execute "virtual coeffs_t ISpecularStrategy::Execute(const std::vector< Slice > &slices, const kvector_t &k) const =0
 ";
 
@@ -11103,6 +11115,9 @@ The following functions return the transmitted and reflected amplitudes for diff
 Returns z-part of the two wavevector eigenmodes. 
 ";
 
+%feature("docstring")  MatrixRTCoefficients_v2::getReflectionMatrix "Eigen::Matrix2cd MatrixRTCoefficients_v2::getReflectionMatrix() const override
+";
+
 
 // File: classMesoCrystal.xml
 %feature("docstring") MesoCrystal "
@@ -17101,9 +17116,6 @@ C++ includes: ZLimits.h
 // File: namespace_0d530.xml
 
 
-// File: namespace_0d532.xml
-
-
 // File: namespace_0d536.xml
 
 
diff --git a/auto/Wrap/libBornAgainCore.py b/auto/Wrap/libBornAgainCore.py
index 9edbc33490779cda80469a2377afe9b8efc56b8a..4c0d78ac48750c3b66f9a9fea211186726c9ebcf 100644
--- a/auto/Wrap/libBornAgainCore.py
+++ b/auto/Wrap/libBornAgainCore.py
@@ -1,5 +1,5 @@
 # This file was automatically generated by SWIG (http://www.swig.org).
-# Version 4.0.1
+# Version 4.0.2
 #
 # Do not make changes to this file unless you know what you are doing--modify
 # the SWIG interface file instead.
@@ -20991,6 +20991,14 @@ class Instrument(INode):
         """
         return _libBornAgainCore.Instrument_getDetector(self, *args)
 
+    def detector2D(self):
+        r"""
+        detector2D(Instrument self) -> IDetector2D
+        IDetector2D & Instrument::detector2D()
+
+        """
+        return _libBornAgainCore.Instrument_detector2D(self)
+
     def getDetectorMask(self):
         r"""
         getDetectorMask(Instrument self) -> DetectorMask
diff --git a/auto/Wrap/libBornAgainCore_wrap.cpp b/auto/Wrap/libBornAgainCore_wrap.cpp
index 6c3c7ec63cb6ec5eafc2870a34df2639b6e15144..322ad584e9c699f486d6182f69633505bc2e872f 100644
--- a/auto/Wrap/libBornAgainCore_wrap.cpp
+++ b/auto/Wrap/libBornAgainCore_wrap.cpp
@@ -1,6 +1,6 @@
 /* ----------------------------------------------------------------------------
  * This file was automatically generated by SWIG (http://www.swig.org).
- * Version 4.0.1
+ * Version 4.0.2
  *
  * This file is not intended to be easily readable and contains a number of
  * coding conventions designed to improve portability and efficiency. Do not make
@@ -809,15 +809,19 @@ SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) {
 SWIGINTERN char*
 SWIG_Python_str_AsChar(PyObject *str)
 {
-#if PY_VERSION_HEX >= 0x03000000
+#if PY_VERSION_HEX >= 0x03030000
+  return (char *)PyUnicode_AsUTF8(str);
+#elif PY_VERSION_HEX >= 0x03000000
   char *newstr = 0;
   str = PyUnicode_AsUTF8String(str);
   if (str) {
     char *cstr;
     Py_ssize_t len;
-    PyBytes_AsStringAndSize(str, &cstr, &len);
-    newstr = (char *) malloc(len+1);
-    memcpy(newstr, cstr, len+1);
+    if (PyBytes_AsStringAndSize(str, &cstr, &len) != -1) {
+      newstr = (char *) malloc(len+1);
+      if (newstr)
+        memcpy(newstr, cstr, len+1);
+    }
     Py_XDECREF(str);
   }
   return newstr;
@@ -826,10 +830,10 @@ SWIG_Python_str_AsChar(PyObject *str)
 #endif
 }
 
-#if PY_VERSION_HEX >= 0x03000000
-#  define SWIG_Python_str_DelForPy3(x) free( (void*) (x) )
+#if PY_VERSION_HEX >= 0x03030000 || PY_VERSION_HEX < 0x03000000
+#  define SWIG_Python_str_DelForPy3(x)
 #else
-#  define SWIG_Python_str_DelForPy3(x) 
+#  define SWIG_Python_str_DelForPy3(x) free( (void*) (x) )
 #endif
 
 
@@ -1244,6 +1248,19 @@ SWIG_Python_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssi
   }
 }
 
+SWIGINTERN int
+SWIG_Python_CheckNoKeywords(PyObject *kwargs, const char *name) {
+  int no_kwargs = 1;
+  if (kwargs) {
+    assert(PyDict_Check(kwargs));
+    if (PyDict_Size(kwargs) > 0) {
+      PyErr_Format(PyExc_TypeError, "%s() does not take keyword arguments", name);
+      no_kwargs = 0;
+    }
+  }
+  return no_kwargs;
+}
+
 /* A functor is a function object with one single object argument */
 #define SWIG_Python_CallFunctor(functor, obj)	        PyObject_CallFunctionObjArgs(functor, obj, NULL);
 
@@ -1757,6 +1774,12 @@ SwigPyObject_TypeOnce(void) {
 #if PY_VERSION_HEX >= 0x03040000
       0,                                    /* tp_finalize */
 #endif
+#if PY_VERSION_HEX >= 0x03080000
+      0,                                    /* tp_vectorcall */
+#endif
+#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)
+      0,                                    /* tp_print */
+#endif
 #ifdef COUNT_ALLOCS
       0,                                    /* tp_allocs */
       0,                                    /* tp_frees */
@@ -1918,6 +1941,12 @@ SwigPyPacked_TypeOnce(void) {
 #if PY_VERSION_HEX >= 0x03040000
       0,                                    /* tp_finalize */
 #endif
+#if PY_VERSION_HEX >= 0x03080000
+      0,                                    /* tp_vectorcall */
+#endif
+#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)
+      0,                                    /* tp_print */
+#endif
 #ifdef COUNT_ALLOCS
       0,                                    /* tp_allocs */
       0,                                    /* tp_frees */
@@ -2244,8 +2273,10 @@ SWIG_Python_NewShadowInstance(SwigPyClientData *data, PyObject *swig_this)
 	}
       }
 #else
-      PyObject *key = SWIG_This();
-      PyObject_SetAttr(inst, key, swig_this);
+      if (PyObject_SetAttr(inst, SWIG_This(), swig_this) == -1) {
+        Py_DECREF(inst);
+        inst = 0;
+      }
 #endif
     }
   } else {
@@ -2257,8 +2288,12 @@ SWIG_Python_NewShadowInstance(SwigPyClientData *data, PyObject *swig_this)
         inst = ((PyTypeObject *)data->newargs)->tp_new((PyTypeObject *)data->newargs, empty_args, empty_kwargs);
         Py_DECREF(empty_kwargs);
         if (inst) {
-          PyObject_SetAttr(inst, SWIG_This(), swig_this);
-          Py_TYPE(inst)->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
+          if (PyObject_SetAttr(inst, SWIG_This(), swig_this) == -1) {
+            Py_DECREF(inst);
+            inst = 0;
+          } else {
+            Py_TYPE(inst)->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
+          }
         }
       }
       Py_DECREF(empty_args);
@@ -2275,25 +2310,21 @@ SWIG_Python_NewShadowInstance(SwigPyClientData *data, PyObject *swig_this)
   return inst;
 }
 
-SWIGRUNTIME void
+SWIGRUNTIME int
 SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this)
 {
- PyObject *dict;
 #if !defined(SWIG_PYTHON_SLOW_GETSET_THIS)
- PyObject **dictptr = _PyObject_GetDictPtr(inst);
- if (dictptr != NULL) {
-   dict = *dictptr;
-   if (dict == NULL) {
-     dict = PyDict_New();
-     *dictptr = dict;
-   }
-   PyDict_SetItem(dict, SWIG_This(), swig_this);
-   return;
- }
+  PyObject **dictptr = _PyObject_GetDictPtr(inst);
+  if (dictptr != NULL) {
+    PyObject *dict = *dictptr;
+    if (dict == NULL) {
+      dict = PyDict_New();
+      *dictptr = dict;
+    }
+    return PyDict_SetItem(dict, SWIG_This(), swig_this);
+  }
 #endif
- dict = PyObject_GetAttrString(inst, "__dict__");
- PyDict_SetItem(dict, SWIG_This(), swig_this);
- Py_DECREF(dict);
+  return PyObject_SetAttr(inst, SWIG_This(), swig_this);
 } 
 
 
@@ -2307,7 +2338,8 @@ SWIG_Python_InitShadowInstance(PyObject *args) {
     if (sthis) {
       SwigPyObject_append((PyObject*) sthis, obj[1]);
     } else {
-      SWIG_Python_SetSwigThis(obj[0], obj[1]);
+      if (SWIG_Python_SetSwigThis(obj[0], obj[1]) != 0)
+        return NULL;
     }
     return SWIG_Py_Void();
   }
@@ -3428,7 +3460,7 @@ static swig_module_info swig_module = {swig_types, 339, 0, 0, 0, 0};
 #endif
 #define SWIG_name    "_libBornAgainCore"
 
-#define SWIGVERSION 0x040001 
+#define SWIGVERSION 0x040002 
 #define SWIG_VERSION SWIGVERSION
 
 
@@ -4166,11 +4198,20 @@ namespace swig {
   template <class Type>
   struct traits_asptr {   
     static int asptr(PyObject *obj, Type **val) {
-      Type *p = 0;
+      int res = SWIG_ERROR;
       swig_type_info *descriptor = type_info<Type>();
-      int res = descriptor ? SWIG_ConvertPtr(obj, (void **)&p, descriptor, 0) : SWIG_ERROR;
-      if (SWIG_IsOK(res)) {
-	if (val) *val = p;
+      if (val) {
+        Type *p = 0;
+        int newmem = 0;
+        res = descriptor ? SWIG_ConvertPtrAndOwn(obj, (void **)&p, descriptor, 0, &newmem) : SWIG_ERROR;
+        if (SWIG_IsOK(res)) {
+          if (newmem & SWIG_CAST_NEW_MEMORY) {
+            res |= SWIG_NEWOBJMASK;
+          }
+          *val = p;
+        }
+      } else {
+        res = descriptor ? SWIG_ConvertPtr(obj, 0, descriptor, 0) : SWIG_ERROR;
       }
       return res;
     }
@@ -5370,7 +5411,7 @@ namespace swig {
   struct container_owner {
     // By default, do not add the back-reference (for value types)
     // Specialization below will check the reference for pointer types.
-    static bool back_reference(PyObject* child, PyObject* owner) {
+    static bool back_reference(PyObject* /*child*/, PyObject* /*owner*/) {
       return false;
     }
   };
@@ -5387,8 +5428,7 @@ namespace swig {
     static bool back_reference(PyObject* child, PyObject* owner) {
       SwigPyObject* swigThis = SWIG_Python_GetSwigThis(child);
       if (swigThis && (swigThis->own & SWIG_POINTER_OWN) != SWIG_POINTER_OWN) {
-        PyObject_SetAttr(child, container_owner_attribute(), owner);
-        return true;
+        return PyObject_SetAttr(child, container_owner_attribute(), owner) != -1;
       }
       return false;
     }
@@ -5892,7 +5932,7 @@ SWIG_AsVal_std_complex_Sl_double_Sg_  (PyObject *o, std::complex<double>* val)
 
 
 SWIGINTERNINLINE PyObject*
-SWIG_From_std_complex_Sl_double_Sg_  (/*@SWIG:/usr/share/swig4.0/typemaps/swigmacros.swg,104,%ifcplusplus@*/
+SWIG_From_std_complex_Sl_double_Sg_  (/*@SWIG:/usr/local/share/swig/4.0.2/typemaps/swigmacros.swg,104,%ifcplusplus@*/
 
 const std::complex<double>&
 
@@ -6068,9 +6108,11 @@ SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc)
     if (alloc)
       *alloc = SWIG_NEWOBJ;
 #endif
-    PyBytes_AsStringAndSize(obj, &cstr, &len);
+    if (PyBytes_AsStringAndSize(obj, &cstr, &len) == -1)
+      return SWIG_TypeError;
 #else
-    PyString_AsStringAndSize(obj, &cstr, &len);
+    if (PyString_AsStringAndSize(obj, &cstr, &len) == -1)
+      return SWIG_TypeError;
 #endif
     if (cptr) {
       if (alloc) {
@@ -6445,7 +6487,7 @@ SWIGINTERN void std_vector_Sl_std_string_Sg__insert__SWIG_1(std::vector< std::st
 	    res = get_pair(first, second, val);
 	  }
 	} else {
-	  value_type *p;
+	  value_type *p = 0;
 	  swig_type_info *descriptor = swig::type_info<value_type>();
 	  res = descriptor ? SWIG_ConvertPtr(obj, (void **)&p, descriptor, 0) : SWIG_ERROR;
 	  if (SWIG_IsOK(res) && val)  *val = p;
@@ -6607,7 +6649,7 @@ SWIGINTERN void std_vector_Sl_std_string_Sg__insert__SWIG_1(std::vector< std::st
 #endif
 	  res = traits_asptr_stdseq<map_type, std::pair<K, T> >::asptr(items, val);
 	} else {
-	  map_type *p;
+	  map_type *p = 0;
 	  swig_type_info *descriptor = swig::type_info<map_type>();
 	  res = descriptor ? SWIG_ConvertPtr(obj, (void **)&p, descriptor, 0) : SWIG_ERROR;
 	  if (SWIG_IsOK(res) && val)  *val = p;
@@ -115698,6 +115740,29 @@ fail:
 }
 
 
+SWIGINTERN PyObject *_wrap_Instrument_detector2D(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  Instrument *arg1 = (Instrument *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject *swig_obj[1] ;
+  IDetector2D *result = 0 ;
+  
+  if (!args) SWIG_fail;
+  swig_obj[0] = args;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Instrument, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Instrument_detector2D" "', argument " "1"" of type '" "Instrument *""'"); 
+  }
+  arg1 = reinterpret_cast< Instrument * >(argp1);
+  result = (IDetector2D *) &(arg1)->detector2D();
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_IDetector2D, 0 |  0 );
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
 SWIGINTERN PyObject *_wrap_Instrument_getDetectorMask(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   Instrument *arg1 = (Instrument *) 0 ;
@@ -133560,6 +133625,11 @@ static PyMethodDef SwigMethods[] = {
 		"IDetector * Instrument::getDetector()\n"
 		"\n"
 		""},
+	 { "Instrument_detector2D", _wrap_Instrument_detector2D, METH_O, "\n"
+		"Instrument_detector2D(Instrument self) -> IDetector2D\n"
+		"IDetector2D & Instrument::detector2D()\n"
+		"\n"
+		""},
 	 { "Instrument_getDetectorMask", _wrap_Instrument_getDetectorMask, METH_O, "\n"
 		"Instrument_getDetectorMask(Instrument self) -> DetectorMask\n"
 		"const DetectorMask * Instrument::getDetectorMask() const\n"
@@ -138381,6 +138451,12 @@ extern "C" {
 #if PY_VERSION_HEX >= 0x03040000
         0,                                  /* tp_finalize */
 #endif
+#if PY_VERSION_HEX >= 0x03080000
+        0,                                  /* tp_vectorcall */
+#endif
+#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)
+        0,                                  /* tp_print */
+#endif
 #ifdef COUNT_ALLOCS
         0,                                  /* tp_allocs */
         0,                                  /* tp_frees */
diff --git a/auto/Wrap/libBornAgainCore_wrap.h b/auto/Wrap/libBornAgainCore_wrap.h
index 8fbe15520695e753a7dce723eac7ac3bdd8a19b2..03bab1484a299bbe427052758ddbf03c7ca168fe 100644
--- a/auto/Wrap/libBornAgainCore_wrap.h
+++ b/auto/Wrap/libBornAgainCore_wrap.h
@@ -1,6 +1,6 @@
 /* ----------------------------------------------------------------------------
  * This file was automatically generated by SWIG (http://www.swig.org).
- * Version 4.0.1
+ * Version 4.0.2
  *
  * This file is not intended to be easily readable and contains a number of
  * coding conventions designed to improve portability and efficiency. Do not make
diff --git a/auto/Wrap/swig_runtime.h b/auto/Wrap/swig_runtime.h
index abc07c95740d46e9e4eb7d3bfbd4bfa71a1b9c11..2c4fcac1df35cbb0539ee3a9ddfc3a0645eeb96a 100644
--- a/auto/Wrap/swig_runtime.h
+++ b/auto/Wrap/swig_runtime.h
@@ -1,6 +1,6 @@
 /* ----------------------------------------------------------------------------
  * This file was automatically generated by SWIG (http://www.swig.org).
- * Version 4.0.1
+ * Version 4.0.2
  *
  * This file is not intended to be easily readable and contains a number of
  * coding conventions designed to improve portability and efficiency. Do not make
@@ -759,15 +759,19 @@ SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) {
 SWIGINTERN char*
 SWIG_Python_str_AsChar(PyObject *str)
 {
-#if PY_VERSION_HEX >= 0x03000000
+#if PY_VERSION_HEX >= 0x03030000
+  return (char *)PyUnicode_AsUTF8(str);
+#elif PY_VERSION_HEX >= 0x03000000
   char *newstr = 0;
   str = PyUnicode_AsUTF8String(str);
   if (str) {
     char *cstr;
     Py_ssize_t len;
-    PyBytes_AsStringAndSize(str, &cstr, &len);
-    newstr = (char *) malloc(len+1);
-    memcpy(newstr, cstr, len+1);
+    if (PyBytes_AsStringAndSize(str, &cstr, &len) != -1) {
+      newstr = (char *) malloc(len+1);
+      if (newstr)
+        memcpy(newstr, cstr, len+1);
+    }
     Py_XDECREF(str);
   }
   return newstr;
@@ -776,10 +780,10 @@ SWIG_Python_str_AsChar(PyObject *str)
 #endif
 }
 
-#if PY_VERSION_HEX >= 0x03000000
-#  define SWIG_Python_str_DelForPy3(x) free( (void*) (x) )
+#if PY_VERSION_HEX >= 0x03030000 || PY_VERSION_HEX < 0x03000000
+#  define SWIG_Python_str_DelForPy3(x)
 #else
-#  define SWIG_Python_str_DelForPy3(x) 
+#  define SWIG_Python_str_DelForPy3(x) free( (void*) (x) )
 #endif
 
 
@@ -1190,6 +1194,19 @@ SWIG_Python_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssi
   }
 }
 
+SWIGINTERN int
+SWIG_Python_CheckNoKeywords(PyObject *kwargs, const char *name) {
+  int no_kwargs = 1;
+  if (kwargs) {
+    assert(PyDict_Check(kwargs));
+    if (PyDict_Size(kwargs) > 0) {
+      PyErr_Format(PyExc_TypeError, "%s() does not take keyword arguments", name);
+      no_kwargs = 0;
+    }
+  }
+  return no_kwargs;
+}
+
 /* A functor is a function object with one single object argument */
 #define SWIG_Python_CallFunctor(functor, obj)	        PyObject_CallFunctionObjArgs(functor, obj, NULL);
 
@@ -1703,6 +1720,12 @@ SwigPyObject_TypeOnce(void) {
 #if PY_VERSION_HEX >= 0x03040000
       0,                                    /* tp_finalize */
 #endif
+#if PY_VERSION_HEX >= 0x03080000
+      0,                                    /* tp_vectorcall */
+#endif
+#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)
+      0,                                    /* tp_print */
+#endif
 #ifdef COUNT_ALLOCS
       0,                                    /* tp_allocs */
       0,                                    /* tp_frees */
@@ -1864,6 +1887,12 @@ SwigPyPacked_TypeOnce(void) {
 #if PY_VERSION_HEX >= 0x03040000
       0,                                    /* tp_finalize */
 #endif
+#if PY_VERSION_HEX >= 0x03080000
+      0,                                    /* tp_vectorcall */
+#endif
+#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)
+      0,                                    /* tp_print */
+#endif
 #ifdef COUNT_ALLOCS
       0,                                    /* tp_allocs */
       0,                                    /* tp_frees */
@@ -2190,8 +2219,10 @@ SWIG_Python_NewShadowInstance(SwigPyClientData *data, PyObject *swig_this)
 	}
       }
 #else
-      PyObject *key = SWIG_This();
-      PyObject_SetAttr(inst, key, swig_this);
+      if (PyObject_SetAttr(inst, SWIG_This(), swig_this) == -1) {
+        Py_DECREF(inst);
+        inst = 0;
+      }
 #endif
     }
   } else {
@@ -2203,8 +2234,12 @@ SWIG_Python_NewShadowInstance(SwigPyClientData *data, PyObject *swig_this)
         inst = ((PyTypeObject *)data->newargs)->tp_new((PyTypeObject *)data->newargs, empty_args, empty_kwargs);
         Py_DECREF(empty_kwargs);
         if (inst) {
-          PyObject_SetAttr(inst, SWIG_This(), swig_this);
-          Py_TYPE(inst)->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
+          if (PyObject_SetAttr(inst, SWIG_This(), swig_this) == -1) {
+            Py_DECREF(inst);
+            inst = 0;
+          } else {
+            Py_TYPE(inst)->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
+          }
         }
       }
       Py_DECREF(empty_args);
@@ -2221,25 +2256,21 @@ SWIG_Python_NewShadowInstance(SwigPyClientData *data, PyObject *swig_this)
   return inst;
 }
 
-SWIGRUNTIME void
+SWIGRUNTIME int
 SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this)
 {
- PyObject *dict;
 #if !defined(SWIG_PYTHON_SLOW_GETSET_THIS)
- PyObject **dictptr = _PyObject_GetDictPtr(inst);
- if (dictptr != NULL) {
-   dict = *dictptr;
-   if (dict == NULL) {
-     dict = PyDict_New();
-     *dictptr = dict;
-   }
-   PyDict_SetItem(dict, SWIG_This(), swig_this);
-   return;
- }
-#endif
- dict = PyObject_GetAttrString(inst, "__dict__");
- PyDict_SetItem(dict, SWIG_This(), swig_this);
- Py_DECREF(dict);
+  PyObject **dictptr = _PyObject_GetDictPtr(inst);
+  if (dictptr != NULL) {
+    PyObject *dict = *dictptr;
+    if (dict == NULL) {
+      dict = PyDict_New();
+      *dictptr = dict;
+    }
+    return PyDict_SetItem(dict, SWIG_This(), swig_this);
+  }
+#endif
+  return PyObject_SetAttr(inst, SWIG_This(), swig_this);
 } 
 
 
@@ -2253,7 +2284,8 @@ SWIG_Python_InitShadowInstance(PyObject *args) {
     if (sthis) {
       SwigPyObject_append((PyObject*) sthis, obj[1]);
     } else {
-      SWIG_Python_SetSwigThis(obj[0], obj[1]);
+      if (SWIG_Python_SetSwigThis(obj[0], obj[1]) != 0)
+        return NULL;
     }
     return SWIG_Py_Void();
   }