@@ -87,7 +87,7 @@ def calc_ang_scat(m, x, angles, mie = True, check = False):
8787 """
8888 if mie :
8989 # Mie scattering preliminaries
90- nstop = _nstop (np . array ( x ) .max ())
90+ nstop = _nstop (x .max ())
9191
9292 coeffs = _scatcoeffs (m , x , nstop )
9393 n = np .arange (nstop )+ 1.
@@ -118,6 +118,7 @@ def calc_ang_scat(m, x, angles, mie = True, check = False):
118118
119119 return np .array ([ipar , iperp ])
120120
121+
121122def calc_cross_sections (m , x , eps1 = DEFAULT_EPS1 ,
122123 eps2 = DEFAULT_EPS2 ):
123124 """
@@ -156,7 +157,7 @@ def calc_cross_sections(m, x, eps1 = DEFAULT_EPS1,
156157
157158 where I_0 is the incident intensity. See van de Hulst, p. 14.
158159 """
159- lmax = _nstop (np . array ( x ) .max ())
160+ lmax = _nstop (x .max ())
160161 albl = _scatcoeffs (m , x , lmax , eps1 = eps1 , eps2 = eps2 )
161162
162163 cscat , cext , cback = tuple (c * 2 * np .pi for c in
@@ -172,6 +173,7 @@ def calc_cross_sections(m, x, eps1 = DEFAULT_EPS1,
172173
173174 return cscat , cext , cabs , cback , asym
174175
176+
175177def calc_efficiencies (m , x ):
176178 """
177179 Scattering, extinction, backscattering efficiencies
@@ -181,36 +183,38 @@ def calc_efficiencies(m, x):
181183 scattering cross-section in the backscattering direction, divided by the
182184 geometrical cross-section
183185 """
184- nstop = _nstop (np . array ( x ) .max ())
186+ nstop = _nstop (x .max ())
185187 coeffs = _scatcoeffs (m , x , nstop )
186188
187189 cscat , cext , cback = _cross_sections (coeffs [0 ], coeffs [1 ])
188190
189191 # for multilayer spheres, scale by the size parameter corresponding to
190192 # outermost radius
191- x_outer = np . atleast_2d ( x ) .max (axis = - 1 )
193+ x_outer = x .max (axis = - 1 )
192194 qscat = cscat * 2. / np .abs (x_outer )** 2
193195 qext = cext * 2. / np .abs (x_outer )** 2
194196 qback = cback * 1. / np .abs (x_outer )** 2
195197
196198 # in order: scattering, extinction and backscattering efficiency
197199 return qscat , qext , qback
198200
201+
199202def calc_g (m , x , nstop = None ):
200203 """
201204 Asymmetry parameter
202205 """
203206 if nstop is None :
204- nstop = _nstop (np . array ( x ) .max ())
207+ nstop = _nstop (x .max ())
205208 coeffs = _scatcoeffs (m , x , nstop )
206209
207210 # for multilayer particle, need to scale by the x of the outermost layer
208- outer_x = np . array ( x ) .max (axis = - 1 )
211+ outer_x = x .max (axis = - 1 )
209212 cscat = _cross_sections (coeffs [0 ], coeffs [1 ])[0 ] * 2. / outer_x ** 2
210213 g = ((4. / (outer_x ** 2 * cscat ))
211214 * _asymmetry_parameter (coeffs [0 ], coeffs [1 ]))
212215 return g
213216
217+
214218def calc_integrated_cross_section (m , x , thetas ):
215219 """
216220 Calculate (dimensionless) integrated cross section using quadrature
@@ -234,13 +238,12 @@ def calc_integrated_cross_section(m, x, thetas):
234238 """
235239 form_factor = calc_ang_scat (m , x , thetas )
236240
237- integrand_par = form_factor [ 0 ] * np .sin (thetas )
238- integrand_perp = form_factor [ 1 ] * np .sin ( thetas )
241+ integrand = form_factor * np .sin (thetas )
242+ integral = 2 * np .pi * np . trapezoid ( integrand , x = thetas )
239243
240- integral_par = 2 * np . pi * np . trapezoid ( integrand_par , x = thetas )
241- integral_perp = 2 * np . pi * np . trapezoid ( integrand_perp , x = thetas )
244+ # average over two polarizations
245+ return ( integral . sum ( axis = 0 )) / 2.0
242246
243- return (integral_par + integral_perp )/ 2.0
244247
245248def calc_energy (radius , n_medium , m , x , nstop ,
246249 eps1 = DEFAULT_EPS1 , eps2 = DEFAULT_EPS2 ):
@@ -276,6 +279,7 @@ def calc_energy(radius, n_medium, m, x, nstop,
276279
277280 return W
278281
282+
279283def calc_dwell_time (radius , n_medium , n_particle , wavelen ,
280284 min_angle = 0.01 , num_angles = 200 ,
281285 eps1 = DEFAULT_EPS1 , eps2 = DEFAULT_EPS2 ):
@@ -339,6 +343,7 @@ def calc_dwell_time(radius, n_medium, n_particle, wavelen,
339343
340344 return dwell_time
341345
346+
342347# TODO: document and test the correctness of this function, or delete (it is
343348# not currently used anywhere)
344349@ureg .check ('[length]' , None , None , '[length]' , None , None )
@@ -375,6 +380,7 @@ def calc_reflectance(radius, n_medium, n_particle, wavelen,
375380
376381 return reflectance
377382
383+
378384# Mie functions used internally
379385
380386def _pis_and_taus (nstop , thetas ):
@@ -408,6 +414,8 @@ def _pis_and_taus(nstop, thetas):
408414 ang_shape = list (thetas .shape )
409415
410416 # flatten to make calculations easier
417+ # TODO if thetas specified as meshgrid, this will square the number of
418+ # calculations done
411419 thetas = np .ndarray .flatten (thetas )
412420
413421 mu = np .cos (thetas )
@@ -433,12 +441,12 @@ def _pis_and_taus(nstop, thetas):
433441 taus = np .reshape (taus , ang_shape )
434442 return pis [...,1 :nstop + 1 ], taus [...,1 :nstop + 1 ]
435443
444+
436445def _scatcoeffs (m , x , nstop , eps1 = DEFAULT_EPS1 , eps2 = DEFAULT_EPS2 ):
437446 # index ratio should be specified as a 2D array with shape
438447 # [num_values, num_layers] to calculate over a set of different values,
439448 # such as wavelengths. If specified as a 1D array, shape is [num_layers].
440- num_layers = np .atleast_2d (m ).shape [- 1 ]
441- if num_layers > 1 :
449+ if m .shape [- 1 ] > 1 :
442450 return _scatcoeffs_multi (m , x )
443451
444452 # Scattering coefficients for single-layer particles.
@@ -447,17 +455,13 @@ def _scatcoeffs(m, x, nstop, eps1 = DEFAULT_EPS1, eps2 = DEFAULT_EPS2):
447455 # nmx = np.array([nstop, np.round(np.absolute(m*x))]).max() + 20
448456 # Dnmx = mie_specfuncs.log_der_1(m*x, nmx, nstop)
449457 # above replaced with Lentz algorithm
450- z = np .atleast_1d (m * x )
451- # remove unneded layer axis
452- z = z [..., 0 ]
458+ z = m * x
459+ z = z [..., 0 ] # remove unneeded layer axis
453460 Dnmx = mie_specfuncs .dn_1_down (z , nstop + 1 , nstop ,
454461 mie_specfuncs .lentz_dn1 (z , nstop + 1 ,
455462 eps1 , eps2 ))
456463
457464 n = np .arange (nstop + 1 )
458- if np .ndim (x ) <= 1 :
459- x = np .atleast_1d (x )[..., np .newaxis ]
460-
461465 psi , xi = mie_specfuncs .riccati_psi_xi (x , nstop )
462466
463467 # insert zeroes at the beginning of second axis (order axis)
@@ -469,6 +473,7 @@ def _scatcoeffs(m, x, nstop, eps1 = DEFAULT_EPS1, eps2 = DEFAULT_EPS2):
469473 # coefficient array has shape [2, num_values, nstop]
470474 return np .array ([an [..., 1 :nstop + 1 ], bn [..., 1 :nstop + 1 ]])
471475
476+
472477def _scatcoeffs_multi (marray , xarray , nstop = None , eps1 = 1e-3 , eps2 = 1e-16 ):
473478 '''Calculate scattered field expansion coefficients (in the Mie formalism)
474479 for a particle with an arbitrary number of spherically symmetric layers
@@ -498,8 +503,8 @@ def _scatcoeffs_multi(marray, xarray, nstop=None, eps1 = 1e-3, eps2 = 1e-16):
498503
499504 '''
500505 # ensure correct data types and shapes
501- marray = np . atleast_2d ( marray ) .astype (complex )
502- xarray = np . atleast_2d ( xarray ) .astype (complex )
506+ marray = marray .astype (complex )
507+ xarray = xarray .astype (complex )
503508
504509 # sanity check: marray and xarray must be same size
505510 if marray .size != xarray .size :
@@ -585,6 +590,7 @@ def _scatcoeffs_multi(marray, xarray, nstop=None, eps1 = 1e-3, eps2 = 1e-16):
585590 # output begins at n=1
586591 return np .array ([an [..., 1 :nstop + 1 ], bn [..., 1 :nstop + 1 ]])
587592
593+
588594def _internal_coeffs (m , x , n_max , eps1 = DEFAULT_EPS1 , eps2 = DEFAULT_EPS2 ):
589595 '''
590596 Calculate internal Mie coefficients c_n and d_n given
@@ -594,13 +600,13 @@ def _internal_coeffs(m, x, n_max, eps1 = DEFAULT_EPS1, eps2 = DEFAULT_EPS2):
594600 have different conventions (labeling of c_n and d_n and factors of m)
595601 for their internal coefficients.
596602 '''
597- if np . atleast_2d ( x ) .shape [- 1 ] > 1 :
603+ if x .shape [- 1 ] > 1 :
598604 raise ValueError ("Internal Mie coefficients cannot yet be calculated "
599605 "for layered sphere" )
600606
601- m = np . reshape ( m , ( np . size ( m ), 1 )) .astype (complex )
602- x = np . reshape ( x , ( np . size ( x ), 1 )) .astype (complex )
603- z = np . array ( m * x )
607+ m = m .astype (complex )
608+ x = x .astype (complex )
609+ z = m * x
604610
605611 ratio = mie_specfuncs .R_psi (x , z , n_max , eps1 , eps2 )
606612 D1x , D3x = mie_specfuncs .log_der_13 (x , n_max , eps1 , eps2 )
@@ -653,6 +659,7 @@ def _trans_coeffs(m, x, n_max, eps1 = DEFAULT_EPS1, eps2 = DEFAULT_EPS2):
653659
654660 return np .array ([cn , dn ])
655661
662+
656663def _time_coeffs (m , x , nstop , eps1 = DEFAULT_EPS1 , eps2 = DEFAULT_EPS2 ):
657664 '''
658665 Calculate what we refer to as the time Mie coefficients gamma_n and An,
@@ -681,6 +688,7 @@ def _time_coeffs(m, x, nstop, eps1 = DEFAULT_EPS1, eps2 = DEFAULT_EPS2):
681688
682689 return gamma_n , An
683690
691+
684692def _W0 (radius , n_medium ):
685693 '''
686694 Calculates the time-averaged electromagnetic energy of a sphere having the
@@ -707,6 +715,7 @@ def _W0(radius, n_medium):
707715
708716 return W0
709717
718+
710719def _nstop (x ):
711720 # Takes size parameter, outputs order to compute. Previously used
712721 # criterion from Wiscombe, Applied Optics 19, 1505 (1980):
@@ -716,6 +725,7 @@ def _nstop(x):
716725 # (J. R. Allardice and E. C. Le Ru, Applied Optics, Vol. 53, No. 31 (2014).
717726 return (np .round (np .absolute (x + 11 * x ** (1. / 3. )+ 1 ))).squeeze ().astype ('int' )
718727
728+
719729def _asymmetry_parameter (al , bl ):
720730 '''
721731 Inputs: an, bn coefficient arrays from Mie solution
@@ -733,6 +743,7 @@ def _asymmetry_parameter(al, bl):
733743 np .real (al * np .conj (bl ))).sum (axis = - 1 )
734744 return selfterm + crossterm
735745
746+
736747def _cross_sections (al , bl ):
737748 '''
738749 Calculates scattering and extinction cross sections
@@ -760,6 +771,7 @@ def _cross_sections(al, bl):
760771
761772 return cscat , cext , cback
762773
774+
763775def _cross_sections_complex_medium_fu (al , bl , cl , dl , radius , n_particle ,
764776 n_medium , x_scatterer , x_medium ,
765777 wavelen ):
@@ -797,7 +809,7 @@ def _cross_sections_complex_medium_fu(al, bl, cl, dl, radius, n_particle,
797809 prefactor1 = eta ** 2 * wavelen / (2 * np .pi * radius ** 2 * n_medium .real *
798810 (1 + (eta - 1 )* np .exp (eta )))
799811
800- lmax = np . atleast_1d ( al ) .shape [- 1 ]
812+ lmax = al .shape [- 1 ]
801813 l = np .arange (lmax ) + 1
802814 prefactor2 = (2. * l + 1. )[np .newaxis , ...]
803815
@@ -833,6 +845,7 @@ def _cross_sections_complex_medium_fu(al, bl, cl, dl, radius, n_particle,
833845
834846 return (cscat , cabs , cext )
835847
848+
836849def _cross_sections_complex_medium_sudiarta (al , bl , x , radius ):
837850 '''
838851 Calculates dimensional scattering, absorption, and extinction cross
@@ -852,13 +865,13 @@ def _cross_sections_complex_medium_sudiarta(al, bl, x, radius):
852865 # if multilayer, use outermost radius and size parameter corresponding to
853866 # outermost radius
854867 radius = np .array (radius .magnitude ).max () * radius .units
855- x = np . array ( x ) .max (axis = - 1 )
868+ x = x .max (axis = - 1 )
856869 k = x / radius
857870
858871 # add newaxis corresponding to order (l)
859872 x = x [..., np .newaxis ]
860873
861- lmax = np . atleast_1d ( al ) .shape [- 1 ]
874+ lmax = al .shape [- 1 ]
862875 l = np .arange (lmax ) + 1
863876 prefactor = (2. * l + 1. )[np .newaxis , ...]
864877
@@ -975,7 +988,7 @@ def _scat_fields_complex_medium(m, x, thetas, kd, near_field=False):
975988 in an absorbing medium". Applied Optics, 40, 9 (2001).
976989 '''
977990 # calculate mie coefficients
978- nstop = _nstop (np . array ( x ) .max ())
991+ nstop = _nstop (x .max ())
979992 n = np .arange (nstop )+ 1.
980993
981994 an , bn = _scatcoeffs (m , x , nstop )
@@ -1058,6 +1071,7 @@ def _scat_fields_complex_medium(m, x, thetas, kd, near_field=False):
10581071
10591072 return Es_theta , Es_phi , Hs_theta , Hs_phi
10601073
1074+
10611075def diff_scat_intensity_complex_medium (m , x , thetas , kd , phis = None ,
10621076 cartesian = False , near_field = False ,
10631077 incident_vector = None ):
@@ -1229,6 +1243,7 @@ def diff_scat_intensity_complex_medium(m, x, thetas, kd, phis=None,
12291243 # functions)
12301244 return np .array ([I_1 .real , I_2 .real ])* np .abs (kd )** 2
12311245
1246+
12321247def integrate_intensity_complex_medium (dscat , thetas , kd ,
12331248 phi_min = 0.0 ,
12341249 phi_max = 2 * np .pi ,
@@ -1369,6 +1384,7 @@ def integrate_intensity_complex_medium(dscat, thetas, kd,
13691384 (sigma_2 * factor ), (dsigma_1 * factor .reshape (kd_shape )/ 2 ),
13701385 (dsigma_2 * factor .reshape (kd_shape )/ 2 ))
13711386
1387+
13721388def diff_abs_intensity_complex_medium (m , x , thetas , ktd ):
13731389 '''
13741390 Calculates the differential absorbed intensity as a function of scattering
@@ -1408,7 +1424,7 @@ def diff_abs_intensity_complex_medium(m, x, thetas, ktd):
14081424
14091425 '''
14101426 # calculate mie coefficients
1411- nstop = _nstop (np . array ( x ) .max ())
1427+ nstop = _nstop (x .max ())
14121428 n = np .arange (nstop )+ 1.
14131429 cn , dn = _internal_coeffs (m , x , nstop )
14141430
@@ -1455,6 +1471,7 @@ def diff_abs_intensity_complex_medium(m, x, thetas, ktd):
14551471
14561472 return I_par .real , I_perp .real
14571473
1474+
14581475def amplitude_scattering_matrix (m , x , thetas ,
14591476 cartesian = False ,
14601477 phis = None ):
@@ -1523,7 +1540,7 @@ def amplitude_scattering_matrix(m, x, thetas,
15231540 and theta. Shapes of all arrays are (num_values, num_theta, [num_phi])
15241541 """
15251542 # calculate n-array
1526- nstop = _nstop (np . array ( x ) .max ())
1543+ nstop = _nstop (x .max ())
15271544 n = np .arange (nstop )+ 1.
15281545 prefactor = (2 * n + 1 )/ (n * (n + 1 ))
15291546
@@ -1696,7 +1713,7 @@ def _amplitude_scattering_matrix_RG(prefactor, x, thetas):
16961713 """Amplitude scattering matrix from Rayleigh-Gans approximation
16971714
16981715 """
1699- if np . atleast_2d ( x ) .shape [- 1 ] > 1 :
1716+ if x .shape [- 1 ] > 1 :
17001717 raise ValueError ("Rayleigh-Gans approximation cannot be used for "
17011718 "layered spheres" )
17021719
0 commit comments