From 9bd0f843fc18066c264bf220531030c5915fd8f5 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Tue, 11 Jul 2023 16:48:28 +0200
Subject: [PATCH] plot error handling ... Transmission.py now plots

---
 Base/Axis/Frame.cpp                     |  9 +++++++++
 Base/Axis/Frame.h                       |  1 +
 Device/Data/Datafield.cpp               |  5 +++++
 Device/Data/Datafield.h                 |  1 +
 PyCore/Embed/PyInterpreter.cpp          | 17 ++++++-----------
 Wrap/Python/ba_plot.py                  |  3 +++
 auto/Examples/varia/Transmission.py     |  5 ++---
 auto/MiniExamples/varia/Transmission.py |  5 ++---
 auto/Wrap/libBornAgainBase.py           |  4 ++++
 auto/Wrap/libBornAgainBase_wrap.cpp     | 24 ++++++++++++++++++++++++
 auto/Wrap/libBornAgainDevice.py         |  4 ++++
 auto/Wrap/libBornAgainDevice_wrap.cpp   | 24 ++++++++++++++++++++++++
 rawEx/varia/Transmission.py             |  5 ++---
 13 files changed, 87 insertions(+), 20 deletions(-)

diff --git a/Base/Axis/Frame.cpp b/Base/Axis/Frame.cpp
index e7d7c2f386e..2142b974bab 100644
--- a/Base/Axis/Frame.cpp
+++ b/Base/Axis/Frame.cpp
@@ -146,3 +146,12 @@ Frame* Frame::plottableFrame() const
         outaxes.emplace_back(new Scale(s->plottableScale()));
     return new Frame(std::move(outaxes));
 }
+
+Frame* Frame::flat() const
+{
+    std::vector<const Scale*> outaxes;
+    for (const Scale* s : m_axes)
+        if (s->size() > 1)
+            outaxes.emplace_back(s->clone());
+    return new Frame(std::move(outaxes));
+}
diff --git a/Base/Axis/Frame.h b/Base/Axis/Frame.h
index 33e016a5653..1cfba5a41e5 100644
--- a/Base/Axis/Frame.h
+++ b/Base/Axis/Frame.h
@@ -82,6 +82,7 @@ public:
 #endif // SWIG
 
     Frame* plottableFrame() const;
+    Frame* flat() const;
 
 protected:
     OwningVector<const Scale> m_axes;
diff --git a/Device/Data/Datafield.cpp b/Device/Data/Datafield.cpp
index 17de3fcb83b..e41dee0a216 100644
--- a/Device/Data/Datafield.cpp
+++ b/Device/Data/Datafield.cpp
@@ -326,3 +326,8 @@ Datafield Datafield::plottableField() const
 {
     return {frame().plottableFrame(), m_values, m_errSigmas};
 }
+
+Datafield Datafield::flat() const
+{
+    return {frame().flat(), m_values, m_errSigmas};
+}
diff --git a/Device/Data/Datafield.h b/Device/Data/Datafield.h
index 2f54635c39a..2b870f331ad 100644
--- a/Device/Data/Datafield.h
+++ b/Device/Data/Datafield.h
@@ -79,6 +79,7 @@ public:
     //... modifiers
 
     Datafield plottableField() const;
+    Datafield flat() const;
 
     //! Multiplies contents by constant factor, e.g. to shift curves in log plot
     void scale(double factor);
diff --git a/PyCore/Embed/PyInterpreter.cpp b/PyCore/Embed/PyInterpreter.cpp
index d4a574c13ef..3f470a958d4 100644
--- a/PyCore/Embed/PyInterpreter.cpp
+++ b/PyCore/Embed/PyInterpreter.cpp
@@ -532,17 +532,12 @@ PyObjectPtr PyInterpreter::Numpy::arrayND(std::vector<std::size_t>& dimensions)
     const std::size_t n_dims = dimensions.size();
     if (n_dims < 1) {
         throw std::runtime_error(
-            errorDescription("Cannot make a Numpy with the given number "
+            errorDescription("Cannot make a Numpy array with the given number "
                              "of dimensions; number of dimensions must be >= 1"));
     }
 
-    for (std::size_t d = 0; d < n_dims; ++d) {
-        if (dimensions[d] < 2) {
-            throw std::runtime_error(
-                errorDescription("Cannot make a Numpy with the given dimensions; "
-                                 "dimensions must be >= 2"));
-        }
-    }
+    for (std::size_t d = 0; d < n_dims; ++d)
+        ASSERT(dimensions[d]);
 
     npy_int ndim_numpy = static_cast<npy_int>(n_dims);
     npy_intp* ndimsizes_numpy = new npy_intp[n_dims];
@@ -555,9 +550,9 @@ PyObjectPtr PyInterpreter::Numpy::arrayND(std::vector<std::size_t>& dimensions)
 
     if (!npyArray_ptr) {
         checkError();
-        throw std::runtime_error(errorDescription("PyInterpreter::Numpy: Cannot create a Numpy "
-                                                  + std::to_string(n_dims)
-                                                  + "D-array from the given data"));
+        throw std::runtime_error(
+            errorDescription("PyInterpreter::Numpy: Cannot create a Numpy array"
+                             + std::to_string(n_dims) + "D-array from the given data"));
     }
 
     return {npyArray_ptr};
diff --git a/Wrap/Python/ba_plot.py b/Wrap/Python/ba_plot.py
index 900642d05b2..de2255d6801 100644
--- a/Wrap/Python/ba_plot.py
+++ b/Wrap/Python/ba_plot.py
@@ -120,6 +120,9 @@ def get_axes_limits(result):
     limits = []
     for i in range(result.rank()):
         ax = result.axis(i)
+        if ax.size() == 1:
+            raise Exception(f'Axis {i} "{ax.axisName()}" has size 1:'
+                            + ' rather plot <datafield>.flat()')
         ami = ax.min()
         ama = ax.max()
         assert ami < ama, f'Datafield has invalid axis {i}, extending from {ami} to {ama}'
diff --git a/auto/Examples/varia/Transmission.py b/auto/Examples/varia/Transmission.py
index 8a5117aa1da..5393792a8bc 100755
--- a/auto/Examples/varia/Transmission.py
+++ b/auto/Examples/varia/Transmission.py
@@ -23,16 +23,15 @@ def get_simulation(sample, flags):
     scan = ba.AlphaScan(1, alpha, alpha)
     scan.setWavelength(0.3*nm)
 
-    z_axis = ba.FixedBinAxis("z (nm)", 500, -130*nm, 30*nm)
+    z_axis = ba.EquiDivision("z (nm)", 500, -130*nm, 30*nm)
     simulation = ba.DepthprobeSimulation(scan, sample, z_axis, flags)
 
     return simulation
 
 def run_example(flags=0):
-    bp.parse_args(aspect='auto', intensity_max=1e2, intensity_min=1e-12)
     sample = get_sample()
     simulation = get_simulation(sample, flags)
-    result = simulation.simulate()
+    result = simulation.simulate().flat()
     bp.plot_simulation_result(result)
 
 if __name__ == '__main__':
diff --git a/auto/MiniExamples/varia/Transmission.py b/auto/MiniExamples/varia/Transmission.py
index 8a5117aa1da..5393792a8bc 100755
--- a/auto/MiniExamples/varia/Transmission.py
+++ b/auto/MiniExamples/varia/Transmission.py
@@ -23,16 +23,15 @@ def get_simulation(sample, flags):
     scan = ba.AlphaScan(1, alpha, alpha)
     scan.setWavelength(0.3*nm)
 
-    z_axis = ba.FixedBinAxis("z (nm)", 500, -130*nm, 30*nm)
+    z_axis = ba.EquiDivision("z (nm)", 500, -130*nm, 30*nm)
     simulation = ba.DepthprobeSimulation(scan, sample, z_axis, flags)
 
     return simulation
 
 def run_example(flags=0):
-    bp.parse_args(aspect='auto', intensity_max=1e2, intensity_min=1e-12)
     sample = get_sample()
     simulation = get_simulation(sample, flags)
-    result = simulation.simulate()
+    result = simulation.simulate().flat()
     bp.plot_simulation_result(result)
 
 if __name__ == '__main__':
diff --git a/auto/Wrap/libBornAgainBase.py b/auto/Wrap/libBornAgainBase.py
index 1becc07e63c..89ab3f76268 100644
--- a/auto/Wrap/libBornAgainBase.py
+++ b/auto/Wrap/libBornAgainBase.py
@@ -2031,6 +2031,10 @@ class Frame(ICloneable):
         r"""plottableFrame(Frame self) -> Frame"""
         return _libBornAgainBase.Frame_plottableFrame(self)
 
+    def flat(self):
+        r"""flat(Frame self) -> Frame"""
+        return _libBornAgainBase.Frame_flat(self)
+
 # Register Frame in _libBornAgainBase:
 _libBornAgainBase.Frame_swigregister(Frame)
 class R3(object):
diff --git a/auto/Wrap/libBornAgainBase_wrap.cpp b/auto/Wrap/libBornAgainBase_wrap.cpp
index 502c690395f..55abea8f3e2 100644
--- a/auto/Wrap/libBornAgainBase_wrap.cpp
+++ b/auto/Wrap/libBornAgainBase_wrap.cpp
@@ -26747,6 +26747,29 @@ fail:
 }
 
 
+SWIGINTERN PyObject *_wrap_Frame_flat(PyObject *self, PyObject *args) {
+  PyObject *resultobj = 0;
+  Frame *arg1 = (Frame *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject *swig_obj[1] ;
+  Frame *result = 0 ;
+  
+  if (!args) SWIG_fail;
+  swig_obj[0] = args;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Frame, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Frame_flat" "', argument " "1"" of type '" "Frame const *""'"); 
+  }
+  arg1 = reinterpret_cast< Frame * >(argp1);
+  result = (Frame *)((Frame const *)arg1)->flat();
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Frame, 0 |  0 );
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
 SWIGINTERN PyObject *Frame_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *obj;
   if (!SWIG_Python_UnpackTuple(args, "swigregister", 1, 1, &obj)) return NULL;
@@ -28816,6 +28839,7 @@ static PyMethodDef SwigMethods[] = {
 	 { "Frame_hasSameSizes", _wrap_Frame_hasSameSizes, METH_VARARGS, "Frame_hasSameSizes(Frame self, Frame arg2) -> bool"},
 	 { "Frame___eq__", _wrap_Frame___eq__, METH_VARARGS, "Frame___eq__(Frame self, Frame arg2) -> bool"},
 	 { "Frame_plottableFrame", _wrap_Frame_plottableFrame, METH_O, "Frame_plottableFrame(Frame self) -> Frame"},
+	 { "Frame_flat", _wrap_Frame_flat, METH_O, "Frame_flat(Frame self) -> Frame"},
 	 { "Frame_swigregister", Frame_swigregister, METH_O, NULL},
 	 { "Frame_swiginit", Frame_swiginit, METH_VARARGS, NULL},
 	 { "new_R3", _wrap_new_R3, METH_VARARGS, "\n"
diff --git a/auto/Wrap/libBornAgainDevice.py b/auto/Wrap/libBornAgainDevice.py
index 7e26a636234..20364077fe9 100644
--- a/auto/Wrap/libBornAgainDevice.py
+++ b/auto/Wrap/libBornAgainDevice.py
@@ -2140,6 +2140,10 @@ class Datafield(object):
         r"""plottableField(Datafield self) -> Datafield"""
         return _libBornAgainDevice.Datafield_plottableField(self)
 
+    def flat(self):
+        r"""flat(Datafield self) -> Datafield"""
+        return _libBornAgainDevice.Datafield_flat(self)
+
     def scale(self, factor):
         r"""scale(Datafield self, double factor)"""
         return _libBornAgainDevice.Datafield_scale(self, factor)
diff --git a/auto/Wrap/libBornAgainDevice_wrap.cpp b/auto/Wrap/libBornAgainDevice_wrap.cpp
index 257ae13d248..85a6c720356 100644
--- a/auto/Wrap/libBornAgainDevice_wrap.cpp
+++ b/auto/Wrap/libBornAgainDevice_wrap.cpp
@@ -28653,6 +28653,29 @@ fail:
 }
 
 
+SWIGINTERN PyObject *_wrap_Datafield_flat(PyObject *self, PyObject *args) {
+  PyObject *resultobj = 0;
+  Datafield *arg1 = (Datafield *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject *swig_obj[1] ;
+  SwigValueWrapper< Datafield > result;
+  
+  if (!args) SWIG_fail;
+  swig_obj[0] = args;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Datafield, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Datafield_flat" "', argument " "1"" of type '" "Datafield const *""'"); 
+  }
+  arg1 = reinterpret_cast< Datafield * >(argp1);
+  result = ((Datafield const *)arg1)->flat();
+  resultobj = SWIG_NewPointerObj((new Datafield(result)), SWIGTYPE_p_Datafield, SWIG_POINTER_OWN |  0 );
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
 SWIGINTERN PyObject *_wrap_Datafield_scale(PyObject *self, PyObject *args) {
   PyObject *resultobj = 0;
   Datafield *arg1 = (Datafield *) 0 ;
@@ -37596,6 +37619,7 @@ static PyMethodDef SwigMethods[] = {
 	 { "Datafield_maxVal", _wrap_Datafield_maxVal, METH_O, "Datafield_maxVal(Datafield self) -> double"},
 	 { "Datafield_minVal", _wrap_Datafield_minVal, METH_O, "Datafield_minVal(Datafield self) -> double"},
 	 { "Datafield_plottableField", _wrap_Datafield_plottableField, METH_O, "Datafield_plottableField(Datafield self) -> Datafield"},
+	 { "Datafield_flat", _wrap_Datafield_flat, METH_O, "Datafield_flat(Datafield self) -> Datafield"},
 	 { "Datafield_scale", _wrap_Datafield_scale, METH_VARARGS, "Datafield_scale(Datafield self, double factor)"},
 	 { "Datafield_crop", _wrap_Datafield_crop, METH_VARARGS, "\n"
 		"Datafield_crop(Datafield self, double xmin, double ymin, double xmax, double ymax) -> Datafield\n"
diff --git a/rawEx/varia/Transmission.py b/rawEx/varia/Transmission.py
index 8a5117aa1da..5393792a8bc 100644
--- a/rawEx/varia/Transmission.py
+++ b/rawEx/varia/Transmission.py
@@ -23,16 +23,15 @@ def get_simulation(sample, flags):
     scan = ba.AlphaScan(1, alpha, alpha)
     scan.setWavelength(0.3*nm)
 
-    z_axis = ba.FixedBinAxis("z (nm)", 500, -130*nm, 30*nm)
+    z_axis = ba.EquiDivision("z (nm)", 500, -130*nm, 30*nm)
     simulation = ba.DepthprobeSimulation(scan, sample, z_axis, flags)
 
     return simulation
 
 def run_example(flags=0):
-    bp.parse_args(aspect='auto', intensity_max=1e2, intensity_min=1e-12)
     sample = get_sample()
     simulation = get_simulation(sample, flags)
-    result = simulation.simulate()
+    result = simulation.simulate().flat()
     bp.plot_simulation_result(result)
 
 if __name__ == '__main__':
-- 
GitLab