diff --git a/Device/Detector/DetectorContext.cpp b/Device/Detector/DetectorContext.cpp
deleted file mode 100644
index faaa9870ebaa9e682f827589a10346802cb12d89..0000000000000000000000000000000000000000
--- a/Device/Detector/DetectorContext.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-//  ************************************************************************************************
-//
-//  BornAgain: simulate and fit reflection and scattering
-//
-//! @file      Device/Detector/DetectorContext.cpp
-//! @brief     Implements DetectorContext class.
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-//  ************************************************************************************************
-
-#include "Device/Detector/DetectorContext.h"
-#include "Device/Detector/IDetector.h"
-
-DetectorContext::DetectorContext(const IDetector* detector)
-{
-    setup_context(detector);
-}
-
-size_t DetectorContext::numberOfElements() const
-{
-    return m_active_indices.size();
-}
-
-//! Creates pixel for given element index. Element index is sequential index in a vector
-//! of DiffuseElements. Corresponds to sequence of detector bins inside ROI and outside
-//! of masked areas.
-
-std::unique_ptr<const IPixel> DetectorContext::createPixel(size_t element_index) const
-{
-    return std::unique_ptr<IPixel>(m_pixels[element_index]->clone());
-}
-
-size_t DetectorContext::detectorIndex(size_t element_index) const
-{
-    return m_active_indices[element_index];
-}
-
-void DetectorContext::setup_context(const IDetector* detector)
-{
-    m_active_indices = detector->active_indices();
-    m_analyzer_operator = detector->analyzer().matrix();
-    m_pixels.reserve(m_active_indices.size());
-    for (auto detector_index : m_active_indices)
-        m_pixels.emplace_back(detector->createPixel(detector_index));
-}
diff --git a/Device/Detector/DetectorContext.h b/Device/Detector/DetectorContext.h
deleted file mode 100644
index e710cf8243c978dc2016398527ecbe6e4699abe9..0000000000000000000000000000000000000000
--- a/Device/Detector/DetectorContext.h
+++ /dev/null
@@ -1,52 +0,0 @@
-//  ************************************************************************************************
-//
-//  BornAgain: simulate and fit reflection and scattering
-//
-//! @file      Device/Detector/DetectorContext.h
-//! @brief     Define DetectorContext class.
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-//  ************************************************************************************************
-
-#ifndef USER_API
-#ifndef BORNAGAIN_DEVICE_DETECTOR_DETECTORCONTEXT_H
-#define BORNAGAIN_DEVICE_DETECTOR_DETECTORCONTEXT_H
-
-#include "Base/Pixel/IPixel.h"
-#include "Base/Spin/SpinMatrix.h"
-#include "Base/Types/OwningVector.h"
-#include <memory>
-#include <vector>
-
-class IDetector;
-
-//! Holds precalculated information for faster DiffuseElement generation.
-//! @ingroup detector
-
-class DetectorContext {
-public:
-    DetectorContext(const IDetector* detector);
-
-    DetectorContext(const DetectorContext& other) = delete;
-    DetectorContext& operator=(const DetectorContext& other) = delete;
-
-    size_t numberOfElements() const;
-
-    std::unique_ptr<const IPixel> createPixel(size_t element_index) const;
-
-    size_t detectorIndex(size_t element_index) const;
-
-private:
-    void setup_context(const IDetector* detector);
-
-    SpinMatrix m_analyzer_operator;
-    OwningVector<const IPixel> m_pixels;  //! All unmasked pixels inside ROI.
-    std::vector<size_t> m_active_indices; //! The sequence of bin indices (unmasked, in ROI)
-};
-
-#endif // BORNAGAIN_DEVICE_DETECTOR_DETECTORCONTEXT_H
-#endif // USER_API
diff --git a/Device/Detector/IDetector.cpp b/Device/Detector/IDetector.cpp
index e7a218c043c194b5e90d0e0fcfba982fa6109d3c..4b93c91063b322178a46c20a78bc287f96652f64 100644
--- a/Device/Detector/IDetector.cpp
+++ b/Device/Detector/IDetector.cpp
@@ -19,7 +19,6 @@
 #include "Base/Const/Units.h"
 #include "Base/Util/Assert.h"
 #include "Device/Beam/Beam.h"
-#include "Device/Detector/DetectorContext.h"
 #include "Device/Detector/SimulationAreaIterator.h"
 #include "Device/Mask/DetectorMask.h"
 #include "Device/Mask/InfinitePlane.h"
@@ -341,11 +340,6 @@ std::vector<size_t> IDetector::active_indices() const
     return result;
 }
 
-std::unique_ptr<DetectorContext> IDetector::createContext() const
-{
-    return std::make_unique<DetectorContext>(this);
-}
-
 void IDetector::addMask(const IShape2D& shape, bool mask_value)
 {
     m_mask->addMask(shape, mask_value);
@@ -365,7 +359,6 @@ const DetectorMask* IDetector::detectorMask() const
 
 size_t IDetector::getGlobalIndex(size_t x, size_t y) const
 {
-    if (rank() != 2)
-        return totalSize();
+    ASSERT(rank() == 2);
     return x * axis(1).size() + y;
 }
diff --git a/Device/Detector/IDetector.h b/Device/Detector/IDetector.h
index 4c3522ea5482c5bb26504afaf4ce791f905e3430..4e68ad2f7b3d8520648447808a8662621f3e12e2 100644
--- a/Device/Detector/IDetector.h
+++ b/Device/Detector/IDetector.h
@@ -23,7 +23,6 @@
 class Beam;
 class CoordSystem2D;
 class Datafield;
-class DetectorContext;
 class DetectorMask;
 class DiffuseElement;
 class Direction;
@@ -36,7 +35,7 @@ class IShape2D;
 class SimulationAreaIterator;
 
 
-//! Abstract detector interface.
+//! Abstract base for 2D detectors, realized by RectangularDetector and SphericalDetector.
 //!
 //! Handles also "region of interest" (ROI). In general, the ROI is the whole
 //! detector, and all methods related to ROI work on the whole detector.
@@ -170,8 +169,6 @@ public:
     std::pair<double, double> regionOfInterestBounds(size_t iAxis) const;
 
 #ifndef SWIG
-    std::unique_ptr<DetectorContext> createContext() const;
-
     //! Create begin-iterator to iterate over all points which are not masked and lay
     //! within the "Region of Interest"
     SimulationAreaIterator beginNonMaskedPoints() const;
@@ -211,25 +208,22 @@ protected:
     //! Returns the name for the axis with given index
     virtual std::string axisName(size_t index) const = 0;
 
-    //! Return 0 if no ROI has been explicitly set.
-    //! Size means number of data points.
+    //! Return number of data points in Roi, or 0 if no Roi is set.
     virtual size_t sizeOfExplicitRegionOfInterest() const;
 
-    //! Lower and upper bound of one axis of an explicitly set ROI.
-    //! Return 0/0 if no ROI has been explicitly set.
+    //! Returns lower and upper Roi bound of one axis, or (0,0) if no Roi is set.
     virtual std::pair<double, double> boundsOfExplicitRegionOfInterest(size_t iAxis) const;
 
-    //! Calculate global index from two axis indices
+    //! Returns flattened index computed from two axis indices.
     size_t getGlobalIndex(size_t x, size_t y) const;
 
 #ifndef SWIG
-    //! Keeps RegionOfInterest (ROI) data of one axis
+    //! Keeps RegionOfInterest (ROI) data of one axis.
     struct RoiOfAxis {
         double lower;
         double upper;
 
-        // The following values are all pre-computed values. Aim is to speed up repeated
-        // calculations.
+        // Precomputed values, to speed up repeated calculations.
         size_t lowerIndex;   //!< index corresponding to 'lower'
         size_t upperIndex;   //!< index corresponding to 'upper'
         size_t roiSize;      //!< number of bins on axis of ROI
diff --git a/Sim/Simulation/ISimulation.h b/Sim/Simulation/ISimulation.h
index 1460ca02eabe836c312153aaed6a0a075933fd8c..9c3095e47f983479d6aa8e2283fc1b02848d13df 100644
--- a/Sim/Simulation/ISimulation.h
+++ b/Sim/Simulation/ISimulation.h
@@ -20,15 +20,15 @@
 #include "Param/Node/INode.h"
 #include <heinz/Vectors3D.h>
 
+class Datafield;
 class IBackground;
 class IComputation;
 class ICoordSystem;
 class MultiLayer;
 class ProgressHandler;
-class Datafield;
+class ReSample;
 class SimulationOptions;
 class SimulationResult;
-class ReSample;
 
 //! Abstract base class, holds the infrastructure to run a simulation.
 //!
diff --git a/Sim/Simulation/ISimulation2D.cpp b/Sim/Simulation/ISimulation2D.cpp
index d5e3dc29ae2c9b4026ffa09d88d34c34bbaff35c..fec12f50863dafe73162fdf12ea49606cd3908d1 100644
--- a/Sim/Simulation/ISimulation2D.cpp
+++ b/Sim/Simulation/ISimulation2D.cpp
@@ -13,9 +13,9 @@
 //  ************************************************************************************************
 
 #include "Sim/Simulation/ISimulation2D.h"
+#include "Base/Pixel/IPixel.h"
 #include "Base/Util/Assert.h"
 #include "Device/Beam/Beam.h"
-#include "Device/Detector/DetectorContext.h"
 #include "Device/Detector/IDetector.h"
 #include "Device/Detector/SphericalDetector.h"
 #include "Resample/Element/DiffuseElement.h"
@@ -50,7 +50,10 @@ std::vector<const INode*> ISimulation2D::nodeChildren() const
 
 void ISimulation2D::prepareSimulation()
 {
-    m_detector_context = m_detector->createContext();
+    m_active_indices = m_detector->active_indices();
+    m_pixels.reserve(m_active_indices.size());
+    for (auto detector_index : m_active_indices)
+        m_pixels.emplace_back(m_detector->createPixel(detector_index));
 }
 
 void ISimulation2D::addMask(const IShape2D& shape, bool mask_value)
@@ -70,9 +73,7 @@ void ISimulation2D::setRegionOfInterest(double xlow, double ylow, double xup, do
 
 size_t ISimulation2D::numberOfElements() const
 {
-    if (!m_detector_context)
-        throw std::runtime_error("Error in numberOfElements(): no detector context");
-    return m_detector_context->numberOfElements();
+    return m_active_indices.size();
 }
 
 std::unique_ptr<IComputation> ISimulation2D::createComputation(const ReSample& re_sample,
@@ -92,16 +93,16 @@ std::vector<DiffuseElement> ISimulation2D::generateElements(const Beam& beam)
     const SpinMatrix beam_polMatrices = beam.polMatrix();
 
     const SpinMatrix analyzer_operator = m_detector->analyzer().matrix();
-    const size_t spec_index = m_detector->indexOfSpecular(beam);
+    const size_t i_specular = m_detector->indexOfSpecular(beam);
 
-    const size_t N = m_detector_context->numberOfElements();
+    const size_t N = m_active_indices.size();
 
     std::vector<DiffuseElement> result;
     result.reserve(N);
     for (size_t i = 0; i < N; ++i)
         result.emplace_back(DiffuseElement(
-            wavelength, alpha_i, phi_i, m_detector_context->createPixel(i), beam_polMatrices,
-            analyzer_operator, m_detector_context->detectorIndex(i) == spec_index));
+            wavelength, alpha_i, phi_i, std::unique_ptr<IPixel>(m_pixels[i]->clone()),
+            beam_polMatrices, analyzer_operator, m_active_indices[i] == i_specular));
     return result;
 }
 
diff --git a/Sim/Simulation/ISimulation2D.h b/Sim/Simulation/ISimulation2D.h
index cf5c7c448ff350cf9fa9d5fb390084487ab6ddf0..2d6907613f82aed2b142a0255a033f9a2e868b5f 100644
--- a/Sim/Simulation/ISimulation2D.h
+++ b/Sim/Simulation/ISimulation2D.h
@@ -15,14 +15,14 @@
 #ifndef BORNAGAIN_SIM_SIMULATION_ISIMULATION2D_H
 #define BORNAGAIN_SIM_SIMULATION_ISIMULATION2D_H
 
+#include "Base/Types/OwningVector.h"
 #include "Sim/Simulation/ISimulation.h"
-#include <memory>
 
 class Beam;
 class IDetector;
-class DetectorContext;
 class DiffuseElement;
 class IDetector;
+class IPixel;
 class IShape2D;
 
 //! Abstract base class of simulations that generate 2D patterns.
@@ -108,8 +108,9 @@ protected:
     std::vector<DiffuseElement> m_eles;
 
 private:
-    std::unique_ptr<DetectorContext> m_detector_context;
-#endif // SWIG
+    std::vector<size_t> m_active_indices; //!< The sequence of bin indices (unmasked, in ROI)
+    OwningVector<const IPixel> m_pixels;  //!< All unmasked pixels inside ROI.
+#endif                                    // SWIG
 };
 
 #endif // BORNAGAIN_SIM_SIMULATION_ISIMULATION2D_H