//**********************************************************************************// // Copyright (C) 2009-2019 Ovidio Pena // // Copyright (C) 2013-2019 Konstantin Ladutenko // // // // This file is part of 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. // // // // You should have received a copy of the GNU General Public License // // along with this program. If not, see . // //**********************************************************************************// #include #include #include "nmie.hpp" #include #include #include namespace py = pybind11; py::array_t< std::complex> VectorComplex2Py(const std::vector > &c_x) { auto py_x = py::array_t< std::complex>(c_x.size()); auto py_x_buffer = py_x.request(); auto *py_x_ptr = (std::complex *) py_x_buffer.ptr; std::memcpy(py_x_ptr, c_x.data(), c_x.size()*sizeof(std::complex)); return py_x; } // https://stackoverflow.com/questions/17294629/merging-flattening-sub-vectors-into-a-single-vector-c-converting-2d-to-1d template std::vector flatten(const std::vector> &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 result; result.reserve(total_size); for (const auto &sub : v) result.insert(result.end(), sub.begin(), sub.end()); return result; } template py::array Vector2DComplex2Py(const std::vector > &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 shape = {dim1, dim2}; std::vector 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::format(), /* data type */ ndim, /* number of dimensions */ shape, /* shape of the matrix */ strides /* strides for each axis */ )); } template std::vector Py2Vector(const py::array_t &py_x) { std::vector c_x(py_x.size()); std::memcpy(c_x.data(), py_x.data(), py_x.size()*sizeof(T)); return c_x; } py::tuple py_ScattCoeffs(const py::array_t &py_x, const py::array_t, py::array::c_style | py::array::forcecast> &py_m, const int nmax=-1, const int pl=-1) { auto c_x = Py2Vector(py_x); auto c_m = Py2Vector< std::complex >(py_m); int terms = 0; std::vector > c_an, c_bn; int L = py_x.size(); terms = nmie::ScattCoeffs(L, pl, c_x, c_m, nmax, c_an, c_bn); return py::make_tuple(terms, VectorComplex2Py(c_an), VectorComplex2Py(c_bn)); } py::tuple py_ExpanCoeffs(const py::array_t &py_x, const py::array_t, py::array::c_style | py::array::forcecast> &py_m, const int nmax=-1, const int pl=-1) { auto c_x = Py2Vector(py_x); auto c_m = Py2Vector< std::complex >(py_m); int terms = 0; int L = py_x.size(); std::vector > > c_an(L + 1), c_bn(L + 1), c_cn(L + 1), c_dn(L + 1); terms = nmie::ExpanCoeffs(L, pl, c_x, c_m, nmax, c_an, c_bn, c_cn, c_dn); return py::make_tuple(terms, Vector2DComplex2Py(c_an), Vector2DComplex2Py(c_bn), Vector2DComplex2Py(c_cn), Vector2DComplex2Py(c_dn)); } py::tuple py_scattnlay(const py::array_t &py_x, const py::array_t, py::array::c_style | py::array::forcecast> &py_m, const py::array_t &py_theta, const int nmax=-1, const int pl=-1) { auto c_x = Py2Vector(py_x); auto c_m = Py2Vector< std::complex >(py_m); auto c_theta = Py2Vector(py_theta); int L = py_x.size(), nTheta = c_theta.size(), terms; double Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo; std::vector > c_S1, c_S2; terms = nmie::nMie(L, pl, c_x, c_m, nTheta, c_theta, nmax, &Qext, &Qsca, &Qabs, &Qbk, &Qpr, &g, &Albedo, c_S1, c_S2); return py::make_tuple(terms, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, VectorComplex2Py(c_S1), VectorComplex2Py(c_S2)); } py::tuple py_fieldnlay(const py::array_t &py_x, const py::array_t, py::array::c_style | py::array::forcecast> &py_m, const py::array_t &py_Xp, const py::array_t &py_Yp, const py::array_t &py_Zp, const int nmax=-1, const int pl=-1) { auto c_x = Py2Vector(py_x); auto c_m = Py2Vector< std::complex >(py_m); auto c_Xp = Py2Vector(py_Xp); auto c_Yp = Py2Vector(py_Yp); auto c_Zp = Py2Vector(py_Zp); unsigned int ncoord = py_Xp.size(); std::vector > > E(ncoord); std::vector > > 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 >(E); auto py_H = Vector2DComplex2Py >(H); return py::make_tuple(terms, py_E, py_H); }