nmie.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. //**********************************************************************************//
  2. // Copyright (C) 2009-2015 Ovidio Pena <ovidio@bytesfall.com> //
  3. // Copyright (C) 2013-2015 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 the following reference: //
  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. // //
  24. // You should have received a copy of the GNU General Public License //
  25. // along with this program. If not, see <http://www.gnu.org/licenses/>. //
  26. //**********************************************************************************//
  27. //**********************************************************************************//
  28. // This class implements the algorithm for a multilayered sphere described by: //
  29. // [1] W. Yang, "Improved recursive algorithm for light scattering by a //
  30. // multilayered sphere,” Applied Optics, vol. 42, Mar. 2003, pp. 1710-1720. //
  31. // //
  32. // You can find the description of all the used equations in: //
  33. // [2] O. Pena and U. Pal, "Scattering of electromagnetic radiation by //
  34. // a multilayered sphere," Computer Physics Communications, //
  35. // vol. 180, Nov. 2009, pp. 2348-2354. //
  36. // //
  37. // Hereinafter all equations numbers refer to [2] //
  38. //**********************************************************************************//
  39. #include "nmie.hpp"
  40. #include "nmie-impl.hpp"
  41. #include <array>
  42. #include <algorithm>
  43. #include <cstdio>
  44. #include <cstdlib>
  45. #include <stdexcept>
  46. #include <iostream>
  47. #include <iomanip>
  48. #include <vector>
  49. #include <boost/multiprecision/cpp_bin_float.hpp>
  50. //#include <boost/math/special_functions/gamma.hpp>
  51. namespace nmie {
  52. //typedef float FloatType;
  53. //typedef double FloatType;
  54. typedef boost::multiprecision::cpp_bin_float_100 FloatType;
  55. //**********************************************************************************//
  56. // This function emulates a C call to calculate the scattering coefficients //
  57. // required to calculate both the near- and far-field parameters. //
  58. // //
  59. // Input parameters: //
  60. // L: Number of layers //
  61. // pl: Index of PEC layer. If there is none just send -1 //
  62. // x: Array containing the size parameters of the layers [0..L-1] //
  63. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  64. // nmax: Maximum number of multipolar expansion terms to be used for the //
  65. // calculations. Only use it if you know what you are doing, otherwise //
  66. // set this parameter to -1 and the function will calculate it. //
  67. // //
  68. // Output parameters: //
  69. // an, bn: Complex scattering amplitudes //
  70. // //
  71. // Return value: //
  72. // Number of multipolar expansion terms used for the calculations //
  73. //**********************************************************************************//
  74. int ScattCoeffs(const unsigned int L, const int pl, std::vector<double>& x, std::vector<std::complex<double> >& m, 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. return -1;
  92. }
  93. return 0;
  94. }
  95. //**********************************************************************************//
  96. // This function emulates a C call to calculate the actual scattering parameters //
  97. // and amplitudes. //
  98. // //
  99. // Input parameters: //
  100. // L: Number of layers //
  101. // pl: Index of PEC layer. If there is none just send -1 //
  102. // x: Array containing the size parameters of the layers [0..L-1] //
  103. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  104. // nTheta: Number of scattering angles //
  105. // Theta: Array containing all the scattering angles where the scattering //
  106. // amplitudes will be calculated //
  107. // nmax: Maximum number of multipolar expansion terms to be used for the //
  108. // calculations. Only use it if you know what you are doing, otherwise //
  109. // set this parameter to -1 and the function will calculate it //
  110. // //
  111. // Output parameters: //
  112. // Qext: Efficiency factor for extinction //
  113. // Qsca: Efficiency factor for scattering //
  114. // Qabs: Efficiency factor for absorption (Qabs = Qext - Qsca) //
  115. // Qbk: Efficiency factor for backscattering //
  116. // Qpr: Efficiency factor for the radiation pressure //
  117. // g: Asymmetry factor (g = (Qext-Qpr)/Qsca) //
  118. // Albedo: Single scattering albedo (Albedo = Qsca/Qext) //
  119. // S1, S2: Complex scattering amplitudes //
  120. // //
  121. // Return value: //
  122. // Number of multipolar expansion terms used for the calculations //
  123. //**********************************************************************************//
  124. int nMie(const unsigned int L, const int pl, std::vector<double>& x, std::vector<std::complex<double> >& m, const unsigned int nTheta, std::vector<double>& Theta, const int nmax, double *Qext, double *Qsca, double *Qabs, double *Qbk, double *Qpr, double *g, double *Albedo, std::vector<std::complex<double> >& S1, std::vector<std::complex<double> >& S2) {
  125. if (x.size() != L || m.size() != L)
  126. throw std::invalid_argument("Declared number of layers do not fit x and m!");
  127. if (Theta.size() != nTheta)
  128. throw std::invalid_argument("Declared number of sample for Theta is not correct!");
  129. try {
  130. MultiLayerMie<FloatType> ml_mie;
  131. ml_mie.SetLayersSize(ConvertVector<FloatType>(x));
  132. ml_mie.SetLayersIndex(ConvertComplexVector<FloatType>(m));
  133. ml_mie.SetAngles(ConvertVector<FloatType>(Theta));
  134. ml_mie.SetPECLayer(pl);
  135. ml_mie.SetMaxTerms(nmax);
  136. ml_mie.RunMieCalculation();
  137. std::cout
  138. << std::setprecision(std::numeric_limits<FloatType>::digits10)
  139. << "Qext = "
  140. << ml_mie.GetQext()
  141. << std::endl;
  142. *Qext = static_cast<double>(ml_mie.GetQext());
  143. *Qsca = static_cast<double>(ml_mie.GetQsca());
  144. *Qabs = static_cast<double>(ml_mie.GetQabs());
  145. *Qbk = static_cast<double>(ml_mie.GetQbk());
  146. *Qpr = static_cast<double>(ml_mie.GetQpr());
  147. *g = static_cast<double>(ml_mie.GetAsymmetryFactor());
  148. *Albedo = static_cast<double>(ml_mie.GetAlbedo());
  149. S1 = ConvertComplexVector<double>(ml_mie.GetS1());
  150. S2 = ConvertComplexVector<double>(ml_mie.GetS2());
  151. return ml_mie.GetMaxTerms();
  152. } catch(const std::invalid_argument& ia) {
  153. // Will catch if ml_mie fails or other errors.
  154. std::cerr << "Invalid argument: " << ia.what() << std::endl;
  155. throw std::invalid_argument(ia);
  156. return -1;
  157. }
  158. return 0;
  159. }
  160. //**********************************************************************************//
  161. // This function is just a wrapper to call the full 'nMie' function with fewer //
  162. // parameters, it is here mainly for compatibility with older versions of the //
  163. // program. Also, you can use it if you neither have a PEC layer nor want to define //
  164. // any limit for the maximum number of terms. //
  165. // //
  166. // Input parameters: //
  167. // L: Number of layers //
  168. // x: Array containing the size parameters of the layers [0..L-1] //
  169. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  170. // nTheta: Number of scattering angles //
  171. // Theta: Array containing all the scattering angles where the scattering //
  172. // amplitudes will be calculated //
  173. // //
  174. // Output parameters: //
  175. // Qext: Efficiency factor for extinction //
  176. // Qsca: Efficiency factor for scattering //
  177. // Qabs: Efficiency factor for absorption (Qabs = Qext - Qsca) //
  178. // Qbk: Efficiency factor for backscattering //
  179. // Qpr: Efficiency factor for the radiation pressure //
  180. // g: Asymmetry factor (g = (Qext-Qpr)/Qsca) //
  181. // Albedo: Single scattering albedo (Albedo = Qsca/Qext) //
  182. // S1, S2: Complex scattering amplitudes //
  183. // //
  184. // Return value: //
  185. // Number of multipolar expansion terms used for the calculations //
  186. //**********************************************************************************//
  187. int nMie(const unsigned int L, std::vector<double>& x, std::vector<std::complex<double> >& m, const unsigned int nTheta, std::vector<double>& Theta, double *Qext, double *Qsca, double *Qabs, double *Qbk, double *Qpr, double *g, double *Albedo, std::vector<std::complex<double> >& S1, std::vector<std::complex<double> >& S2) {
  188. return nmie::nMie(L, -1, x, m, nTheta, Theta, -1, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2);
  189. }
  190. //**********************************************************************************//
  191. // This function is just a wrapper to call the full 'nMie' function with fewer //
  192. // parameters, it is useful if you want to include a PEC layer but not a limit //
  193. // for the maximum number of terms. //
  194. // //
  195. // Input parameters: //
  196. // L: Number of layers //
  197. // pl: Index of PEC layer. If there is none just send -1 //
  198. // x: Array containing the size parameters of the layers [0..L-1] //
  199. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  200. // nTheta: Number of scattering angles //
  201. // Theta: Array containing all the scattering angles where the scattering //
  202. // amplitudes will be calculated //
  203. // //
  204. // Output parameters: //
  205. // Qext: Efficiency factor for extinction //
  206. // Qsca: Efficiency factor for scattering //
  207. // Qabs: Efficiency factor for absorption (Qabs = Qext - Qsca) //
  208. // Qbk: Efficiency factor for backscattering //
  209. // Qpr: Efficiency factor for the radiation pressure //
  210. // g: Asymmetry factor (g = (Qext-Qpr)/Qsca) //
  211. // Albedo: Single scattering albedo (Albedo = Qsca/Qext) //
  212. // S1, S2: Complex scattering amplitudes //
  213. // //
  214. // Return value: //
  215. // Number of multipolar expansion terms used for the calculations //
  216. //**********************************************************************************//
  217. int nMie(const unsigned int L, const int pl, std::vector<double>& x, std::vector<std::complex<double> >& m, const unsigned int nTheta, std::vector<double>& Theta, double *Qext, double *Qsca, double *Qabs, double *Qbk, double *Qpr, double *g, double *Albedo, std::vector<std::complex<double> >& S1, std::vector<std::complex<double> >& S2) {
  218. return nmie::nMie(L, pl, x, m, nTheta, Theta, -1, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2);
  219. }
  220. //**********************************************************************************//
  221. // This function is just a wrapper to call the full 'nMie' function with fewer //
  222. // parameters, it is useful if you want to include a limit for the maximum number //
  223. // of terms but not a PEC layer. //
  224. // //
  225. // Input parameters: //
  226. // L: Number of layers //
  227. // x: Array containing the size parameters of the layers [0..L-1] //
  228. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  229. // nTheta: Number of scattering angles //
  230. // Theta: Array containing all the scattering angles where the scattering //
  231. // amplitudes will be calculated //
  232. // nmax: Maximum number of multipolar expansion terms to be used for the //
  233. // calculations. Only use it if you know what you are doing, otherwise //
  234. // set this parameter to -1 and the function will calculate it //
  235. // //
  236. // Output parameters: //
  237. // Qext: Efficiency factor for extinction //
  238. // Qsca: Efficiency factor for scattering //
  239. // Qabs: Efficiency factor for absorption (Qabs = Qext - Qsca) //
  240. // Qbk: Efficiency factor for backscattering //
  241. // Qpr: Efficiency factor for the radiation pressure //
  242. // g: Asymmetry factor (g = (Qext-Qpr)/Qsca) //
  243. // Albedo: Single scattering albedo (Albedo = Qsca/Qext) //
  244. // S1, S2: Complex scattering amplitudes //
  245. // //
  246. // Return value: //
  247. // Number of multipolar expansion terms used for the calculations //
  248. //**********************************************************************************//
  249. int nMie(const unsigned int L, std::vector<double>& x, std::vector<std::complex<double> >& m, const unsigned int nTheta, std::vector<double>& Theta, const int nmax, double *Qext, double *Qsca, double *Qabs, double *Qbk, double *Qpr, double *g, double *Albedo, std::vector<std::complex<double> >& S1, std::vector<std::complex<double> >& S2) {
  250. return nmie::nMie(L, -1, x, m, nTheta, Theta, nmax, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2);
  251. }
  252. //**********************************************************************************//
  253. // This function emulates a C call to calculate complex electric and magnetic field //
  254. // in the surroundings and inside the particle. //
  255. // //
  256. // Input parameters: //
  257. // L: Number of layers //
  258. // pl: Index of PEC layer. If there is none just send 0 (zero) //
  259. // x: Array containing the size parameters of the layers [0..L-1] //
  260. // m: Array containing the relative refractive indexes of the layers [0..L-1] //
  261. // nmax: Maximum number of multipolar expansion terms to be used for the //
  262. // calculations. Only use it if you know what you are doing, otherwise //
  263. // set this parameter to 0 (zero) and the function will calculate it. //
  264. // ncoord: Number of coordinate points //
  265. // Coords: Array containing all coordinates where the complex electric and //
  266. // magnetic fields will be calculated //
  267. // //
  268. // Output parameters: //
  269. // E, H: Complex electric and magnetic field at the provided coordinates //
  270. // //
  271. // Return value: //
  272. // Number of multipolar expansion terms used for the calculations //
  273. //**********************************************************************************//
  274. int nField(const unsigned int L, const int pl, const std::vector<double>& x, const std::vector<std::complex<double> >& m, const int nmax, const unsigned int ncoord, const std::vector<double>& Xp_vec, const std::vector<double>& Yp_vec, const std::vector<double>& Zp_vec, std::vector<std::vector<std::complex<double> > >& E, std::vector<std::vector<std::complex<double> > >& H) {
  275. if (x.size() != L || m.size() != L)
  276. throw std::invalid_argument("Declared number of layers do not fit x and m!");
  277. if (Xp_vec.size() != ncoord || Yp_vec.size() != ncoord || Zp_vec.size() != ncoord
  278. || E.size() != ncoord || H.size() != ncoord)
  279. throw std::invalid_argument("Declared number of coords do not fit Xp, Yp, Zp, E, or H!");
  280. for (auto f:E)
  281. if (f.size() != 3)
  282. throw std::invalid_argument("Field E is not 3D!");
  283. for (auto f:H)
  284. if (f.size() != 3)
  285. throw std::invalid_argument("Field H is not 3D!");
  286. try {
  287. MultiLayerMie<FloatType> ml_mie;
  288. ml_mie.SetLayersSize(ConvertVector<FloatType>(x));
  289. ml_mie.SetLayersIndex(ConvertComplexVector<FloatType>(m));
  290. ml_mie.SetPECLayer(pl);
  291. ml_mie.SetFieldCoords({ConvertVector<FloatType>(Xp_vec),
  292. ConvertVector<FloatType>(Yp_vec),
  293. ConvertVector<FloatType>(Zp_vec) });
  294. ml_mie.RunFieldCalculation();
  295. E = ConvertComplexVectorVector<double>(ml_mie.GetFieldE());
  296. H = ConvertComplexVectorVector<double>(ml_mie.GetFieldH());
  297. return ml_mie.GetMaxTerms();
  298. } catch(const std::invalid_argument& ia) {
  299. // Will catch if ml_mie fails or other errors.
  300. std::cerr << "Invalid argument: " << ia.what() << std::endl;
  301. throw std::invalid_argument(ia);
  302. return - 1;
  303. }
  304. return 0;
  305. }
  306. } // end of namespace nmie