main.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. #!/usr/bin/env python
  2. # -*- coding: UTF-8 -*-
  3. #
  4. # Copyright (C) 2009-2019 Ovidio Peña Rodríguez <ovidio@bytesfall.com>
  5. # Copyright (C) 2013-2019 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. Peña 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. Peña-Rodríguez, "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. import numpy as np
  33. def scattcoeffs(x, m, nmax=-1, pl=-1, mp=False):
  34. """
  35. scattcoeffs(x, m[, nmax, pl, mp])
  36. Calculate the scattering coefficients required to calculate both the
  37. near- and far-field parameters.
  38. x: Size parameters (1D or 2D ndarray)
  39. m: Relative refractive indices (1D or 2D ndarray)
  40. nmax: Maximum number of multipolar expansion terms to be used for the
  41. calculations. Only use it if you know what you are doing, otherwise
  42. set this parameter to -1 and the function will calculate it.
  43. pl: Index of PEC layer. If there is none just send -1.
  44. mp: Use multiple (True) or double (False) precision.
  45. Returns: (terms, an, bn)
  46. with
  47. terms: Number of multipolar expansion terms used for the calculations
  48. an, bn: Complex scattering coefficients
  49. """
  50. if mp:
  51. from scattnlay_mp import scattcoeffs as scattcoeffs_
  52. else:
  53. from scattnlay_dp import scattcoeffs as scattcoeffs_
  54. if len(m.shape) != 1 and len(m.shape) != 2:
  55. raise ValueError('The relative refractive index (m) should be a 1-D or 2-D NumPy array.')
  56. if len(x.shape) == 1:
  57. if len(m.shape) == 1:
  58. return scattcoeffs_(x, m, nmax=nmax, pl=pl)
  59. else:
  60. raise ValueError('The number of of dimensions for the relative refractive index (m) and for the size parameter (x) must be equal.')
  61. elif len(x.shape) != 2:
  62. raise ValueError('The size parameter (x) should be a 1-D or 2-D NumPy array.')
  63. # Repeat the same m for all wavelengths
  64. if len(m.shape) == 1:
  65. m = np.repeat(m[np.newaxis, :], x.shape[0], axis=0)
  66. if nmax == -1:
  67. nstore = 0
  68. else:
  69. nstore = nmax
  70. terms = np.zeros((x.shape[0]), dtype=int)
  71. an = np.zeros((0, nstore), dtype=complex)
  72. bn = np.zeros((0, nstore), dtype=complex)
  73. for i, xi in enumerate(x):
  74. terms[i], a, b = scattcoeffs_(xi, m[i], nmax=nmax, pl=pl)
  75. if terms[i] > nstore:
  76. nstore = terms[i]
  77. an.resize((an.shape[0], nstore))
  78. bn.resize((bn.shape[0], nstore))
  79. an = np.vstack((an, a))
  80. bn = np.vstack((bn, b))
  81. return terms, an, bn
  82. #scattcoeffs()
  83. def expancoeffs(x, m, li=-1, nmax=-1, pl=-1, mp=False):
  84. """
  85. expancoeffs(x, m[, li, nmax, pl, mp])
  86. Calculate the scattering coefficients required to calculate both the
  87. near- and far-field parameters.
  88. x: Size parameters (1D or 2D ndarray)
  89. m: Relative refractive indices (1D or 2D ndarray)
  90. li: Index of layer to get expansion coefficients. -1 means outside the sphere.
  91. nmax: Maximum number of multipolar expansion terms to be used for the
  92. calculations. Only use it if you know what you are doing, otherwise
  93. set this parameter to -1 and the function will calculate it.
  94. pl: Index of PEC layer. If there is none just send -1.
  95. mp: Use multiple (True) or double (False) precision.
  96. Returns: (terms, an, bn, cn, dn)
  97. with
  98. terms: Number of multipolar expansion terms used for the calculations
  99. an, bn, cn, dn: Complex expansion coefficients of ith layer
  100. """
  101. if mp:
  102. from scattnlay_mp import expancoeffs as expancoeffs_
  103. else:
  104. from scattnlay_dp import expancoeffs as expancoeffs_
  105. if len(m.shape) != 1 and len(m.shape) != 2:
  106. raise ValueError('The relative refractive index (m) should be a 1-D or 2-D NumPy array.')
  107. if len(x.shape) == 1:
  108. if len(m.shape) == 1:
  109. terms, an, bn, cn, dn = expancoeffs_(x, m, nmax=nmax, pl=pl)
  110. if li >= 0 and li <= x.shape:
  111. return terms, an[li], bn[li], cn[li], dn[li]
  112. else:
  113. return terms, an, bn, cn, dn
  114. else:
  115. raise ValueError('The number of of dimensions for the relative refractive index (m) and for the size parameter (x) must be equal.')
  116. elif len(x.shape) != 2:
  117. raise ValueError('The size parameter (x) should be a 1-D or 2-D NumPy array.')
  118. # Repeat the same m for all wavelengths
  119. if len(m.shape) == 1:
  120. m = np.repeat(m[np.newaxis, :], x.shape[0], axis=0)
  121. if nmax == -1:
  122. nstore = 0
  123. else:
  124. nstore = nmax
  125. terms = np.zeros((x.shape[0]), dtype=int)
  126. an = np.zeros((0, x.shape[1], nstore), dtype=complex)
  127. bn = np.zeros((0, x.shape[1], nstore), dtype=complex)
  128. cn = np.zeros((0, x.shape[1], nstore), dtype=complex)
  129. dn = np.zeros((0, x.shape[1], nstore), dtype=complex)
  130. for i, xi in enumerate(x):
  131. terms[i], a, b, c, d = expancoeffs_(xi, m[i], li=li, nmax=nmax, pl=pl)
  132. if terms[i] > nstore:
  133. nstore = terms[i]
  134. an.resize((an.shape[0], an.shape[1], nstore))
  135. bn.resize((bn.shape[0], bn.shape[1], nstore))
  136. cn.resize((cn.shape[0], cn.shape[1], nstore))
  137. dn.resize((dn.shape[0], dn.shape[1], nstore))
  138. an = np.vstack((an, a))
  139. bn = np.vstack((bn, b))
  140. cn = np.vstack((cn, c))
  141. dn = np.vstack((dn, d))
  142. if li >= 0 and li <= x.shape:
  143. return terms, an[:, li, :], bn[:, li, :], cn[:, li, :], dn[:, li, :]
  144. else:
  145. return terms, an, bn, cn, dn
  146. #expancoeffs()
  147. def scattnlay(x, m, theta=np.zeros(0, dtype=float), nmax=-1, pl=-1, mp=False):
  148. """
  149. scattnlay(x, m[, theta, nmax, pl, mp])
  150. Calculate the actual scattering parameters and amplitudes.
  151. x: Size parameters (1D or 2D ndarray)
  152. m: Relative refractive indices (1D or 2D ndarray)
  153. theta: Scattering angles where the scattering amplitudes will be
  154. calculated (optional, 1D ndarray)
  155. nmax: Maximum number of multipolar expansion terms to be used for the
  156. calculations. Only use it if you know what you are doing.
  157. pl: Index of PEC layer. If there is none just send -1.
  158. mp: Use multiple (True) or double (False) precision.
  159. Returns: (terms, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2)
  160. with
  161. terms: Number of multipolar expansion terms used for the calculations
  162. Qext: Efficiency factor for extinction
  163. Qsca: Efficiency factor for scattering
  164. Qabs: Efficiency factor for absorption (Qabs = Qext - Qsca)
  165. Qbk: Efficiency factor for backscattering
  166. Qpr: Efficiency factor for the radiation pressure
  167. g: Asymmetry factor (g = (Qext-Qpr)/Qsca)
  168. Albedo: Single scattering albedo (Albedo = Qsca/Qext)
  169. S1, S2: Complex scattering amplitudes
  170. """
  171. if mp:
  172. from scattnlay_mp import scattnlay as scattnlay_
  173. else:
  174. from scattnlay_dp import scattnlay as scattnlay_
  175. if len(m.shape) != 1 and len(m.shape) != 2:
  176. raise ValueError('The relative refractive index (m) should be a 1-D or 2-D NumPy array.')
  177. if len(x.shape) == 1:
  178. if len(m.shape) == 1:
  179. return scattnlay_(x, m, theta, nmax=nmax, pl=pl)
  180. else:
  181. raise ValueError('The number of of dimensions for the relative refractive index (m) and for the size parameter (x) must be equal.')
  182. elif len(x.shape) != 2:
  183. raise ValueError('The size parameter (x) should be a 1-D or 2-D NumPy array.')
  184. if len(theta.shape) != 1:
  185. raise ValueError('The scattering angles (theta) should be a 1-D NumPy array.')
  186. # Repeat the same m for all wavelengths
  187. if len(m.shape) == 1:
  188. m = np.repeat(m[np.newaxis, :], x.shape[0], axis=0)
  189. terms = np.zeros((x.shape[0]), dtype=int)
  190. Qext = np.zeros((x.shape[0]), dtype=float)
  191. Qsca = np.zeros((x.shape[0]), dtype=float)
  192. Qabs = np.zeros((x.shape[0]), dtype=float)
  193. Qbk = np.zeros((x.shape[0]), dtype=float)
  194. Qpr = np.zeros((x.shape[0]), dtype=float)
  195. g = np.zeros((x.shape[0]), dtype=float)
  196. Albedo = np.zeros((x.shape[0]), dtype=float)
  197. S1 = np.zeros((x.shape[0], theta.shape[0]), dtype=complex)
  198. S2 = np.zeros((x.shape[0], theta.shape[0]), dtype=complex)
  199. for i, xi in enumerate(x):
  200. terms[i], Qext[i], Qsca[i], Qabs[i], Qbk[i], Qpr[i], g[i], Albedo[i], S1[i], S2[i] = scattnlay_(xi, m[i], theta, nmax=nmax, pl=pl)
  201. return terms, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2
  202. #scattnlay()
  203. def fieldnlay(x, m, xp, yp, zp, nmax=-1, pl=-1, mp=False):
  204. """
  205. fieldnlay(x, m, xp, yp, zp[, nmax, pl, mp])
  206. Calculate the actual scattering parameters and amplitudes.
  207. x: Size parameters (1D or 2D ndarray)
  208. m: Relative refractive indices (1D or 2D ndarray)
  209. xp: Array containing all X coordinates to calculate the complex
  210. electric and magnetic fields (1D* ndarray)
  211. yp: Array containing all Y coordinates to calculate the complex
  212. electric and magnetic fields (1D* ndarray)
  213. zp: Array containing all Z coordinates to calculate the complex
  214. electric and magnetic fields (1D* ndarray)
  215. nmax: Maximum number of multipolar expansion terms to be used for the
  216. calculations. Only use it if you know what you are doing.
  217. pl: Index of PEC layer. If there is none just send -1.
  218. mp: Use multiple (True) or double (False) precision.
  219. Returns: (terms, E, H)
  220. with
  221. terms: Number of multipolar expansion terms used for the calculations
  222. E, H: Complex electric and magnetic field at the provided coordinates
  223. *Note: We assume that the coordinates are referred to the first wavelength
  224. (or structure) and correct it for the following ones
  225. """
  226. if mp:
  227. from scattnlay_mp import fieldnlay as fieldnlay_
  228. else:
  229. from scattnlay_dp import fieldnlay as fieldnlay_
  230. if len(m.shape) != 1 and len(m.shape) != 2:
  231. raise ValueError('The relative refractive index (m) should be a 1-D or 2-D NumPy array.')
  232. if len(x.shape) == 1:
  233. if len(m.shape) == 1:
  234. return fieldnlay_(x, m, xp, yp, zp, nmax=nmax, pl=pl)
  235. else:
  236. raise ValueError('The number of of dimensions for the relative refractive index (m) and for the size parameter (x) must be equal.')
  237. elif len(x.shape) != 2:
  238. raise ValueError('The size parameter (x) should be a 1-D or 2-D NumPy array.')
  239. # Repeat the same m for all wavelengths
  240. if len(m.shape) == 1:
  241. m = np.repeat(m[np.newaxis, :], x.shape[0], axis=0)
  242. terms = np.zeros((x.shape[0]), dtype=int)
  243. E = np.zeros((x.shape[0], xp.shape[0], 3), dtype=complex)
  244. H = np.zeros((x.shape[0], xp.shape[0], 3), dtype=complex)
  245. for i, xi in enumerate(x):
  246. # (2020/05/12) We assume that the coordinates are referred to the first wavelength
  247. # (or structure) and correct it for the following ones
  248. terms[i], E[i], H[i] = fieldnlay_(xi, m[i], xp*xi[-1]/x[0, -1], yp*xi[-1]/x[0, -1], zp*xi[-1]/x[0, -1], nmax=nmax, pl=pl)
  249. return terms, E, H
  250. #fieldnlay()