scattnlay.pyx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. # Copyright (C) 2009-2018 Ovidio Pena <ovidio@bytesfall.com>
  2. # Copyright (C) 2013-2018 Konstantin Ladutenko <kostyfisik@gmail.com>
  3. #
  4. # This file is part of scattnlay
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # The only additional remark is that we expect that all publications
  17. # describing work using this software, or all commercial products
  18. # using it, cite at least one of the following references:
  19. # [1] O. Peña and U. Pal, "Scattering of electromagnetic radiation by
  20. # a multilayered sphere," Computer Physics Communications,
  21. # vol. 180, Nov. 2009, pp. 2348-2354.
  22. # [2] K. Ladutenko, U. Pal, A. Rivera, and O. Peña-Rodríguez, "Mie
  23. # calculation of electromagnetic near-field for a multilayered
  24. # sphere," Computer Physics Communications, vol. 214, May 2017,
  25. # pp. 225-230.
  26. #
  27. # You should have received a copy of the GNU General Public License
  28. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  29. # distutils: language = c++
  30. # distutils: sources = nmie.cc
  31. from __future__ import division
  32. import numpy as np
  33. cimport numpy as np
  34. from libcpp.vector cimport vector
  35. from libcpp.vector cimport complex
  36. cdef inline double *npy2c(np.ndarray a):
  37. assert a.dtype == np.float64
  38. if not (<object>a).flags["C_CONTIGUOUS"]: # Array is not contiguous, need to make contiguous copy
  39. a = a.copy('C')
  40. # Return data pointer
  41. return <double *>(a.data)
  42. cdef extern from "py_nmie.h":
  43. cdef int ScattCoeffs(int L, int pl, vector[double] x, vector[complex] m, int nmax, double anr[], double ani[], double bnr[], double bni[])
  44. cdef int nMie(int L, int pl, vector[double] x, vector[complex] m, int nTheta, vector[double] Theta, int nmax, double *Qext, double *Qsca, double *Qabs, double *Qbk, double *Qpr, double *g, double *Albedo, double S1r[], double S1i[], double S2r[], double S2i[])
  45. cdef int nField(int L, int pl, vector[double] x, vector[complex] m, int nmax, int nCoords, vector[double] Xp, vector[double] Yp, vector[double] Zp, double Erx[], double Ery[], double Erz[], double Eix[], double Eiy[], double Eiz[], double Hrx[], double Hry[], double Hrz[], double Hix[], double Hiy[], double Hiz[])
  46. def scattcoeffs(np.ndarray[np.float64_t, ndim = 2] x, np.ndarray[np.complex128_t, ndim = 2] m, np.int_t nmax, np.int_t pl = -1):
  47. """
  48. scattcoeffs(x, m[, nmax, pl])
  49. Calculate the scattering coefficients required to calculate both the
  50. near- and far-field parameters.
  51. x: Size parameters (2D ndarray)
  52. m: Relative refractive indices (2D ndarray)
  53. nmax: Maximum number of multipolar expansion terms to be used for the
  54. calculations. Only use it if you know what you are doing, otherwise
  55. set this parameter to -1 and the function will calculate it.
  56. pl: Index of PEC layer. If there is none just send -1
  57. Returns: (terms, an, bn)
  58. with
  59. terms: Number of multipolar expansion terms used for the calculations
  60. an, bn: Complex scattering coefficients
  61. """
  62. cdef Py_ssize_t i
  63. cdef np.ndarray[np.int_t, ndim = 1] terms = np.zeros(x.shape[0], dtype = np.int)
  64. cdef np.ndarray[np.complex128_t, ndim = 2] an = np.zeros((x.shape[0], nmax), dtype = np.complex128)
  65. cdef np.ndarray[np.complex128_t, ndim = 2] bn = np.zeros((x.shape[0], nmax), dtype = np.complex128)
  66. cdef np.ndarray[np.float64_t, ndim = 1] anr
  67. cdef np.ndarray[np.float64_t, ndim = 1] ani
  68. cdef np.ndarray[np.float64_t, ndim = 1] bnr
  69. cdef np.ndarray[np.float64_t, ndim = 1] bni
  70. for i in range(x.shape[0]):
  71. anr = np.zeros(nmax, dtype = np.float64)
  72. ani = np.zeros(nmax, dtype = np.float64)
  73. bnr = np.zeros(nmax, dtype = np.float64)
  74. bni = np.zeros(nmax, dtype = np.float64)
  75. terms[i] = ScattCoeffs(x.shape[1], pl, x[i].copy('C'), m[i].copy('C'), nmax, npy2c(anr), npy2c(ani), npy2c(bnr), npy2c(bni))
  76. an[i] = anr.copy('C') + 1.0j*ani.copy('C')
  77. bn[i] = bnr.copy('C') + 1.0j*bni.copy('C')
  78. return terms, an, bn
  79. def scattnlay(np.ndarray[np.float64_t, ndim = 2] x, np.ndarray[np.complex128_t, ndim = 2] m, np.ndarray[np.float64_t, ndim = 1] theta = np.zeros(0, dtype = np.float64), np.int_t nmax = -1, np.int_t pl = -1):
  80. """
  81. scattnlay(x, m[, theta, nmax, pl])
  82. Calculate the actual scattering parameters and amplitudes.
  83. x: Size parameters (2D ndarray)
  84. m: Relative refractive indices (2D ndarray)
  85. theta: Scattering angles where the scattering amplitudes will be
  86. calculated (optional, 1D ndarray)
  87. nmax: Maximum number of multipolar expansion terms to be used for the
  88. calculations. Only use it if you know what you are doing.
  89. pl: Index of PEC layer.
  90. Returns: (terms, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2)
  91. with
  92. terms: Number of multipolar expansion terms used for the calculations
  93. Qext: Efficiency factor for extinction
  94. Qsca: Efficiency factor for scattering
  95. Qabs: Efficiency factor for absorption (Qabs = Qext - Qsca)
  96. Qbk: Efficiency factor for backscattering
  97. Qpr: Efficiency factor for the radiation pressure
  98. g: Asymmetry factor (g = (Qext-Qpr)/Qsca)
  99. Albedo: Single scattering albedo (Albedo = Qsca/Qext)
  100. S1, S2: Complex scattering amplitudes
  101. """
  102. cdef Py_ssize_t i
  103. cdef np.ndarray[np.int_t, ndim = 1] terms = np.zeros(x.shape[0], dtype = np.int)
  104. cdef np.ndarray[np.float64_t, ndim = 1] Qext = np.zeros(x.shape[0], dtype = np.float64)
  105. cdef np.ndarray[np.float64_t, ndim = 1] Qabs = np.zeros(x.shape[0], dtype = np.float64)
  106. cdef np.ndarray[np.float64_t, ndim = 1] Qsca = np.zeros(x.shape[0], dtype = np.float64)
  107. cdef np.ndarray[np.float64_t, ndim = 1] Qbk = np.zeros(x.shape[0], dtype = np.float64)
  108. cdef np.ndarray[np.float64_t, ndim = 1] Qpr = np.zeros(x.shape[0], dtype = np.float64)
  109. cdef np.ndarray[np.float64_t, ndim = 1] g = np.zeros(x.shape[0], dtype = np.float64)
  110. cdef np.ndarray[np.float64_t, ndim = 1] Albedo = np.zeros(x.shape[0], dtype = np.float64)
  111. cdef np.ndarray[np.complex128_t, ndim = 2] S1 = np.zeros((x.shape[0], theta.shape[0]), dtype = np.complex128)
  112. cdef np.ndarray[np.complex128_t, ndim = 2] S2 = np.zeros((x.shape[0], theta.shape[0]), dtype = np.complex128)
  113. cdef np.ndarray[np.float64_t, ndim = 1] S1r
  114. cdef np.ndarray[np.float64_t, ndim = 1] S1i
  115. cdef np.ndarray[np.float64_t, ndim = 1] S2r
  116. cdef np.ndarray[np.float64_t, ndim = 1] S2i
  117. for i in range(x.shape[0]):
  118. S1r = np.zeros(theta.shape[0], dtype = np.float64)
  119. S1i = np.zeros(theta.shape[0], dtype = np.float64)
  120. S2r = np.zeros(theta.shape[0], dtype = np.float64)
  121. S2i = np.zeros(theta.shape[0], dtype = np.float64)
  122. terms[i] = nMie(x.shape[1], pl, x[i].copy('C'), m[i].copy('C'), theta.shape[0], theta.copy('C'), nmax, &Qext[i], &Qsca[i], &Qabs[i], &Qbk[i], &Qpr[i], &g[i], &Albedo[i], npy2c(S1r), npy2c(S1i), npy2c(S2r), npy2c(S2i))
  123. S1[i] = S1r.copy('C') + 1.0j*S1i.copy('C')
  124. S2[i] = S2r.copy('C') + 1.0j*S2i.copy('C')
  125. return terms, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2
  126. def fieldnlay(np.ndarray[np.float64_t, ndim = 2] x, np.ndarray[np.complex128_t, ndim = 2] m, np.ndarray[np.float64_t, ndim = 2] coords, np.int_t nmax = -1, np.int_t pl = -1):
  127. """
  128. fieldnlay(x, m, coords[, theta, nmax, pl])
  129. Calculate the actual scattering parameters and amplitudes.
  130. x: Size parameters (2D ndarray)
  131. m: Relative refractive indices (2D ndarray)
  132. coords: Array containing all coordinates where the complex electric
  133. and magnetic fields will be calculated (2D ndarray)
  134. nmax: Maximum number of multipolar expansion terms to be used for the
  135. calculations. Only use it if you know what you are doing.
  136. pl: Index of PEC layer.
  137. Returns: (terms, E, H)
  138. with
  139. terms: Number of multipolar expansion terms used for the calculations
  140. E, H: Complex electric and magnetic field at the provided coordinates
  141. """
  142. cdef Py_ssize_t i
  143. cdef np.ndarray[np.int_t, ndim = 1] terms = np.zeros(x.shape[0], dtype = np.int)
  144. cdef np.ndarray[np.complex128_t, ndim = 3] E = np.zeros((x.shape[0], coords.shape[0], 3), dtype = np.complex128)
  145. cdef np.ndarray[np.complex128_t, ndim = 3] H = np.zeros((x.shape[0], coords.shape[0], 3), dtype = np.complex128)
  146. cdef np.ndarray[np.float64_t, ndim = 1] Erx
  147. cdef np.ndarray[np.float64_t, ndim = 1] Ery
  148. cdef np.ndarray[np.float64_t, ndim = 1] Erz
  149. cdef np.ndarray[np.float64_t, ndim = 1] Eix
  150. cdef np.ndarray[np.float64_t, ndim = 1] Eiy
  151. cdef np.ndarray[np.float64_t, ndim = 1] Eiz
  152. cdef np.ndarray[np.float64_t, ndim = 1] Hrx
  153. cdef np.ndarray[np.float64_t, ndim = 1] Hry
  154. cdef np.ndarray[np.float64_t, ndim = 1] Hrz
  155. cdef np.ndarray[np.float64_t, ndim = 1] Hix
  156. cdef np.ndarray[np.float64_t, ndim = 1] Hiy
  157. cdef np.ndarray[np.float64_t, ndim = 1] Hiz
  158. for i in range(x.shape[0]):
  159. Erx = np.zeros(coords.shape[0], dtype = np.float64)
  160. Ery = np.zeros(coords.shape[0], dtype = np.float64)
  161. Erz = np.zeros(coords.shape[0], dtype = np.float64)
  162. Eix = np.zeros(coords.shape[0], dtype = np.float64)
  163. Eiy = np.zeros(coords.shape[0], dtype = np.float64)
  164. Eiz = np.zeros(coords.shape[0], dtype = np.float64)
  165. Hrx = np.zeros(coords.shape[0], dtype = np.float64)
  166. Hry = np.zeros(coords.shape[0], dtype = np.float64)
  167. Hrz = np.zeros(coords.shape[0], dtype = np.float64)
  168. Hix = np.zeros(coords.shape[0], dtype = np.float64)
  169. Hiy = np.zeros(coords.shape[0], dtype = np.float64)
  170. Hiz = np.zeros(coords.shape[0], dtype = np.float64)
  171. terms[i] = nField(x.shape[1], pl, x[i].copy('C'), m[i].copy('C'), nmax, coords.shape[0], coords[:, 0].copy('C'), coords[:, 1].copy('C'), coords[:, 2].copy('C'), npy2c(Erx), npy2c(Ery), npy2c(Erz), npy2c(Eix), npy2c(Eiy), npy2c(Eiz), npy2c(Hrx), npy2c(Hry), npy2c(Hrz), npy2c(Hix), npy2c(Hiy), npy2c(Hiz))
  172. E[i] = np.vstack((Erx.copy('C') + 1.0j*Eix.copy('C'), Ery.copy('C') + 1.0j*Eiy.copy('C'), Erz.copy('C') + 1.0j*Eiz.copy('C'))).transpose()
  173. H[i] = np.vstack((Hrx.copy('C') + 1.0j*Hix.copy('C'), Hry.copy('C') + 1.0j*Hiy.copy('C'), Hrz.copy('C') + 1.0j*Hiz.copy('C'))).transpose()
  174. return terms, E, H