123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- #!/usr/bin/env python
- # -*- coding: UTF-8 -*-
- #
- # Copyright (C) 2009-2021 Ovidio Peña Rodríguez <ovidio@bytesfall.com>
- # Copyright (C) 2013-2021 Konstantin Ladutenko <kostyfisik@gmail.com>
- #
- # This file is part of scattnlay
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # The only additional remark is that we expect that all publications
- # describing work using this software, or all commercial products
- # using it, cite at least one of the following references:
- # [1] O. Peña and U. Pal, "Scattering of electromagnetic radiation by
- # a multilayered sphere," Computer Physics Communications,
- # vol. 180, Nov. 2009, pp. 2348-2354.
- # [2] K. Ladutenko, U. Pal, A. Rivera, and O. Peña-Rodríguez, "Mie
- # calculation of electromagnetic near-field for a multilayered
- # sphere," Computer Physics Communications, vol. 214, May 2017,
- # pp. 225-230.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
- from scattnlay_dp import mie_dp
- import numpy as np
- import sys
- mie_mp = None
- try:
- from scattnlay_mp import mie_mp as mie_mp_
- mie_mp = mie_mp_()
- except:
- pass
- mie = mie_dp()
- def scattcoeffs_(x, m, nmax=-1, pl=-1, mp=False):
- if mp and mie_mp:
- from scattnlay_mp import mie_mp as mie_
- else:
- if mp:
- print('Failed to load multiprecision module, using double precision instead...',
- file=sys.stderr)
- from scattnlay_dp import mie_dp as mie_
- # from scattnlay_mp import mie_mp as mie_
- mie = mie_()
- mie.SetLayersSize(x)
- mie.SetLayersIndex(m)
- mie.SetPECLayer(pl)
- mie.SetMaxTerms(nmax)
- mie.calcScattCoeffs()
- terms = mie.GetMaxTerms()
- a = mie.GetAn()
- b = mie.GetBn()
- return terms, a, b
- def scattcoeffs(x, m, nmax=-1, pl=-1, mp=False):
- """
- scattcoeffs(x, m[, nmax, pl, mp])
- Calculate the scattering coefficients required to calculate both the
- near- and far-field parameters.
- x: Size parameters (1D or 2D ndarray)
- m: Relative refractive indices (1D or 2D ndarray)
- nmax: Maximum number of multipolar expansion terms to be used for the
- calculations. Only use it if you know what you are doing, otherwise
- set this parameter to -1 and the function will calculate it.
- pl: Index of PEC layer. If there is none just send -1.
- mp: Use multiple (True) or double (False) precision.
- Returns: (terms, an, bn)
- with
- terms: Number of multipolar expansion terms used for the calculations
- an, bn: Complex scattering coefficients
- """
- if len(m.shape) != 1 and len(m.shape) != 2:
- raise ValueError(
- 'The relative refractive index (m) should be a 1-D or 2-D NumPy array.')
- if len(x.shape) == 1:
- if len(m.shape) == 1:
- return scattcoeffs_(x, m, nmax=nmax, pl=pl, mp=mp)
- else:
- raise ValueError(
- 'The number of of dimensions for the relative refractive index (m) and for the size parameter (x) must be equal.')
- elif len(x.shape) != 2:
- raise ValueError(
- 'The size parameter (x) should be a 1-D or 2-D NumPy array.')
- # Repeat the same m for all wavelengths
- if len(m.shape) == 1:
- m = np.repeat(m[np.newaxis, :], x.shape[0], axis=0)
- if nmax == -1:
- nstore = 0
- else:
- nstore = nmax
- terms = np.zeros((x.shape[0]), dtype=int)
- an = np.zeros((0, nstore), dtype=complex)
- bn = np.zeros((0, nstore), dtype=complex)
- for i, xi in enumerate(x):
- terms[i], a, b = scattcoeffs_(xi, m[i], nmax=nmax, pl=pl, mp=mp)
- if terms[i] > nstore:
- nstore = terms[i]
- an.resize((an.shape[0], nstore))
- bn.resize((bn.shape[0], nstore))
- an = np.vstack((an, a))
- bn = np.vstack((bn, b))
- return terms, an, bn
- def expancoeffs_(x, m, nmax=-1, pl=-1, mp=False):
- if mp and mie_mp:
- from scattnlay_mp import mie_mp as mie_
- else:
- if mp:
- print('Failed to load multiprecision module, using double precision instead...',
- file=sys.stderr)
- from scattnlay_dp import mie_dp as mie_
- # from scattnlay_mp import mie_mp as mie_
- mie = mie_()
- mie.SetLayersSize(x)
- mie.SetLayersIndex(m)
- mie.SetPECLayer(pl)
- mie.SetMaxTerms(nmax)
- mie.calcScattCoeffs()
- mie.calcExpanCoeffs()
- terms = mie.GetMaxTerms()
- an = mie.GetLayerAn()
- bn = mie.GetLayerBn()
- cn = mie.GetLayerCn()
- dn = mie.GetLayerDn()
- return terms, an, bn, cn, dn
- # TODO verify that expancoeffs() is really working
- def expancoeffs(x, m, nmax=-1, pl=-1, mp=False):
- """
- expancoeffs(x, m[, nmax, pl, mp])
- Calculate the scattering coefficients required to calculate both the
- near- and far-field parameters.
- x: Size parameters (1D or 2D ndarray)
- m: Relative refractive indices (1D or 2D ndarray)
- nmax: Maximum number of multipolar expansion terms to be used for the
- calculations. Only use it if you know what you are doing, otherwise
- set this parameter to -1 and the function will calculate it.
- pl: Index of PEC layer. If there is none just send -1.
- mp: Use multiple (True) or double (False) precision.
- Returns: (terms, an, bn, cn, dn)
- with
- terms: Number of multipolar expansion terms used for the calculations
- an, bn, cn, dn: Complex expansion coefficients of each layer
- """
- if len(m.shape) != 1 and len(m.shape) != 2:
- raise ValueError(
- 'The relative refractive index (m) should be a 1-D or 2-D NumPy array.')
- if len(x.shape) == 1:
- if len(m.shape) == 1:
- return expancoeffs_(x, m, nmax=nmax, pl=pl, mp=mp)
- else:
- raise ValueError(
- 'The number of of dimensions for the relative refractive index (m) and for the size parameter (x) must be equal.')
- elif len(x.shape) != 2:
- raise ValueError(
- 'The size parameter (x) should be a 1-D or 2-D NumPy array.')
- # Repeat the same m for all wavelengths
- if len(m.shape) == 1:
- m = np.repeat(m[np.newaxis, :], x.shape[0], axis=0)
- if nmax == -1:
- nstore = 0
- else:
- nstore = nmax
- terms = np.zeros((x.shape[0]), dtype=int)
- an = np.zeros((0, x.shape[1]+1, nstore), dtype=complex)
- bn = np.zeros((0, x.shape[1]+1, nstore), dtype=complex)
- cn = np.zeros((0, x.shape[1]+1, nstore), dtype=complex)
- dn = np.zeros((0, x.shape[1]+1, nstore), dtype=complex)
- for i, xi in enumerate(x):
- terms[i], a, b, c, d = expancoeffs_(xi, m[i], nmax=nmax, pl=pl, mp=mp)
- if terms[i] > nstore:
- nstore = terms[i]
- an.resize((an.shape[0], an.shape[1], nstore))
- bn.resize((bn.shape[0], bn.shape[1], nstore))
- cn.resize((cn.shape[0], cn.shape[1], nstore))
- dn.resize((dn.shape[0], dn.shape[1], nstore))
- an = np.vstack((an, [a]))
- bn = np.vstack((bn, [b]))
- cn = np.vstack((cn, [c]))
- dn = np.vstack((dn, [d]))
- return terms, an, bn, cn, dn
- def scattnlay_(x, m, theta=np.zeros(0, dtype=float), nmax=-1, pl=-1, mp=False):
- if mp and mie_mp:
- from scattnlay_mp import mie_mp as mie_
- else:
- if mp:
- print('Failed to load multiprecision module, using double precision instead...',
- file=sys.stderr)
- from scattnlay_dp import mie_dp as mie_
- mie = mie_()
- mie.SetLayersSize(x)
- mie.SetLayersIndex(m)
- mie.SetAngles(theta)
- mie.SetPECLayer(pl)
- mie.SetMaxTerms(nmax)
- mie.RunMieCalculation()
- Qext = mie.GetQext()
- Qsca = mie.GetQsca()
- Qabs = mie.GetQabs()
- Qbk = mie.GetQbk()
- Qpr = mie.GetQpr()
- g = mie.GetAsymmetryFactor()
- Albedo = mie.GetAlbedo()
- terms = mie.GetMaxTerms()
- S1 = mie.GetS1()
- S2 = mie.GetS2()
- return terms, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2
- def scattnlay(x, m, theta=np.zeros(0, dtype=float), nmax=-1, pl=-1, mp=False):
- """
- scattnlay(x, m[, theta, nmax, pl, mp])
- Calculate the actual scattering parameters and amplitudes.
- x: Size parameters (1D or 2D ndarray)
- m: Relative refractive indices (1D or 2D ndarray)
- theta: Scattering angles where the scattering amplitudes will be
- calculated (optional, 1D ndarray)
- nmax: Maximum number of multipolar expansion terms to be used for the
- calculations. Only use it if you know what you are doing.
- pl: Index of PEC layer. If there is none just send -1.
- mp: Use multiple (True) or double (False) precision.
- Returns: (terms, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2)
- with
- terms: Number of multipolar expansion terms used for the calculations
- Qext: Efficiency factor for extinction
- Qsca: Efficiency factor for scattering
- Qabs: Efficiency factor for absorption (Qabs = Qext - Qsca)
- Qbk: Efficiency factor for backscattering
- Qpr: Efficiency factor for the radiation pressure
- g: Asymmetry factor (g = (Qext-Qpr)/Qsca)
- Albedo: Single scattering albedo (Albedo = Qsca/Qext)
- S1, S2: Complex scattering amplitudes
- """
- if len(m.shape) != 1 and len(m.shape) != 2:
- raise ValueError(
- 'The relative refractive index (m) should be a 1-D or 2-D NumPy array.')
- if len(x.shape) == 1:
- if len(m.shape) == 1:
- return scattnlay_(x, m, theta, nmax=nmax, pl=pl, mp=mp)
- else:
- raise ValueError(
- 'The number of of dimensions for the relative refractive index (m) and for the size parameter (x) must be equal.')
- elif len(x.shape) != 2:
- raise ValueError(
- 'The size parameter (x) should be a 1-D or 2-D NumPy array.')
- if len(theta.shape) != 1:
- raise ValueError(
- 'The scattering angles (theta) should be a 1-D NumPy array.')
- # Repeat the same m for all wavelengths
- if len(m.shape) == 1:
- m = np.repeat(m[np.newaxis, :], x.shape[0], axis=0)
- terms = np.zeros((x.shape[0]), dtype=int)
- Qext = np.zeros((x.shape[0]), dtype=float)
- Qsca = np.zeros((x.shape[0]), dtype=float)
- Qabs = np.zeros((x.shape[0]), dtype=float)
- Qbk = np.zeros((x.shape[0]), dtype=float)
- Qpr = np.zeros((x.shape[0]), dtype=float)
- g = np.zeros((x.shape[0]), dtype=float)
- Albedo = np.zeros((x.shape[0]), dtype=float)
- S1 = np.zeros((x.shape[0], theta.shape[0]), dtype=complex)
- S2 = np.zeros((x.shape[0], theta.shape[0]), dtype=complex)
- for i, xi in enumerate(x):
- 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, mp=mp)
- return terms, Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo, S1, S2
- def fieldnlay_(x, m, xp, yp, zp, nmax=-1, pl=-1, mp=False):
- if mp and mie_mp:
- from scattnlay_mp import mie_mp as mie_
- else:
- if mp:
- print('Failed to load multiprecision module, using double precision instead...',
- file=sys.stderr)
- from scattnlay_dp import mie_dp as mie_
- # from scattnlay_mp import mie_mp as mie_
- mie = mie_()
- mie.SetLayersSize(x)
- mie.SetLayersIndex(m)
- mie.SetPECLayer(pl)
- mie.SetMaxTerms(nmax)
- mie.SetFieldCoords(xp, yp, zp)
- mie.RunFieldCalculation()
- terms = mie.GetMaxTerms()
- E = mie.GetFieldE()
- H = mie.GetFieldH()
- return terms, E, H
- def fieldnlay(x, m, xp, yp, zp, nmax=-1, pl=-1, mp=False):
- """
- fieldnlay(x, m, xp, yp, zp[, nmax, pl, mp])
- Calculate the actual scattering parameters and amplitudes.
- x: Size parameters (1D or 2D ndarray)
- m: Relative refractive indices (1D or 2D ndarray)
- xp: Array containing all X coordinates to calculate the complex
- electric and magnetic fields (1D* ndarray)
- yp: Array containing all Y coordinates to calculate the complex
- electric and magnetic fields (1D* ndarray)
- zp: Array containing all Z coordinates to calculate the complex
- electric and magnetic fields (1D* ndarray)
- nmax: Maximum number of multipolar expansion terms to be used for the
- calculations. Only use it if you know what you are doing.
- pl: Index of PEC layer. If there is none just send -1.
- mp: Use multiple (True) or double (False) precision.
- Returns: (terms, E, H)
- with
- terms: Number of multipolar expansion terms used for the calculations
- E, H: Complex electric and magnetic field at the provided coordinates
- *Note: We assume that the coordinates are referred to the first wavelength
- (or structure) and correct it for the following ones
- """
- if len(m.shape) != 1 and len(m.shape) != 2:
- raise ValueError(
- 'The relative refractive index (m) should be a 1-D or 2-D NumPy array.')
- if len(x.shape) == 1:
- if len(m.shape) == 1:
- return fieldnlay_(x, m, xp, yp, zp, nmax=nmax, pl=pl, mp=mp)
- else:
- raise ValueError(
- 'The number of of dimensions for the relative refractive index (m) and for the size parameter (x) must be equal.')
- elif len(x.shape) != 2:
- raise ValueError(
- 'The size parameter (x) should be a 1-D or 2-D NumPy array.')
- # Repeat the same m for all wavelengths
- if len(m.shape) == 1:
- m = np.repeat(m[np.newaxis, :], x.shape[0], axis=0)
- terms = np.zeros((x.shape[0]), dtype=int)
- E = np.zeros((x.shape[0], xp.shape[0], 3), dtype=complex)
- H = np.zeros((x.shape[0], xp.shape[0], 3), dtype=complex)
- for i, xi in enumerate(x):
- # (2020/05/12) We assume that the coordinates are referred to the first wavelength
- # (or structure) and correct it for the following ones
- 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, mp=mp)
- return terms, E, H
|