nmie.cc 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  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 <stdexcept>
  48. #include <iostream>
  49. #include <vector>
  50. #include "nmie.hpp"
  51. #include "nmie-basic.hpp"
  52. #include "nmie-nearfield.hpp"
  53. namespace nmie {
  54. //**********************************************************************************//
  55. // This function emulates a C call to calculate the scattering coefficients //
  56. // required to calculate both the near- and far-field parameters. //
  57. // //
  58. // Input parameters: //
  59. // L: Number of layers //
  60. // pl: Index of PEC layer. If there is none just send -1 //
  61. // x: Array containing the size parameters of the layers [0..L-1] //
  62. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  63. // nmax: Maximum number of multipolar expansion terms to be used for the //
  64. // calculations. Only use it if you know what you are doing, otherwise //
  65. // set this parameter to -1 and the function will calculate it. //
  66. // //
  67. // Output parameters: //
  68. // an, bn: Complex scattering amplitudes //
  69. // //
  70. // Return value: //
  71. // Number of multipolar expansion terms used for the calculations //
  72. //**********************************************************************************//
  73. int ScattCoeffs(const unsigned int L, const int pl, const std::vector<double> &x, const std::vector<std::complex<double> > &m,
  74. const int nmax, std::vector<std::complex<double> > &an, std::vector<std::complex<double> > &bn) {
  75. if (x.size() != L || m.size() != L)
  76. throw std::invalid_argument("Declared number of layers do not fit x and m!");
  77. try {
  78. MultiLayerMie<FloatType> ml_mie;
  79. ml_mie.SetLayersSize(ConvertVector<FloatType>(x));
  80. ml_mie.SetLayersIndex(ConvertComplexVector<FloatType>(m));
  81. ml_mie.SetPECLayer(pl);
  82. ml_mie.SetMaxTerms(nmax);
  83. ml_mie.calcScattCoeffs();
  84. an = ConvertComplexVector<double>(ml_mie.GetAn());
  85. bn = ConvertComplexVector<double>(ml_mie.GetBn());
  86. return ml_mie.GetMaxTerms();
  87. } catch(const std::invalid_argument &ia) {
  88. // Will catch if ml_mie fails or other errors.
  89. std::cerr << "Invalid argument: " << ia.what() << std::endl;
  90. throw std::invalid_argument(ia);
  91. }
  92. } //end of int ScattCoeffs(...)
  93. //**********************************************************************************//
  94. // This function emulates a C call to calculate the expansion coefficients //
  95. // required to calculate both the near- and far-field parameters. //
  96. // //
  97. // Input parameters: //
  98. // L: Number of layers //
  99. // pl: Index of PEC layer. If there is none just send -1 //
  100. // x: Array containing the size parameters of the layers [0..L-1] //
  101. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  102. // nmax: Maximum number of multipolar expansion terms to be used for the //
  103. // calculations. Only use it if you know what you are doing, otherwise //
  104. // set this parameter to -1 and the function will calculate it. //
  105. // //
  106. // Output parameters: //
  107. // aln, bln, cln, dln: Complex expansion coefficients //
  108. // //
  109. // Return value: //
  110. // Number of multipolar expansion terms used for the calculations //
  111. //**********************************************************************************//
  112. int ExpanCoeffs(const unsigned int L, const int pl, const std::vector<double> &x, const std::vector<std::complex<double> > &m, const int nmax,
  113. std::vector<std::vector<std::complex<double> > > &aln, std::vector<std::vector<std::complex<double> > > &bln,
  114. std::vector<std::vector<std::complex<double> > > &cln, std::vector<std::vector<std::complex<double> > > &dln) {
  115. if (x.size() != L || m.size() != L)
  116. throw std::invalid_argument("Declared number of layers do not fit x and m!");
  117. try {
  118. MultiLayerMie<FloatType> ml_mie;
  119. ml_mie.SetLayersSize(ConvertVector<FloatType>(x));
  120. ml_mie.SetLayersIndex(ConvertComplexVector<FloatType>(m));
  121. ml_mie.SetPECLayer(pl);
  122. ml_mie.SetMaxTerms(nmax);
  123. // Calculate scattering coefficients an_ and bn_
  124. ml_mie.calcScattCoeffs();
  125. // Calculate expansion coefficients aln_, bln_, cln_, and dln_
  126. ml_mie.calcExpanCoeffs();
  127. aln = ConvertComplexVectorVector<double>(ml_mie.GetLayerAn());
  128. bln = ConvertComplexVectorVector<double>(ml_mie.GetLayerBn());
  129. cln = ConvertComplexVectorVector<double>(ml_mie.GetLayerCn());
  130. dln = ConvertComplexVectorVector<double>(ml_mie.GetLayerDn());
  131. return ml_mie.GetMaxTerms();
  132. } catch(const std::invalid_argument &ia) {
  133. // Will catch if ml_mie fails or other errors.
  134. std::cerr << "Invalid argument: " << ia.what() << std::endl;
  135. throw std::invalid_argument(ia);
  136. }
  137. } // end of int ExpanCoeffs(...)
  138. //**********************************************************************************//
  139. // This function emulates a C call to calculate the actual scattering parameters //
  140. // and amplitudes. //
  141. // //
  142. // Input parameters: //
  143. // L: Number of layers //
  144. // pl: Index of PEC layer. If there is none just send -1 //
  145. // x: Array containing the size parameters of the layers [0..L-1] //
  146. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  147. // nTheta: Number of scattering angles //
  148. // Theta: Array containing all the scattering angles where the scattering //
  149. // amplitudes will be calculated //
  150. // nmax: Maximum number of multipolar expansion terms to be used for the //
  151. // calculations. Only use it if you know what you are doing, otherwise //
  152. // set this parameter to -1 and the function will calculate it //
  153. // //
  154. // Output parameters: //
  155. // Qext: Efficiency factor for extinction //
  156. // Qsca: Efficiency factor for scattering //
  157. // Qabs: Efficiency factor for absorption (Qabs = Qext - Qsca) //
  158. // Qbk: Efficiency factor for backscattering //
  159. // Qpr: Efficiency factor for the radiation pressure //
  160. // g: Asymmetry factor (g = (Qext-Qpr)/Qsca) //
  161. // Albedo: Single scattering albedo (Albedo = Qsca/Qext) //
  162. // S1, S2: Complex scattering amplitudes //
  163. // //
  164. // Return value: //
  165. // Number of multipolar expansion terms used for the calculations //
  166. //**********************************************************************************//
  167. int nMie(const unsigned int L, const int pl, std::vector<double> &x, std::vector<std::complex<double> > &m,
  168. const unsigned int nTheta, std::vector<double> &Theta, const int nmax,
  169. double *Qext, double *Qsca, double *Qabs, double *Qbk, double *Qpr, double *g, double *Albedo,
  170. std::vector<std::complex<double> > &S1, std::vector<std::complex<double> > &S2,
  171. int mode_n, int mode_type) {
  172. if (x.size() != L || m.size() != L)
  173. throw std::invalid_argument("Declared number of layers do not fit x and m!");
  174. if (Theta.size() != nTheta)
  175. throw std::invalid_argument("Declared number of sample for Theta is not correct!");
  176. try {
  177. MultiLayerMie<FloatType> mie;
  178. mie.SetLayersSize(ConvertVector<FloatType>(x));
  179. mie.SetLayersIndex(ConvertComplexVector<FloatType>(m));
  180. mie.SetAngles(ConvertVector<FloatType>(Theta));
  181. mie.SetPECLayer(pl);
  182. mie.SetMaxTerms(nmax);
  183. mie.SetModeNmaxAndType(mode_n, mode_type);
  184. mie.RunMieCalculation();
  185. // std::cout
  186. // << std::setprecision(std::numeric_limits<FloatType>::digits10)
  187. // << "Qext = "
  188. // << mie.GetQext()
  189. // << std::endl;
  190. *Qext = static_cast<double>(mie.GetQext());
  191. *Qsca = static_cast<double>(mie.GetQsca());
  192. *Qabs = static_cast<double>(mie.GetQabs());
  193. *Qbk = static_cast<double>(mie.GetQbk());
  194. *Qpr = static_cast<double>(mie.GetQpr());
  195. *g = static_cast<double>(mie.GetAsymmetryFactor());
  196. *Albedo = static_cast<double>(mie.GetAlbedo());
  197. S1 = ConvertComplexVector<double>(mie.GetS1());
  198. S2 = ConvertComplexVector<double>(mie.GetS2());
  199. return mie.GetMaxTerms();
  200. } catch(const std::invalid_argument &ia) {
  201. // Will catch if ml_mie fails or other errors.
  202. std::cerr << "Invalid argument: " << ia.what() << std::endl;
  203. throw std::invalid_argument(ia);
  204. }
  205. } // end of int nMie(...)
  206. //**********************************************************************************//
  207. // This function is just a wrapper to call the full 'nMie' function with fewer //
  208. // parameters, it is here mainly for compatibility with older versions of the //
  209. // program. Also, you can use it if you neither have a PEC layer nor want to define //
  210. // any limit for the maximum number of terms nor limit to some mode. //
  211. // //
  212. // Input parameters: //
  213. // L: Number of layers //
  214. // pl: Index of PEC layer. If there is none just send -1 //
  215. // x: Array containing the size parameters of the layers [0..L-1] //
  216. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  217. // nTheta: Number of scattering angles //
  218. // Theta: Array containing all the scattering angles where the scattering //
  219. // amplitudes will be calculated //
  220. // nmax: Maximum number of multipolar expansion terms to be used for the //
  221. // calculations. Only use it if you know what you are doing, otherwise //
  222. // set this parameter to -1 and the function will calculate it //
  223. // //
  224. // Output parameters: //
  225. // Qext: Efficiency factor for extinction //
  226. // Qsca: Efficiency factor for scattering //
  227. // Qabs: Efficiency factor for absorption (Qabs = Qext - Qsca) //
  228. // Qbk: Efficiency factor for backscattering //
  229. // Qpr: Efficiency factor for the radiation pressure //
  230. // g: Asymmetry factor (g = (Qext-Qpr)/Qsca) //
  231. // Albedo: Single scattering albedo (Albedo = Qsca/Qext) //
  232. // S1, S2: Complex scattering amplitudes //
  233. // //
  234. // Return value: //
  235. // Number of multipolar expansion terms used for the calculations //
  236. //**********************************************************************************//
  237. int nMie(const unsigned int L, const int pl,
  238. std::vector<double> &x, std::vector<std::complex<double> > &m,
  239. const unsigned int nTheta, std::vector<double> &Theta, const int nmax,
  240. double *Qext, double *Qsca, double *Qabs, double *Qbk, double *Qpr, double *g, double *Albedo,
  241. std::vector<std::complex<double> > &S1, std::vector<std::complex<double> > &S2) {
  242. return nmie::nMie(L, pl, x, m, nTheta, Theta, nmax, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2, -1, -1);
  243. }
  244. //**********************************************************************************//
  245. // This function is just a wrapper to call the full 'nMie' function with fewer //
  246. // parameters, it is here mainly for compatibility with older versions of the //
  247. // program. Also, you can use it if you neither have a PEC layer nor want to define //
  248. // any limit for the maximum number of terms. //
  249. // //
  250. // Input parameters: //
  251. // L: Number of layers //
  252. // x: Array containing the size parameters of the layers [0..L-1] //
  253. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  254. // nTheta: Number of scattering angles //
  255. // Theta: Array containing all the scattering angles where the scattering //
  256. // amplitudes will be calculated //
  257. // //
  258. // Output parameters: //
  259. // Qext: Efficiency factor for extinction //
  260. // Qsca: Efficiency factor for scattering //
  261. // Qabs: Efficiency factor for absorption (Qabs = Qext - Qsca) //
  262. // Qbk: Efficiency factor for backscattering //
  263. // Qpr: Efficiency factor for the radiation pressure //
  264. // g: Asymmetry factor (g = (Qext-Qpr)/Qsca) //
  265. // Albedo: Single scattering albedo (Albedo = Qsca/Qext) //
  266. // S1, S2: Complex scattering amplitudes //
  267. // //
  268. // Return value: //
  269. // Number of multipolar expansion terms used for the calculations //
  270. //**********************************************************************************//
  271. int nMie(const unsigned int L, std::vector<double> &x, std::vector<std::complex<double> > &m,
  272. const unsigned int nTheta, std::vector<double> &Theta,
  273. double *Qext, double *Qsca, double *Qabs, double *Qbk, double *Qpr, double *g, double *Albedo,
  274. std::vector<std::complex<double> > &S1, std::vector<std::complex<double> > &S2) {
  275. return nmie::nMie(L, -1, x, m, nTheta, Theta, -1, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2);
  276. }
  277. //**********************************************************************************//
  278. // This function is just a wrapper to call the full 'nMie' function with fewer //
  279. // parameters, it is useful if you want to include a PEC layer but not a limit //
  280. // for the maximum number of terms. //
  281. // //
  282. // Input parameters: //
  283. // L: Number of layers //
  284. // pl: Index of PEC layer. If there is none just send -1 //
  285. // x: Array containing the size parameters of the layers [0..L-1] //
  286. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  287. // nTheta: Number of scattering angles //
  288. // Theta: Array containing all the scattering angles where the scattering //
  289. // amplitudes will be calculated //
  290. // //
  291. // Output parameters: //
  292. // Qext: Efficiency factor for extinction //
  293. // Qsca: Efficiency factor for scattering //
  294. // Qabs: Efficiency factor for absorption (Qabs = Qext - Qsca) //
  295. // Qbk: Efficiency factor for backscattering //
  296. // Qpr: Efficiency factor for the radiation pressure //
  297. // g: Asymmetry factor (g = (Qext-Qpr)/Qsca) //
  298. // Albedo: Single scattering albedo (Albedo = Qsca/Qext) //
  299. // S1, S2: Complex scattering amplitudes //
  300. // //
  301. // Return value: //
  302. // Number of multipolar expansion terms used for the calculations //
  303. //**********************************************************************************//
  304. int nMie(const unsigned int L, const int pl, std::vector<double> &x, std::vector<std::complex<double> > &m,
  305. const unsigned int nTheta, std::vector<double> &Theta,
  306. double *Qext, double *Qsca, double *Qabs, double *Qbk, double *Qpr, double *g, double *Albedo,
  307. std::vector<std::complex<double> > &S1, std::vector<std::complex<double> > &S2) {
  308. return nmie::nMie(L, pl, x, m, nTheta, Theta, -1, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2);
  309. }
  310. //**********************************************************************************//
  311. // This function is just a wrapper to call the full 'nMie' function with fewer //
  312. // parameters, it is useful if you want to include a limit for the maximum number //
  313. // of terms but not a PEC layer. //
  314. // //
  315. // Input parameters: //
  316. // L: Number of layers //
  317. // x: Array containing the size parameters of the layers [0..L-1] //
  318. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  319. // nTheta: Number of scattering angles //
  320. // Theta: Array containing all the scattering angles where the scattering //
  321. // amplitudes will be calculated //
  322. // nmax: Maximum number of multipolar expansion terms to be used for the //
  323. // calculations. Only use it if you know what you are doing, otherwise //
  324. // set this parameter to -1 and the function will calculate it //
  325. // //
  326. // Output parameters: //
  327. // Qext: Efficiency factor for extinction //
  328. // Qsca: Efficiency factor for scattering //
  329. // Qabs: Efficiency factor for absorption (Qabs = Qext - Qsca) //
  330. // Qbk: Efficiency factor for backscattering //
  331. // Qpr: Efficiency factor for the radiation pressure //
  332. // g: Asymmetry factor (g = (Qext-Qpr)/Qsca) //
  333. // Albedo: Single scattering albedo (Albedo = Qsca/Qext) //
  334. // S1, S2: Complex scattering amplitudes //
  335. // //
  336. // Return value: //
  337. // Number of multipolar expansion terms used for the calculations //
  338. //**********************************************************************************//
  339. int nMie(const unsigned int L, std::vector<double> &x, std::vector<std::complex<double> > &m,
  340. const unsigned int nTheta, std::vector<double> &Theta, const int nmax,
  341. double *Qext, double *Qsca, double *Qabs, double *Qbk, double *Qpr, double *g, double *Albedo,
  342. std::vector<std::complex<double> > &S1, std::vector<std::complex<double> > &S2) {
  343. return nmie::nMie(L, -1, x, m, nTheta, Theta, nmax, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2);
  344. }
  345. //**********************************************************************************//
  346. // This function emulates a C call to calculate complex electric and magnetic field //
  347. // in the surroundings and inside the particle. //
  348. // //
  349. // Input parameters: //
  350. // L: Number of layers //
  351. // pl: Index of PEC layer. If there is none just send 0 (zero) //
  352. // x: Array containing the size parameters of the layers [0..L-1] //
  353. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  354. // nmax: Maximum number of multipolar expansion terms to be used for the //
  355. // calculations. Only use it if you know what you are doing, otherwise //
  356. // set this parameter to -1 and the function will calculate it. //
  357. // ncoord: Number of coordinate points //
  358. // Coords: Array containing all coordinates where the complex electric and //
  359. // magnetic fields will be calculated //
  360. // //
  361. // Output parameters: //
  362. // E, H: Complex electric and magnetic field at the provided coordinates //
  363. // //
  364. // Return value: //
  365. // Number of multipolar expansion terms used for the calculations //
  366. //**********************************************************************************//
  367. int nField(const unsigned int L, const int pl,
  368. const std::vector<double> &x, const std::vector<std::complex<double> > &m, const int nmax,
  369. const int mode_n, const int mode_type, const unsigned int ncoord,
  370. const std::vector<double> &Xp_vec, const std::vector<double> &Yp_vec, const std::vector<double> &Zp_vec,
  371. std::vector<std::vector<std::complex<double> > > &E, std::vector<std::vector<std::complex<double> > > &H) {
  372. if (x.size() != L || m.size() != L)
  373. throw std::invalid_argument("Declared number of layers do not fit x and m!");
  374. if (Xp_vec.size() != ncoord || Yp_vec.size() != ncoord || Zp_vec.size() != ncoord
  375. || E.size() != ncoord || H.size() != ncoord)
  376. throw std::invalid_argument("Declared number of coords do not fit Xp, Yp, Zp, E, or H!");
  377. for (const auto &f:E)
  378. if (f.size() != 3)
  379. throw std::invalid_argument("Field E is not 3D!");
  380. for (const auto &f:H)
  381. if (f.size() != 3)
  382. throw std::invalid_argument("Field H is not 3D!");
  383. try {
  384. MultiLayerMie<FloatType> ml_mie;
  385. ml_mie.SetLayersSize(ConvertVector<FloatType>(x));
  386. ml_mie.SetLayersIndex(ConvertComplexVector<FloatType>(m));
  387. ml_mie.SetPECLayer(pl);
  388. ml_mie.SetFieldCoords({ConvertVector<FloatType>(Xp_vec),
  389. ConvertVector<FloatType>(Yp_vec),
  390. ConvertVector<FloatType>(Zp_vec) });
  391. ml_mie.SetMaxTerms(nmax);
  392. ml_mie.SetModeNmaxAndType(mode_n, mode_type);
  393. ml_mie.RunFieldCalculation();
  394. E = ConvertComplexVectorVector<double>(ml_mie.GetFieldE());
  395. H = ConvertComplexVectorVector<double>(ml_mie.GetFieldH());
  396. return ml_mie.GetMaxTerms();
  397. } catch(const std::invalid_argument &ia) {
  398. // Will catch if ml_mie fails or other errors.
  399. std::cerr << "Invalid argument: " << ia.what() << std::endl;
  400. throw std::invalid_argument(ia);
  401. }
  402. } // end of int nField(...)
  403. } // end of namespace nmie