nmie.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. //**********************************************************************************//
  2. // Copyright (C) 2009-2018 Ovidio Pena <ovidio@bytesfall.com> //
  3. // Copyright (C) 2013-2018 Konstantin Ladutenko <kostyfisik@gmail.com> //
  4. // //
  5. // This file is part of scattnlay //
  6. // //
  7. // This program is free software: you can redistribute it and/or modify //
  8. // it under the terms of the GNU General Public License as published by //
  9. // the Free Software Foundation, either version 3 of the License, or //
  10. // (at your option) any later version. //
  11. // //
  12. // This program is distributed in the hope that it will be useful, //
  13. // but WITHOUT ANY WARRANTY; without even the implied warranty of //
  14. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
  15. // GNU General Public License for more details. //
  16. // //
  17. // The only additional remark is that we expect that all publications //
  18. // describing work using this software, or all commercial products //
  19. // using it, cite at least one of the following references: //
  20. // [1] O. Pena and U. Pal, "Scattering of electromagnetic radiation by //
  21. // a multilayered sphere," Computer Physics Communications, //
  22. // vol. 180, Nov. 2009, pp. 2348-2354. //
  23. // [2] K. Ladutenko, U. Pal, A. Rivera, and O. Pena-Rodriguez, "Mie //
  24. // calculation of electromagnetic near-field for a multilayered //
  25. // sphere," Computer Physics Communications, vol. 214, May 2017, //
  26. // pp. 225-230. //
  27. // //
  28. // You should have received a copy of the GNU General Public License //
  29. // along with this program. If not, see <http://www.gnu.org/licenses/>. //
  30. //**********************************************************************************//
  31. //**********************************************************************************//
  32. // This class implements the algorithm for a multilayered sphere described by: //
  33. // [1] W. Yang, "Improved recursive algorithm for light scattering by a //
  34. // multilayered sphere,” Applied Optics, vol. 42, Mar. 2003, pp. 1710-1720. //
  35. // //
  36. // You can find the description of all the used equations in: //
  37. // [2] O. Pena and U. Pal, "Scattering of electromagnetic radiation by //
  38. // a multilayered sphere," Computer Physics Communications, //
  39. // vol. 180, Nov. 2009, pp. 2348-2354. //
  40. // [3] K. Ladutenko, U. Pal, A. Rivera, and O. Pena-Rodriguez, "Mie //
  41. // calculation of electromagnetic near-field for a multilayered //
  42. // sphere," Computer Physics Communications, vol. 214, May 2017, //
  43. // pp. 225-230. //
  44. // //
  45. // Hereinafter all equations numbers refer to [2] //
  46. //**********************************************************************************//
  47. #include "nmie.hpp"
  48. #include "nmie-precision.hpp"
  49. #include "nmie-impl.cc"
  50. #include <array>
  51. #include <algorithm>
  52. #include <cstdio>
  53. #include <cstdlib>
  54. #include <stdexcept>
  55. #include <iostream>
  56. #include <iomanip>
  57. #include <vector>
  58. namespace nmie {
  59. //**********************************************************************************//
  60. // This function emulates a C call to calculate the scattering coefficients //
  61. // required to calculate both the near- and far-field parameters. //
  62. // //
  63. // Input parameters: //
  64. // L: Number of layers //
  65. // pl: Index of PEC layer. If there is none just send -1 //
  66. // x: Array containing the size parameters of the layers [0..L-1] //
  67. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  68. // nmax: Maximum number of multipolar expansion terms to be used for the //
  69. // calculations. Only use it if you know what you are doing, otherwise //
  70. // set this parameter to -1 and the function will calculate it. //
  71. // //
  72. // Output parameters: //
  73. // an, bn: Complex scattering amplitudes //
  74. // //
  75. // Return value: //
  76. // Number of multipolar expansion terms used for the calculations //
  77. //**********************************************************************************//
  78. int ScattCoeffs(const unsigned int L, const int pl, std::vector<double>& x, std::vector<std::complex<double> >& m,
  79. const int nmax, std::vector<std::complex<double> >& an, std::vector<std::complex<double> >& bn) {
  80. if (x.size() != L || m.size() != L)
  81. throw std::invalid_argument("Declared number of layers do not fit x and m!");
  82. try {
  83. MultiLayerMie<FloatType> ml_mie;
  84. ml_mie.SetLayersSize(ConvertVector<FloatType>(x));
  85. ml_mie.SetLayersIndex(ConvertComplexVector<FloatType>(m));
  86. ml_mie.SetPECLayer(pl);
  87. ml_mie.SetMaxTerms(nmax);
  88. ml_mie.calcScattCoeffs();
  89. an = ConvertComplexVector<double>(ml_mie.GetAn());
  90. bn = ConvertComplexVector<double>(ml_mie.GetBn());
  91. return ml_mie.GetMaxTerms();
  92. } catch(const std::invalid_argument& ia) {
  93. // Will catch if ml_mie fails or other errors.
  94. std::cerr << "Invalid argument: " << ia.what() << std::endl;
  95. throw std::invalid_argument(ia);
  96. return -1;
  97. }
  98. return 0;
  99. }
  100. //**********************************************************************************//
  101. // This function emulates a C call to calculate the expansion coefficients //
  102. // required to calculate both the near- and far-field parameters. //
  103. // //
  104. // Input parameters: //
  105. // L: Number of layers //
  106. // pl: Index of PEC layer. If there is none just send -1 //
  107. // x: Array containing the size parameters of the layers [0..L-1] //
  108. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  109. // li: Index of layer to get expansion coefficients. -1 means outside the sphere //
  110. // nmax: Maximum number of multipolar expansion terms to be used for the //
  111. // calculations. Only use it if you know what you are doing, otherwise //
  112. // set this parameter to -1 and the function will calculate it. //
  113. // //
  114. // Output parameters: //
  115. // an[li], bn[li], cn[li], dn[li]: Complex expansion coefficients of ith layer //
  116. // //
  117. // Return value: //
  118. // Number of multipolar expansion terms used for the calculations //
  119. //**********************************************************************************//
  120. int ExpanCoeffs(const unsigned int L, const int pl, std::vector<double>& x, std::vector<std::complex<double> >& m,
  121. const int li, const int nmax,
  122. std::vector<std::complex<double> >& an, std::vector<std::complex<double> >& bn,
  123. std::vector<std::complex<double> >& cn, std::vector<std::complex<double> >& dn) {
  124. if (x.size() != L || m.size() != L)
  125. throw std::invalid_argument("Declared number of layers do not fit x and m!");
  126. try {
  127. MultiLayerMie<FloatType> ml_mie;
  128. ml_mie.SetLayersSize(ConvertVector<FloatType>(x));
  129. ml_mie.SetLayersIndex(ConvertComplexVector<FloatType>(m));
  130. ml_mie.SetPECLayer(pl);
  131. ml_mie.SetMaxTerms(nmax);
  132. // Calculate scattering coefficients an_ and bn_
  133. ml_mie.calcScattCoeffs();
  134. // Calculate expansion coefficients aln_, bln_, cln_, and dln_
  135. ml_mie.calcExpanCoeffs();
  136. if (li >= L || li < 0) { // Just return the scattering coefficients
  137. an = ConvertComplexVector<double>(ml_mie.GetLayerAn()[L]);
  138. bn = ConvertComplexVector<double>(ml_mie.GetLayerBn()[L]);
  139. cn = ConvertComplexVector<double>(ml_mie.GetLayerCn()[L]);
  140. dn = ConvertComplexVector<double>(ml_mie.GetLayerDn()[L]);
  141. } else { // Return the expansion coefficients for ith layer
  142. an = ConvertComplexVector<double>(ml_mie.GetLayerAn()[li]);
  143. bn = ConvertComplexVector<double>(ml_mie.GetLayerBn()[li]);
  144. cn = ConvertComplexVector<double>(ml_mie.GetLayerCn()[li]);
  145. dn = ConvertComplexVector<double>(ml_mie.GetLayerDn()[li]);
  146. }
  147. return ml_mie.GetMaxTerms();
  148. } catch(const std::invalid_argument& ia) {
  149. // Will catch if ml_mie fails or other errors.
  150. std::cerr << "Invalid argument: " << ia.what() << std::endl;
  151. throw std::invalid_argument(ia);
  152. return -1;
  153. }
  154. return 0;
  155. }
  156. //**********************************************************************************//
  157. // This function emulates a C call to calculate the actual scattering parameters //
  158. // and amplitudes. //
  159. // //
  160. // Input parameters: //
  161. // L: Number of layers //
  162. // pl: Index of PEC layer. If there is none just send -1 //
  163. // x: Array containing the size parameters of the layers [0..L-1] //
  164. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  165. // nTheta: Number of scattering angles //
  166. // Theta: Array containing all the scattering angles where the scattering //
  167. // amplitudes will be calculated //
  168. // nmax: Maximum number of multipolar expansion terms to be used for the //
  169. // calculations. Only use it if you know what you are doing, otherwise //
  170. // set this parameter to -1 and the function will calculate it //
  171. // //
  172. // Output parameters: //
  173. // Qext: Efficiency factor for extinction //
  174. // Qsca: Efficiency factor for scattering //
  175. // Qabs: Efficiency factor for absorption (Qabs = Qext - Qsca) //
  176. // Qbk: Efficiency factor for backscattering //
  177. // Qpr: Efficiency factor for the radiation pressure //
  178. // g: Asymmetry factor (g = (Qext-Qpr)/Qsca) //
  179. // Albedo: Single scattering albedo (Albedo = Qsca/Qext) //
  180. // S1, S2: Complex scattering amplitudes //
  181. // //
  182. // Return value: //
  183. // Number of multipolar expansion terms used for the calculations //
  184. //**********************************************************************************//
  185. int nMie(const unsigned int L, const int pl, std::vector<double>& x, std::vector<std::complex<double> >& m,
  186. const unsigned int nTheta, std::vector<double>& Theta, const int nmax,
  187. double *Qext, double *Qsca, double *Qabs, double *Qbk, double *Qpr, double *g, double *Albedo,
  188. std::vector<std::complex<double> >& S1, std::vector<std::complex<double> >& S2) {
  189. if (x.size() != L || m.size() != L)
  190. throw std::invalid_argument("Declared number of layers do not fit x and m!");
  191. if (Theta.size() != nTheta)
  192. throw std::invalid_argument("Declared number of sample for Theta is not correct!");
  193. try {
  194. MultiLayerMie<FloatType> ml_mie;
  195. ml_mie.SetLayersSize(ConvertVector<FloatType>(x));
  196. ml_mie.SetLayersIndex(ConvertComplexVector<FloatType>(m));
  197. ml_mie.SetAngles(ConvertVector<FloatType>(Theta));
  198. ml_mie.SetPECLayer(pl);
  199. ml_mie.SetMaxTerms(nmax);
  200. ml_mie.RunMieCalculation();
  201. // std::cout
  202. // << std::setprecision(std::numeric_limits<FloatType>::digits10)
  203. // << "Qext = "
  204. // << ml_mie.GetQext()
  205. // << std::endl;
  206. *Qext = static_cast<double>(ml_mie.GetQext());
  207. *Qsca = static_cast<double>(ml_mie.GetQsca());
  208. *Qabs = static_cast<double>(ml_mie.GetQabs());
  209. *Qbk = static_cast<double>(ml_mie.GetQbk());
  210. *Qpr = static_cast<double>(ml_mie.GetQpr());
  211. *g = static_cast<double>(ml_mie.GetAsymmetryFactor());
  212. *Albedo = static_cast<double>(ml_mie.GetAlbedo());
  213. S1 = ConvertComplexVector<double>(ml_mie.GetS1());
  214. S2 = ConvertComplexVector<double>(ml_mie.GetS2());
  215. return ml_mie.GetMaxTerms();
  216. } catch(const std::invalid_argument& ia) {
  217. // Will catch if ml_mie fails or other errors.
  218. std::cerr << "Invalid argument: " << ia.what() << std::endl;
  219. throw std::invalid_argument(ia);
  220. return -1;
  221. }
  222. return 0;
  223. }
  224. //**********************************************************************************//
  225. // This function is just a wrapper to call the full 'nMie' function with fewer //
  226. // parameters, it is here mainly for compatibility with older versions of the //
  227. // program. Also, you can use it if you neither have a PEC layer nor want to define //
  228. // any limit for the maximum number of terms. //
  229. // //
  230. // Input parameters: //
  231. // L: Number of layers //
  232. // x: Array containing the size parameters of the layers [0..L-1] //
  233. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  234. // nTheta: Number of scattering angles //
  235. // Theta: Array containing all the scattering angles where the scattering //
  236. // amplitudes will be calculated //
  237. // //
  238. // Output parameters: //
  239. // Qext: Efficiency factor for extinction //
  240. // Qsca: Efficiency factor for scattering //
  241. // Qabs: Efficiency factor for absorption (Qabs = Qext - Qsca) //
  242. // Qbk: Efficiency factor for backscattering //
  243. // Qpr: Efficiency factor for the radiation pressure //
  244. // g: Asymmetry factor (g = (Qext-Qpr)/Qsca) //
  245. // Albedo: Single scattering albedo (Albedo = Qsca/Qext) //
  246. // S1, S2: Complex scattering amplitudes //
  247. // //
  248. // Return value: //
  249. // Number of multipolar expansion terms used for the calculations //
  250. //**********************************************************************************//
  251. int nMie(const unsigned int L, std::vector<double>& x, std::vector<std::complex<double> >& m,
  252. const unsigned int nTheta, std::vector<double>& Theta,
  253. double *Qext, double *Qsca, double *Qabs, double *Qbk, double *Qpr, double *g, double *Albedo,
  254. std::vector<std::complex<double> >& S1, std::vector<std::complex<double> >& S2) {
  255. return nmie::nMie(L, -1, x, m, nTheta, Theta, -1, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2);
  256. }
  257. //**********************************************************************************//
  258. // This function is just a wrapper to call the full 'nMie' function with fewer //
  259. // parameters, it is useful if you want to include a PEC layer but not a limit //
  260. // for the maximum number of terms. //
  261. // //
  262. // Input parameters: //
  263. // L: Number of layers //
  264. // pl: Index of PEC layer. If there is none just send -1 //
  265. // x: Array containing the size parameters of the layers [0..L-1] //
  266. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  267. // nTheta: Number of scattering angles //
  268. // Theta: Array containing all the scattering angles where the scattering //
  269. // amplitudes will be calculated //
  270. // //
  271. // Output parameters: //
  272. // Qext: Efficiency factor for extinction //
  273. // Qsca: Efficiency factor for scattering //
  274. // Qabs: Efficiency factor for absorption (Qabs = Qext - Qsca) //
  275. // Qbk: Efficiency factor for backscattering //
  276. // Qpr: Efficiency factor for the radiation pressure //
  277. // g: Asymmetry factor (g = (Qext-Qpr)/Qsca) //
  278. // Albedo: Single scattering albedo (Albedo = Qsca/Qext) //
  279. // S1, S2: Complex scattering amplitudes //
  280. // //
  281. // Return value: //
  282. // Number of multipolar expansion terms used for the calculations //
  283. //**********************************************************************************//
  284. int nMie(const unsigned int L, const int pl, std::vector<double>& x, std::vector<std::complex<double> >& m,
  285. const unsigned int nTheta, std::vector<double>& Theta,
  286. double *Qext, double *Qsca, double *Qabs, double *Qbk, double *Qpr, double *g, double *Albedo,
  287. std::vector<std::complex<double> >& S1, std::vector<std::complex<double> >& S2) {
  288. return nmie::nMie(L, pl, x, m, nTheta, Theta, -1, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2);
  289. }
  290. //**********************************************************************************//
  291. // This function is just a wrapper to call the full 'nMie' function with fewer //
  292. // parameters, it is useful if you want to include a limit for the maximum number //
  293. // of terms but not a PEC layer. //
  294. // //
  295. // Input parameters: //
  296. // L: Number of layers //
  297. // x: Array containing the size parameters of the layers [0..L-1] //
  298. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  299. // nTheta: Number of scattering angles //
  300. // Theta: Array containing all the scattering angles where the scattering //
  301. // amplitudes will be calculated //
  302. // nmax: Maximum number of multipolar expansion terms to be used for the //
  303. // calculations. Only use it if you know what you are doing, otherwise //
  304. // set this parameter to -1 and the function will calculate it //
  305. // //
  306. // Output parameters: //
  307. // Qext: Efficiency factor for extinction //
  308. // Qsca: Efficiency factor for scattering //
  309. // Qabs: Efficiency factor for absorption (Qabs = Qext - Qsca) //
  310. // Qbk: Efficiency factor for backscattering //
  311. // Qpr: Efficiency factor for the radiation pressure //
  312. // g: Asymmetry factor (g = (Qext-Qpr)/Qsca) //
  313. // Albedo: Single scattering albedo (Albedo = Qsca/Qext) //
  314. // S1, S2: Complex scattering amplitudes //
  315. // //
  316. // Return value: //
  317. // Number of multipolar expansion terms used for the calculations //
  318. //**********************************************************************************//
  319. int nMie(const unsigned int L, std::vector<double>& x, std::vector<std::complex<double> >& m,
  320. const unsigned int nTheta, std::vector<double>& Theta, const int nmax,
  321. double *Qext, double *Qsca, double *Qabs, double *Qbk, double *Qpr, double *g, double *Albedo,
  322. std::vector<std::complex<double> >& S1, std::vector<std::complex<double> >& S2) {
  323. return nmie::nMie(L, -1, x, m, nTheta, Theta, nmax, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2);
  324. }
  325. //**********************************************************************************//
  326. // This function emulates a C call to calculate complex electric and magnetic field //
  327. // in the surroundings and inside the particle. //
  328. // //
  329. // Input parameters: //
  330. // L: Number of layers //
  331. // pl: Index of PEC layer. If there is none just send 0 (zero) //
  332. // x: Array containing the size parameters of the layers [0..L-1] //
  333. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  334. // nmax: Maximum number of multipolar expansion terms to be used for the //
  335. // calculations. Only use it if you know what you are doing, otherwise //
  336. // set this parameter to 0 (zero) and the function will calculate it. //
  337. // ncoord: Number of coordinate points //
  338. // Coords: Array containing all coordinates where the complex electric and //
  339. // magnetic fields will be calculated //
  340. // //
  341. // Output parameters: //
  342. // E, H: Complex electric and magnetic field at the provided coordinates //
  343. // //
  344. // Return value: //
  345. // Number of multipolar expansion terms used for the calculations //
  346. //**********************************************************************************//
  347. int nField(const unsigned int L, const int pl, const std::vector<double>& x, const std::vector<std::complex<double> >& m,
  348. const int nmax, const unsigned int ncoord,
  349. const std::vector<double>& Xp_vec, const std::vector<double>& Yp_vec, const std::vector<double>& Zp_vec,
  350. std::vector<std::vector<std::complex<double> > >& E, std::vector<std::vector<std::complex<double> > >& H) {
  351. if (x.size() != L || m.size() != L)
  352. throw std::invalid_argument("Declared number of layers do not fit x and m!");
  353. if (Xp_vec.size() != ncoord || Yp_vec.size() != ncoord || Zp_vec.size() != ncoord
  354. || E.size() != ncoord || H.size() != ncoord)
  355. throw std::invalid_argument("Declared number of coords do not fit Xp, Yp, Zp, E, or H!");
  356. for (auto f:E)
  357. if (f.size() != 3)
  358. throw std::invalid_argument("Field E is not 3D!");
  359. for (auto f:H)
  360. if (f.size() != 3)
  361. throw std::invalid_argument("Field H is not 3D!");
  362. try {
  363. MultiLayerMie<FloatType> ml_mie;
  364. ml_mie.SetLayersSize(ConvertVector<FloatType>(x));
  365. ml_mie.SetLayersIndex(ConvertComplexVector<FloatType>(m));
  366. ml_mie.SetPECLayer(pl);
  367. ml_mie.SetFieldCoords({ConvertVector<FloatType>(Xp_vec),
  368. ConvertVector<FloatType>(Yp_vec),
  369. ConvertVector<FloatType>(Zp_vec) });
  370. ml_mie.RunFieldCalculation();
  371. E = ConvertComplexVectorVector<double>(ml_mie.GetFieldE());
  372. H = ConvertComplexVectorVector<double>(ml_mie.GetFieldH());
  373. return ml_mie.GetMaxTerms();
  374. } catch(const std::invalid_argument& ia) {
  375. // Will catch if ml_mie fails or other errors.
  376. std::cerr << "Invalid argument: " << ia.what() << std::endl;
  377. throw std::invalid_argument(ia);
  378. return - 1;
  379. }
  380. return 0;
  381. }
  382. } // end of namespace nmie