nmie.hpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. #ifndef SRC_NMIE_HPP_
  2. #define SRC_NMIE_HPP_
  3. //******************************************************************************
  4. // Copyright (C) 2009-2022 Ovidio Pena <ovidio@bytesfall.com>
  5. // Copyright (C) 2013-2022 Konstantin Ladutenko <kostyfisik@gmail.com>
  6. //
  7. // This file is part of scattnlay
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU General Public License as published by
  11. // the Free Software Foundation, either version 3 of the License, or
  12. // (at your option) any later version.
  13. //
  14. // This program is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. // GNU General Public License for more details.
  18. //
  19. // The only additional remark is that we expect that all publications
  20. // describing work using this software, or all commercial products
  21. // using it, cite at least one of the following references:
  22. // [1] O. Pena and U. Pal, "Scattering of electromagnetic radiation by
  23. // a multilayered sphere," Computer Physics Communications,
  24. // vol. 180, Nov. 2009, pp. 2348-2354.
  25. // [2] K. Ladutenko, U. Pal, A. Rivera, and O. Pena-Rodriguez, "Mie
  26. // calculation of electromagnetic near-field for a multilayered
  27. // sphere," Computer Physics Communications, vol. 214, May 2017,
  28. // pp. 225-230.
  29. //
  30. // You should have received a copy of the GNU General Public License
  31. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  32. //******************************************************************************
  33. #define VERSION "2.2" // Compare with Makefile and setup.py
  34. #include <array>
  35. #include <complex>
  36. #include <cstdlib>
  37. #include <iostream>
  38. #include <vector>
  39. #include "nmie-precision.hpp"
  40. //#ifdef MULTI_PRECISION
  41. //#include <boost/math/constants/constants.hpp>
  42. //#endif
  43. namespace nmie {
  44. //******************************************************************************
  45. int ScattCoeffs(const unsigned int L,
  46. const int pl,
  47. const std::vector<double>& x,
  48. const std::vector<std::complex<double>>& m,
  49. const int nmax,
  50. std::vector<std::complex<double>>& an,
  51. std::vector<std::complex<double>>& bn);
  52. int ExpanCoeffs(const unsigned int L,
  53. const int pl,
  54. const std::vector<double>& x,
  55. const std::vector<std::complex<double>>& m,
  56. const int nmax,
  57. std::vector<std::vector<std::complex<double>>>& an,
  58. std::vector<std::vector<std::complex<double>>>& bn,
  59. std::vector<std::vector<std::complex<double>>>& cn,
  60. std::vector<std::vector<std::complex<double>>>& dn);
  61. //******************************************************************************
  62. // helper functions
  63. //******************************************************************************
  64. template <typename FloatType>
  65. double eval_delta(const unsigned int steps,
  66. const double from_value,
  67. const double to_value);
  68. template <class T>
  69. inline T pow2(const T value) {
  70. return value * value;
  71. }
  72. template <class T>
  73. inline T cabs(const std::complex<T> value) {
  74. return sqrt_t(pow2(value.real()) + pow2(value.imag()));
  75. }
  76. template <class T>
  77. inline T vabs(const std::vector<std::complex<T>> value) {
  78. return nmm::sqrt(pow2(value[0].real()) + pow2(value[1].real()) +
  79. pow2(value[2].real()) + pow2(value[0].imag()) +
  80. pow2(value[1].imag()) + pow2(value[2].imag()));
  81. }
  82. template <typename FloatType>
  83. int newround(FloatType x) {
  84. return x >= 0 ? static_cast<int>(x + 0.5) : static_cast<int>(x - 0.5);
  85. // return x >= 0 ? (x + 0.5).convert_to<int>():(x - 0.5).convert_to<int>();
  86. }
  87. template <typename T>
  88. inline std::complex<T> my_exp(const std::complex<T>& x) {
  89. using std::exp; // use ADL
  90. T const& r = exp(x.real());
  91. return std::polar(r, x.imag());
  92. }
  93. //******************************************************************************
  94. // pl, nmax, mode_n, mode_type
  95. int nMie(const unsigned int L,
  96. const int pl,
  97. std::vector<double>& x,
  98. std::vector<std::complex<double>>& m,
  99. const unsigned int nTheta,
  100. std::vector<double>& Theta,
  101. const int nmax,
  102. double* Qext,
  103. double* Qsca,
  104. double* Qabs,
  105. double* Qbk,
  106. double* Qpr,
  107. double* g,
  108. double* Albedo,
  109. std::vector<std::complex<double>>& S1,
  110. std::vector<std::complex<double>>& S2,
  111. int mode_n,
  112. int mode_type);
  113. //******************************************************************************
  114. // pl and nmax
  115. int nMie(const unsigned int L,
  116. const int pl,
  117. std::vector<double>& x,
  118. std::vector<std::complex<double>>& m,
  119. const unsigned int nTheta,
  120. std::vector<double>& Theta,
  121. const int nmax,
  122. double* Qext,
  123. double* Qsca,
  124. double* Qabs,
  125. double* Qbk,
  126. double* Qpr,
  127. double* g,
  128. double* Albedo,
  129. std::vector<std::complex<double>>& S1,
  130. std::vector<std::complex<double>>& S2);
  131. //******************************************************************************
  132. // no pl and nmax
  133. int nMie(const unsigned int L,
  134. std::vector<double>& x,
  135. std::vector<std::complex<double>>& m,
  136. const unsigned int nTheta,
  137. std::vector<double>& Theta,
  138. double* Qext,
  139. double* Qsca,
  140. double* Qabs,
  141. double* Qbk,
  142. double* Qpr,
  143. double* g,
  144. double* Albedo,
  145. std::vector<std::complex<double>>& S1,
  146. std::vector<std::complex<double>>& S2);
  147. //******************************************************************************
  148. // pl
  149. int nMie(const unsigned int L,
  150. const int pl,
  151. std::vector<double>& x,
  152. std::vector<std::complex<double>>& m,
  153. const unsigned int nTheta,
  154. std::vector<double>& Theta,
  155. double* Qext,
  156. double* Qsca,
  157. double* Qabs,
  158. double* Qbk,
  159. double* Qpr,
  160. double* g,
  161. double* Albedo,
  162. std::vector<std::complex<double>>& S1,
  163. std::vector<std::complex<double>>& S2);
  164. //******************************************************************************
  165. // nmax
  166. int nMie(const unsigned int L,
  167. std::vector<double>& x,
  168. std::vector<std::complex<double>>& m,
  169. const unsigned int nTheta,
  170. std::vector<double>& Theta,
  171. const int nmax,
  172. double* Qext,
  173. double* Qsca,
  174. double* Qabs,
  175. double* Qbk,
  176. double* Qpr,
  177. double* g,
  178. double* Albedo,
  179. std::vector<std::complex<double>>& S1,
  180. std::vector<std::complex<double>>& S2);
  181. //******************************************************************************
  182. int nField(const unsigned int L,
  183. const int pl,
  184. const std::vector<double>& x,
  185. const std::vector<std::complex<double>>& m,
  186. const int nmax,
  187. const int mode_n,
  188. const int mode_type,
  189. const unsigned int ncoord,
  190. const std::vector<double>& Xp,
  191. const std::vector<double>& Yp,
  192. const std::vector<double>& Zp,
  193. std::vector<std::vector<std::complex<double>>>& E,
  194. std::vector<std::vector<std::complex<double>>>& H);
  195. //******************************************************************************
  196. // constants for per mode evaluation
  197. //******************************************************************************
  198. enum Modes { kAll = -1, kElectric = 0, kMagnetic = 1 };
  199. enum Planes { kEk = 0, kHk = 1, kEH = 2 };
  200. //******************************************************************************
  201. const FloatType PI_ =
  202. 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420198938095257201065485863278865936153381827968230301952035301852968995773622599413891249721775283479131515574857242454150695950829533116861727855889075098381754637464939319255060400927701671139009848824012858361603563707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104752162056966024058038150193511253382430035587640247496473263914199272604269922796782354781636009341721641219924586315030286182974555706749838505494588586926995690927210797509302955321165344987202755960236480665499119881834797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548161361157352552133475741849468438523323907394143334547762416862518983569485562099219222184272550254256887671790494601653466804988627232791786085784383827967976681454100953883786360950680064225125205117392984896084128488626945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645995813390478027590099465764078951269468398352595709825822620522489407726719478268482601476990902640136394437455305068203496252451749399651431429809190659250937221696461515709858387410597885959772975498930161753928468138268683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244136549762780797715691435997700129616089441694868555848406353422072225828488648158456028506016842739452267467678895252138522549954666727823986456596116354886230577456498035593634568174324112515076069479451096596094025228879710893145669136867228748940560101503308;
  203. // light speed [m/s]
  204. const double cc_ = 2.99792458e8;
  205. // assume non-magnetic (MU=MU0=const) [N/A^2]
  206. const FloatType mu_ = 4.0 * PI_ * 1.0e-7;
  207. //******************************************************************************
  208. //******************************************************************************
  209. template <typename FloatType = double>
  210. class MultiLayerMie {
  211. public:
  212. #ifdef MULTI_PRECISION
  213. const FloatType convergence_threshold_ = std::pow(10, -MULTI_PRECISION / 2);
  214. // const FloatType convergence_threshold_ = 1e-50;
  215. // const FloatType nearfield_convergence_threshold_ = std::pow(10,
  216. // -MULTI_PRECISION/2);
  217. // For near-field evaluation we use Le Ru cutoff which is valid only for
  218. // double precision, so convergence threshold is the same
  219. const FloatType nearfield_convergence_threshold_ = 1e-14;
  220. #else
  221. const double convergence_threshold_ = 1e-25;
  222. const double nearfield_convergence_threshold_ = 1e-14;
  223. #endif
  224. void RunMieCalculation();
  225. void RunFieldCalculation(bool isMarkUnconverged = true);
  226. void RunFieldCalculationPolar(
  227. const int outer_arc_points = 1,
  228. const int radius_points = 1,
  229. const double from_Rho = 0,
  230. const double to_Rho = static_cast<double>(1.),
  231. const double from_Theta = 0,
  232. const double to_Theta = static_cast<double>(3.14159265358979323),
  233. const double from_Phi = 0,
  234. const double to_Phi = static_cast<double>(3.14159265358979323),
  235. const bool isMarkUnconverged = true,
  236. int nmax_in = -1);
  237. void RunFieldCalculationCartesian(const int first_side_points = 2,
  238. const int second_side_points = 2,
  239. const double relative_side_length = 2,
  240. const int plane_selected = Planes::kEk,
  241. const double at_x = 0,
  242. const double at_y = 0,
  243. const double at_z = 0,
  244. const bool isMarkUnconverged = true,
  245. const int nmax_in = -1);
  246. void calcScattCoeffs();
  247. void calcExpanCoeffs();
  248. //****************************************************************************
  249. // Return calculation results
  250. //****************************************************************************
  251. template <typename outputType = FloatType>
  252. outputType GetQext();
  253. template <typename outputType = FloatType>
  254. outputType GetQsca();
  255. template <typename outputType = FloatType>
  256. outputType GetQabs();
  257. template <typename outputType = FloatType>
  258. outputType GetQbk();
  259. template <typename outputType = FloatType>
  260. outputType GetQpr();
  261. template <typename outputType = FloatType>
  262. outputType GetAsymmetryFactor();
  263. template <typename outputType = FloatType>
  264. outputType GetAlbedo();
  265. std::vector<std::complex<FloatType>> GetS1();
  266. std::vector<std::complex<FloatType>> GetS2();
  267. std::vector<std::complex<FloatType>> GetAn() { return an_; };
  268. std::vector<std::complex<FloatType>> GetBn() { return bn_; };
  269. std::vector<std::vector<std::complex<FloatType>>> GetLayerAn() {
  270. return aln_;
  271. };
  272. std::vector<std::vector<std::complex<FloatType>>> GetLayerBn() {
  273. return bln_;
  274. };
  275. std::vector<std::vector<std::complex<FloatType>>> GetLayerCn() {
  276. return cln_;
  277. };
  278. std::vector<std::vector<std::complex<FloatType>>> GetLayerDn() {
  279. return dln_;
  280. };
  281. //****************************************************************************
  282. // Problem definition
  283. // Modify size of all layers
  284. //****************************************************************************
  285. void SetLayersSize(const std::vector<FloatType>& layer_size);
  286. // Modify refractive index of all layers
  287. void SetLayersIndex(const std::vector<std::complex<FloatType>>& index);
  288. template <typename evalType = FloatType>
  289. void GetIndexAtRadius(const evalType Rho,
  290. std::complex<evalType>& ml,
  291. unsigned int& l);
  292. template <typename evalType = FloatType>
  293. void GetIndexAtRadius(const evalType Rho, std::complex<evalType>& ml);
  294. // Modify scattering (theta) angles
  295. void SetAngles(const std::vector<FloatType>& angles);
  296. // Modify coordinates for field calculation
  297. void SetFieldCoords(const std::vector<std::vector<FloatType>>& coords);
  298. // Modify index of PEC layer
  299. void SetPECLayer(int layer_position = 0);
  300. // Modify the mode taking into account for evaluation of output variables
  301. void SetModeNmaxAndType(int mode_n, int mode_type) {
  302. mode_n_ = mode_n;
  303. mode_type_ = mode_type;
  304. };
  305. // Set a fixed value for the maximum number of terms
  306. void SetMaxTerms(int nmax);
  307. // Get maximum number of terms
  308. int GetMaxTerms() { return nmax_; };
  309. bool isMieCalculated() { return isMieCalculated_; };
  310. // Clear layer information
  311. void ClearLayers();
  312. void MarkUncalculated();
  313. // Read parameters
  314. // Get total size parameter of particle
  315. FloatType GetSizeParameter();
  316. // Returns size of all layers
  317. std::vector<FloatType> GetLayersSize() { return size_param_; };
  318. // Returns refractive index of all layers
  319. std::vector<std::complex<FloatType>> GetLayersIndex() {
  320. return refractive_index_;
  321. };
  322. // Returns scattering (theta) angles
  323. std::vector<FloatType> GetAngles() { return theta_; };
  324. // Returns coordinates used for field calculation
  325. std::vector<std::vector<FloatType>> GetFieldCoords() { return coords_; };
  326. // Returns index of PEC layer
  327. int GetPECLayer() { return PEC_layer_position_; };
  328. std::vector<std::vector<std::complex<FloatType>>> GetFieldE() {
  329. return E_;
  330. }; // {X[], Y[], Z[]}
  331. std::vector<std::vector<std::complex<FloatType>>> GetFieldH() { return H_; };
  332. std::vector<FloatType> GetFieldEabs() { return Eabs_; }; // {X[], Y[], Z[]}
  333. std::vector<FloatType> GetFieldHabs() { return Habs_; };
  334. bool GetFieldConvergence();
  335. // Get fields in spherical coordinates.
  336. std::vector<std::vector<std::complex<FloatType>>> GetFieldEs() {
  337. return Es_;
  338. }; // {rho[], theta[], phi[]}
  339. std::vector<std::vector<std::complex<FloatType>>> GetFieldHs() {
  340. return Hs_;
  341. };
  342. protected:
  343. // Size parameter for all layers
  344. std::vector<FloatType> size_param_;
  345. // Refractive index for all layers
  346. std::vector<std::complex<FloatType>> refractive_index_;
  347. // Scattering coefficients
  348. std::vector<std::complex<FloatType>> an_, bn_;
  349. std::vector<std::vector<std::complex<FloatType>>> aln_, bln_, cln_, dln_;
  350. // Points for field evaluation
  351. std::vector<std::vector<FloatType>> coords_;
  352. std::vector<std::vector<FloatType>> coords_polar_;
  353. private:
  354. unsigned int calcNstop(FloatType xL = -1);
  355. unsigned int calcNmax(FloatType xL = -1);
  356. std::complex<FloatType> calc_an(int n,
  357. FloatType XL,
  358. std::complex<FloatType> Ha,
  359. std::complex<FloatType> mL,
  360. std::complex<FloatType> PsiXL,
  361. std::complex<FloatType> ZetaXL,
  362. std::complex<FloatType> PsiXLM1,
  363. std::complex<FloatType> ZetaXLM1);
  364. std::complex<FloatType> calc_bn(int n,
  365. FloatType XL,
  366. std::complex<FloatType> Hb,
  367. std::complex<FloatType> mL,
  368. std::complex<FloatType> PsiXL,
  369. std::complex<FloatType> ZetaXL,
  370. std::complex<FloatType> PsiXLM1,
  371. std::complex<FloatType> ZetaXLM1);
  372. std::complex<FloatType> calc_S1(int n,
  373. std::complex<FloatType> an,
  374. std::complex<FloatType> bn,
  375. FloatType Pi,
  376. FloatType Tau);
  377. std::complex<FloatType> calc_S2(int n,
  378. std::complex<FloatType> an,
  379. std::complex<FloatType> bn,
  380. FloatType Pi,
  381. FloatType Tau);
  382. void calcD1D3(std::complex<FloatType> z,
  383. std::vector<std::complex<FloatType>>& D1,
  384. std::vector<std::complex<FloatType>>& D3);
  385. void calcPsiZeta(std::complex<FloatType> x,
  386. std::vector<std::complex<FloatType>>& Psi,
  387. std::vector<std::complex<FloatType>>& Zeta);
  388. void calcPiTau(const FloatType& costheta,
  389. std::vector<FloatType>& Pi,
  390. std::vector<FloatType>& Tau);
  391. template <typename evalType = FloatType>
  392. void calcSpherHarm(const std::complex<evalType> Rho,
  393. const evalType Theta,
  394. const evalType Phi,
  395. const std::complex<evalType>& rn,
  396. const std::complex<evalType>& Dn,
  397. const evalType& Pi,
  398. const evalType& Tau,
  399. const evalType& n,
  400. std::vector<std::complex<evalType>>& Mo1n,
  401. std::vector<std::complex<evalType>>& Me1n,
  402. std::vector<std::complex<evalType>>& No1n,
  403. std::vector<std::complex<evalType>>& Ne1n);
  404. template <typename evalType = FloatType>
  405. void calcFieldByComponents(const evalType Rho,
  406. const evalType Theta,
  407. const evalType Phi,
  408. const std::vector<std::complex<evalType>>& Psi,
  409. const std::vector<std::complex<evalType>>& D1n,
  410. const std::vector<std::complex<evalType>>& Zeta,
  411. const std::vector<std::complex<evalType>>& D3n,
  412. const std::vector<evalType>& Pi,
  413. const std::vector<evalType>& Tau,
  414. std::vector<std::complex<evalType>>& E,
  415. std::vector<std::complex<evalType>>& H,
  416. std::vector<bool>& isConvergedE,
  417. std::vector<bool>& isConvergedH,
  418. bool isMarkUnconverged);
  419. bool isExpCoeffsCalc_ = false;
  420. bool isScaCoeffsCalc_ = false;
  421. bool isMieCalculated_ = false;
  422. std::vector<bool> isConvergedE_ = {false, false, false};
  423. std::vector<bool> isConvergedH_ = {false, false, false};
  424. // Scattering angles for scattering pattern in radians
  425. std::vector<FloatType> theta_;
  426. // Should be -1 if there is no PEC.
  427. int PEC_layer_position_ = -1;
  428. int mode_n_ = Modes::kAll;
  429. int mode_type_ = Modes::kAll;
  430. // with calcNmax(int first_layer);
  431. int nmax_ = -1;
  432. int nmax_preset_ = -1;
  433. int available_maximal_nmax_ = -1;
  434. // Store result
  435. FloatType Qsca_ = 0.0, Qext_ = 0.0, Qabs_ = 0.0, Qbk_ = 0.0, Qpr_ = 0.0,
  436. asymmetry_factor_ = 0.0, albedo_ = 0.0;
  437. // {X[], Y[], Z[]}
  438. std::vector<std::vector<std::complex<FloatType>>> E_, H_;
  439. std::vector<std::vector<std::complex<FloatType>>> Es_, Hs_;
  440. std::vector<FloatType> Eabs_, Habs_;
  441. std::vector<std::complex<FloatType>> S1_, S2_;
  442. void calcMieSeriesNeededToConverge(const FloatType Rho, int nmax_in = -1);
  443. void calcPiTauAllTheta(const double from_Theta,
  444. const double to_Theta,
  445. std::vector<std::vector<FloatType>>& Pi,
  446. std::vector<std::vector<FloatType>>& Tau);
  447. void calcRadialOnlyDependantFunctions(
  448. const double from_Rho,
  449. const double to_Rho,
  450. std::vector<std::vector<std::complex<FloatType>>>& Psi,
  451. std::vector<std::vector<std::complex<FloatType>>>& D1n,
  452. std::vector<std::vector<std::complex<FloatType>>>& Zeta,
  453. std::vector<std::vector<std::complex<FloatType>>>& D3n,
  454. int nmax_in = -1);
  455. void convertFieldsFromSphericalToCartesian();
  456. void UpdateConvergenceStatus(std::vector<bool> isConvergedE,
  457. std::vector<bool> isConvergedH);
  458. }; // end of class MultiLayerMie
  459. //******************************************************************************
  460. //******************************************************************************
  461. template <typename FloatType = double>
  462. class MesoMie {
  463. public:
  464. std::vector<std::complex<FloatType>> an_, bn_;
  465. void calc_ab(int n,
  466. FloatType R,
  467. FloatType xd,
  468. FloatType xm,
  469. FloatType eps_d,
  470. FloatType eps_m,
  471. FloatType d_parallel,
  472. FloatType d_perp);
  473. }; // end of class MesoMie
  474. } // end of namespace nmie
  475. #endif // SRC_NMIE_HPP_