From 18f70251f23daec3fd40571369450d20908a41b4 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (h)" <j.wuttke@fz-juelich.de>
Date: Wed, 7 Dec 2022 10:34:44 +0100
Subject: [PATCH] ZLimits duplicated in Base/Types/Span, for use in formfactors

---
 Base/Types/Span.cpp                 | 57 +++++++++++++++++++++++++
 Base/Types/Span.h                   | 65 +++++++++++++++++++++++++++++
 Resample/Particle/IReParticle.cpp   |  1 -
 Resample/Particle/IReParticle.h     |  4 +-
 Resample/Particle/ReCompound.cpp    |  8 ++--
 Resample/Particle/ReCompound.h      |  2 +-
 Resample/Particle/ReMesocrystal.cpp |  4 +-
 Resample/Particle/ReMesocrystal.h   |  2 +-
 Resample/Particle/ReParticle.cpp    |  4 +-
 Resample/Particle/ReParticle.h      |  2 +-
 Resample/Processed/ReSample.cpp     |  3 +-
 Resample/Processed/Slicer.cpp       | 22 +++++-----
 Resample/Processed/Slicer.h         |  6 +--
 13 files changed, 151 insertions(+), 29 deletions(-)
 create mode 100644 Base/Types/Span.cpp
 create mode 100644 Base/Types/Span.h

diff --git a/Base/Types/Span.cpp b/Base/Types/Span.cpp
new file mode 100644
index 00000000000..368a3d8b3c4
--- /dev/null
+++ b/Base/Types/Span.cpp
@@ -0,0 +1,57 @@
+//  ************************************************************************************************
+//
+//  BornAgain: simulate and fit reflection and scattering
+//
+//! @file      Base/Types/Span.cpp
+//! @brief     Defines class Span.
+//!
+//! @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 "Base/Types/Span.h"
+#include "Base/Util/Assert.h"
+#include <algorithm>
+#include <cmath>
+
+Span::Span(double _min, double _max)
+    : m_zmin(_min)
+    , m_zmax(_max)
+{
+    ASSERT(_min < _max);
+}
+
+Span::Span()
+    : Span(-inf, inf)
+{
+}
+
+bool Span::isFinite() const
+{
+    return !std::isinf(m_zmin) && !std::isinf(m_zmax);
+}
+
+// TODO sep22: rm all the following if they remain UNUSED
+
+Span Span::enclosingInterval(const Span& left, const Span& right)
+{
+    return {std::min(left.zBottom(), right.zBottom()), std::max(left.zTop(), right.zTop())};
+}
+
+bool operator==(const Span& left, const Span& right)
+{
+    return (left.zBottom() == right.zBottom() && left.zTop() == right.zTop());
+}
+
+bool operator!=(const Span& left, const Span& right)
+{
+    return !(left == right);
+}
+
+std::ostream& operator<<(std::ostream& ostr, const Span& limits)
+{
+    return ostr << "Lower: " << limits.zBottom() << ", Upper: " << limits.zTop();
+}
diff --git a/Base/Types/Span.h b/Base/Types/Span.h
new file mode 100644
index 00000000000..9db6ef2cbed
--- /dev/null
+++ b/Base/Types/Span.h
@@ -0,0 +1,65 @@
+//  ************************************************************************************************
+//
+//  BornAgain: simulate and fit reflection and scattering
+//
+//! @file      Base/Types/Span.h
+//! @brief     Defines class Span.
+//!
+//! @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)
+//
+//  ************************************************************************************************
+
+#ifdef SWIG
+#error no need to expose this header to Swig
+#endif
+
+#ifndef USER_API
+#ifndef BORNAGAIN_BASE_TYPES_SPAN_H
+#define BORNAGAIN_BASE_TYPES_SPAN_H
+
+#include <cmath>
+#include <iostream>
+#include <limits>
+
+//! An interval. Limits are of type double, and may be infinite.
+//! Used for the z-coordinate, especially when slicing form factors.
+//!
+//! @ingroup intern
+
+class Span {
+public:
+    Span();
+    Span(double _min, double _max);
+
+    bool isFinite() const;
+
+    double zBottom() const { return m_zmin; }
+    double zTop() const { return m_zmax; }
+    double zTopOr0() const { return std::isfinite(m_zmax) ? m_zmax : 0; }
+    double thicknessOr0() const { return isFinite() ? m_zmax - m_zmin : 0; }
+
+    bool contains(double z) const { return m_zmin <= z && z <= m_zmax; }
+
+    std::pair<double, double> pair() const { return {m_zmin, m_zmax}; }
+
+    static constexpr double inf = std::numeric_limits<double>::infinity();
+
+    //! Returns the union of two Span (the minimal interval that contains both input intervals).
+    static Span enclosingInterval(const Span& left, const Span& right);
+
+private:
+    // members are not const because we need the implicit copy assignement operator
+    double m_zmin;
+    double m_zmax;
+};
+
+bool operator==(const Span& left, const Span& right);
+bool operator!=(const Span& left, const Span& right);
+
+std::ostream& operator<<(std::ostream& ostr, const Span& limits);
+
+#endif // BORNAGAIN_BASE_TYPES_SPAN_H
+#endif // USER_API
diff --git a/Resample/Particle/IReParticle.cpp b/Resample/Particle/IReParticle.cpp
index 17dd8e2c2dc..328ffa456bf 100644
--- a/Resample/Particle/IReParticle.cpp
+++ b/Resample/Particle/IReParticle.cpp
@@ -19,7 +19,6 @@
 #include "Resample/Element/DiffuseElement.h"
 #include "Resample/Flux/MatrixFlux.h"
 #include "Resample/Flux/ScalarFlux.h"
-#include "Resample/Slice/ZLimits.h"
 #include "Sample/Material/Admixtures.h"
 #include <memory>
 
diff --git a/Resample/Particle/IReParticle.h b/Resample/Particle/IReParticle.h
index 77739fca028..db3f32b5990 100644
--- a/Resample/Particle/IReParticle.h
+++ b/Resample/Particle/IReParticle.h
@@ -32,7 +32,7 @@ class IRotation;
 class Material;
 class SpinMatrix;
 class WavevectorInfo;
-class ZLimits;
+class Span;
 
 //! Abstract base class for reprocessed particles.
 //!
@@ -62,7 +62,7 @@ public:
     //! form factor's shape. This is used for SSCA calculations
     virtual double radialExtension() const = 0;
 
-    virtual ZLimits Z_span() const = 0;
+    virtual Span Z_span() const = 0;
 
     //! Returns the total volume of the particle of this form factor's shape
     virtual double volume() const;
diff --git a/Resample/Particle/ReCompound.cpp b/Resample/Particle/ReCompound.cpp
index 9a2b1869d73..7d600b583d3 100644
--- a/Resample/Particle/ReCompound.cpp
+++ b/Resample/Particle/ReCompound.cpp
@@ -13,9 +13,9 @@
 //  ************************************************************************************************
 
 #include "Resample/Particle/ReCompound.h"
+#include "Base/Types/Span.h"
 #include "Base/Util/Assert.h"
 #include "Base/Vector/WavevectorInfo.h" // debug
-#include "Resample/Slice/ZLimits.h"
 
 ReCompound::ReCompound(const std::optional<size_t>& i_layer)
     : IReParticle(i_layer)
@@ -40,12 +40,12 @@ double ReCompound::radialExtension() const
     return result;
 }
 
-ZLimits ReCompound::Z_span() const
+Span ReCompound::Z_span() const
 {
     ASSERT(!m_components.empty());
-    ZLimits result = m_components[0]->Z_span();
+    Span result = m_components[0]->Z_span();
     for (size_t i = 1; i < m_components.size(); ++i)
-        result = ZLimits::enclosingInterval(result, m_components[i]->Z_span());
+        result = Span::enclosingInterval(result, m_components[i]->Z_span());
     return result;
 }
 
diff --git a/Resample/Particle/ReCompound.h b/Resample/Particle/ReCompound.h
index cd7ca56edf2..71e8cbf08d8 100644
--- a/Resample/Particle/ReCompound.h
+++ b/Resample/Particle/ReCompound.h
@@ -38,7 +38,7 @@ public:
 
     double radialExtension() const override;
 
-    ZLimits Z_span() const override;
+    Span Z_span() const override;
 
     void addFormFactor(const IReParticle& formfactor);
 
diff --git a/Resample/Particle/ReMesocrystal.cpp b/Resample/Particle/ReMesocrystal.cpp
index 2d7855d7695..e73ad406a6d 100644
--- a/Resample/Particle/ReMesocrystal.cpp
+++ b/Resample/Particle/ReMesocrystal.cpp
@@ -15,9 +15,9 @@
 #include "Resample/Particle/ReMesocrystal.h"
 #include "Base/Math/Constants.h"
 #include "Base/Spin/SpinMatrix.h"
+#include "Base/Types/Span.h"
 #include "Base/Vector/WavevectorInfo.h"
 #include "Resample/Particle/ReParticle.h"
-#include "Resample/Slice/ZLimits.h"
 
 ReMesocrystal::ReMesocrystal(const std::optional<size_t>& i_layer, const Lattice3D& lattice,
                              const IReParticle& basis, const ReParticle& outer_shape,
@@ -48,7 +48,7 @@ double ReMesocrystal::radialExtension() const
     return m_outer_shape->radialExtension();
 }
 
-ZLimits ReMesocrystal::Z_span() const
+Span ReMesocrystal::Z_span() const
 {
     return m_outer_shape->Z_span();
 }
diff --git a/Resample/Particle/ReMesocrystal.h b/Resample/Particle/ReMesocrystal.h
index a2cfe61915d..e92922a5f89 100644
--- a/Resample/Particle/ReMesocrystal.h
+++ b/Resample/Particle/ReMesocrystal.h
@@ -43,7 +43,7 @@ public:
     double volume() const override;
     double radialExtension() const override;
 
-    ZLimits Z_span() const override;
+    Span Z_span() const override;
 
     complex_t theFF(const WavevectorInfo& wavevectors) const override;
     SpinMatrix thePolFF(const WavevectorInfo& wavevectors) const override;
diff --git a/Resample/Particle/ReParticle.cpp b/Resample/Particle/ReParticle.cpp
index 8067b88ac8c..4ca8ec62ad9 100644
--- a/Resample/Particle/ReParticle.cpp
+++ b/Resample/Particle/ReParticle.cpp
@@ -13,9 +13,9 @@
 //  ************************************************************************************************
 
 #include "Resample/Particle/ReParticle.h"
+#include "Base/Types/Span.h"
 #include "Base/Util/Assert.h"
 #include "Base/Vector/WavevectorInfo.h" // debug
-#include "Resample/Slice/ZLimits.h"
 #include "Sample/Material/Material.h"
 #include "Sample/Material/MaterialFactoryFuncs.h"
 #include "Sample/Particle/IFormFactor.h"
@@ -113,7 +113,7 @@ SpinMatrix ReParticle::thePolFF(const WavevectorInfo& wavevectors) const
     return result;
 }
 
-ZLimits ReParticle::Z_span() const
+Span ReParticle::Z_span() const
 {
     RotMatrix transform = m_rotMatrix ? *m_rotMatrix : RotMatrix();
     std::unique_ptr<const IRotation> total_rotation(IRotation::createRotation(transform));
diff --git a/Resample/Particle/ReParticle.h b/Resample/Particle/ReParticle.h
index e01cfafe76b..3e291c34231 100644
--- a/Resample/Particle/ReParticle.h
+++ b/Resample/Particle/ReParticle.h
@@ -50,7 +50,7 @@ public:
 
     double radialExtension() const override;
 
-    ZLimits Z_span() const override;
+    Span Z_span() const override;
 
     const IFormFactor* iformfactor() const;
 
diff --git a/Resample/Processed/ReSample.cpp b/Resample/Processed/ReSample.cpp
index d7616b3541d..1262d45aa60 100644
--- a/Resample/Processed/ReSample.cpp
+++ b/Resample/Processed/ReSample.cpp
@@ -13,6 +13,7 @@
 //  ************************************************************************************************
 
 #include "Resample/Processed/ReSample.h"
+#include "Base/Types/Span.h"
 #include "Base/Util/Assert.h"
 #include "Resample/Coherence/CoheringSubparticles.h"
 #include "Resample/Flux/IFlux.h"
@@ -252,7 +253,7 @@ ReLayout makeReLayout(const ParticleLayout& layout, const SliceStack& slices, do
                 myparticle->translate(translation);
 
                 // if subparticle is contained in this layer, set limits to infinite:
-                ZLimits limits;
+                Span limits;
                 if (!single_layer) {
                     double z1 = slice.zTopOr0();
                     limits = {slice.zBottom() - z1, slice.zTop() - z1};
diff --git a/Resample/Processed/Slicer.cpp b/Resample/Processed/Slicer.cpp
index a8e93a2d06e..9841a2b78dd 100644
--- a/Resample/Processed/Slicer.cpp
+++ b/Resample/Processed/Slicer.cpp
@@ -15,12 +15,12 @@
 #include "Resample/Processed/Slicer.h"
 #include "Base/Math/Constants.h"
 #include "Base/Math/Functions.h"
+#include "Base/Types/Span.h"
 #include "Base/Util/Assert.h"
 #include "Base/Vector/RotMatrix.h"
 #include "Resample/Particle/ReCompound.h"
 #include "Resample/Particle/ReMesocrystal.h"
 #include "Resample/Particle/ReParticle.h"
-#include "Resample/Slice/ZLimits.h"
 #include "Sample/HardParticle/HardParticles.h"
 #include "Sample/Material/MaterialFactoryFuncs.h"
 #include "Sample/Material/MaterialUtils.h"
@@ -41,7 +41,7 @@ struct SlicingEffects {
     double dz_top;
 };
 
-SlicingEffects computeSlicingEffects(ZLimits limits, const R3& position, double height)
+SlicingEffects computeSlicingEffects(Span limits, const R3& position, double height)
 {
     R3 new_position(position);
     double z_bottom = position.z();
@@ -60,7 +60,7 @@ SlicingEffects computeSlicingEffects(ZLimits limits, const R3& position, double
     return {new_position, dz_bottom, dz_top};
 }
 
-bool shapeIsContainedInLimits(const IFormFactor& formfactor, ZLimits limits, R3 translation,
+bool shapeIsContainedInLimits(const IFormFactor& formfactor, Span limits, R3 translation,
                               const IRotation* rotation)
 {
     double zbottom = formfactor.bottomZ(rotation) + translation.z();
@@ -69,7 +69,7 @@ bool shapeIsContainedInLimits(const IFormFactor& formfactor, ZLimits limits, R3
     return limits.zBottom() <= zbottom && ztop <= limits.zTop();
 }
 
-bool shapeOutsideLimits(const IFormFactor& formfactor, ZLimits limits, R3 translation,
+bool shapeOutsideLimits(const IFormFactor& formfactor, Span limits, R3 translation,
                         const IRotation* rotation)
 {
     double zbottom = formfactor.bottomZ(rotation) + translation.z();
@@ -86,7 +86,7 @@ ReParticle* createTransformedFormFactor(const IFormFactor* formfactor, const R3&
                                                     : nullptr);
 }
 
-ReParticle* createParticleSlice(const IFormFactor* ff, ZLimits limits, const R3& translation,
+ReParticle* createParticleSlice(const IFormFactor* ff, Span limits, const R3& translation,
                                 const IRotation* rot)
 {
     if (shapeOutsideLimits(*ff, limits, translation, rot))
@@ -263,7 +263,7 @@ IReParticle* processBasis(const IParticle* basis, const Material& ambientMat)
 
 
 OwningVector<IReParticle> Compute::Slicing::particlesInSlice(const IParticle* particle,
-                                                             const ZLimits& limits,
+                                                             const Span& limits,
                                                              const Material& ambientMat)
 {
     if (const auto* p = dynamic_cast<const Particle*>(particle)) {
@@ -374,12 +374,12 @@ OwningVector<IReParticle> Compute::Slicing::particlesInSlice(const IParticle* pa
         ASSERT(0);
 }
 
-ZLimits Compute::Slicing::zSpan(const IParticle* particle)
+Span Compute::Slicing::zSpan(const IParticle* particle)
 {
     if (const auto* p = dynamic_cast<const Particle*>(particle)) {
         ASSERT(p->pFormfactor());
         std::unique_ptr<ReParticle> particleSlice(
-            createParticleSlice(p->pFormfactor(), ZLimits(), p->particlePosition(), p->rotation()));
+            createParticleSlice(p->pFormfactor(), Span(), p->particlePosition(), p->rotation()));
         if (!particleSlice)
             return {};
         return particleSlice->Z_span();
@@ -387,10 +387,10 @@ ZLimits Compute::Slicing::zSpan(const IParticle* particle)
     } else if (const auto* p = dynamic_cast<const Compound*>(particle)) {
         const auto subparticles = p->decompose();
         ASSERT(subparticles.size() > 0);
-        ZLimits result = zSpan(subparticles[0]);
+        Span result = zSpan(subparticles[0]);
         for (const auto* subparticle : subparticles)
             // TODO why no rotation and translation as for CoreAndShell ??
-            result = ZLimits::enclosingInterval(result, zSpan(subparticle));
+            result = Span::enclosingInterval(result, zSpan(subparticle));
         return result;
 
     } else if (const auto* p = dynamic_cast<const CoreAndShell*>(particle)) {
@@ -407,7 +407,7 @@ ZLimits Compute::Slicing::zSpan(const IParticle* particle)
         const IFormFactor* meso_formfactor = p->outerShape();
         ASSERT(meso_formfactor);
         std::unique_ptr<ReParticle> new_shape(
-            createParticleSlice(meso_formfactor, ZLimits(), p->particlePosition(), p->rotation()));
+            createParticleSlice(meso_formfactor, Span(), p->particlePosition(), p->rotation()));
 
         return new_shape->Z_span();
 
diff --git a/Resample/Processed/Slicer.h b/Resample/Processed/Slicer.h
index 2c37c0cb0b8..36a75063061 100644
--- a/Resample/Processed/Slicer.h
+++ b/Resample/Processed/Slicer.h
@@ -27,14 +27,14 @@
 class IParticle;
 class Material;
 class IReParticle;
-class ZLimits;
+class Span;
 
 namespace Compute::Slicing {
 
-OwningVector<IReParticle> particlesInSlice(const IParticle* particle, const ZLimits&,
+OwningVector<IReParticle> particlesInSlice(const IParticle* particle, const Span&,
                                            const Material& ambientMat);
 
-ZLimits zSpan(const IParticle* particle);
+Span zSpan(const IParticle* particle);
 
 } // namespace Compute::Slicing
 
-- 
GitLab