Browse Source

JS bindings for near-field. Move Python bindings to a separate class. (#38)

* strange

* small bag fix

* somehow works

* moved Python interface to a separate class. Initial support of near-field evaluation in JS

* GetFieldEabs works in JS
Konstantin Ladutenko 3 years ago
parent
commit
554087e4fd

+ 1 - 1
Makefile

@@ -58,7 +58,7 @@ wasm: $(SRCDIR)/nmie-js-wrapper.cc $(CXX_NMIE_HEADERS)
 #	emcc --bind -lm -Wall -O2 -std=c++11 -s WASM=1 -s NO_EXIT_RUNTIME=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['addOnPostRun']" -o nmiejs.js $(SRCDIR)/nmie-js-wrapper.cc
 
 # 	emcc --bind -lm -Wall -O2 -std=c++11 -s MODULARIZE=1 -s WASM=1 -o nmie.js $(SRCDIR)/nmie-js-wrapper.cc
-	emcc --bind -lm -Wall -pedantic -Oz -std=c++11 -s MODULARIZE=1 -s ASSERTIONS=1 -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s EXPORT_NAME="nmiejs" -s ENVIRONMENT="web" -o nmiejs.js $(SRCDIR)/nmie-js-wrapper.cc
+	emcc --bind -lm -Wall -pedantic -Oz -std=c++11 -s NO_DISABLE_EXCEPTION_CATCHING -s MODULARIZE=1 -s ASSERTIONS=1 -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s EXPORT_NAME="nmiejs" -s ENVIRONMENT="web" -o nmiejs.js $(SRCDIR)/nmie-js-wrapper.cc
 #	emcc --bind -lm -Wall -O3 -std=c++11 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]' -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE=1 -s 'EXPORT_NAME="nmiejs"' -o ./nmiejs.js $(SRCDIR)/nmie-js-wrapper.cc
 
 # 	emcc -g --bind -lm -Wall -std=c++11 -s WASM=1 -s NO_EXIT_RUNTIME=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['addOnPostRun']" -o nmie.js $(SRCDIR)/nmie-js-wrapper.cc

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

@@ -38,7 +38,7 @@ from matplotlib import pyplot as plt
 import inspect
 print("Using scattnlay from ", inspect.getfile(scattnlay))
 
-npts = 351
+npts = 11
 # npts = 11
 factor = 2 # plot extent compared to sphere radius
 index_H2O = 1.33+(1e-6)*1j

+ 129 - 0
examples/Opt.Commun.-2010-Geints-Nanojets_of_dielectric_microspheres/fig1_polar.py

@@ -0,0 +1,129 @@
+#!/usr/bin/env python3
+# -*- coding: UTF-8 -*-
+#
+#    Copyright (C) 2009-2021 Ovidio Peña Rodríguez <ovidio@bytesfall.com>
+#    Copyright (C) 2013-2021  Konstantin Ladutenko <kostyfisik@gmail.com>
+#
+#    This file is part of python-scattnlay
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    The only additional remark is that we expect that all publications
+#    describing work using this software, or all commercial products
+#    using it, cite at least one of the following references:
+#    [1] O. Pena and U. Pal, "Scattering of electromagnetic radiation by
+#        a multilayered sphere," Computer Physics Communications,
+#        vol. 180, Nov. 2009, pp. 2348-2354.
+#    [2] K. Ladutenko, U. Pal, A. Rivera, and O. Pena-Rodriguez, "Mie
+#        calculation of electromagnetic near-field for a multilayered
+#        sphere," Computer Physics Communications, vol. 214, May 2017,
+#        pp. 225-230.
+#
+import numpy as np
+import matplotlib.pyplot as plt
+from scattnlay import mie, mie_mp
+
+npts = 11/2
+# npts = 11
+
+
+from_theta = 0
+to_theta = np.pi*2
+outer_arc_points = int(abs(to_theta-from_theta)*npts)
+# outer_arc_points = 600
+
+
+factor = 2 # plot extent compared to sphere radius
+index_H2O = 1.33+(1e-6)*1j
+
+WL = 0.532 #mkm
+total_r = 125 #mkm
+isMP = False
+# isMP = True
+
+
+nm = 1.0  # host medium
+# x = 2.0 * np.pi * np.array([total_r/2, total_r], dtype=np.float64) / WL
+# m = np.array((index_H2O, index_H2O), dtype=np.complex128) / nm
+
+x = 2.0 * np.pi * np.array([total_r], dtype=np.float64) / WL
+m = np.array((index_H2O), dtype=np.complex128) / nm
+
+from_r = 0.01*x[-1]
+to_r = x[-1]*factor
+r_points = int(outer_arc_points/abs(to_theta-from_theta))
+
+# nmax = int(np.max(x*factor + 11 * (x*factor)**(1.0 / 3.0) + 1))
+nmax = -1
+
+print("x =", x)
+print("m =", m)
+mie.SetLayersSize(x)
+mie.SetLayersIndex(m)
+mie.RunMieCalculation()
+Qsca =  mie.GetQsca()
+terms = mie.GetMaxTerms()
+print("   Qsca = " + str(Qsca)+" terms = "+str(terms))
+mie_mp.SetLayersSize(x)
+mie_mp.SetLayersIndex(m)
+mie_mp.RunMieCalculation()
+Qsca =  mie_mp.GetQsca()
+terms = mie_mp.GetMaxTerms()
+
+print("mp Qsca = " + str(Qsca)+" terms = "+str(terms))
+
+
+# mie.SetFieldCoords(xp, yp, zp)
+# mie.RunFieldCalculation()
+# terms = mie.GetMaxTerms()
+# E = mie.GetFieldE()
+# H = mie.GetFieldH()
+
+theta_all = np.linspace(from_theta, to_theta, outer_arc_points);
+r_all = np.linspace(from_r, to_r, r_points)
+
+theta = []
+r = []
+for i in range(len(r_all)):
+    for j in range(len(theta_all)):
+        theta.append(theta_all[j])
+        r.append(r_all[i])
+
+mie_mp.RunFieldCalculationPolar(outer_arc_points, r_points, from_r, to_r, from_theta, to_theta, 0, 0, True)
+Ec = mie_mp.GetFieldE()
+# mie.RunFieldCalculationPolar(outer_arc_points, r_points, from_r, to_r, from_theta, to_theta, 0, 0, True)
+# Ec = mie.GetFieldE()
+print("Field evaluation done.")
+Er = np.absolute(Ec)
+Eabs = (Er[:, 0]**2 + Er[:, 1]**2 + Er[:, 2]**2)
+# Eabs = np.resize(Eabs2, (outer_arc_points, r_points))
+print("min(Eabs)=", np.min(Eabs)," max(Eabs)=", np.max(Eabs)," terms = "+str(terms), ' size=', Eabs.size)
+
+
+fig, ax = plt.subplots(subplot_kw=dict(projection='polar'))
+
+vmax = 14
+Eabs[Eabs>vmax] = vmax
+pos = ax.tricontourf(theta, r, Eabs,
+                     levels=1000,
+               cmap='gnuplot',
+               )
+plt.colorbar(pos)
+ax.yaxis.grid(False)
+ax.xaxis.grid(False)
+
+# ax.plot(theta,r, 'ro', ms=0.1)
+mp = ''
+if isMP: mp = '_mp'
+plt.savefig("R"+str(total_r)+"mkm"+mp+"_polar.jpg",
+            dpi=600
+            )
+# plt.show()

+ 31 - 1
src/nmie-applied-impl.hpp

@@ -404,7 +404,37 @@ c    MM + 1  and - 1, alternately
     ConvertToSP();
     this->MultiLayerMie<FloatType>::RunMieCalculation();
   }
-  // ********************************************************************** //
+
+  template <typename FloatType>
+  void MultiLayerMieApplied<FloatType>::RunFieldCalculationPolar(const int outer_arc_points,
+                                                                 const int radius_points,
+                                                                 const double from_Rho, const double to_Rho,
+                                                                 const double from_Theta, const double to_Theta,
+                                                                 const double from_Phi, const double to_Phi,
+                                                                 const int isIgnoreAvailableNmax) {
+//    ConvertToSP();
+    this->MultiLayerMie<FloatType>::RunFieldCalculationPolar(outer_arc_points, radius_points, from_Rho, to_Rho,
+                                                               from_Theta, to_Theta, from_Phi, to_Phi,
+                                                               isIgnoreAvailableNmax == 0 ? false : true);
+  }
+
+//from https://toughengineer.github.io/demo/dsp/fft-perf/
+template <typename FloatType=double>
+emscripten::val toJSFloat64Array(const std::vector<double> &v) {
+  emscripten::val view{ emscripten::typed_memory_view(v.size(), v.data()) };  // make a view of local object
+
+  auto result = emscripten::val::global("Float64Array").new_(v.size());  // make a JS typed array
+  result.call<void>("set", view);  // set typed array values "on the JS side" using the memory view
+
+  return result;
+}
+
+template <typename FloatType>
+emscripten::val MultiLayerMieApplied<FloatType>::GetFieldEabs() {
+  auto Eabs = this->MultiLayerMie<FloatType>::GetFieldEabs();
+  return toJSFloat64Array(Eabs);
+}
+// ********************************************************************** //
   // ********************************************************************** //
   // ********************************************************************** //
   template <typename FloatType>

+ 12 - 3
src/nmie-applied.hpp

@@ -39,6 +39,10 @@
 
 #include "nmie.hpp"
 #include "nmie-basic.hpp"
+#include "nmie-nearfield.hpp"
+
+#include <emscripten/bind.h>
+#include <emscripten/val.h>
 
 
 namespace nmie {
@@ -54,6 +58,14 @@ namespace nmie {
     // Will throw for any error!
    public:
     void RunMieCalculation();
+    void RunFieldCalculationPolar(const int outer_arc_points,
+                                  const int radius_points,
+                                  const double from_Rho, const double to_Rho,
+                                  const double from_Theta, const double to_Theta,
+                                  const double from_Phi, const double to_Phi,
+                                  const int isIgnoreAvailableNmax);
+    emscripten::val GetFieldEabs();
+
     void GetFailed();
     long iformat = 0;
     bool output = true;
@@ -173,9 +185,6 @@ namespace nmie {
 
     std::vector< std::vector<FloatType> > coords_sp_;
 
-
-
-
   };  // end of class MultiLayerMie
 
 }  // end of namespace nmie

+ 4 - 99
src/nmie-basic.hpp

@@ -535,10 +535,10 @@ namespace nmie {
     // using eq 4.50 in BH
     std::complex<evalType> c_zero(0.0, 0.0);
 
-    using nmm::sin;
-    using nmm::cos;
-    auto sin_Phi = sin(Phi);
-    auto cos_Phi = cos(Phi);
+//    using nmm::sin;
+//    using nmm::cos;
+    auto sin_Phi = sin_t(Phi);
+    auto cos_Phi = cos_t(Phi);
     auto sin_Theta = sin(Theta);
     Mo1n[0] = c_zero;
     Mo1n[1] = cos_Phi*Pi*rn/Rho;
@@ -873,101 +873,6 @@ namespace nmie {
     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> template <typename outputType>
-  py::array MultiLayerMie<FloatType>::GetLayerAn() {
-    return Vector2DComplex2Py<std::complex<outputType> >(
-        ConvertComplexVectorVector<outputType>(GetLayerAn())
-    );
-  }
-
-  template <typename FloatType> template <typename outputType>
-  py::array MultiLayerMie<FloatType>::GetLayerBn() {
-    return Vector2DComplex2Py<std::complex<outputType> >(
-        ConvertComplexVectorVector<outputType>(GetLayerBn())
-    );
-  }
-
-  template <typename FloatType> template <typename outputType>
-  py::array MultiLayerMie<FloatType>::GetLayerCn() {
-    return Vector2DComplex2Py<std::complex<outputType> >(
-        ConvertComplexVectorVector<outputType>(GetLayerCn())
-    );
-  }
-
-  template <typename FloatType> template <typename outputType>
-  py::array MultiLayerMie<FloatType>::GetLayerDn() {
-    return Vector2DComplex2Py<std::complex<outputType> >(
-        ConvertComplexVectorVector<outputType>(GetLayerDn())
-    );
-  }
-
-  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
 #endif  // SRC_NMIE_BASIC_HPP_

+ 2 - 1
src/nmie-js-wrapper.cc

@@ -34,7 +34,6 @@
 #include "nmie-applied.hpp"
 #include "nmie-applied-impl.hpp"
 #include "nmie-precision.hpp"
-#include <emscripten/bind.h>
 
 using namespace emscripten;
 
@@ -48,6 +47,8 @@ EMSCRIPTEN_BINDINGS (c) {
                 .function("SetModeNmaxAndType",&nmie::MultiLayerMieApplied<double>::SetModeNmaxAndType)
                 .function("ClearTarget",&nmie::MultiLayerMieApplied<double>::ClearTarget)
                 .function("RunMieCalculation",&nmie::MultiLayerMieApplied<double>::RunMieCalculation)
+                .function("RunFieldCalculationPolar",&nmie::MultiLayerMieApplied<double>::RunFieldCalculationPolar)
+                .function("GetFieldEabs",&nmie::MultiLayerMieApplied<double>::GetFieldEabs)
                 .function("GetQsca",&nmie::MultiLayerMieApplied<double>::GetQsca)
                 .function("GetQext",&nmie::MultiLayerMieApplied<double>::GetQext)
                 .function("GetQabs",&nmie::MultiLayerMieApplied<double>::GetQabs)

+ 55 - 31
src/nmie-nearfield.hpp

@@ -191,6 +191,7 @@ namespace nmie {
   void MultiLayerMie<FloatType>::convertFieldsFromSphericalToCartesian() {
     long total_points = coords_polar_.size();
     E_.clear(); H_.clear();
+    Eabs_.clear(); Habs_.clear();
     for (int point=0; point < total_points; point++) {
       auto Theta = coords_polar_[point][1];
       auto Phi = coords_polar_[point][2];
@@ -204,6 +205,8 @@ namespace nmie {
       H_.push_back({ sin(Theta)*cos(Phi)*Hs[0] + cos(Theta)*cos(Phi)*Hs[1] - sin(Phi)*Hs[2],
                      sin(Theta)*sin(Phi)*Hs[0] + cos(Theta)*sin(Phi)*Hs[1] + cos(Phi)*Hs[2],
                      cos(Theta)*Hs[0] - sin(Theta)*Hs[1]});
+      Eabs_.push_back(vabs(E_.back()));
+      Habs_.push_back(vabs(H_.back()));
     }
 
   }  // end of void MultiLayerMie::convertFieldsFromSphericalToCartesian()
@@ -273,14 +276,20 @@ namespace nmie {
       std::complex<evalType> En = ipow[n1 % 4]
       *static_cast<evalType>((rn + rn + 1.0)/(rn*rn + rn));
       std::complex<evalType> Ediff, Hdiff;
+      std::complex<FloatType> Ediff_ft, Hdiff_ft;
       for (int i = 0; i < 3; i++) {
-        Ediff = En*(      cln_[l][n]*M1o1n[i] - c_i*dln_[l][n]*N1e1n[i]
-                         + c_i*aln_[l][n]*N3e1n[i] -     bln_[l][n]*M3o1n[i]);
-        Hdiff = En*(     -dln_[l][n]*M1e1n[i] - c_i*cln_[l][n]*N1o1n[i]
-                         + c_i*bln_[l][n]*N3o1n[i] +     aln_[l][n]*M3e1n[i]);
-        if (nmm::isnan(Ediff.real()) || nmm::isnan(Ediff.imag()) ||
-            nmm::isnan(Hdiff.real()) || nmm::isnan(Hdiff.imag())
-            ) {
+        std::complex<evalType> aln = ConvertComplex<evalType>(aln_[l][n]);
+        std::complex<evalType> bln = ConvertComplex<evalType>(bln_[l][n]);
+        std::complex<evalType> cln = ConvertComplex<evalType>(cln_[l][n]);
+        std::complex<evalType> dln = ConvertComplex<evalType>(dln_[l][n]);
+        Ediff = En*(      cln*M1o1n[i] - c_i*dln*N1e1n[i]
+                         + c_i*aln*N3e1n[i] -     bln*M3o1n[i]);
+        Hdiff = En*(     -dln*M1e1n[i] - c_i*cln*N1o1n[i]
+                         + c_i*bln*N3o1n[i] +     aln*M3e1n[i]);
+        Ediff_ft = ConvertComplex<FloatType>(Ediff);
+        Hdiff_ft = ConvertComplex<FloatType>(Hdiff);
+        if ( nmm::isnan(Ediff_ft.real()) || nmm::isnan(Ediff_ft.imag()) ||
+             nmm::isnan(Hdiff_ft.real()) || nmm::isnan(Hdiff_ft.imag()) ) {
           std::cout << "Unexpected truncation during near-field evaluation at n = "<< n
                     << " (of total nmax = "<<nmax<<")!!!"<<std::endl;
           break;
@@ -293,27 +302,27 @@ namespace nmie {
         }
         if (n1 == mode_n_) {
           if (mode_type_ == Modes::kElectric || mode_type_ == Modes::kAll) {
-            E[i] += En*( -c_i*dln_[l][n]*N1e1n[i]
-                        + c_i*aln_[l][n]*N3e1n[i]);
+            E[i] += En*( -c_i*dln*N1e1n[i]
+                        + c_i*aln*N3e1n[i]);
 
-            H[i] += En*(-dln_[l][n]*M1e1n[i]
-                        +aln_[l][n]*M3e1n[i]);
+            H[i] += En*(-dln*M1e1n[i]
+                        +aln*M3e1n[i]);
             //std::cout << mode_n_;
           }
           if (mode_type_ == Modes::kMagnetic  || mode_type_ == Modes::kAll) {
-            E[i] += En*(  cln_[l][n]*M1o1n[i]
-                        - bln_[l][n]*M3o1n[i]);
+            E[i] += En*(  cln*M1o1n[i]
+                        - bln*M3o1n[i]);
 
-            H[i] += En*( -c_i*cln_[l][n]*N1o1n[i]
-                        + c_i*bln_[l][n]*N3o1n[i]);
+            H[i] += En*( -c_i*cln*N1o1n[i]
+                        + c_i*bln*N3o1n[i]);
             //std::cout << mode_n_;
           }
           //std::cout << std::endl;
         }
         //throw std::invalid_argument("Error! Unexpected mode for field evaluation!\n mode_n="+std::to_string(mode_n)+", mode_type="+std::to_string(mode_type)+"\n=====*****=====");
       }
-      if (nmm::isnan(Ediff.real()) || nmm::isnan(Ediff.imag()) ||
-          nmm::isnan(Hdiff.real()) || nmm::isnan(Hdiff.imag())
+      if (nmm::isnan(Ediff_ft.real()) || nmm::isnan(Ediff_ft.imag()) ||
+          nmm::isnan(Hdiff_ft.real()) || nmm::isnan(Hdiff_ft.imag())
           ) break;
     }  // end of for all n
 
@@ -429,14 +438,14 @@ void MultiLayerMie<FloatType>::GetIndexAtRadius(const evalType Rho,
   l = 0;
   if (Rho > size_param_.back()) {
     l = size_param_.size();
-    ml = std::complex<FloatType>(1.0, 0.0);
+    ml = std::complex<evalType>(1.0, 0.0);
   } else {
     for (int i = size_param_.size() - 1; i >= 0 ; i--) {
       if (Rho <= size_param_[i]) {
         l = i;
       }
     }
-    ml = refractive_index_[l];
+    ml = ConvertComplex<evalType>(refractive_index_[l]);
   }
 }
 template <typename FloatType> template <typename evalType>
@@ -506,6 +515,7 @@ void MultiLayerMie<FloatType>::RunFieldCalculationPolar(const int outer_arc_poin
       || outer_arc_points < 1 || radius_points < 1
       || from_Rho < 0.)
     throw std::invalid_argument("Error! Invalid argument for RunFieldCalculationPolar() !");
+  auto nmax_old = nmax_;
   int theta_points = 0, phi_points = 0;
   if (to_Theta-from_Theta > to_Phi-from_Phi) {
     theta_points = outer_arc_points;
@@ -531,24 +541,38 @@ void MultiLayerMie<FloatType>::RunFieldCalculationPolar(const int outer_arc_poin
   double delta_Phi = eval_delta<double>(phi_points, from_Phi, to_Phi);
   Es_.clear(); Hs_.clear(); coords_polar_.clear();
   for (int j=0; j < radius_points; j++) {
-    auto Rho = static_cast<FloatType>(from_Rho + j * delta_Rho);
-    for (int i = 0; i < outer_arc_points; i++) {
-      auto Theta = static_cast<FloatType>(from_Theta + i * delta_Theta);
-      for (int k = 0; k < outer_arc_points; k++) {
-        auto Phi = static_cast<FloatType>(from_Phi + k * delta_Phi);
+    auto Rho = from_Rho + j * delta_Rho;
+    std::vector< std::complex<double> > Psi_dp = ConvertComplexVector<double>(Psi[j]);
+    std::vector< std::complex<double> > Zeta_dp = ConvertComplexVector<double>(Zeta[j]);
+    std::vector< std::complex<double> > D1n_dp = ConvertComplexVector<double>(D1n[j]);
+    std::vector< std::complex<double> > D3n_dp = ConvertComplexVector<double>(D3n[j]);
+    for (int i = 0; i < theta_points; i++) {
+      auto Theta = from_Theta + i * delta_Theta;
+      std::vector<double> Pi_dp = ConvertVector<double>(Pi[i]);
+      std::vector<double> Tau_dp = ConvertVector<double>(Tau[i]);
+      for (int k = 0; k < phi_points; k++) {
+
+        auto Phi = from_Phi + k * delta_Phi;
         coords_polar_.push_back({Rho, Theta, Phi});
+
         // This array contains the fields in spherical coordinates
-        std::vector<std::complex<FloatType> > Es(3), Hs(3);
-        calcFieldByComponents(Rho, Theta, Phi,
-                              Psi[j], D1n[j], Zeta[j], D3n[j],
-                              Pi[i], Tau[i], Es, Hs);
-        Es_.push_back(Es);
-        Hs_.push_back(Hs);
+//        std::vector<std::complex<FloatType> > Es(3), Hs(3);
+        std::vector<std::complex<double> > Es(3), Hs(3);
+        calcFieldByComponents(
+            Rho, Theta, Phi,
+                              Psi_dp, D1n_dp, Zeta_dp, D3n_dp,
+                              Pi_dp, Tau_dp, Es, Hs
+//        Rho, Theta, Phi,
+//            Psi[j], D1n[j], Zeta[j], D3n[j],
+//            Pi[i], Tau[i], Es, Hs
+        );
+        Es_.push_back(ConvertComplexVector<FloatType>(Es));
+        Hs_.push_back(ConvertComplexVector<FloatType>(Hs));
       }
     }
   }
   convertFieldsFromSphericalToCartesian();
-
+  nmax_ = nmax_old;
 }
 
 // Python interface

+ 11 - 1
src/nmie-precision.hpp

@@ -58,7 +58,17 @@ namespace nmie {
   //typedef float FloatType;
   #endif  // MULTI_PRECISION
 
-  template <typename ToFloatType, typename FromFloatType>
+  template<class T> T sin_t(T v) {
+    if (std::is_same<T, double>::value) return static_cast<T>(std::sin(static_cast<double>(v)));
+    return static_cast<T>(nmm::sin(static_cast<FloatType >(v)));
+  }
+  template<class T> T cos_t(T v) {
+    if (std::is_same<T, double>::value) return static_cast<T>(std::cos(static_cast<double>(v)));
+    return static_cast<T>(nmm::cos(static_cast<FloatType >(v)));
+  }
+
+
+template <typename ToFloatType, typename FromFloatType>
   std::vector<ToFloatType> ConvertVector(const std::vector<FromFloatType> x) {
     std::vector<ToFloatType> new_x;
     for (auto element : x) {

+ 13 - 80
src/nmie.hpp

@@ -38,67 +38,10 @@
 #include <iostream>
 #include <vector>
 
-#include <pybind11/pybind11.h>
-#include <pybind11/numpy.h>
-#include <pybind11/complex.h>
-
 #include "nmie-precision.hpp"
 #ifdef MULTI_PRECISION
 #include <boost/math/constants/constants.hpp>
 #endif
-namespace py = pybind11;
-
-template <typename T>
-std::vector<T> Py2Vector(const py::array_t<T> &py_x) {
-  std::vector<T> c_x(py_x.size());
-  std::memcpy(c_x.data(), py_x.data(), py_x.size()*sizeof(T));
-  return c_x;
-}
-
-template <typename inputType=double, typename outputType=double>
-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_buffer = py_x.request();
-  auto *py_x_ptr = (std::complex<outputType> *) py_x_buffer.ptr;
-  std::memcpy(py_x_ptr, c_x.data(), c_x.size()*sizeof(std::complex<outputType>));
-  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 {
   int ScattCoeffs(const unsigned int L, const int pl,
@@ -125,6 +68,11 @@ template<class T> inline T pow2(const T value) {return value*value;}
 template<class T> inline T cabs(const std::complex<T> value)
 {return nmm::sqrt(pow2(value.real()) + pow2(value.imag()));}
 
+template<class T> inline T vabs(const std::vector<std::complex<T>> value)
+{return nmm::sqrt(
+    pow2(value[0].real()) + pow2(value[1].real()) + pow2(value[2].real())
+    +pow2(value[0].imag()) + pow2(value[1].imag()) + pow2(value[2].imag()));}
+
 template <typename FloatType>
 int newround(FloatType x) {
   return x >= 0 ? static_cast<int>(x + 0.5):static_cast<int>(x - 0.5);
@@ -219,44 +167,27 @@ inline std::complex<T> my_exp(const std::complex<T> &x) {
     template <typename outputType = FloatType> outputType  GetAlbedo();
     std::vector<std::complex<FloatType> > GetS1();
     std::vector<std::complex<FloatType> > GetS2();
-    template <typename outputType> py::array_t< std::complex<outputType>>  GetS1();
-    template <typename outputType> py::array_t< std::complex<outputType>>  GetS2();
 
     std::vector<std::complex<FloatType> > GetAn(){return an_;};
     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> > > GetLayerBn(){return bln_;};
     std::vector< std::vector<std::complex<FloatType> > > GetLayerCn(){return cln_;};
     std::vector< std::vector<std::complex<FloatType> > > GetLayerDn(){return dln_;};
-    template <typename outputType> py::array GetLayerAn();
-    template <typename outputType> py::array GetLayerBn();
-    template <typename outputType> py::array GetLayerCn();
-    template <typename outputType> py::array GetLayerDn();
 
     // Problem definition
     // Modify size of all layers
     void SetLayersSize(const std::vector<FloatType> &layer_size);
-    template <typename inputType>
-    void SetLayersSize(const py::array_t<inputType, py::array::c_style | py::array::forcecast> &py_layer_size);
     // Modify refractive index of all layers
     void SetLayersIndex(const std::vector< std::complex<FloatType> > &index);
-    template <typename inputType>
-    void SetLayersIndex(const py::array_t<std::complex<inputType>, py::array::c_style | py::array::forcecast> &py_index);
 
     template <typename evalType=FloatType> void GetIndexAtRadius(const evalType Rho, std::complex<evalType> &ml, unsigned int &l);
     template <typename evalType=FloatType> void GetIndexAtRadius(const evalType Rho, std::complex<evalType> &ml);
-    // Modify scattering (theta) py_angles
-    void SetAngles(const std::vector<FloatType> &py_angles);
-    template <typename inputType>
-    void SetAngles(const py::array_t<inputType, py::array::c_style | py::array::forcecast> &py_angles);
+    // Modify scattering (theta) angles
+    void SetAngles(const std::vector<FloatType> &angles);
     // Modify coordinates for field calculation
     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
     void SetPECLayer(int layer_position = 0);
     // Modify the mode taking into account for evaluation of output variables
@@ -288,12 +219,13 @@ 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> > > GetFieldH(){return H_;};
-    template <typename outputType> py::array GetFieldE();
-    template <typename outputType> py::array GetFieldH();
+
+    std::vector< FloatType> GetFieldEabs(){return Eabs_;};   // {X[], Y[], Z[]}
+    std::vector< FloatType> GetFieldHabs(){return Habs_;};
 
     // 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> > > GetFieldHs(){return H_;};
+    std::vector<std::vector< std::complex<FloatType> > > GetFieldEs(){return Es_;};   // {rho[], teha[], phi[]}
+    std::vector<std::vector< std::complex<FloatType> > > GetFieldHs(){return Hs_;};
 
   protected:
     // Size parameter for all layers
@@ -367,6 +299,7 @@ inline std::complex<T> my_exp(const std::complex<T> &x) {
     FloatType Qsca_ = 0.0, Qext_ = 0.0, Qabs_ = 0.0, Qbk_ = 0.0, Qpr_ = 0.0, asymmetry_factor_ = 0.0, albedo_ = 0.0;
     std::vector<std::vector< std::complex<FloatType> > > E_, H_;  // {X[], Y[], Z[]}
     std::vector<std::vector< std::complex<FloatType> > > Es_, Hs_;  // {X[], Y[], Z[]}
+    std::vector<FloatType> Eabs_, Habs_;  // {X[], Y[], Z[]}
     std::vector<std::complex<FloatType> > S1_, S2_;
     void calcMieSeriesNeededToConverge(const FloatType Rho);
     void calcPiTauAllTheta(const double from_Theta,

+ 262 - 2
src/pb11_wrapper.cc

@@ -3,9 +3,266 @@
 #include "nmie-basic.hpp"
 #include "nmie-nearfield.hpp"
 
-template<typename T>
+#include <pybind11/pybind11.h>
+#include <pybind11/numpy.h>
+#include <pybind11/complex.h>
+
+namespace py = pybind11;
+
+template <typename T>
+std::vector<T> Py2Vector(const py::array_t<T> &py_x) {
+  std::vector<T> c_x(py_x.size());
+  std::memcpy(c_x.data(), py_x.data(), py_x.size()*sizeof(T));
+  return c_x;
+}
+
+// https://github.com/pybind/pybind11/issues/1042#issuecomment-508582847
+//template <typename Sequence>
+//inline py::array_t<typename Sequence::value_type> Vector2Py(Sequence&& seq) {
+//  // Move entire object to heap (Ensure is moveable!). Memory handled via Python capsule
+//  Sequence* seq_ptr = new Sequence(std::move(seq));
+//  auto capsule = py::capsule(seq_ptr, [](void* p) { delete reinterpret_cast<Sequence*>(p); });
+//  return py::array(seq_ptr->size(),  // shape of array
+//                   seq_ptr->data(),  // c-style contiguous strides for Sequence
+//                   capsule           // numpy array references this parent
+//  );
+//}
+template <typename outputType>
+inline py::array_t<outputType> Vector2Py(const std::vector<outputType>& seq) {
+  return py::array(seq.size(), seq.data());
+}
+
+template <typename inputType=double, typename outputType=double>
+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_buffer = py_x.request();
+  auto *py_x_ptr = (std::complex<outputType> *) py_x_buffer.ptr;
+  std::memcpy(py_x_ptr, c_x.data(), c_x.size()*sizeof(std::complex<outputType>));
+  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 {
+template<typename FloatType>
+class PyMultiLayerMie : public MultiLayerMie<FloatType> {
+ public:
+  template<typename outputType>
+  py::array_t<std::complex<outputType>> GetS1();
+  template<typename outputType>
+  py::array_t<std::complex<outputType>> GetS2();
+  template<typename outputType>
+  py::array_t<std::complex<outputType>> GetAn();
+  template<typename outputType>
+  py::array_t<std::complex<outputType>> GetBn();
+  template<typename outputType>
+  py::array GetLayerAn();
+  template<typename outputType>
+  py::array GetLayerBn();
+  template<typename outputType>
+  py::array GetLayerCn();
+  template<typename outputType>
+  py::array GetLayerDn();
+  template<typename outputType>
+  py::array GetFieldE();
+  template<typename outputType>
+  py::array GetFieldH();
+//    template <typename outputType> py::array_t<outputType>  GetFieldEabs();
+//    template <typename outputType> py::array_t<outputType>  GetFieldHabs();
+
+  template<typename inputType>
+  void SetLayersSize(const py::array_t<inputType, py::array::c_style | py::array::forcecast> &py_layer_size);
+  template<typename inputType>
+  void SetLayersIndex(const py::array_t<std::complex<inputType>, py::array::c_style | py::array::forcecast> &py_index);
+  template<typename inputType>
+  void SetAngles(const py::array_t<inputType, py::array::c_style | py::array::forcecast> &py_angles);
+  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);
+
+};
+
+// Python interface
+template<typename FloatType>
+template<typename inputType>
+void PyMultiLayerMie<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);
+  this->MultiLayerMie<FloatType>::SetLayersSize(ConvertVector<FloatType>(layer_size_dp));
+}
+
+template<typename FloatType>
+template<typename inputType>
+void PyMultiLayerMie<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);
+  this->MultiLayerMie<FloatType>::SetLayersIndex(ConvertComplexVector<FloatType>(index_dp));
+}
+
+template<typename FloatType>
+template<typename inputType>
+void PyMultiLayerMie<FloatType>::SetAngles(const py::array_t<inputType,
+                                                             py::array::c_style | py::array::forcecast> &py_angles) {
+  auto angles_dp = Py2Vector<inputType>(py_angles);
+  this->MultiLayerMie<FloatType>::SetAngles(ConvertVector<FloatType>(angles_dp));
+}
+
+template<typename FloatType>
+template<typename outputType>
+py::array_t<std::complex<outputType>> PyMultiLayerMie<FloatType>::GetS1() {
+  return VectorComplex2Py<FloatType, outputType>(
+      this->MultiLayerMie<FloatType>::GetS1()
+  );
+}
+
+template<typename FloatType>
+template<typename outputType>
+py::array_t<std::complex<outputType>> PyMultiLayerMie<FloatType>::GetS2() {
+  return VectorComplex2Py<FloatType, outputType>(
+      this->MultiLayerMie<FloatType>::GetS2()
+      );
+}
+
+template<typename FloatType>
+template<typename outputType>
+py::array_t<std::complex<outputType>> PyMultiLayerMie<FloatType>::GetAn() {
+  return VectorComplex2Py<FloatType, outputType>(
+      this->MultiLayerMie<FloatType>::GetAn()
+      );
+}
+
+template<typename FloatType>
+template<typename outputType>
+py::array_t<std::complex<outputType>> PyMultiLayerMie<FloatType>::GetBn() {
+  return VectorComplex2Py<FloatType, outputType>(
+      this->MultiLayerMie<FloatType>::GetBn()
+      );
+}
+
+template<typename FloatType>
+template<typename outputType>
+py::array PyMultiLayerMie<FloatType>::GetFieldE() {
+  return Vector2DComplex2Py<std::complex<outputType> >(
+      ConvertComplexVectorVector<outputType>(
+          this->MultiLayerMie<FloatType>::GetFieldE()
+          )
+  );
+}
+
+template<typename FloatType>
+template<typename outputType>
+py::array PyMultiLayerMie<FloatType>::GetFieldH() {
+  return Vector2DComplex2Py<std::complex<outputType> >(
+      ConvertComplexVectorVector<outputType>(
+          this->MultiLayerMie<FloatType>::GetFieldH()
+          )
+  );
+}
+
+//  template <typename FloatType> template <typename outputType>
+//  py::array_t<outputType>  PyMultiLayerMie<FloatType>::GetFieldEabs() {
+//    return Vector2Py(ConvertVector<double>(
+//    this->MultiLayerMie<FloatType>::GetFieldEabs()
+//    ));
+//  }
+//
+//  template <typename FloatType> template <typename outputType>
+//  py::array_t<outputType>  PyMultiLayerMie<FloatType>::GetFieldHabs() {
+//    return Vector2Py(ConvertVector<double>(
+//    this->MultiLayerMie<FloatType>::GetFieldHabs()
+//    ));
+//  }
+
+template<typename FloatType>
+template<typename outputType>
+py::array PyMultiLayerMie<FloatType>::GetLayerAn() {
+  return Vector2DComplex2Py<std::complex<outputType> >(
+      ConvertComplexVectorVector<outputType>(
+          this->MultiLayerMie<FloatType>::GetLayerAn()
+          )
+  );
+}
+
+template<typename FloatType>
+template<typename outputType>
+py::array PyMultiLayerMie<FloatType>::GetLayerBn() {
+  return Vector2DComplex2Py<std::complex<outputType> >(
+      ConvertComplexVectorVector<outputType>(
+          this->MultiLayerMie<FloatType>::GetLayerBn()
+          )
+  );
+}
+
+template<typename FloatType>
+template<typename outputType>
+py::array PyMultiLayerMie<FloatType>::GetLayerCn() {
+  return Vector2DComplex2Py<std::complex<outputType> >(
+      ConvertComplexVectorVector<outputType>(
+          this->MultiLayerMie<FloatType>::GetLayerCn()
+          )
+  );
+}
+
+template<typename FloatType>
+template<typename outputType>
+py::array PyMultiLayerMie<FloatType>::GetLayerDn() {
+  return Vector2DComplex2Py<std::complex<outputType> >(
+      ConvertComplexVectorVector<outputType>(
+          this->MultiLayerMie<FloatType>::GetLayerDn()
+          )
+  );
+}
+
+template<typename FloatType>
+void PyMultiLayerMie<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);
+  this->MultiLayerMie<FloatType>::SetFieldCoords({ConvertVector<FloatType>(c_Xp),
+                  ConvertVector<FloatType>(c_Yp),
+                  ConvertVector<FloatType>(c_Zp)});
+}
+}
+
+  template<typename T>
 void declare_nmie(py::module &m, const std::string &typestr) {
-  using mie_typed = nmie::MultiLayerMie<nmie::FloatType>;
+  using mie_typed = nmie::PyMultiLayerMie<nmie::FloatType>;
   std::string pyclass_name = std::string("mie") + typestr;
   py::class_<mie_typed>(m, pyclass_name.c_str(), py::buffer_protocol(), py::dynamic_attr())
       .def(py::init<>())
@@ -58,6 +315,8 @@ void declare_nmie(py::module &m, const std::string &typestr) {
       .def("GetBn", &mie_typed::GetBn<double>)
       .def("GetFieldE", &mie_typed::GetFieldE<double>)
       .def("GetFieldH", &mie_typed::GetFieldH<double>)
+//      .def("GetFieldEabs", &mie_typed::GetFieldEabs<double>)
+//      .def("GetFieldHabs", &mie_typed::GetFieldHabs<double>)
       .def("GetLayerAn", &mie_typed::GetLayerAn<double>)
       .def("GetLayerBn", &mie_typed::GetLayerBn<double>)
       .def("GetLayerCn", &mie_typed::GetLayerCn<double>)
@@ -77,3 +336,4 @@ PYBIND11_MODULE(scattnlay_dp, m)
   m.doc() = "The Python version of scattnlay";
   declare_nmie<nmie::FloatType>(m, precision_name);
 }
+

+ 8 - 0
tests/CMakeLists.txt

@@ -15,6 +15,14 @@ target_link_libraries("test_near_field" ${LIBS})
 add_test(NAME "test_near_field"
         COMMAND "test_near_field")
 
+add_executable("test_near_field_multi_precision"
+        test_near_field.cc)
+target_compile_options("test_near_field_multi_precision"
+        PRIVATE -DMULTI_PRECISION=100)
+target_link_libraries("test_near_field_multi_precision" ${LIBS})
+add_test(NAME "test_near_field_multi_precision"
+        COMMAND "test_near_field_multi_precision")
+
 
 # In included file test_spec_functions_data.hpp there are results of multiple
 # precision computation that may overflow double precision at compile time.

+ 6 - 3
tests/test_near_field.cc

@@ -6,10 +6,13 @@ TEST(RunFieldCalculationPolar, HandlesInput) {
   nmie::MultiLayerMie<nmie::FloatType> nmie;
   EXPECT_THROW(nmie.RunFieldCalculationPolar(0), std::invalid_argument);
   EXPECT_THROW(nmie.RunFieldCalculationPolar(1,1,10,5), std::invalid_argument);
-  nmie.SetLayersSize({0.099});
-  nmie.SetLayersIndex({ {0.75,0}});
+  nmie.SetLayersSize({1.099});
+  nmie.SetLayersIndex({ {1.,0}});
   nmie.RunMieCalculation();
-  nmie.RunFieldCalculationPolar(2);
+  nmie.RunFieldCalculationPolar(2, 2, 0.1, 1.5);
+  auto Eabs = nmie.GetFieldEabs();
+  std::cout<<"nmax = " << nmie.GetMaxTerms() << std::endl;
+
 }
 //TEST(BulkSphere, HandlesInput) {
 //  nmie::MultiLayerMie<nmie::FloatType> nmie;

+ 29 - 25
vue-cli3-webapp/src/App.vue

@@ -126,31 +126,34 @@
   // );
 
   import nmiejs from './nmiejs.js';
-  // // Test nmiejs if working
-  // (async () => {
-  //   const module = await nmiejs({
-  //     locateFile(path) {
-  //       let deploy_path = process.env.BASE_URL;
-  //       // '/themes/custom/physics/mie/';
-  //       // console.log();
-  //       // // let deploy_path = '';
-  //       console.log(deploy_path + path);
-  //       return deploy_path + path;
-  //     }
-  //   })
-  //     const nmie = new module.nmie();
-  //       nmie.ClearTarget();
-  //       let R = 100.0;
-  //       let reN = 4.0;
-  //       let imN = 0.01;
-  //       nmie.AddTargetLayerReIm(R, reN, imN)
-  //       nmie.SetModeNmaxAndType(-1, -1);
-  //       let WL = 800;
-  //       nmie.SetWavelength(WL);
-  //       nmie.RunMieCalculation();
-  //       console.log(nmie.GetQsca());
-  //
-  // })();
+  // Test nmiejs if working
+  (async () => {
+    const module = await nmiejs({
+      locateFile(path) {
+        let deploy_path = process.env.BASE_URL;
+        // '/themes/custom/physics/mie/';
+        // console.log();
+        // // let deploy_path = '';
+        console.log(deploy_path + path);
+        return deploy_path + path;
+      }
+    })
+    const nmie = new module.nmie();
+    nmie.ClearTarget();
+    let R = 100.0;
+    let reN = 4.0;
+    let imN = 0.01;
+    nmie.AddTargetLayerReIm(R, reN, imN)
+    nmie.SetModeNmaxAndType(-1, -1);
+    let WL = 800;
+    nmie.SetWavelength(WL);
+    nmie.RunMieCalculation();
+    console.log(nmie.GetQsca());
+    // outer_arc_points, radius_points, from_Rho, to_Rho,
+    // from_Theta, to_Theta, from_Phi, to_Phi, isIgnoreAvailableNmax
+    nmie.RunFieldCalculationPolar(2, 2, 0.1, 1.5, 0, 3.1415, 0, 3.1415, 0);
+    console.log("Field Eabs:", nmie.GetFieldEabs());
+  })();
 
   const range = (start, stop, step = 1) => Array(Math.ceil((stop - start) / step)).fill(start).map((x, y) => x + y * step);
 
@@ -573,6 +576,7 @@
                     reN/host, imN/host);
 
           }
+
           nmie.SetModeNmaxAndType(-1, -1);
           nmie.SetWavelength(WL);
           nmie.RunMieCalculation();