From 32f1b48f8bfd9c52be491097b6c7bea50b602bc2 Mon Sep 17 00:00:00 2001
From: Dmitry Yurov <d.yurov@fz-juelich.de>
Date: Mon, 20 Nov 2017 12:29:55 +0100
Subject: [PATCH] Moved detector resolution to IDetector

Redmine: #1895
---
 Core/Instrument/IDetector.cpp                 | 71 ++++++++++++++++++-
 Core/Instrument/IDetector.h                   | 32 ++++++++-
 Core/Instrument/IDetector2D.cpp               | 68 ------------------
 Core/Instrument/IDetector2D.h                 | 30 +-------
 .../Core/Detector/SphericalDetectorTest.h     |  2 +-
 5 files changed, 101 insertions(+), 102 deletions(-)

diff --git a/Core/Instrument/IDetector.cpp b/Core/Instrument/IDetector.cpp
index af2d862ad08..7b5d41277f2 100644
--- a/Core/Instrument/IDetector.cpp
+++ b/Core/Instrument/IDetector.cpp
@@ -1,5 +1,8 @@
+#include "IAxis.h"
 #include "IDetector.h"
 #include "OutputData.h"
+#include "IDetectorResolution.h"
+#include "ConvolutionDetectorResolution.h"
 
 IDetector::IDetector()
 {
@@ -10,10 +13,14 @@ IDetector::IDetector(const IDetector& other)
     : m_axes(other.m_axes)
     , m_detection_properties(other.m_detection_properties)
 {
+    if(other.mP_detector_resolution)
+        setDetectorResolution(*other.mP_detector_resolution);
     setName(other.getName());
     registerChild(&m_detection_properties);
 }
 
+IDetector::~IDetector() = default;
+
 void IDetector::addAxis(const IAxis& axis)
 {
     m_axes.push_back(axis.clone());
@@ -69,6 +76,38 @@ void IDetector::setAnalyzerProperties(const kvector_t direction, double efficien
     m_detection_properties.setAnalyzerProperties(direction, efficiency, total_transmission);
 }
 
+void IDetector::setDetectorResolution(const IDetectorResolution& p_detector_resolution)
+{
+    mP_detector_resolution.reset(p_detector_resolution.clone());
+    registerChild(mP_detector_resolution.get());
+}
+
+// TODO: pass dimension-independent argument to this function
+void IDetector::setResolutionFunction(const IResolutionFunction2D& resFunc)
+{
+    ConvolutionDetectorResolution convFunc(resFunc);
+    setDetectorResolution(convFunc);
+}
+
+void IDetector::applyDetectorResolution(OutputData<double> *p_intensity_map) const
+{
+    if (!p_intensity_map)
+        throw std::runtime_error("IDetector::applyDetectorResolution() -> "
+                                   "Error! Null pointer to intensity map");
+    if (mP_detector_resolution)
+        mP_detector_resolution->applyDetectorResolution(p_intensity_map);
+}
+
+void IDetector::removeDetectorResolution()
+{
+    mP_detector_resolution.reset();
+}
+
+const IDetectorResolution* IDetector::detectorResolution() const
+{
+    return mP_detector_resolution.get();
+}
+
 void IDetector::initOutputData(OutputData<double> &data) const {
   data.clear();
   for (size_t i = 0; i < dimension(); ++i)
@@ -76,6 +115,33 @@ void IDetector::initOutputData(OutputData<double> &data) const {
   data.setAllTo(0.);
 }
 
+OutputData<double>*
+IDetector::createDetectorIntensity(const std::vector<SimulationElement>& elements, const Beam& beam,
+                                   AxesUnits units_type) const
+{
+    std::unique_ptr<OutputData<double>> detectorMap(createDetectorMap(beam, units_type));
+    if (!detectorMap)
+        throw Exceptions::RuntimeErrorException("Instrument::createDetectorIntensity:"
+                                                "can't create detector map.");
+
+    if (mP_detector_resolution) {
+        if (units_type != AxesUnits::DEFAULT) {
+            std::unique_ptr<OutputData<double>> defaultMap(
+                createDetectorMap(beam, AxesUnits::DEFAULT));
+            setDataToDetectorMap(*defaultMap, elements);
+            applyDetectorResolution(defaultMap.get());
+            detectorMap->setRawDataVector(defaultMap->getRawDataVector());
+        } else {
+            setDataToDetectorMap(*detectorMap, elements);
+            applyDetectorResolution(detectorMap.get());
+        }
+    } else {
+        setDataToDetectorMap(*detectorMap, elements);
+    }
+
+    return detectorMap.release();
+}
+
 void IDetector::checkAxesUnits(AxesUnits units) const
 {
     if(units == AxesUnits::DEFAULT)
@@ -94,7 +160,7 @@ void IDetector::checkAxesUnits(AxesUnits units) const
     }
 }
 
-void IDetector::calculateAxisRange(size_t axis_index, const Beam& beam, AxesUnits units,
+void IDetector::calculateAxisRange(size_t axis_index, const Beam&, AxesUnits units,
                                    double& amin, double& amax) const
 {
     if (units == AxesUnits::DEFAULT) {
@@ -128,6 +194,5 @@ std::unique_ptr<OutputData<double>> IDetector::createDetectorMap(const Beam& bea
 
 std::vector<const INode*> IDetector::getChildren() const
 {
-    return std::vector<const INode*>() << &m_detection_properties;
+    return std::vector<const INode*>() << &m_detection_properties << mP_detector_resolution;
 }
-
diff --git a/Core/Instrument/IDetector.h b/Core/Instrument/IDetector.h
index 4298ae53dc0..c993f97d876 100644
--- a/Core/Instrument/IDetector.h
+++ b/Core/Instrument/IDetector.h
@@ -17,12 +17,15 @@
 #define IDETECTOR_H_
 
 #include "DetectionProperties.h"
-#include "IAxis.h"
 #include "ICloneable.h"
 #include "INode.h"
 #include "SafePointerVector.h"
 
 template<class T> class OutputData;
+class IAxis;
+class IDetectorResolution;
+class IResolutionFunction2D;
+class SimulationElement;
 
 //! Wrapper for detector axes units, required for a better representation of
 //! detector axes units in python
@@ -41,7 +44,7 @@ class BA_CORE_API_ IDetector :  public ICloneable, public INode {
 public:
     IDetector();
 
-    virtual ~IDetector() = default;
+    virtual ~IDetector();
 
     void clear() {m_axes.clear();}
 
@@ -62,6 +65,19 @@ public:
     void setAnalyzerProperties(const kvector_t direction, double efficiency,
                                double total_transmission);
 
+    //! Sets the detector resolution
+    void setDetectorResolution(const IDetectorResolution& p_detector_resolution);
+    void setResolutionFunction(const IResolutionFunction2D& resFunc);
+
+    //! Applies the detector resolution to the given intensity maps
+    void applyDetectorResolution(OutputData<double>* p_intensity_map) const;
+
+    //! Removes detector resolution function.
+    void removeDetectorResolution();
+
+    //! Returns a pointer to detector resolution object
+    const IDetectorResolution* detectorResolution() const;
+
 #ifndef SWIG
     //! Returns empty detector map in given axes units.
     std::unique_ptr<OutputData<double>> createDetectorMap(const Beam& beam, AxesUnits units) const;
@@ -73,13 +89,18 @@ public:
     //! Inits axes of OutputData to match the detector and sets values to zero.
     virtual void initOutputData(OutputData<double>& data) const;
 
+    //! Returns new intensity map with detector resolution applied and axes in requested units
+    OutputData<double>* createDetectorIntensity(const std::vector<SimulationElement>& elements,
+                                                const Beam& beam,
+                                                AxesUnits units_type = AxesUnits::DEFAULT) const;
+
     //! Return default axes units
     virtual AxesUnits getDefaultAxesUnits() const {return AxesUnits::DEFAULT;}
 
     //! Returns vector of valid axes units
     virtual std::vector<AxesUnits> getValidAxesUnits() const {return {AxesUnits::NBINS};}
 
-    virtual std::vector<const INode*> getChildren() const;
+    virtual std::vector<const INode*> getChildren() const override;
 
 protected:
     IDetector(const IDetector& other);
@@ -103,8 +124,13 @@ private:
     //! Checks if given unit is valid for the detector. Throws exception if it is not the case.
     void checkAxesUnits(AxesUnits units) const;
 
+    virtual void
+    setDataToDetectorMap(OutputData<double>& detectorMap,
+                         const std::vector<SimulationElement>& elements) const = 0;
+
     SafePointerVector<IAxis> m_axes;
     DetectionProperties m_detection_properties;
+    std::unique_ptr<IDetectorResolution> mP_detector_resolution;
 };
 
 #endif /* IDETECTOR_H_ */
diff --git a/Core/Instrument/IDetector2D.cpp b/Core/Instrument/IDetector2D.cpp
index 52f71f28d6a..ecc1b8290a7 100644
--- a/Core/Instrument/IDetector2D.cpp
+++ b/Core/Instrument/IDetector2D.cpp
@@ -15,7 +15,6 @@
 
 #include "IDetector2D.h"
 #include "Beam.h"
-#include "IDetectorResolution.h"
 #include "InfinitePlane.h"
 #include "SimulationElement.h"
 #include "SimulationArea.h"
@@ -23,7 +22,6 @@
 #include "Units.h"
 #include "RegionOfInterest.h"
 #include "Exceptions.h"
-#include "ConvolutionDetectorResolution.h"
 #include "DetectorFunctions.h"
 
 IDetector2D::IDetector2D() = default;
@@ -32,8 +30,6 @@ IDetector2D::IDetector2D(const IDetector2D &other)
     : IDetector(other)
     , m_detector_mask(other.m_detector_mask)
 {
-    if(other.mP_detector_resolution)
-        setDetectorResolution(*other.mP_detector_resolution);
     if(other.regionOfInterest())
         m_region_of_interest.reset(other.regionOfInterest()->clone());
 }
@@ -55,41 +51,6 @@ void IDetector2D::setDetectorAxes(const IAxis &axis0, const IAxis &axis1)
     addAxis(axis1);
 }
 
-void IDetector2D::applyDetectorResolution(OutputData<double> *p_intensity_map) const
-{
-    if (!p_intensity_map)
-        throw Exceptions::NullPointerException("IDetector2D::applyDetectorResolution() -> "
-                                   "Error! Null pointer to intensity map");
-    if (mP_detector_resolution)
-        mP_detector_resolution->applyDetectorResolution(p_intensity_map);
-}
-
-OutputData<double> *IDetector2D::createDetectorIntensity(
-        const std::vector<SimulationElement> &elements,
-        const Beam &beam, AxesUnits units_type) const
-{
-    std::unique_ptr<OutputData<double>> detectorMap(createDetectorMap(beam, units_type));
-    if(!detectorMap)
-        throw Exceptions::RuntimeErrorException("Instrument::createDetectorIntensity:"
-                                                "can't create detector map.");
-
-    if (mP_detector_resolution) {
-        if(units_type != AxesUnits::DEFAULT) {
-            std::unique_ptr<OutputData<double>> defaultMap(createDetectorMap(beam, AxesUnits::DEFAULT));
-            setDataToDetectorMap(*defaultMap, elements);
-            applyDetectorResolution(defaultMap.get());
-            detectorMap->setRawDataVector(defaultMap->getRawDataVector());
-        } else {
-            setDataToDetectorMap(*detectorMap, elements);
-            applyDetectorResolution(detectorMap.get());
-        }
-    } else {
-        setDataToDetectorMap(*detectorMap, elements);
-    }
-
-    return detectorMap.release();
-}
-
 const RegionOfInterest *IDetector2D::regionOfInterest() const
 {
     return m_region_of_interest.get();
@@ -197,13 +158,6 @@ size_t IDetector2D::numberOfSimulationElements() const
     return result;
 }
 
-std::vector<const INode*> IDetector2D::getChildren() const
-{
-    std::vector<const INode*> result = IDetector::getChildren();
-    result << mP_detector_resolution;
-    return result;
-}
-
 std::unique_ptr<IAxis> IDetector2D::constructAxis(size_t axis_index, const Beam &beam,
                                                   AxesUnits units) const
 {
@@ -263,25 +217,3 @@ void IDetector2D::setDataToDetectorMap(OutputData<double> &detectorMap,
 
 }
 
-void IDetector2D::setDetectorResolution(const IDetectorResolution& p_detector_resolution)
-{
-    mP_detector_resolution.reset(p_detector_resolution.clone());
-    registerChild(mP_detector_resolution.get());
-}
-
-void IDetector2D::setResolutionFunction(const IResolutionFunction2D& resFunc)
-{
-    ConvolutionDetectorResolution convFunc(resFunc);
-    setDetectorResolution(convFunc);
-}
-
-void IDetector2D::removeDetectorResolution()
-{
-    mP_detector_resolution.reset();
-}
-
-const IDetectorResolution* IDetector2D::detectorResolution() const
-{
-    return mP_detector_resolution.get();
-}
-
diff --git a/Core/Instrument/IDetector2D.h b/Core/Instrument/IDetector2D.h
index 7742f798524..8ef40ca5593 100644
--- a/Core/Instrument/IDetector2D.h
+++ b/Core/Instrument/IDetector2D.h
@@ -19,18 +19,12 @@
 #include "IDetector.h"
 #include "Beam.h"
 #include "DetectorMask.h"
-#include "SafePointerVector.h"
-#include "DetectionProperties.h"
 #include <memory>
 
 class Beam;
-class IAxis;
-class IDetectorResolution;
-class IResolutionFunction2D;
 class IPixel;
 class IShape2D;
 class RegionOfInterest;
-class SimulationElement;
 
 //! Abstract 2D detector interface.
 //! @ingroup simulation
@@ -55,18 +49,6 @@ public:
     //! Sets detector parameters using axes
     void setDetectorAxes(const IAxis& axis0, const IAxis& axis1);
 
-    //! Sets the detector resolution
-    void setDetectorResolution(const IDetectorResolution& p_detector_resolution);
-    void setResolutionFunction(const IResolutionFunction2D& resFunc);
-
-    //! Removes detector resolution function.
-    void removeDetectorResolution();
-
-    //! Applies the detector resolution to the given intensity maps
-    void applyDetectorResolution(OutputData<double>* p_intensity_map) const;
-
-    const IDetectorResolution* detectorResolution() const;
-
     //! Removes all masks from the detector
     void removeMasks();
 
@@ -97,10 +79,6 @@ public:
     SimulationElement getSimulationElement(size_t index, const Beam& beam) const;
 #endif
 
-    //! Returns new intensity map with detector resolution applied and axes in requested units
-    OutputData<double>* createDetectorIntensity(const std::vector<SimulationElement> &elements,
-            const Beam& beam, AxesUnits units_type=AxesUnits::DEFAULT) const;
-
     //! Returns region of  interest if exists.
     const RegionOfInterest* regionOfInterest() const;
 
@@ -113,8 +91,6 @@ public:
     //! Returns number of simulation elements.
     size_t numberOfSimulationElements() const;
 
-    virtual std::vector<const INode*> getChildren() const override;
-
 protected:
     IDetector2D(const IDetector2D& other);
 
@@ -137,12 +113,12 @@ protected:
     //! returned. This corresponds to an overflow index.
     virtual size_t getIndexOfSpecular(const Beam& beam) const=0;
 
-    std::unique_ptr<IDetectorResolution> mP_detector_resolution;
     DetectorMask m_detector_mask;
 
 private:
-    void setDataToDetectorMap(OutputData<double> &detectorMap,
-                              const std::vector<SimulationElement> &elements) const;
+    virtual void
+    setDataToDetectorMap(OutputData<double>& detectorMap,
+                         const std::vector<SimulationElement>& elements) const override;
 
     std::unique_ptr<RegionOfInterest> m_region_of_interest;
 };
diff --git a/Tests/UnitTests/Core/Detector/SphericalDetectorTest.h b/Tests/UnitTests/Core/Detector/SphericalDetectorTest.h
index 675b05fb03c..fe462c68c7e 100644
--- a/Tests/UnitTests/Core/Detector/SphericalDetectorTest.h
+++ b/Tests/UnitTests/Core/Detector/SphericalDetectorTest.h
@@ -49,7 +49,7 @@ TEST_F(SphericalDetectorTest, initialState)
     ASSERT_THROW(detector.getAxis(0), std::runtime_error);
     OutputData<double>* p_intensity_map(nullptr);
     ASSERT_THROW(detector.applyDetectorResolution(p_intensity_map),
-                 Exceptions::NullPointerException);
+                 std::runtime_error);
 }
 
 // Construction of the detector with axes.
-- 
GitLab