Browse Source

scattcoeffs is now emulated on Python via C++ object calls

Konstantin Ladutenko 3 years ago
parent
commit
80eb8a6fd7

+ 7 - 4
examples/Opt.Commun.-2010-Geints-Nanojets_of_dielectric_microspheres/fig1.py

@@ -31,8 +31,7 @@
 #    along with this program.  If not, see <http:#www.gnu.org/licenses/>.
 #    along with this program.  If not, see <http:#www.gnu.org/licenses/>.
 
 
 import scattnlay
 import scattnlay
-from scattnlay import fieldnlay
-from scattnlay import scattnlay
+from scattnlay import fieldnlay, scattnlay, scattcoeffs, expancoeffs
 import numpy as np
 import numpy as np
 from matplotlib import pyplot as plt
 from matplotlib import pyplot as plt
 
 
@@ -40,7 +39,7 @@ import inspect
 print("Using scattnlay from ", inspect.getfile(scattnlay))
 print("Using scattnlay from ", inspect.getfile(scattnlay))
 
 
 npts = 351
 npts = 351
-# npts = 51
+# npts = 11
 factor = 3 # plot extent compared to sphere radius
 factor = 3 # plot extent compared to sphere radius
 index_H2O = 1.33+(1e-6)*1j
 index_H2O = 1.33+(1e-6)*1j
 
 
@@ -67,8 +66,12 @@ print("   Qsca = " + str(Qsca)+" terms = "+str(terms))
 terms, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2 = scattnlay(
 terms, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2 = scattnlay(
     np.array([x]), np.array([m]), mp=True)
     np.array([x]), np.array([m]), mp=True)
 print("mp Qsca = " + str(Qsca)+" terms = "+str(terms))
 print("mp Qsca = " + str(Qsca)+" terms = "+str(terms))
-exit(1)
 
 
+terms, a,b = scattcoeffs(np.array([x]), np.array([m]))
+print(a)
+print(b)
+
+exit(1)
 scan = np.linspace(-factor*x[-1], factor*x[-1], npts)
 scan = np.linspace(-factor*x[-1], factor*x[-1], npts)
 zero = np.zeros(npts*npts, dtype = np.float64)
 zero = np.zeros(npts*npts, dtype = np.float64)
 
 

+ 43 - 14
scattnlay/main.py

@@ -32,6 +32,25 @@
 
 
 import numpy as np
 import numpy as np
 
 
+
+def scattcoeffs_(x, m, nmax=-1, pl=-1, mp=False):
+    if mp:
+        from scattnlay_mp import mie_mp as mie_
+    else:
+        # from scattnlay_dp import mie_dp as mie_
+        from scattnlay_mp import mie_mp as mie_
+    mie = mie_()
+    mie.SetLayersSize(x)
+    mie.SetLayersIndex(m)
+    mie.SetPECLayer(pl)
+    mie.SetMaxTerms(nmax)
+    mie.calcScattCoeffs()
+    terms = mie.GetMaxTerms()
+    a = mie.GetAn()
+    b = mie.GetBn()
+    return terms, a, b
+
+
 def scattcoeffs(x, m, nmax=-1, pl=-1, mp=False):
 def scattcoeffs(x, m, nmax=-1, pl=-1, mp=False):
     """
     """
     scattcoeffs(x, m[, nmax, pl, mp])
     scattcoeffs(x, m[, nmax, pl, mp])
@@ -53,16 +72,11 @@ def scattcoeffs(x, m, nmax=-1, pl=-1, mp=False):
         an, bn: Complex scattering coefficients
         an, bn: Complex scattering coefficients
     """
     """
 
 
-    if mp:
-        from scattnlay_mp import scattcoeffs as scattcoeffs_
-    else:
-        from scattnlay_dp import scattcoeffs as scattcoeffs_
-
     if len(m.shape) != 1 and len(m.shape) != 2:
     if len(m.shape) != 1 and len(m.shape) != 2:
         raise ValueError('The relative refractive index (m) should be a 1-D or 2-D NumPy array.')
         raise ValueError('The relative refractive index (m) should be a 1-D or 2-D NumPy array.')
     if len(x.shape) == 1:
     if len(x.shape) == 1:
         if len(m.shape) == 1:
         if len(m.shape) == 1:
-            return scattcoeffs_(x, m, nmax=nmax, pl=pl)
+            return scattcoeffs_(x, m, nmax=nmax, pl=pl, mp=mp)
         else:
         else:
             raise ValueError('The number of of dimensions for the relative refractive index (m) and for the size parameter (x) must be equal.')
             raise ValueError('The number of of dimensions for the relative refractive index (m) and for the size parameter (x) must be equal.')
     elif len(x.shape) != 2:
     elif len(x.shape) != 2:
@@ -82,7 +96,7 @@ def scattcoeffs(x, m, nmax=-1, pl=-1, mp=False):
     bn = np.zeros((0, nstore), dtype=complex)
     bn = np.zeros((0, nstore), dtype=complex)
 
 
     for i, xi in enumerate(x):
     for i, xi in enumerate(x):
-        terms[i], a, b = scattcoeffs_(xi, m[i], nmax=nmax, pl=pl)
+        terms[i], a, b = scattcoeffs_(xi, m[i], nmax=nmax, pl=pl, mp=mp)
 
 
         if terms[i] > nstore:
         if terms[i] > nstore:
             nstore = terms[i]
             nstore = terms[i]
@@ -220,7 +234,7 @@ def scattnlay(x, m, theta=np.zeros(0, dtype=float), nmax=-1, pl=-1, mp=False):
         raise ValueError('The relative refractive index (m) should be a 1-D or 2-D NumPy array.')
         raise ValueError('The relative refractive index (m) should be a 1-D or 2-D NumPy array.')
     if len(x.shape) == 1:
     if len(x.shape) == 1:
         if len(m.shape) == 1:
         if len(m.shape) == 1:
-            return scattnlay_(x, m, theta, nmax=nmax, pl=pl)
+            return scattnlay_(x, m, theta, nmax=nmax, pl=pl, mp=mp)
         else:
         else:
             raise ValueError('The number of of dimensions for the relative refractive index (m) and for the size parameter (x) must be equal.')
             raise ValueError('The number of of dimensions for the relative refractive index (m) and for the size parameter (x) must be equal.')
     elif len(x.shape) != 2:
     elif len(x.shape) != 2:
@@ -250,6 +264,25 @@ def scattnlay(x, m, theta=np.zeros(0, dtype=float), nmax=-1, pl=-1, mp=False):
 #scattnlay()
 #scattnlay()
 
 
 
 
+def fieldnlay_(x, m, xp, yp, zp, nmax=-1, pl=-1, mp=False):
+    if mp:
+        from scattnlay_mp import mie_mp as mie_
+    else:
+        from scattnlay_dp import mie_dp as mie_
+        # from scattnlay_mp import mie_mp as mie_
+    mie = mie_()
+    mie.SetLayersSize(x)
+    mie.SetLayersIndex(m)
+    mie.SetPECLayer(pl)
+    mie.SetMaxTerms(nmax)
+    mie.SetFieldCoords(xp, yp, zp)
+    mie.RunFieldCalculation()
+    terms = mie.GetMaxTerms()
+    E = mie.GetFieldE()
+    H = mie.GetFieldH()
+    return terms, E, H
+
+
 def fieldnlay(x, m, xp, yp, zp, nmax=-1, pl=-1, mp=False):
 def fieldnlay(x, m, xp, yp, zp, nmax=-1, pl=-1, mp=False):
     """
     """
     fieldnlay(x, m, xp, yp, zp[, nmax, pl, mp])
     fieldnlay(x, m, xp, yp, zp[, nmax, pl, mp])
@@ -278,16 +311,12 @@ def fieldnlay(x, m, xp, yp, zp, nmax=-1, pl=-1, mp=False):
            (or structure) and correct it for the following ones
            (or structure) and correct it for the following ones
     """
     """
 
 
-    if mp:
-        from scattnlay_mp import fieldnlay as fieldnlay_
-    else:
-        from scattnlay_dp import fieldnlay as fieldnlay_
 
 
     if len(m.shape) != 1 and len(m.shape) != 2:
     if len(m.shape) != 1 and len(m.shape) != 2:
         raise ValueError('The relative refractive index (m) should be a 1-D or 2-D NumPy array.')
         raise ValueError('The relative refractive index (m) should be a 1-D or 2-D NumPy array.')
     if len(x.shape) == 1:
     if len(x.shape) == 1:
         if len(m.shape) == 1:
         if len(m.shape) == 1:
-            return fieldnlay_(x, m, xp, yp, zp, nmax=nmax, pl=pl)
+            return fieldnlay_(x, m, xp, yp, zp, nmax=nmax, pl=pl, mp=mp)
         else:
         else:
             raise ValueError('The number of of dimensions for the relative refractive index (m) and for the size parameter (x) must be equal.')
             raise ValueError('The number of of dimensions for the relative refractive index (m) and for the size parameter (x) must be equal.')
     elif len(x.shape) != 2:
     elif len(x.shape) != 2:
@@ -304,7 +333,7 @@ def fieldnlay(x, m, xp, yp, zp, nmax=-1, pl=-1, mp=False):
     for i, xi in enumerate(x):
     for i, xi in enumerate(x):
         # (2020/05/12) We assume that the coordinates are referred to the first wavelength
         # (2020/05/12) We assume that the coordinates are referred to the first wavelength
         #              (or structure) and correct it for the following ones
         #              (or structure) and correct it for the following ones
-        terms[i], E[i], H[i] = fieldnlay_(xi, m[i], xp*xi[-1]/x[0, -1], yp*xi[-1]/x[0, -1], zp*xi[-1]/x[0, -1], nmax=nmax, pl=pl)
+        terms[i], E[i], H[i] = fieldnlay_(xi, m[i], xp*xi[-1]/x[0, -1], yp*xi[-1]/x[0, -1], zp*xi[-1]/x[0, -1], nmax=nmax, pl=pl, mp=mp)
 
 
     return terms, E, H
     return terms, E, H
 #fieldnlay()
 #fieldnlay()

+ 71 - 34
src/nmie-basic.hpp

@@ -163,14 +163,7 @@ namespace nmie {
       throw std::invalid_argument("You should run calculations before result request!");
       throw std::invalid_argument("You should run calculations before result request!");
     return S2_;
     return S2_;
   }
   }
-template <typename FloatType> template <typename outputType>
-py::array_t< std::complex<outputType>>  MultiLayerMie<FloatType>::GetS1() {
-  return VectorComplex2Py<FloatType,outputType>(GetS1());
-}
-template <typename FloatType> template <typename outputType>
-py::array_t< std::complex<outputType>>  MultiLayerMie<FloatType>::GetS2() {
-  return VectorComplex2Py<FloatType,outputType>(GetS2());
-}
+
 
 
 
 
 // ********************************************************************** //
 // ********************************************************************** //
@@ -248,30 +241,6 @@ py::array_t< std::complex<outputType>>  MultiLayerMie<FloatType>::GetS2() {
     nmax_preset_ = nmax;
     nmax_preset_ = nmax;
   }
   }
 
 
-  // Python interface
-  template <typename FloatType>
-  template <typename inputType>
-  void MultiLayerMie<FloatType>::SetLayersSize(
-      const py::array_t<inputType, py::array::c_style | py::array::forcecast> &py_layer_size) {
-    auto layer_size_dp = Py2Vector<inputType>(py_layer_size);
-    SetLayersSize(ConvertVector<FloatType>(layer_size_dp));
-  }
-
-  template <typename FloatType>
-  template <typename inputType>
-  void MultiLayerMie<FloatType>::SetLayersIndex(
-      const py::array_t<std::complex<inputType>, py::array::c_style | py::array::forcecast> &py_index) {
-    auto index_dp = Py2Vector<std::complex<inputType> >(py_index);
-    SetLayersIndex(ConvertComplexVector<FloatType>(index_dp));
-  }
-
- template <typename FloatType>
- template <typename inputType>
- void MultiLayerMie<FloatType>::SetAngles(const py::array_t<inputType, py::array::c_style | py::array::forcecast> &py_angles) {
-   auto angles_dp = Py2Vector<inputType>(py_angles);
-   SetAngles(ConvertVector<FloatType>(angles_dp));
- }
-
 // ********************************************************************** //
 // ********************************************************************** //
   // Get total size parameter of particle                                   //
   // Get total size parameter of particle                                   //
   // ********************************************************************** //
   // ********************************************************************** //
@@ -489,10 +458,10 @@ py::array_t< std::complex<outputType>>  MultiLayerMie<FloatType>::GetS2() {
   void MultiLayerMie<FloatType>::calcPiTauAllTheta(const double from_Theta, const double to_Theta,
   void MultiLayerMie<FloatType>::calcPiTauAllTheta(const double from_Theta, const double to_Theta,
                                                    std::vector<std::vector<FloatType> > &Pi,
                                                    std::vector<std::vector<FloatType> > &Pi,
                                                    std::vector<std::vector<FloatType> > &Tau) {
                                                    std::vector<std::vector<FloatType> > &Tau) {
-    auto perimeter_points = Pi.size();
+    const unsigned int perimeter_points = Pi.size();
     for (auto &val:Pi) val.resize(available_maximal_nmax_);
     for (auto &val:Pi) val.resize(available_maximal_nmax_);
     for (auto &val:Tau) val.resize(available_maximal_nmax_);
     for (auto &val:Tau) val.resize(available_maximal_nmax_);
-    double delta_Theta = eval_delta<FloatType>(perimeter_points, from_Theta, to_Theta);
+    double delta_Theta = eval_delta<double>(perimeter_points, from_Theta, to_Theta);
     for (unsigned int i=0; i < perimeter_points; i++) {
     for (unsigned int i=0; i < perimeter_points; i++) {
       auto Theta = static_cast<FloatType>(from_Theta + i*delta_Theta);
       auto Theta = static_cast<FloatType>(from_Theta + i*delta_Theta);
       // Calculate angular functions Pi and Tau
       // Calculate angular functions Pi and Tau
@@ -901,5 +870,73 @@ py::array_t< std::complex<outputType>>  MultiLayerMie<FloatType>::GetS2() {
     isMieCalculated_ = true;
     isMieCalculated_ = true;
   }
   }
 
 
+  // Python interface
+  template <typename FloatType> template <typename inputType>
+  void MultiLayerMie<FloatType>::SetLayersSize(
+      const py::array_t<inputType, py::array::c_style | py::array::forcecast> &py_layer_size) {
+    auto layer_size_dp = Py2Vector<inputType>(py_layer_size);
+    SetLayersSize(ConvertVector<FloatType>(layer_size_dp));
+  }
+
+  template <typename FloatType> template <typename inputType>
+  void MultiLayerMie<FloatType>::SetLayersIndex(
+      const py::array_t<std::complex<inputType>, py::array::c_style | py::array::forcecast> &py_index) {
+    auto index_dp = Py2Vector<std::complex<inputType> >(py_index);
+    SetLayersIndex(ConvertComplexVector<FloatType>(index_dp));
+  }
+
+  template <typename FloatType> template <typename inputType>
+  void MultiLayerMie<FloatType>::SetAngles(const py::array_t<inputType, py::array::c_style | py::array::forcecast> &py_angles) {
+    auto angles_dp = Py2Vector<inputType>(py_angles);
+    SetAngles(ConvertVector<FloatType>(angles_dp));
+  }
+
+  template <typename FloatType> template <typename outputType>
+  py::array_t< std::complex<outputType>>  MultiLayerMie<FloatType>::GetS1() {
+    return VectorComplex2Py<FloatType,outputType>(GetS1());
+  }
+
+  template <typename FloatType> template <typename outputType>
+  py::array_t< std::complex<outputType>>  MultiLayerMie<FloatType>::GetS2() {
+    return VectorComplex2Py<FloatType,outputType>(GetS2());
+  }
+
+  template <typename FloatType> template <typename outputType>
+  py::array_t< std::complex<outputType>>  MultiLayerMie<FloatType>::GetAn() {
+    return VectorComplex2Py<FloatType,outputType>(GetAn());
+  }
+
+  template <typename FloatType> template <typename outputType>
+  py::array_t< std::complex<outputType>>  MultiLayerMie<FloatType>::GetBn() {
+    return VectorComplex2Py<FloatType,outputType>(GetBn());
+  }
+
+  template <typename FloatType> template <typename outputType>
+  py::array MultiLayerMie<FloatType>::GetFieldE() {
+    return Vector2DComplex2Py<std::complex<outputType> >(
+        ConvertComplexVectorVector<outputType>(GetFieldE())
+    );
+  }
+
+  template <typename FloatType> template <typename outputType>
+  py::array MultiLayerMie<FloatType>::GetFieldH() {
+    return Vector2DComplex2Py<std::complex<outputType> >(
+        ConvertComplexVectorVector<outputType>(GetFieldH())
+    );
+  }
+
+  template <typename FloatType>
+  void MultiLayerMie<FloatType>::SetFieldCoords(
+      const py::array_t<double, py::array::c_style | py::array::forcecast> &py_Xp,
+      const py::array_t<double, py::array::c_style | py::array::forcecast> &py_Yp,
+      const py::array_t<double, py::array::c_style | py::array::forcecast> &py_Zp) {
+    auto c_Xp = Py2Vector<double>(py_Xp);
+    auto c_Yp = Py2Vector<double>(py_Yp);
+    auto c_Zp = Py2Vector<double>(py_Zp);
+    SetFieldCoords({ConvertVector<FloatType>(c_Xp),
+                    ConvertVector<FloatType>(c_Yp),
+                    ConvertVector<FloatType>(c_Zp) });
+  }
+
 }  // end of namespace nmie
 }  // end of namespace nmie
 #endif  // SRC_NMIE_BASIC_HPP_
 #endif  // SRC_NMIE_BASIC_HPP_

+ 11 - 8
src/nmie-nearfield.hpp

@@ -408,9 +408,8 @@ namespace nmie {
     convertFieldsFromSphericalToCartesian();
     convertFieldsFromSphericalToCartesian();
   }  //  end of MultiLayerMie::RunFieldCalculation()
   }  //  end of MultiLayerMie::RunFieldCalculation()
 
 
-
 template <typename FloatType>
 template <typename FloatType>
-double eval_delta(const int steps, const double from_value, const double to_value) {
+double eval_delta(const unsigned int steps, const double from_value, const double to_value) {
   auto delta = std::abs(from_value - to_value);
   auto delta = std::abs(from_value - to_value);
   if (steps < 2) return delta;
   if (steps < 2) return delta;
   delta /= static_cast<double>(steps-1);
   delta /= static_cast<double>(steps-1);
@@ -461,15 +460,15 @@ void MultiLayerMie<FloatType>::calcMieSeriesNeededToConverge(const FloatType Rho
 
 
 
 
 template <typename FloatType>
 template <typename FloatType>
-void MultiLayerMie<FloatType>::calcRadialOnlyDependantFunctions(const FloatType from_Rho, const FloatType to_Rho,
+void MultiLayerMie<FloatType>::calcRadialOnlyDependantFunctions(const double from_Rho, const double to_Rho,
                                                                 const bool isIgnoreAvailableNmax,
                                                                 const bool isIgnoreAvailableNmax,
                                                                 std::vector<std::vector<std::complex<FloatType> > > &Psi,
                                                                 std::vector<std::vector<std::complex<FloatType> > > &Psi,
                                                                 std::vector<std::vector<std::complex<FloatType> > > &D1n,
                                                                 std::vector<std::vector<std::complex<FloatType> > > &D1n,
                                                                 std::vector<std::vector<std::complex<FloatType> > > &Zeta,
                                                                 std::vector<std::vector<std::complex<FloatType> > > &Zeta,
                                                                 std::vector<std::vector<std::complex<FloatType> > > &D3n) {
                                                                 std::vector<std::vector<std::complex<FloatType> > > &D3n) {
-  unsigned int radius_points = Psi.size();
+  auto radius_points = Psi.size();
   std::vector<std::vector<std::complex<FloatType> > > PsiZeta(radius_points);
   std::vector<std::vector<std::complex<FloatType> > > PsiZeta(radius_points);
-  double delta_Rho = eval_delta<FloatType>(radius_points, from_Rho, to_Rho);
+  double delta_Rho = eval_delta<double>(radius_points, from_Rho, to_Rho);
   for (unsigned int j=0; j < radius_points; j++) {
   for (unsigned int j=0; j < radius_points; j++) {
     auto Rho = static_cast<FloatType>(from_Rho + j*delta_Rho);
     auto Rho = static_cast<FloatType>(from_Rho + j*delta_Rho);
 //    if (Rho < 1e-5) Rho = 1e-5; // TODO do we need this?.
 //    if (Rho < 1e-5) Rho = 1e-5; // TODO do we need this?.
@@ -518,9 +517,9 @@ void MultiLayerMie<FloatType>::RunFieldCalculationPolar(const int outer_arc_poin
   calcRadialOnlyDependantFunctions(from_Rho, to_Rho, isIgnoreAvailableNmax,
   calcRadialOnlyDependantFunctions(from_Rho, to_Rho, isIgnoreAvailableNmax,
                                    Psi, D1n, Zeta, D3n);
                                    Psi, D1n, Zeta, D3n);
 
 
-  double delta_Rho = eval_delta<FloatType>(radius_points, from_Rho, to_Rho);
-  double delta_Theta = eval_delta<FloatType>(outer_arc_points, from_Theta, to_Theta);
-  double delta_Phi = eval_delta<FloatType>(radius_points, from_Phi, to_Phi);
+  double delta_Rho = eval_delta<double>(radius_points, from_Rho, to_Rho);
+  double delta_Theta = eval_delta<double>(outer_arc_points, from_Theta, to_Theta);
+  double delta_Phi = eval_delta<double>(radius_points, from_Phi, to_Phi);
   Es_.clear(); Hs_.clear(); coords_polar_.clear();
   Es_.clear(); Hs_.clear(); coords_polar_.clear();
   for (int j=0; j < radius_points; j++) {
   for (int j=0; j < radius_points; j++) {
     auto Rho = static_cast<FloatType>(from_Rho + j * delta_Rho);
     auto Rho = static_cast<FloatType>(from_Rho + j * delta_Rho);
@@ -542,5 +541,9 @@ void MultiLayerMie<FloatType>::RunFieldCalculationPolar(const int outer_arc_poin
   convertFieldsFromSphericalToCartesian();
   convertFieldsFromSphericalToCartesian();
 
 
 }
 }
+
+// Python interface
+
+
 }  // end of namespace nmie
 }  // end of namespace nmie
 #endif  // SRC_NMIE_NEARFIELD_HPP_
 #endif  // SRC_NMIE_NEARFIELD_HPP_

+ 0 - 65
src/nmie-pybind11.cc

@@ -40,44 +40,6 @@
 namespace py = pybind11;
 namespace py = pybind11;
 
 
 
 
-// https://stackoverflow.com/questions/17294629/merging-flattening-sub-vectors-into-a-single-vector-c-converting-2d-to-1d
-template <typename T>
-std::vector<T> flatten(const std::vector<std::vector<T>> &v) {
-    std::size_t total_size = 0;
-    for (const auto &sub : v)
-        total_size += sub.size(); // I wish there was a transform_accumulate
-    std::vector<T> result;
-    result.reserve(total_size);
-    for (const auto &sub : v)
-        result.insert(result.end(), sub.begin(), sub.end());
-    return result;
-}
-
-
-template <typename T>
-py::array Vector2DComplex2Py(const std::vector<std::vector<T > > &x) {
-  size_t dim1 = x.size();
-  size_t dim2 = x[0].size();
-  auto result = flatten(x);
-  // https://github.com/tdegeus/pybind11_examples/blob/master/04_numpy-2D_cpp-vector/example.cpp
-  size_t              ndim    = 2;
-  std::vector<size_t> shape   = {dim1, dim2};
-  std::vector<size_t> strides = {sizeof(T)*dim2, sizeof(T)};
-
-  // return 2-D NumPy array
-  return py::array(py::buffer_info(
-    result.data(),                       /* data as contiguous array  */
-    sizeof(T),                           /* size of one scalar        */
-    py::format_descriptor<T>::format(),  /* data type                 */
-    ndim,                                /* number of dimensions      */
-    shape,                               /* shape of the matrix       */
-    strides                              /* strides for each axis     */
-  ));
-}
-
-
-
-
 py::tuple py_ScattCoeffs(const py::array_t<double, py::array::c_style | py::array::forcecast> &py_x,
 py::tuple py_ScattCoeffs(const py::array_t<double, py::array::c_style | py::array::forcecast> &py_x,
                          const py::array_t<std::complex<double>, py::array::c_style | py::array::forcecast> &py_m,
                          const py::array_t<std::complex<double>, py::array::c_style | py::array::forcecast> &py_m,
                          const int nmax=-1, const int pl=-1) {
                          const int nmax=-1, const int pl=-1) {
@@ -110,30 +72,3 @@ py::tuple py_ExpanCoeffs(const py::array_t<double, py::array::c_style | py::arra
 
 
   return py::make_tuple(terms, Vector2DComplex2Py(c_an), Vector2DComplex2Py(c_bn), Vector2DComplex2Py(c_cn), Vector2DComplex2Py(c_dn));
   return py::make_tuple(terms, Vector2DComplex2Py(c_an), Vector2DComplex2Py(c_bn), Vector2DComplex2Py(c_cn), Vector2DComplex2Py(c_dn));
 }
 }
-
-
-py::tuple py_fieldnlay(const py::array_t<double, py::array::c_style | py::array::forcecast> &py_x,
-                       const py::array_t<std::complex<double>, py::array::c_style | py::array::forcecast> &py_m,
-                       const py::array_t<double, py::array::c_style | py::array::forcecast> &py_Xp,
-                       const py::array_t<double, py::array::c_style | py::array::forcecast> &py_Yp,
-                       const py::array_t<double, py::array::c_style | py::array::forcecast> &py_Zp,
-                       const int nmax=-1, const int pl=-1) {
-
-  auto c_x = Py2Vector<double>(py_x);
-  auto c_m = Py2Vector< std::complex<double> >(py_m);
-  auto c_Xp = Py2Vector<double>(py_Xp);
-  auto c_Yp = Py2Vector<double>(py_Yp);
-  auto c_Zp = Py2Vector<double>(py_Zp);
-  unsigned int ncoord = py_Xp.size();
-  std::vector<std::vector<std::complex<double> > > E(ncoord);
-  std::vector<std::vector<std::complex<double> > > H(ncoord);
-  for (auto &f : E) f.resize(3);
-  for (auto &f : H) f.resize(3);
-  int L = py_x.size(), terms;
-  terms = nmie::nField(L, pl, c_x, c_m, nmax, nmie::Modes::kAll, nmie::Modes::kAll, ncoord, c_Xp, c_Yp, c_Zp, E, H);
-  auto py_E = Vector2DComplex2Py<std::complex<double> >(E);
-  auto py_H = Vector2DComplex2Py<std::complex<double> >(H);
-  return py::make_tuple(terms, py_E, py_H);
-}
-
-

+ 1 - 1
src/nmie.cc

@@ -415,7 +415,7 @@ namespace nmie {
       ml_mie.SetFieldCoords({ConvertVector<FloatType>(Xp_vec),
       ml_mie.SetFieldCoords({ConvertVector<FloatType>(Xp_vec),
 	    ConvertVector<FloatType>(Yp_vec),
 	    ConvertVector<FloatType>(Yp_vec),
 	    ConvertVector<FloatType>(Zp_vec) });
 	    ConvertVector<FloatType>(Zp_vec) });
-      if (nmax != -1) ml_mie.SetMaxTerms(nmax);
+      ml_mie.SetMaxTerms(nmax);
       ml_mie.SetModeNmaxAndType(mode_n, mode_type);
       ml_mie.SetModeNmaxAndType(mode_n, mode_type);
 
 
       ml_mie.RunFieldCalculation();
       ml_mie.RunFieldCalculation();

+ 51 - 5
src/nmie.hpp

@@ -37,8 +37,11 @@
 #include <cstdlib>
 #include <cstdlib>
 #include <iostream>
 #include <iostream>
 #include <vector>
 #include <vector>
+
 #include <pybind11/pybind11.h>
 #include <pybind11/pybind11.h>
 #include <pybind11/numpy.h>
 #include <pybind11/numpy.h>
+#include <pybind11/complex.h>
+
 #include "nmie-precision.hpp"
 #include "nmie-precision.hpp"
 #ifdef MULTI_PRECISION
 #ifdef MULTI_PRECISION
 #include <boost/math/constants/constants.hpp>
 #include <boost/math/constants/constants.hpp>
@@ -53,8 +56,8 @@ std::vector<T> Py2Vector(const py::array_t<T> &py_x) {
 }
 }
 
 
 template <typename inputType=double, typename outputType=double>
 template <typename inputType=double, typename outputType=double>
-py::array_t< std::complex<outputType>> VectorComplex2Py(const std::vector<std::complex<inputType> > &c_f) {
-  auto c_x = nmie::ConvertComplexVector<outputType, inputType>(c_f);
+py::array_t< std::complex<outputType>> VectorComplex2Py(const std::vector<std::complex<inputType> > &cf_x) {
+  auto c_x = nmie::ConvertComplexVector<outputType, inputType>(cf_x);
   auto py_x = py::array_t< std::complex<outputType>>(c_x.size());
   auto py_x = py::array_t< std::complex<outputType>>(c_x.size());
   auto py_x_buffer = py_x.request();
   auto py_x_buffer = py_x.request();
   auto *py_x_ptr = (std::complex<outputType> *) py_x_buffer.ptr;
   auto *py_x_ptr = (std::complex<outputType> *) py_x_buffer.ptr;
@@ -62,6 +65,41 @@ py::array_t< std::complex<outputType>> VectorComplex2Py(const std::vector<std::c
   return py_x;
   return py_x;
 }
 }
 
 
+// https://stackoverflow.com/questions/17294629/merging-flattening-sub-vectors-into-a-single-vector-c-converting-2d-to-1d
+template <typename T>
+std::vector<T> flatten(const std::vector<std::vector<T>> &v) {
+  std::size_t total_size = 0;
+  for (const auto &sub : v)
+    total_size += sub.size(); // I wish there was a transform_accumulate
+  std::vector<T> result;
+  result.reserve(total_size);
+  for (const auto &sub : v)
+    result.insert(result.end(), sub.begin(), sub.end());
+  return result;
+}
+
+
+template <typename T>
+py::array Vector2DComplex2Py(const std::vector<std::vector<T > > &x) {
+  size_t dim1 = x.size();
+  size_t dim2 = x[0].size();
+  auto result = flatten(x);
+  // https://github.com/tdegeus/pybind11_examples/blob/master/04_numpy-2D_cpp-vector/example.cpp
+  size_t              ndim    = 2;
+  std::vector<size_t> shape   = {dim1, dim2};
+  std::vector<size_t> strides = {sizeof(T)*dim2, sizeof(T)};
+
+  // return 2-D NumPy array
+  return py::array(py::buffer_info(
+      result.data(),                       /* data as contiguous array  */
+      sizeof(T),                           /* size of one scalar        */
+      py::format_descriptor<T>::format(),  /* data type                 */
+      ndim,                                /* number of dimensions      */
+      shape,                               /* shape of the matrix       */
+      strides                              /* strides for each axis     */
+  ));
+}
+
 namespace nmie {
 namespace nmie {
   int ScattCoeffs(const unsigned int L, const int pl,
   int ScattCoeffs(const unsigned int L, const int pl,
                   const std::vector<double> &x, const std::vector<std::complex<double> > &m,
                   const std::vector<double> &x, const std::vector<std::complex<double> > &m,
@@ -79,7 +117,7 @@ namespace nmie {
 
 
 //helper functions
 //helper functions
 template <typename FloatType>
 template <typename FloatType>
-double eval_delta(const int steps, const double from_value, const double to_value);
+double eval_delta(const unsigned int steps, const double from_value, const double to_value);
 
 
 
 
 template<class T> inline T pow2(const T value) {return value*value;}
 template<class T> inline T pow2(const T value) {return value*value;}
@@ -186,6 +224,8 @@ inline std::complex<T> my_exp(const std::complex<T> &x) {
 
 
     std::vector<std::complex<FloatType> > GetAn(){return an_;};
     std::vector<std::complex<FloatType> > GetAn(){return an_;};
     std::vector<std::complex<FloatType> > GetBn(){return bn_;};
     std::vector<std::complex<FloatType> > GetBn(){return bn_;};
+    template <typename outputType> py::array_t< std::complex<outputType>>  GetAn();
+    template <typename outputType> py::array_t< std::complex<outputType>>  GetBn();
 
 
     std::vector< std::vector<std::complex<FloatType> > > GetLayerAn(){return aln_;};
     std::vector< std::vector<std::complex<FloatType> > > GetLayerAn(){return aln_;};
     std::vector< std::vector<std::complex<FloatType> > > GetLayerBn(){return bln_;};
     std::vector< std::vector<std::complex<FloatType> > > GetLayerBn(){return bln_;};
@@ -209,6 +249,9 @@ inline std::complex<T> my_exp(const std::complex<T> &x) {
     void SetAngles(const py::array_t<inputType, py::array::c_style | py::array::forcecast> &py_angles);
     void SetAngles(const py::array_t<inputType, py::array::c_style | py::array::forcecast> &py_angles);
     // Modify coordinates for field calculation
     // Modify coordinates for field calculation
     void SetFieldCoords(const std::vector< std::vector<FloatType> > &coords);
     void SetFieldCoords(const std::vector< std::vector<FloatType> > &coords);
+    void SetFieldCoords(const py::array_t<double, py::array::c_style | py::array::forcecast> &py_Xp,
+                        const py::array_t<double, py::array::c_style | py::array::forcecast> &py_Yp,
+                        const py::array_t<double, py::array::c_style | py::array::forcecast> &py_Zp);
     // Modify index of PEC layer
     // Modify index of PEC layer
     void SetPECLayer(int layer_position = 0);
     void SetPECLayer(int layer_position = 0);
     // Modify the mode taking into account for evaluation of output variables
     // Modify the mode taking into account for evaluation of output variables
@@ -240,6 +283,9 @@ inline std::complex<T> my_exp(const std::complex<T> &x) {
 
 
     std::vector<std::vector< std::complex<FloatType> > > GetFieldE(){return E_;};   // {X[], Y[], Z[]}
     std::vector<std::vector< std::complex<FloatType> > > GetFieldE(){return E_;};   // {X[], Y[], Z[]}
     std::vector<std::vector< std::complex<FloatType> > > GetFieldH(){return H_;};
     std::vector<std::vector< std::complex<FloatType> > > GetFieldH(){return H_;};
+    template <typename outputType> py::array GetFieldE();
+    template <typename outputType> py::array GetFieldH();
+
     // Get fields in spherical coordinates.
     // Get fields in spherical coordinates.
     std::vector<std::vector< std::complex<FloatType> > > GetFieldEs(){return E_;};   // {rho[], teha[], phi[]}
     std::vector<std::vector< std::complex<FloatType> > > GetFieldEs(){return E_;};   // {rho[], teha[], phi[]}
     std::vector<std::vector< std::complex<FloatType> > > GetFieldHs(){return H_;};
     std::vector<std::vector< std::complex<FloatType> > > GetFieldHs(){return H_;};
@@ -320,8 +366,8 @@ inline std::complex<T> my_exp(const std::complex<T> &x) {
                            const double to_Theta,
                            const double to_Theta,
                            std::vector<std::vector<FloatType>> &Pi,
                            std::vector<std::vector<FloatType>> &Pi,
                            std::vector<std::vector<FloatType>> &Tau);
                            std::vector<std::vector<FloatType>> &Tau);
-    void calcRadialOnlyDependantFunctions(const FloatType from_Rho,
-                                          const FloatType to_Rho,
+    void calcRadialOnlyDependantFunctions(const double from_Rho,
+                                          const double to_Rho,
                                           const bool isIgnoreAvailableNmax,
                                           const bool isIgnoreAvailableNmax,
                                           std::vector<std::vector<std::complex<FloatType>>> &Psi,
                                           std::vector<std::vector<std::complex<FloatType>>> &Psi,
                                           std::vector<std::vector<std::complex<FloatType>>> &D1n,
                                           std::vector<std::vector<std::complex<FloatType>>> &D1n,

+ 21 - 8
src/pb11_wrapper.cc

@@ -2,6 +2,7 @@
 #include "nmie-pybind11.hpp"
 #include "nmie-pybind11.hpp"
 #include "nmie.hpp"
 #include "nmie.hpp"
 #include "nmie-basic.hpp"
 #include "nmie-basic.hpp"
+#include "nmie-nearfield.hpp"
 
 
 //py::class_<Pet>(m, "Pet")
 //py::class_<Pet>(m, "Pet")
 //.def(py::init<const std::string &, int>())
 //.def(py::init<const std::string &, int>())
@@ -21,6 +22,12 @@ void declare_nmie(py::module &m, std::string &typestr) {
       .def("GetMaxTerms", &mie_typed::GetMaxTerms)
       .def("GetMaxTerms", &mie_typed::GetMaxTerms)
       .def("SetModeNmaxAndType", &mie_typed::SetModeNmaxAndType)
       .def("SetModeNmaxAndType", &mie_typed::SetModeNmaxAndType)
       .def("RunMieCalculation", &mie_typed::RunMieCalculation)
       .def("RunMieCalculation", &mie_typed::RunMieCalculation)
+      .def("calcScattCoeffs", &mie_typed::calcScattCoeffs)
+      .def("calcExpanCoeffs", &mie_typed::calcExpanCoeffs)
+      .def("RunFieldCalculation", &mie_typed::RunFieldCalculation)
+      .def("RunFieldCalculationPolar", &mie_typed::RunFieldCalculationPolar)
+      .def("GetPECLayer", &mie_typed::GetPECLayer)
+
       .def("SetLayersSize", static_cast<
       .def("SetLayersSize", static_cast<
                void (mie_typed::*)
                void (mie_typed::*)
                    (const py::array_t<double, py::array::c_style | py::array::forcecast>&)>
                    (const py::array_t<double, py::array::c_style | py::array::forcecast>&)>
@@ -36,6 +43,15 @@ void declare_nmie(py::module &m, std::string &typestr) {
                    (const py::array_t<double, py::array::c_style | py::array::forcecast>&)>
                    (const py::array_t<double, py::array::c_style | py::array::forcecast>&)>
            (&mie_typed::SetAngles)
            (&mie_typed::SetAngles)
       )
       )
+      .def("SetFieldCoords", static_cast<
+               void (mie_typed::*)
+                   (
+                       const py::array_t<double, py::array::c_style | py::array::forcecast> &py_Xp,
+                       const py::array_t<double, py::array::c_style | py::array::forcecast> &py_Yp,
+                       const py::array_t<double, py::array::c_style | py::array::forcecast> &py_Zp
+                   )>
+           (&mie_typed::SetFieldCoords)
+      )
       .def("GetQext", &mie_typed::GetQext<double>)
       .def("GetQext", &mie_typed::GetQext<double>)
       .def("GetQsca", &mie_typed::GetQsca<double>)
       .def("GetQsca", &mie_typed::GetQsca<double>)
       .def("GetQabs", &mie_typed::GetQabs<double>)
       .def("GetQabs", &mie_typed::GetQabs<double>)
@@ -45,6 +61,10 @@ void declare_nmie(py::module &m, std::string &typestr) {
       .def("GetAlbedo", &mie_typed::GetAlbedo<double>)
       .def("GetAlbedo", &mie_typed::GetAlbedo<double>)
       .def("GetS1", &mie_typed::GetS1<double>)
       .def("GetS1", &mie_typed::GetS1<double>)
       .def("GetS2", &mie_typed::GetS2<double>)
       .def("GetS2", &mie_typed::GetS2<double>)
+      .def("GetAn", &mie_typed::GetAn<double>)
+      .def("GetBn", &mie_typed::GetBn<double>)
+      .def("GetFieldE", &mie_typed::GetFieldE<double>)
+      .def("GetFieldH", &mie_typed::GetFieldH<double>)
       ;
       ;
 }
 }
 
 
@@ -60,15 +80,8 @@ PYBIND11_MODULE(scattnlay_dp, m)
   m.doc() = "The Python version of scattnlay";
   m.doc() = "The Python version of scattnlay";
   declare_nmie<nmie::FloatType>(m, precision_name);
   declare_nmie<nmie::FloatType>(m, precision_name);
 
 
-  m.def("scattcoeffs", &py_ScattCoeffs,
-        "Calculate the scattering coefficients, required to calculate both the near- and far-field parameters.",
-        py::arg("x"), py::arg("m"), py::arg("nmax") = -1, py::arg("pl") = -1);
-
   m.def("expancoeffs", &py_ExpanCoeffs,
   m.def("expancoeffs", &py_ExpanCoeffs,
         "Calculate the expansion coefficients, required to calculate the near-field parameters.",
         "Calculate the expansion coefficients, required to calculate the near-field parameters.",
         py::arg("x"), py::arg("m"), py::arg("nmax") = -1, py::arg("pl") = -1);
         py::arg("x"), py::arg("m"), py::arg("nmax") = -1, py::arg("pl") = -1);
-
-    m.def("fieldnlay", &py_fieldnlay,
-        "Calculate the complex electric and magnetic field in the surroundings and inside the particle.",
-        py::arg("x"), py::arg("m"), py::arg("xp"), py::arg("yp"), py::arg("zp"), py::arg("nmax") = -1, py::arg("pl") = -1);
 }
 }
+