AeroViz 0.1.3__py3-none-any.whl → 0.1.3b0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of AeroViz might be problematic. Click here for more details.

Files changed (107) hide show
  1. AeroViz/__init__.py +4 -4
  2. AeroViz/dataProcess/Chemistry/__init__.py +38 -38
  3. AeroViz/dataProcess/Chemistry/_calculate.py +15 -15
  4. AeroViz/dataProcess/Chemistry/_isoropia.py +69 -68
  5. AeroViz/dataProcess/Chemistry/_mass_volume.py +158 -158
  6. AeroViz/dataProcess/Chemistry/_ocec.py +109 -109
  7. AeroViz/dataProcess/Chemistry/_partition.py +19 -18
  8. AeroViz/dataProcess/Chemistry/_teom.py +8 -11
  9. AeroViz/dataProcess/Optical/_IMPROVE.py +40 -39
  10. AeroViz/dataProcess/Optical/__init__.py +35 -35
  11. AeroViz/dataProcess/Optical/_absorption.py +35 -35
  12. AeroViz/dataProcess/Optical/_extinction.py +25 -24
  13. AeroViz/dataProcess/Optical/_mie.py +5 -6
  14. AeroViz/dataProcess/Optical/_mie_sd.py +89 -90
  15. AeroViz/dataProcess/Optical/_scattering.py +16 -16
  16. AeroViz/dataProcess/SizeDistr/__init__.py +37 -37
  17. AeroViz/dataProcess/SizeDistr/__merge.py +159 -158
  18. AeroViz/dataProcess/SizeDistr/_merge.py +155 -154
  19. AeroViz/dataProcess/SizeDistr/_merge_v1.py +162 -161
  20. AeroViz/dataProcess/SizeDistr/_merge_v2.py +153 -152
  21. AeroViz/dataProcess/SizeDistr/_merge_v3.py +326 -326
  22. AeroViz/dataProcess/SizeDistr/_merge_v4.py +272 -274
  23. AeroViz/dataProcess/SizeDistr/_size_distr.py +51 -51
  24. AeroViz/dataProcess/VOC/__init__.py +7 -7
  25. AeroViz/dataProcess/VOC/_potential_par.py +53 -55
  26. AeroViz/dataProcess/__init__.py +4 -4
  27. AeroViz/dataProcess/core/__init__.py +59 -58
  28. AeroViz/plot/__init__.py +6 -1
  29. AeroViz/plot/bar.py +126 -0
  30. AeroViz/plot/box.py +68 -0
  31. AeroViz/plot/distribution/distribution.py +421 -427
  32. AeroViz/plot/meteorology/meteorology.py +240 -292
  33. AeroViz/plot/optical/__init__.py +0 -1
  34. AeroViz/plot/optical/optical.py +230 -230
  35. AeroViz/plot/pie.py +198 -0
  36. AeroViz/plot/regression.py +210 -0
  37. AeroViz/plot/scatter.py +99 -0
  38. AeroViz/plot/templates/__init__.py +0 -3
  39. AeroViz/plot/templates/contour.py +25 -25
  40. AeroViz/plot/templates/corr_matrix.py +86 -93
  41. AeroViz/plot/templates/diurnal_pattern.py +24 -24
  42. AeroViz/plot/templates/koschmieder.py +106 -106
  43. AeroViz/plot/templates/metal_heatmap.py +34 -34
  44. AeroViz/plot/timeseries/timeseries.py +53 -60
  45. AeroViz/plot/utils/__init__.py +2 -1
  46. AeroViz/plot/utils/_color.py +57 -57
  47. AeroViz/plot/utils/_unit.py +48 -48
  48. AeroViz/plot/utils/plt_utils.py +92 -0
  49. AeroViz/plot/utils/sklearn_utils.py +49 -0
  50. AeroViz/plot/violin.py +79 -0
  51. AeroViz/process/__init__.py +15 -15
  52. AeroViz/process/core/DataProc.py +9 -9
  53. AeroViz/process/core/SizeDist.py +81 -81
  54. AeroViz/process/method/PyMieScatt_update.py +488 -488
  55. AeroViz/process/method/mie_theory.py +231 -229
  56. AeroViz/process/method/prop.py +40 -40
  57. AeroViz/process/script/AbstractDistCalc.py +103 -103
  58. AeroViz/process/script/Chemical.py +166 -166
  59. AeroViz/process/script/IMPACT.py +40 -40
  60. AeroViz/process/script/IMPROVE.py +152 -152
  61. AeroViz/process/script/Others.py +45 -45
  62. AeroViz/process/script/PSD.py +26 -26
  63. AeroViz/process/script/PSD_dry.py +69 -70
  64. AeroViz/process/script/retrieve_RI.py +50 -51
  65. AeroViz/rawDataReader/__init__.py +57 -57
  66. AeroViz/rawDataReader/core/__init__.py +328 -326
  67. AeroViz/rawDataReader/script/AE33.py +18 -18
  68. AeroViz/rawDataReader/script/AE43.py +20 -20
  69. AeroViz/rawDataReader/script/APS_3321.py +30 -30
  70. AeroViz/rawDataReader/script/Aurora.py +23 -23
  71. AeroViz/rawDataReader/script/BC1054.py +40 -40
  72. AeroViz/rawDataReader/script/EPA_vertical.py +9 -9
  73. AeroViz/rawDataReader/script/GRIMM.py +21 -21
  74. AeroViz/rawDataReader/script/IGAC_TH.py +67 -67
  75. AeroViz/rawDataReader/script/IGAC_ZM.py +59 -59
  76. AeroViz/rawDataReader/script/MA350.py +39 -39
  77. AeroViz/rawDataReader/script/NEPH.py +74 -74
  78. AeroViz/rawDataReader/script/OCEC_LCRES.py +21 -21
  79. AeroViz/rawDataReader/script/OCEC_RES.py +16 -16
  80. AeroViz/rawDataReader/script/SMPS_TH.py +25 -25
  81. AeroViz/rawDataReader/script/SMPS_aim11.py +32 -32
  82. AeroViz/rawDataReader/script/SMPS_genr.py +31 -31
  83. AeroViz/rawDataReader/script/TEOM.py +28 -28
  84. AeroViz/rawDataReader/script/Table.py +12 -12
  85. AeroViz/rawDataReader/script/VOC_TH.py +16 -16
  86. AeroViz/rawDataReader/script/VOC_ZM.py +28 -28
  87. AeroViz/rawDataReader/script/__init__.py +20 -20
  88. AeroViz/rawDataReader/utils/config.py +161 -161
  89. AeroViz/tools/database.py +65 -65
  90. AeroViz/tools/dataclassifier.py +106 -106
  91. AeroViz/tools/dataprinter.py +51 -51
  92. AeroViz/tools/datareader.py +38 -38
  93. {AeroViz-0.1.3.dist-info → AeroViz-0.1.3b0.dist-info}/METADATA +5 -4
  94. AeroViz-0.1.3b0.dist-info/RECORD +110 -0
  95. AeroViz/config/__init__.py +0 -0
  96. AeroViz/plot/improve/__init__.py +0 -1
  97. AeroViz/plot/improve/improve.py +0 -240
  98. AeroViz/plot/optical/aethalometer.py +0 -77
  99. AeroViz/plot/templates/event_evolution.py +0 -65
  100. AeroViz/plot/templates/regression.py +0 -256
  101. AeroViz/plot/templates/scatter.py +0 -130
  102. AeroViz/plot/templates/templates.py +0 -398
  103. AeroViz/plot/utils/_decorator.py +0 -74
  104. AeroViz-0.1.3.dist-info/RECORD +0 -111
  105. {AeroViz-0.1.3.dist-info → AeroViz-0.1.3b0.dist-info}/LICENSE +0 -0
  106. {AeroViz-0.1.3.dist-info → AeroViz-0.1.3b0.dist-info}/WHEEL +0 -0
  107. {AeroViz-0.1.3.dist-info → AeroViz-0.1.3b0.dist-info}/top_level.txt +0 -0
@@ -1,567 +1,567 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # http://pymiescatt.readthedocs.io/en/latest/forward.html
3
+ import warnings
4
+
3
5
  import numpy as np
4
6
  from scipy.special import jv, yv
5
- from scipy.integrate import trapezoid
6
- import warnings
7
7
 
8
8
 
9
9
  def coerceDType(d):
10
- if type(d) is not np.ndarray:
11
- return np.array(d)
12
- else:
13
- return d
10
+ if type(d) is not np.ndarray:
11
+ return np.array(d)
12
+ else:
13
+ return d
14
14
 
15
15
 
16
16
  def MieQ(m, wavelength, diameter, nMedium=1.0, asDict=False, asCrossSection=False):
17
- # http://pymiescatt.readthedocs.io/en/latest/forward.html#MieQ
18
- nMedium = nMedium.real
19
- m /= nMedium
20
- wavelength /= nMedium
21
- x = np.pi * diameter / wavelength
22
- if x == 0:
23
- return 0, 0, 0, 1.5, 0, 0, 0
24
- elif x <= 0.05:
25
- return RayleighMieQ(m, wavelength, diameter, nMedium, asDict)
26
- elif x > 0.05:
27
- nmax = np.round(2 + x + 4 * (x ** (1 / 3)))
28
- n = np.arange(1, nmax + 1)
29
- n1 = 2 * n + 1
30
- n2 = n * (n + 2) / (n + 1)
31
- n3 = n1 / (n * (n + 1))
32
- x2 = x ** 2
33
-
34
- an, bn = Mie_ab(m, x)
35
-
36
- qext = (2 / x2) * np.sum(n1 * (an.real + bn.real))
37
- qsca = (2 / x2) * np.sum(n1 * (an.real ** 2 + an.imag ** 2 + bn.real ** 2 + bn.imag ** 2))
38
- qabs = qext - qsca
39
-
40
- g1 = [an.real[1:int(nmax)],
41
- an.imag[1:int(nmax)],
42
- bn.real[1:int(nmax)],
43
- bn.imag[1:int(nmax)]]
44
- g1 = [np.append(x, 0.0) for x in g1]
45
- g = (4 / (qsca * x2)) * np.sum(
46
- (n2 * (an.real * g1[0] + an.imag * g1[1] + bn.real * g1[2] + bn.imag * g1[3])) + (
47
- n3 * (an.real * bn.real + an.imag * bn.imag)))
48
-
49
- qpr = qext - qsca * g
50
- qback = (1 / x2) * (np.abs(np.sum(n1 * ((-1) ** n) * (an - bn))) ** 2)
51
- qratio = qback / qsca
52
- if asCrossSection:
53
- css = np.pi * (diameter / 2) ** 2
54
- cext = css * qext
55
- csca = css * qsca
56
- cabs = css * qabs
57
- cpr = css * qpr
58
- cback = css * qback
59
- cratio = css * qratio
60
- if asDict:
61
- return dict(Cext=cext, Csca=csca, Cabs=cabs, g=g, Cpr=cpr, Cback=cback, Cratio=cratio)
62
- else:
63
- return cext, csca, cabs, g, cpr, cback, cratio
64
- else:
65
- if asDict:
66
- return dict(Qext=qext, Qsca=qsca, Qabs=qabs, g=g, Qpr=qpr, Qback=qback, Qratio=qratio)
67
- else:
68
- return qext, qsca, qabs, g, qpr, qback, qratio
17
+ # http://pymiescatt.readthedocs.io/en/latest/forward.html#MieQ
18
+ nMedium = nMedium.real
19
+ m /= nMedium
20
+ wavelength /= nMedium
21
+ x = np.pi * diameter / wavelength
22
+ if x == 0:
23
+ return 0, 0, 0, 1.5, 0, 0, 0
24
+ elif x <= 0.05:
25
+ return RayleighMieQ(m, wavelength, diameter, nMedium, asDict)
26
+ elif x > 0.05:
27
+ nmax = np.round(2 + x + 4 * (x ** (1 / 3)))
28
+ n = np.arange(1, nmax + 1)
29
+ n1 = 2 * n + 1
30
+ n2 = n * (n + 2) / (n + 1)
31
+ n3 = n1 / (n * (n + 1))
32
+ x2 = x ** 2
33
+
34
+ an, bn = Mie_ab(m, x)
35
+
36
+ qext = (2 / x2) * np.sum(n1 * (an.real + bn.real))
37
+ qsca = (2 / x2) * np.sum(n1 * (an.real ** 2 + an.imag ** 2 + bn.real ** 2 + bn.imag ** 2))
38
+ qabs = qext - qsca
39
+
40
+ g1 = [an.real[1:int(nmax)],
41
+ an.imag[1:int(nmax)],
42
+ bn.real[1:int(nmax)],
43
+ bn.imag[1:int(nmax)]]
44
+ g1 = [np.append(x, 0.0) for x in g1]
45
+ g = (4 / (qsca * x2)) * np.sum(
46
+ (n2 * (an.real * g1[0] + an.imag * g1[1] + bn.real * g1[2] + bn.imag * g1[3])) + (
47
+ n3 * (an.real * bn.real + an.imag * bn.imag)))
48
+
49
+ qpr = qext - qsca * g
50
+ qback = (1 / x2) * (np.abs(np.sum(n1 * ((-1) ** n) * (an - bn))) ** 2)
51
+ qratio = qback / qsca
52
+ if asCrossSection:
53
+ css = np.pi * (diameter / 2) ** 2
54
+ cext = css * qext
55
+ csca = css * qsca
56
+ cabs = css * qabs
57
+ cpr = css * qpr
58
+ cback = css * qback
59
+ cratio = css * qratio
60
+ if asDict:
61
+ return dict(Cext=cext, Csca=csca, Cabs=cabs, g=g, Cpr=cpr, Cback=cback, Cratio=cratio)
62
+ else:
63
+ return cext, csca, cabs, g, cpr, cback, cratio
64
+ else:
65
+ if asDict:
66
+ return dict(Qext=qext, Qsca=qsca, Qabs=qabs, g=g, Qpr=qpr, Qback=qback, Qratio=qratio)
67
+ else:
68
+ return qext, qsca, qabs, g, qpr, qback, qratio
69
69
 
70
70
 
71
71
  def Mie_ab(m, x):
72
- # http://pymiescatt.readthedocs.io/en/latest/forward.html#Mie_ab
73
- mx = m * x
74
- nmax = np.round(2 + x + 4 * (x ** (1 / 3)))
75
- nmx = np.round(max(nmax, np.abs(mx)) + 16)
76
- n = np.arange(1, nmax + 1) #
77
- nu = n + 0.5 #
72
+ # http://pymiescatt.readthedocs.io/en/latest/forward.html#Mie_ab
73
+ mx = m * x
74
+ nmax = np.round(2 + x + 4 * (x ** (1 / 3)))
75
+ nmx = np.round(max(nmax, np.abs(mx)) + 16)
76
+ n = np.arange(1, nmax + 1) #
77
+ nu = n + 0.5 #
78
78
 
79
- sx = np.sqrt(0.5 * np.pi * x)
79
+ sx = np.sqrt(0.5 * np.pi * x)
80
80
 
81
- px = sx * jv(nu, x) #
82
- p1x = np.append(np.sin(x), px[0:int(nmax) - 1]) #
81
+ px = sx * jv(nu, x) #
82
+ p1x = np.append(np.sin(x), px[0:int(nmax) - 1]) #
83
83
 
84
- chx = -sx * yv(nu, x) #
85
- ch1x = np.append(np.cos(x), chx[0:int(nmax) - 1]) #
84
+ chx = -sx * yv(nu, x) #
85
+ ch1x = np.append(np.cos(x), chx[0:int(nmax) - 1]) #
86
86
 
87
- gsx = px - (0 + 1j) * chx #
88
- gs1x = p1x - (0 + 1j) * ch1x #
87
+ gsx = px - (0 + 1j) * chx #
88
+ gs1x = p1x - (0 + 1j) * ch1x #
89
89
 
90
- # B&H Equation 4.89
91
- Dn = np.zeros(int(nmx), dtype=complex)
92
- for i in range(int(nmx) - 1, 1, -1):
93
- Dn[i - 1] = (i / mx) - (1 / (Dn[i] + i / mx))
90
+ # B&H Equation 4.89
91
+ Dn = np.zeros(int(nmx), dtype=complex)
92
+ for i in range(int(nmx) - 1, 1, -1):
93
+ Dn[i - 1] = (i / mx) - (1 / (Dn[i] + i / mx))
94
94
 
95
- D = Dn[1:int(nmax) + 1] # Dn(mx), drop terms beyond nMax
96
- da = D / m + n / x
97
- db = m * D + n / x
95
+ D = Dn[1:int(nmax) + 1] # Dn(mx), drop terms beyond nMax
96
+ da = D / m + n / x
97
+ db = m * D + n / x
98
98
 
99
- an = (da * px - p1x) / (da * gsx - gs1x)
100
- bn = (db * px - p1x) / (db * gsx - gs1x)
99
+ an = (da * px - p1x) / (da * gsx - gs1x)
100
+ bn = (db * px - p1x) / (db * gsx - gs1x)
101
101
 
102
- return an, bn
102
+ return an, bn
103
103
 
104
104
 
105
105
  def Mie_cd(m, x):
106
- # http://pymiescatt.readthedocs.io/en/latest/forward.html#Mie_cd
107
- mx = m * x
108
- nmax = np.round(2 + x + 4 * (x ** (1 / 3)))
109
- nmx = np.round(max(nmax, np.abs(mx)) + 16)
110
- n = np.arange(1, int(nmax) + 1)
111
- nu = n + 0.5
106
+ # http://pymiescatt.readthedocs.io/en/latest/forward.html#Mie_cd
107
+ mx = m * x
108
+ nmax = np.round(2 + x + 4 * (x ** (1 / 3)))
109
+ nmx = np.round(max(nmax, np.abs(mx)) + 16)
110
+ n = np.arange(1, int(nmax) + 1)
111
+ nu = n + 0.5
112
112
 
113
- cnx = np.zeros(int(nmx), dtype=complex)
113
+ cnx = np.zeros(int(nmx), dtype=complex)
114
114
 
115
- for j in np.arange(nmx, 1, -1):
116
- cnx[int(j) - 2] = j - mx * mx / (cnx[int(j) - 1] + j)
115
+ for j in np.arange(nmx, 1, -1):
116
+ cnx[int(j) - 2] = j - mx * mx / (cnx[int(j) - 1] + j)
117
117
 
118
- cnn = np.array([cnx[b] for b in range(0, len(n))])
118
+ cnn = np.array([cnx[b] for b in range(0, len(n))])
119
119
 
120
- jnx = np.sqrt(np.pi / (2 * x)) * jv(nu, x)
121
- jnmx = np.sqrt((2 * mx) / np.pi) / jv(nu, mx)
120
+ jnx = np.sqrt(np.pi / (2 * x)) * jv(nu, x)
121
+ jnmx = np.sqrt((2 * mx) / np.pi) / jv(nu, mx)
122
122
 
123
- yx = np.sqrt(np.pi / (2 * x)) * yv(nu, x)
124
- hx = jnx + (1.0j) * yx
123
+ yx = np.sqrt(np.pi / (2 * x)) * yv(nu, x)
124
+ hx = jnx + (1.0j) * yx
125
125
 
126
- b1x = np.append(np.sin(x) / x, jnx[0:int(nmax) - 1])
127
- y1x = np.append(-np.cos(x) / x, yx[0:int(nmax) - 1])
126
+ b1x = np.append(np.sin(x) / x, jnx[0:int(nmax) - 1])
127
+ y1x = np.append(-np.cos(x) / x, yx[0:int(nmax) - 1])
128
128
 
129
- hn1x = b1x + (1.0j) * y1x
130
- ax = x * b1x - n * jnx
131
- ahx = x * hn1x - n * hx
129
+ hn1x = b1x + (1.0j) * y1x
130
+ ax = x * b1x - n * jnx
131
+ ahx = x * hn1x - n * hx
132
132
 
133
- numerator = jnx * ahx - hx * ax
134
- c_denominator = ahx - hx * cnn
135
- d_denominator = m * m * ahx - hx * cnn
133
+ numerator = jnx * ahx - hx * ax
134
+ c_denominator = ahx - hx * cnn
135
+ d_denominator = m * m * ahx - hx * cnn
136
136
 
137
- cn = jnmx * numerator / c_denominator
138
- dn = jnmx * m * numerator / d_denominator
137
+ cn = jnmx * numerator / c_denominator
138
+ dn = jnmx * m * numerator / d_denominator
139
139
 
140
- return cn, dn
140
+ return cn, dn
141
141
 
142
142
 
143
143
  def RayleighMieQ(m, wavelength, diameter, nMedium=1.0, asDict=False, asCrossSection=False):
144
- # http://pymiescatt.readthedocs.io/en/latest/forward.html#RayleighMieQ
145
- nMedium = nMedium.real
146
- m /= nMedium
147
- wavelength /= nMedium
148
- x = np.pi * diameter / wavelength
149
- if x == 0:
150
- return 0, 0, 0, 1.5, 0, 0, 0
151
- elif x > 0:
152
- LL = (m ** 2 - 1) / (m ** 2 + 2) # Lorentz-Lorenz term
153
- LLabsSq = np.abs(LL) ** 2
154
- qsca = 8 * LLabsSq * (x ** 4) / 3 # B&H eq 5.8
155
- qabs = 4 * x * LL.imag # B&H eq. 5.11
156
- qext = qsca + qabs
157
- qback = 1.5 * qsca # B&H eq. 5.9
158
- qratio = 1.5
159
- g = 0
160
- qpr = qext
161
- if asCrossSection:
162
- css = np.pi * (diameter / 2) ** 2
163
- cext = css * qext
164
- csca = css * qsca
165
- cabs = css * qabs
166
- cpr = css * qpr
167
- cback = css * qback
168
- cratio = css * qratio
169
- if asDict:
170
- return dict(Cext=cext, Csca=csca, Cabs=cabs, g=g, Cpr=cpr, Cback=cback, Cratio=cratio)
171
- else:
172
- return cext, csca, cabs, g, cpr, cback, cratio
173
- else:
174
- if asDict:
175
- return dict(Qext=qext, Qsca=qsca, Qabs=qabs, g=g, Qpr=qpr, Qback=qback, Qratio=qratio)
176
- else:
177
- return qext, qsca, qabs, g, qpr, qback, qratio
144
+ # http://pymiescatt.readthedocs.io/en/latest/forward.html#RayleighMieQ
145
+ nMedium = nMedium.real
146
+ m /= nMedium
147
+ wavelength /= nMedium
148
+ x = np.pi * diameter / wavelength
149
+ if x == 0:
150
+ return 0, 0, 0, 1.5, 0, 0, 0
151
+ elif x > 0:
152
+ LL = (m ** 2 - 1) / (m ** 2 + 2) # Lorentz-Lorenz term
153
+ LLabsSq = np.abs(LL) ** 2
154
+ qsca = 8 * LLabsSq * (x ** 4) / 3 # B&H eq 5.8
155
+ qabs = 4 * x * LL.imag # B&H eq. 5.11
156
+ qext = qsca + qabs
157
+ qback = 1.5 * qsca # B&H eq. 5.9
158
+ qratio = 1.5
159
+ g = 0
160
+ qpr = qext
161
+ if asCrossSection:
162
+ css = np.pi * (diameter / 2) ** 2
163
+ cext = css * qext
164
+ csca = css * qsca
165
+ cabs = css * qabs
166
+ cpr = css * qpr
167
+ cback = css * qback
168
+ cratio = css * qratio
169
+ if asDict:
170
+ return dict(Cext=cext, Csca=csca, Cabs=cabs, g=g, Cpr=cpr, Cback=cback, Cratio=cratio)
171
+ else:
172
+ return cext, csca, cabs, g, cpr, cback, cratio
173
+ else:
174
+ if asDict:
175
+ return dict(Qext=qext, Qsca=qsca, Qabs=qabs, g=g, Qpr=qpr, Qback=qback, Qratio=qratio)
176
+ else:
177
+ return qext, qsca, qabs, g, qpr, qback, qratio
178
178
 
179
179
 
180
180
  def AutoMieQ(m, wavelength, diameter, nMedium=1.0, crossover=0.01, asDict=False, asCrossSection=False):
181
- # http://pymiescatt.readthedocs.io/en/latest/forward.html#AutoMieQ
182
- nMedium = nMedium.real
183
- m_eff = m / nMedium
184
- wavelength_eff = wavelength / nMedium
185
- x_eff = np.pi * diameter / wavelength_eff
186
- if x_eff == 0:
187
- return 0, 0, 0, 1.5, 0, 0, 0
188
- elif x_eff < crossover:
189
- return RayleighMieQ(m, wavelength, diameter, nMedium, asDict=asDict, asCrossSection=asCrossSection)
190
- else:
191
- return MieQ(m, wavelength, diameter, nMedium, asDict=asDict, asCrossSection=asCrossSection)
181
+ # http://pymiescatt.readthedocs.io/en/latest/forward.html#AutoMieQ
182
+ nMedium = nMedium.real
183
+ m_eff = m / nMedium
184
+ wavelength_eff = wavelength / nMedium
185
+ x_eff = np.pi * diameter / wavelength_eff
186
+ if x_eff == 0:
187
+ return 0, 0, 0, 1.5, 0, 0, 0
188
+ elif x_eff < crossover:
189
+ return RayleighMieQ(m, wavelength, diameter, nMedium, asDict=asDict, asCrossSection=asCrossSection)
190
+ else:
191
+ return MieQ(m, wavelength, diameter, nMedium, asDict=asDict, asCrossSection=asCrossSection)
192
192
 
193
193
 
194
194
  def LowFrequencyMieQ(m, wavelength, diameter, nMedium=1.0, asDict=False, asCrossSection=False):
195
- # http://pymiescatt.readthedocs.io/en/latest/forward.html#LowFrequencyMieQ
196
- nMedium = nMedium.real
197
- m /= nMedium
198
- wavelength /= nMedium
199
- x = np.pi * diameter / wavelength
200
- if x == 0:
201
- return 0, 0, 0, 1.5, 0, 0, 0
202
- elif x > 0:
203
- n = np.arange(1, 3)
204
- n1 = 2 * n + 1
205
- n2 = n * (n + 2) / (n + 1)
206
- n3 = n1 / (n * (n + 1))
207
- x2 = x ** 2
208
-
209
- an, bn = LowFrequencyMie_ab(m, x)
210
-
211
- qext = (2 / x2) * np.sum(n1 * (an.real + bn.real))
212
- qsca = (2 / x2) * np.sum(n1 * (an.real ** 2 + an.imag ** 2 + bn.real ** 2 + bn.imag ** 2))
213
- qabs = qext - qsca
214
-
215
- g1 = [an.real[1:2], an.imag[1:2], bn.real[1:2], bn.imag[1:2]]
216
- g1 = [np.append(x, 0.0) for x in g1]
217
- g = (4 / (qsca * x2)) * np.sum(
218
- (n2 * (an.real * g1[0] + an.imag * g1[1] + bn.real * g1[2] + bn.imag * g1[3])) + (
219
- n3 * (an.real * bn.real + an.imag * bn.imag)))
220
-
221
- qpr = qext - qsca * g
222
- qback = (1 / x2) * (np.abs(np.sum(n1 * ((-1) ** n) * (an - bn))) ** 2)
223
- qratio = qback / qsca
224
-
225
- if asCrossSection:
226
- css = np.pi * (diameter / 2) ** 2
227
- cext = css * qext
228
- csca = css * qsca
229
- cabs = css * qabs
230
- cpr = css * qpr
231
- cback = css * qback
232
- cratio = css * qratio
233
- if asDict:
234
- return dict(Cext=cext, Csca=csca, Cabs=cabs, g=g, Cpr=cpr, Cback=cback, Cratio=cratio)
235
- else:
236
- return cext, csca, cabs, g, cpr, cback, cratio
237
- else:
238
- if asDict:
239
- return dict(Qext=qext, Qsca=qsca, Qabs=qabs, g=g, Qpr=qpr, Qback=qback, Qratio=qratio)
240
- else:
241
- return qext, qsca, qabs, g, qpr, qback, qratio
195
+ # http://pymiescatt.readthedocs.io/en/latest/forward.html#LowFrequencyMieQ
196
+ nMedium = nMedium.real
197
+ m /= nMedium
198
+ wavelength /= nMedium
199
+ x = np.pi * diameter / wavelength
200
+ if x == 0:
201
+ return 0, 0, 0, 1.5, 0, 0, 0
202
+ elif x > 0:
203
+ n = np.arange(1, 3)
204
+ n1 = 2 * n + 1
205
+ n2 = n * (n + 2) / (n + 1)
206
+ n3 = n1 / (n * (n + 1))
207
+ x2 = x ** 2
208
+
209
+ an, bn = LowFrequencyMie_ab(m, x)
210
+
211
+ qext = (2 / x2) * np.sum(n1 * (an.real + bn.real))
212
+ qsca = (2 / x2) * np.sum(n1 * (an.real ** 2 + an.imag ** 2 + bn.real ** 2 + bn.imag ** 2))
213
+ qabs = qext - qsca
214
+
215
+ g1 = [an.real[1:2], an.imag[1:2], bn.real[1:2], bn.imag[1:2]]
216
+ g1 = [np.append(x, 0.0) for x in g1]
217
+ g = (4 / (qsca * x2)) * np.sum(
218
+ (n2 * (an.real * g1[0] + an.imag * g1[1] + bn.real * g1[2] + bn.imag * g1[3])) + (
219
+ n3 * (an.real * bn.real + an.imag * bn.imag)))
220
+
221
+ qpr = qext - qsca * g
222
+ qback = (1 / x2) * (np.abs(np.sum(n1 * ((-1) ** n) * (an - bn))) ** 2)
223
+ qratio = qback / qsca
224
+
225
+ if asCrossSection:
226
+ css = np.pi * (diameter / 2) ** 2
227
+ cext = css * qext
228
+ csca = css * qsca
229
+ cabs = css * qabs
230
+ cpr = css * qpr
231
+ cback = css * qback
232
+ cratio = css * qratio
233
+ if asDict:
234
+ return dict(Cext=cext, Csca=csca, Cabs=cabs, g=g, Cpr=cpr, Cback=cback, Cratio=cratio)
235
+ else:
236
+ return cext, csca, cabs, g, cpr, cback, cratio
237
+ else:
238
+ if asDict:
239
+ return dict(Qext=qext, Qsca=qsca, Qabs=qabs, g=g, Qpr=qpr, Qback=qback, Qratio=qratio)
240
+ else:
241
+ return qext, qsca, qabs, g, qpr, qback, qratio
242
242
 
243
243
 
244
244
  def LowFrequencyMie_ab(m, x):
245
- # http://pymiescatt.readthedocs.io/en/latest/forward.html#LowFrequencyMie_ab
246
- # B&H page 131
247
- m2 = m ** 2
248
- LL = (m ** 2 - 1) / (m ** 2 + 2)
249
- x3 = x ** 3
250
- x5 = x ** 5
251
- x6 = x ** 6
252
-
253
- a1 = (-2j * x3 / 3) * LL - (2j * x5 / 5) * LL * (m2 - 2) / (m2 + 2) + (4 * x6 / 9) * (LL ** 2)
254
- a2 = (-1j * x5 / 15) * (m2 - 1) / (2 * m2 + 3)
255
- b1 = (-1j * x5 / 45) * (m2 - 1)
256
- b2 = 0 + 0j
257
- an = np.append(a1, a2)
258
- bn = np.append(b1, b2)
259
- return an, bn
245
+ # http://pymiescatt.readthedocs.io/en/latest/forward.html#LowFrequencyMie_ab
246
+ # B&H page 131
247
+ m2 = m ** 2
248
+ LL = (m ** 2 - 1) / (m ** 2 + 2)
249
+ x3 = x ** 3
250
+ x5 = x ** 5
251
+ x6 = x ** 6
252
+
253
+ a1 = (-2j * x3 / 3) * LL - (2j * x5 / 5) * LL * (m2 - 2) / (m2 + 2) + (4 * x6 / 9) * (LL ** 2)
254
+ a2 = (-1j * x5 / 15) * (m2 - 1) / (2 * m2 + 3)
255
+ b1 = (-1j * x5 / 45) * (m2 - 1)
256
+ b2 = 0 + 0j
257
+ an = np.append(a1, a2)
258
+ bn = np.append(b1, b2)
259
+ return an, bn
260
260
 
261
261
 
262
262
  def AutoMie_ab(m, x):
263
- if x < 0.5:
264
- return LowFrequencyMie_ab(m, x)
265
- else:
266
- return Mie_ab(m, x)
263
+ if x < 0.5:
264
+ return LowFrequencyMie_ab(m, x)
265
+ else:
266
+ return Mie_ab(m, x)
267
267
 
268
268
 
269
269
  def Mie_SD(m, wavelength, dp, ndp, nMedium=1.0, SMPS=True, interpolate=False, asDict=False):
270
- # http://pymiescatt.readthedocs.io/en/latest/forward.html#Mie_SD
271
- nMedium = nMedium.real
272
- m /= nMedium
273
- wavelength /= nMedium
274
- dp = coerceDType(dp)
275
- ndp = coerceDType(ndp)
276
- _length = np.size(dp)
277
- Q_ext = np.zeros(_length)
278
- Q_sca = np.zeros(_length)
279
- Q_abs = np.zeros(_length)
280
- Q_pr = np.zeros(_length)
281
- Q_back = np.zeros(_length)
282
- Q_ratio = np.zeros(_length)
283
- g = np.zeros(_length)
284
-
285
- # scaling of 1e-6 to cast in units of inverse megameters - see docs
286
- aSDn = np.pi * ((dp / 2) ** 2) * ndp * (1e-6)
287
- # _logdp = np.log10(dp)
288
-
289
- for i in range(_length):
290
- Q_ext[i], Q_sca[i], Q_abs[i], g[i], Q_pr[i], Q_back[i], Q_ratio[i] = AutoMieQ(m, wavelength, dp[i], nMedium)
291
-
292
- if SMPS:
293
- Bext = np.sum(Q_ext * aSDn)
294
- Bsca = np.sum(Q_sca * aSDn)
295
- Babs = Bext - Bsca
296
- Bback = np.sum(Q_back * aSDn)
297
- Bratio = np.sum(Q_ratio * aSDn)
298
- bigG = np.sum(g * Q_sca * aSDn) / np.sum(Q_sca * aSDn)
299
- Bpr = Bext - bigG * Bsca
300
- else:
301
- Bext = np.trapz(Q_ext * aSDn, dp)
302
- Bsca = np.trapz(Q_sca * aSDn, dp)
303
- Babs = Bext - Bsca
304
- Bback = np.trapz(Q_back * aSDn, dp)
305
- Bratio = np.trapz(Q_ratio * aSDn, dp)
306
- bigG = np.trapz(g * Q_sca * aSDn, dp) / np.trapz(Q_sca * aSDn, dp)
307
- Bpr = Bext - bigG * Bsca
308
-
309
- if asDict:
310
- return dict(Bext=Bext, Bsca=Bsca, Babs=Babs, G=bigG, Bpr=Bpr, Bback=Bback, Bratio=Bratio)
311
- else:
312
- return Bext, Bsca, Babs, bigG, Bpr, Bback, Bratio
270
+ # http://pymiescatt.readthedocs.io/en/latest/forward.html#Mie_SD
271
+ nMedium = nMedium.real
272
+ m /= nMedium
273
+ wavelength /= nMedium
274
+ dp = coerceDType(dp)
275
+ ndp = coerceDType(ndp)
276
+ _length = np.size(dp)
277
+ Q_ext = np.zeros(_length)
278
+ Q_sca = np.zeros(_length)
279
+ Q_abs = np.zeros(_length)
280
+ Q_pr = np.zeros(_length)
281
+ Q_back = np.zeros(_length)
282
+ Q_ratio = np.zeros(_length)
283
+ g = np.zeros(_length)
284
+
285
+ # scaling of 1e-6 to cast in units of inverse megameters - see docs
286
+ aSDn = np.pi * ((dp / 2) ** 2) * ndp * (1e-6)
287
+ # _logdp = np.log10(dp)
288
+
289
+ for i in range(_length):
290
+ Q_ext[i], Q_sca[i], Q_abs[i], g[i], Q_pr[i], Q_back[i], Q_ratio[i] = AutoMieQ(m, wavelength, dp[i], nMedium)
291
+
292
+ if SMPS:
293
+ Bext = np.sum(Q_ext * aSDn)
294
+ Bsca = np.sum(Q_sca * aSDn)
295
+ Babs = Bext - Bsca
296
+ Bback = np.sum(Q_back * aSDn)
297
+ Bratio = np.sum(Q_ratio * aSDn)
298
+ bigG = np.sum(g * Q_sca * aSDn) / np.sum(Q_sca * aSDn)
299
+ Bpr = Bext - bigG * Bsca
300
+ else:
301
+ Bext = np.trapz(Q_ext * aSDn, dp)
302
+ Bsca = np.trapz(Q_sca * aSDn, dp)
303
+ Babs = Bext - Bsca
304
+ Bback = np.trapz(Q_back * aSDn, dp)
305
+ Bratio = np.trapz(Q_ratio * aSDn, dp)
306
+ bigG = np.trapz(g * Q_sca * aSDn, dp) / np.trapz(Q_sca * aSDn, dp)
307
+ Bpr = Bext - bigG * Bsca
308
+
309
+ if asDict:
310
+ return dict(Bext=Bext, Bsca=Bsca, Babs=Babs, G=bigG, Bpr=Bpr, Bback=Bback, Bratio=Bratio)
311
+ else:
312
+ return Bext, Bsca, Babs, bigG, Bpr, Bback, Bratio
313
313
 
314
314
 
315
315
  def ScatteringFunction(m, wavelength, diameter, nMedium=1.0, minAngle=0, maxAngle=180, angularResolution=0.5,
316
- space='theta', angleMeasure='radians', normalization=None):
317
- # http://pymiescatt.readthedocs.io/en/latest/forward.html#ScatteringFunction
318
- nMedium = nMedium.real
319
- m /= nMedium
320
- wavelength /= nMedium
321
- x = np.pi * diameter / wavelength
322
-
323
- _steps = int(1 + (maxAngle - minAngle) / angularResolution) # default 361
324
-
325
- if angleMeasure in ['radians', 'RADIANS', 'rad', 'RAD']:
326
- adjust = np.pi / 180
327
- elif angleMeasure in ['gradians', 'GRADIANS', 'grad', 'GRAD']:
328
- adjust = 1 / 200
329
- else:
330
- adjust = 1
331
-
332
- if space in ['q', 'qspace', 'QSPACE', 'qSpace']:
333
- # _steps *= 10
334
- _steps += 1
335
- if minAngle == 0:
336
- minAngle = 1e-5
337
- # measure = np.logspace(np.log10(minAngle),np.log10(maxAngle),_steps)*np.pi/180
338
- measure = np.linspace(minAngle, maxAngle, _steps) * np.pi / 180
339
- _q = True
340
- else:
341
- measure = np.linspace(minAngle, maxAngle, _steps) * adjust
342
- _q = False
343
- if x == 0:
344
- return measure, 0, 0, 0
345
- _measure = np.linspace(minAngle, maxAngle, _steps) * np.pi / 180
346
- SL = np.zeros(_steps)
347
- SR = np.zeros(_steps)
348
- SU = np.zeros(_steps)
349
- for j in range(_steps):
350
- u = np.cos(_measure[j])
351
- S1, S2 = MieS1S2(m, x, u)
352
- SL[j] = (np.sum(np.conjugate(S1) * S1)).real
353
- SR[j] = (np.sum(np.conjugate(S2) * S2)).real
354
- SU[j] = (SR[j] + SL[j]) / 2
355
- if normalization in ['m', 'M', 'max', 'MAX']:
356
- SL /= np.max(SL)
357
- SR /= np.max(SR)
358
- SU /= np.max(SU)
359
- elif normalization in ['t', 'T', 'total', 'TOTAL']:
360
- SL /= np.trapz(SL, measure)
361
- SR /= np.trapz(SR, measure)
362
- SU /= np.trapz(SU, measure)
363
- if _q:
364
- measure = (4 * np.pi / wavelength) * np.sin(measure / 2) * (diameter / 2)
365
- return measure, SL, SR, SU
316
+ space='theta', angleMeasure='radians', normalization=None):
317
+ # http://pymiescatt.readthedocs.io/en/latest/forward.html#ScatteringFunction
318
+ nMedium = nMedium.real
319
+ m /= nMedium
320
+ wavelength /= nMedium
321
+ x = np.pi * diameter / wavelength
322
+
323
+ _steps = int(1 + (maxAngle - minAngle) / angularResolution) # default 361
324
+
325
+ if angleMeasure in ['radians', 'RADIANS', 'rad', 'RAD']:
326
+ adjust = np.pi / 180
327
+ elif angleMeasure in ['gradians', 'GRADIANS', 'grad', 'GRAD']:
328
+ adjust = 1 / 200
329
+ else:
330
+ adjust = 1
331
+
332
+ if space in ['q', 'qspace', 'QSPACE', 'qSpace']:
333
+ # _steps *= 10
334
+ _steps += 1
335
+ if minAngle == 0:
336
+ minAngle = 1e-5
337
+ # measure = np.logspace(np.log10(minAngle),np.log10(maxAngle),_steps)*np.pi/180
338
+ measure = np.linspace(minAngle, maxAngle, _steps) * np.pi / 180
339
+ _q = True
340
+ else:
341
+ measure = np.linspace(minAngle, maxAngle, _steps) * adjust
342
+ _q = False
343
+ if x == 0:
344
+ return measure, 0, 0, 0
345
+ _measure = np.linspace(minAngle, maxAngle, _steps) * np.pi / 180
346
+ SL = np.zeros(_steps)
347
+ SR = np.zeros(_steps)
348
+ SU = np.zeros(_steps)
349
+ for j in range(_steps):
350
+ u = np.cos(_measure[j])
351
+ S1, S2 = MieS1S2(m, x, u)
352
+ SL[j] = (np.sum(np.conjugate(S1) * S1)).real
353
+ SR[j] = (np.sum(np.conjugate(S2) * S2)).real
354
+ SU[j] = (SR[j] + SL[j]) / 2
355
+ if normalization in ['m', 'M', 'max', 'MAX']:
356
+ SL /= np.max(SL)
357
+ SR /= np.max(SR)
358
+ SU /= np.max(SU)
359
+ elif normalization in ['t', 'T', 'total', 'TOTAL']:
360
+ SL /= np.trapz(SL, measure)
361
+ SR /= np.trapz(SR, measure)
362
+ SU /= np.trapz(SU, measure)
363
+ if _q:
364
+ measure = (4 * np.pi / wavelength) * np.sin(measure / 2) * (diameter / 2)
365
+ return measure, SL, SR, SU
366
366
 
367
367
 
368
368
  def SF_SD(m, wavelength, dp, ndp, nMedium=1.0, minAngle=0, maxAngle=180, angularResolution=0.5, space='theta',
369
- angleMeasure='radians', normalization=None):
370
- # http://pymiescatt.readthedocs.io/en/latest/forward.html#SF_SD
371
- nMedium = nMedium.real
372
- m /= nMedium
373
- wavelength /= nMedium
374
-
375
- _steps = int(1 + (maxAngle - minAngle) / angularResolution)
376
- ndp = coerceDType(ndp)
377
- dp = coerceDType(dp)
378
- SL = np.zeros(_steps)
379
- SR = np.zeros(_steps)
380
- SU = np.zeros(_steps)
381
- kwargs = {'minAngle': minAngle,
382
- 'maxAngle': maxAngle,
383
- 'angularResolution': angularResolution,
384
- 'space': space,
385
- 'normalization': None}
386
- for n, d in zip(ndp, dp):
387
- measure, l, r, u = ScatteringFunction(m, wavelength, d, **kwargs)
388
- SL += l * n
389
- SR += r * n
390
- SU += u * n
391
- if normalization in ['n', 'N', 'number', 'particles']:
392
- _n = np.trapz(ndp, dp)
393
- SL /= _n
394
- SR /= _n
395
- SU /= _n
396
- elif normalization in ['m', 'M', 'max', 'MAX']:
397
- SL /= np.max(SL)
398
- SR /= np.max(SR)
399
- SU /= np.max(SU)
400
- elif normalization in ['t', 'T', 'total', 'TOTAL']:
401
- SL /= np.trapz(SL, measure)
402
- SR /= np.trapz(SR, measure)
403
- SU /= np.trapz(SU, measure)
404
- return measure, SL, SR, SU
369
+ angleMeasure='radians', normalization=None):
370
+ # http://pymiescatt.readthedocs.io/en/latest/forward.html#SF_SD
371
+ nMedium = nMedium.real
372
+ m /= nMedium
373
+ wavelength /= nMedium
374
+
375
+ _steps = int(1 + (maxAngle - minAngle) / angularResolution)
376
+ ndp = coerceDType(ndp)
377
+ dp = coerceDType(dp)
378
+ SL = np.zeros(_steps)
379
+ SR = np.zeros(_steps)
380
+ SU = np.zeros(_steps)
381
+ kwargs = {'minAngle': minAngle,
382
+ 'maxAngle': maxAngle,
383
+ 'angularResolution': angularResolution,
384
+ 'space': space,
385
+ 'normalization': None}
386
+ for n, d in zip(ndp, dp):
387
+ measure, l, r, u = ScatteringFunction(m, wavelength, d, **kwargs)
388
+ SL += l * n
389
+ SR += r * n
390
+ SU += u * n
391
+ if normalization in ['n', 'N', 'number', 'particles']:
392
+ _n = np.trapz(ndp, dp)
393
+ SL /= _n
394
+ SR /= _n
395
+ SU /= _n
396
+ elif normalization in ['m', 'M', 'max', 'MAX']:
397
+ SL /= np.max(SL)
398
+ SR /= np.max(SR)
399
+ SU /= np.max(SU)
400
+ elif normalization in ['t', 'T', 'total', 'TOTAL']:
401
+ SL /= np.trapz(SL, measure)
402
+ SR /= np.trapz(SR, measure)
403
+ SU /= np.trapz(SU, measure)
404
+ return measure, SL, SR, SU
405
405
 
406
406
 
407
407
  def MieS1S2(m, x, mu):
408
- # http://pymiescatt.readthedocs.io/en/latest/forward.html#MieS1S2
409
- nmax = np.round(2 + x + 4 * np.power(x, 1 / 3))
410
- an, bn = AutoMie_ab(m, x)
411
- pin, taun = MiePiTau(mu, nmax)
412
- n = np.arange(1, int(nmax) + 1)
413
- n2 = (2 * n + 1) / (n * (n + 1))
414
- S1 = np.sum(n2[0:len(an)] * (an * pin[0:len(an)] + bn * taun[0:len(bn)]))
415
- S2 = np.sum(n2[0:len(an)] * (an * taun[0:len(an)] + bn * pin[0:len(bn)]))
416
- return S1, S2
408
+ # http://pymiescatt.readthedocs.io/en/latest/forward.html#MieS1S2
409
+ nmax = np.round(2 + x + 4 * np.power(x, 1 / 3))
410
+ an, bn = AutoMie_ab(m, x)
411
+ pin, taun = MiePiTau(mu, nmax)
412
+ n = np.arange(1, int(nmax) + 1)
413
+ n2 = (2 * n + 1) / (n * (n + 1))
414
+ S1 = np.sum(n2[0:len(an)] * (an * pin[0:len(an)] + bn * taun[0:len(bn)]))
415
+ S2 = np.sum(n2[0:len(an)] * (an * taun[0:len(an)] + bn * pin[0:len(bn)]))
416
+ return S1, S2
417
417
 
418
418
 
419
419
  def MiePiTau(mu, nmax):
420
- # http://pymiescatt.readthedocs.io/en/latest/forward.html#MiePiTau
421
- p = np.zeros(int(nmax))
422
- t = np.zeros(int(nmax))
423
- p[0] = 1
424
- p[1] = 3 * mu
425
- t[0] = mu
426
- t[1] = 3.0 * np.cos(2 * np.arccos(mu))
427
- for n in range(2, int(nmax)):
428
- p[n] = ((2 * n + 1) * (mu * p[n - 1]) - (n + 1) * p[n - 2]) / n
429
- t[n] = (n + 1) * mu * p[n] - (n + 2) * p[n - 1]
430
- return p, t
420
+ # http://pymiescatt.readthedocs.io/en/latest/forward.html#MiePiTau
421
+ p = np.zeros(int(nmax))
422
+ t = np.zeros(int(nmax))
423
+ p[0] = 1
424
+ p[1] = 3 * mu
425
+ t[0] = mu
426
+ t[1] = 3.0 * np.cos(2 * np.arccos(mu))
427
+ for n in range(2, int(nmax)):
428
+ p[n] = ((2 * n + 1) * (mu * p[n - 1]) - (n + 1) * p[n - 2]) / n
429
+ t[n] = (n + 1) * mu * p[n] - (n + 2) * p[n - 1]
430
+ return p, t
431
431
 
432
432
 
433
433
  def MatrixElements(m, wavelength, diameter, mu, nMedium=1.0):
434
- # http://pymiescatt.readthedocs.io/en/latest/forward.html#MatrixElements
435
- nMedium = nMedium.real
436
- m /= nMedium
437
- wavelength /= nMedium
438
- x = np.pi * diameter / wavelength
439
- # B&H eqs. 4.77, where mu=cos(theta)
440
- S1, S2 = MieS1S2(m, x, mu)
441
- S11 = 0.5 * (np.abs(S2) ** 2 + np.abs(S1) ** 2)
442
- S12 = 0.5 * (np.abs(S2) ** 2 - np.abs(S1) ** 2)
443
- S33 = 0.5 * (np.conjugate(S2) * S1 + S2 * np.conjugate(S1))
444
- S34 = 0.5j * (S1 * np.conjugate(S2) - S2 * np.conjugate(S1))
445
- return S11, S12, S33, S34
434
+ # http://pymiescatt.readthedocs.io/en/latest/forward.html#MatrixElements
435
+ nMedium = nMedium.real
436
+ m /= nMedium
437
+ wavelength /= nMedium
438
+ x = np.pi * diameter / wavelength
439
+ # B&H eqs. 4.77, where mu=cos(theta)
440
+ S1, S2 = MieS1S2(m, x, mu)
441
+ S11 = 0.5 * (np.abs(S2) ** 2 + np.abs(S1) ** 2)
442
+ S12 = 0.5 * (np.abs(S2) ** 2 - np.abs(S1) ** 2)
443
+ S33 = 0.5 * (np.conjugate(S2) * S1 + S2 * np.conjugate(S1))
444
+ S34 = 0.5j * (S1 * np.conjugate(S2) - S2 * np.conjugate(S1))
445
+ return S11, S12, S33, S34
446
446
 
447
447
 
448
448
  def MieQ_withDiameterRange(m, wavelength, nMedium=1.0, diameterRange=(10, 1000), nd=1000, logD=False):
449
- # http://pymiescatt.readthedocs.io/en/latest/forward.html#MieQ_withDiameterRange
450
- nMedium = nMedium.real
451
- m /= nMedium
452
- wavelength /= nMedium
453
- if logD:
454
- diameters = np.logspace(np.log10(diameterRange[0]), np.log10(diameterRange[1]), nd)
455
- else:
456
- diameters = np.linspace(diameterRange[0], diameterRange[1], nd)
457
- _qD = [AutoMieQ(m, wavelength, diameter) for diameter in diameters]
458
- qext = np.array([q[0] for q in _qD])
459
- qsca = np.array([q[1] for q in _qD])
460
- qabs = np.array([q[2] for q in _qD])
461
- g = np.array([q[3] for q in _qD])
462
- qpr = np.array([q[4] for q in _qD])
463
- qback = np.array([q[5] for q in _qD])
464
- qratio = np.array([q[6] for q in _qD])
465
- return diameters, qext, qsca, qabs, g, qpr, qback, qratio
449
+ # http://pymiescatt.readthedocs.io/en/latest/forward.html#MieQ_withDiameterRange
450
+ nMedium = nMedium.real
451
+ m /= nMedium
452
+ wavelength /= nMedium
453
+ if logD:
454
+ diameters = np.logspace(np.log10(diameterRange[0]), np.log10(diameterRange[1]), nd)
455
+ else:
456
+ diameters = np.linspace(diameterRange[0], diameterRange[1], nd)
457
+ _qD = [AutoMieQ(m, wavelength, diameter) for diameter in diameters]
458
+ qext = np.array([q[0] for q in _qD])
459
+ qsca = np.array([q[1] for q in _qD])
460
+ qabs = np.array([q[2] for q in _qD])
461
+ g = np.array([q[3] for q in _qD])
462
+ qpr = np.array([q[4] for q in _qD])
463
+ qback = np.array([q[5] for q in _qD])
464
+ qratio = np.array([q[6] for q in _qD])
465
+ return diameters, qext, qsca, qabs, g, qpr, qback, qratio
466
466
 
467
467
 
468
468
  def MieQ_withWavelengthRange(m, diameter, nMedium=1.0, wavelengthRange=(100, 1600), nw=1000, logW=False):
469
- # http://pymiescatt.readthedocs.io/en/latest/forward.html#MieQ_withWavelengthRange
470
- nMedium = nMedium.real
471
- _m = m / nMedium
472
- _wavelengthRange = tuple([x / nMedium for x in wavelengthRange])
473
- if type(_m) == complex and len(_wavelengthRange) == 2:
474
- if logW:
475
- wavelengths = np.logspace(np.log10(_wavelengthRange[0]), np.log10(_wavelengthRange[1]), nw)
476
- else:
477
- wavelengths = np.linspace(_wavelengthRange[0], _wavelengthRange[1], nw)
478
- _qD = [AutoMieQ(_m, wavelength, diameter) for wavelength in wavelengths]
479
- elif type(_m) in [np.ndarray, list, tuple] and len(_wavelengthRange) == len(_m):
480
- wavelengths = _wavelengthRange
481
- _qD = [MieQ(emm, wavelength, diameter) for emm, wavelength in zip(_m, wavelengths)]
482
- else:
483
- warnings.warn("Error: the size of the input data is mismatched. Please examine your inputs and try again.")
484
- return
485
-
486
- qext = np.array([q[0] for q in _qD])
487
- qsca = np.array([q[1] for q in _qD])
488
- qabs = np.array([q[2] for q in _qD])
489
- g = np.array([q[3] for q in _qD])
490
- qpr = np.array([q[4] for q in _qD])
491
- qback = np.array([q[5] for q in _qD])
492
- qratio = np.array([q[6] for q in _qD])
493
- return wavelengths, qext, qsca, qabs, g, qpr, qback, qratio
469
+ # http://pymiescatt.readthedocs.io/en/latest/forward.html#MieQ_withWavelengthRange
470
+ nMedium = nMedium.real
471
+ _m = m / nMedium
472
+ _wavelengthRange = tuple([x / nMedium for x in wavelengthRange])
473
+ if type(_m) == complex and len(_wavelengthRange) == 2:
474
+ if logW:
475
+ wavelengths = np.logspace(np.log10(_wavelengthRange[0]), np.log10(_wavelengthRange[1]), nw)
476
+ else:
477
+ wavelengths = np.linspace(_wavelengthRange[0], _wavelengthRange[1], nw)
478
+ _qD = [AutoMieQ(_m, wavelength, diameter) for wavelength in wavelengths]
479
+ elif type(_m) in [np.ndarray, list, tuple] and len(_wavelengthRange) == len(_m):
480
+ wavelengths = _wavelengthRange
481
+ _qD = [MieQ(emm, wavelength, diameter) for emm, wavelength in zip(_m, wavelengths)]
482
+ else:
483
+ warnings.warn("Error: the size of the input data is mismatched. Please examine your inputs and try again.")
484
+ return
485
+
486
+ qext = np.array([q[0] for q in _qD])
487
+ qsca = np.array([q[1] for q in _qD])
488
+ qabs = np.array([q[2] for q in _qD])
489
+ g = np.array([q[3] for q in _qD])
490
+ qpr = np.array([q[4] for q in _qD])
491
+ qback = np.array([q[5] for q in _qD])
492
+ qratio = np.array([q[6] for q in _qD])
493
+ return wavelengths, qext, qsca, qabs, g, qpr, qback, qratio
494
494
 
495
495
 
496
496
  def MieQ_withSizeParameterRange(m, nMedium=1.0, xRange=(1, 10), nx=1000, logX=False):
497
- # http://pymiescatt.readthedocs.io/en/latest/forward.html#MieQ_withSizeParameterRange
498
- nMedium = nMedium.real
499
- m /= nMedium
500
- _xRange = tuple([x * nMedium for x in xRange]) # I think
501
- if logX:
502
- xValues = list(np.logspace(np.log10(_xRange[0]), np.log10(_xRange[1]), nx))
503
- else:
504
- xValues = list(np.linspace(_xRange[0], _xRange[1], nx))
505
- dValues = [1000 * x / np.pi for x in xValues]
506
- _qD = [AutoMieQ(m, 1000, d) for d in dValues]
507
- qext = np.array([q[0] for q in _qD])
508
- qsca = np.array([q[1] for q in _qD])
509
- qabs = np.array([q[2] for q in _qD])
510
- g = np.array([q[3] for q in _qD])
511
- qpr = np.array([q[4] for q in _qD])
512
- qback = np.array([q[5] for q in _qD])
513
- qratio = np.array([q[6] for q in _qD])
514
- return xValues, qext, qsca, qabs, g, qpr, qback, qratio
497
+ # http://pymiescatt.readthedocs.io/en/latest/forward.html#MieQ_withSizeParameterRange
498
+ nMedium = nMedium.real
499
+ m /= nMedium
500
+ _xRange = tuple([x * nMedium for x in xRange]) # I think
501
+ if logX:
502
+ xValues = list(np.logspace(np.log10(_xRange[0]), np.log10(_xRange[1]), nx))
503
+ else:
504
+ xValues = list(np.linspace(_xRange[0], _xRange[1], nx))
505
+ dValues = [1000 * x / np.pi for x in xValues]
506
+ _qD = [AutoMieQ(m, 1000, d) for d in dValues]
507
+ qext = np.array([q[0] for q in _qD])
508
+ qsca = np.array([q[1] for q in _qD])
509
+ qabs = np.array([q[2] for q in _qD])
510
+ g = np.array([q[3] for q in _qD])
511
+ qpr = np.array([q[4] for q in _qD])
512
+ qback = np.array([q[5] for q in _qD])
513
+ qratio = np.array([q[6] for q in _qD])
514
+ return xValues, qext, qsca, qabs, g, qpr, qback, qratio
515
515
 
516
516
 
517
517
  def Mie_Lognormal(m, wavelength, geoStdDev, geoMean, numberOfParticles, nMedium=1.0, numberOfBins=10000, lower=1,
518
- upper=1000, gamma=[1], returnDistribution=False, decomposeMultimodal=False, asDict=False):
519
- # http://pymiescatt.readthedocs.io/en/latest/forward.html#Mie_Lognormal
520
- nMedium = nMedium.real
521
- m /= nMedium
522
- wavelength /= nMedium
523
- ithPart = lambda gammai, dp, dpgi, sigmagi: (gammai / (np.sqrt(2 * np.pi) * np.log(sigmagi) * dp)) * np.exp(
524
- -(np.log(dp) - np.log(dpgi)) ** 2 / (2 * np.log(sigmagi) ** 2))
525
- dp = np.logspace(np.log10(lower), np.log10(upper), numberOfBins)
526
- if all([type(x) in [list, tuple, np.ndarray] for x in [geoStdDev, geoMean]]):
527
- # multimodal
528
- if len(gamma) == 1 and (len(geoStdDev) == len(geoMean) > 1):
529
- # gamma is distributed equally among modes
530
- gamma = [1 for x in geoStdDev]
531
- gamma = [float(x / np.sum(gamma)) for x in gamma]
532
- ndpi = [numberOfParticles * ithPart(g, dp, dpg, sg) for g, dpg, sg in zip(gamma, geoMean, geoStdDev)]
533
- ndp = np.sum(ndpi, axis=0)
534
- elif len(gamma) == len(geoStdDev) == len(geoMean):
535
- # gamma is fully specified for each mode
536
- gamma = [float(x / np.sum(gamma)) for x in gamma]
537
- ndpi = [numberOfParticles * ithPart(g, dp, dpg, sg) for g, dpg, sg in zip(gamma, geoMean, geoStdDev)]
538
- ndp = np.sum(ndpi, axis=0)
539
- else:
540
- # user fucked up
541
- warnings.warn("Not enough parameters to fully specify each mode.")
542
- return None
543
- else:
544
- # unimodal
545
- decomposeMultimodal = False
546
- ndp = numberOfParticles * ithPart(1, dp, geoMean, geoStdDev)
547
- if ndp[-1] > np.max(ndp) / 100 or ndp[0] > np.max(ndp) / 100:
548
- warnings.warn(
549
- "Warning: distribution may not be compact on the specified interval. Consider using a higher upper bound.")
550
- Bext, Bsca, Babs, bigG, Bpr, Bback, Bratio = Mie_SD(m, wavelength, dp, ndp, SMPS=False)
551
- if returnDistribution:
552
- if decomposeMultimodal:
553
- if asDict == True:
554
- return dict(Bext=Bext, Bsca=Bsca, Babs=Babs, bigG=bigG, Bpr=Bpr, Bback=Bback,
555
- Bratio=Bratio), dp, ndp, ndpi
556
- else:
557
- return Bext, Bsca, Babs, bigG, Bpr, Bback, Bratio, dp, ndp, ndpi
558
- else:
559
- if asDict == True:
560
- return dict(Bext=Bext, Bsca=Bsca, Babs=Babs, bigG=bigG, Bpr=Bpr, Bback=Bback, Bratio=Bratio), dp, ndp
561
- else:
562
- return Bext, Bsca, Babs, bigG, Bpr, Bback, Bratio, dp, ndp
563
- else:
564
- if asDict == True:
565
- return dict(Bext=Bext, Bsca=Bsca, Babs=Babs, bigG=bigG, Bpr=Bpr, Bback=Bback, Bratio=Bratio)
566
- else:
567
- return Bext, Bsca, Babs, bigG, Bpr, Bback, Bratio
518
+ upper=1000, gamma=[1], returnDistribution=False, decomposeMultimodal=False, asDict=False):
519
+ # http://pymiescatt.readthedocs.io/en/latest/forward.html#Mie_Lognormal
520
+ nMedium = nMedium.real
521
+ m /= nMedium
522
+ wavelength /= nMedium
523
+ ithPart = lambda gammai, dp, dpgi, sigmagi: (gammai / (np.sqrt(2 * np.pi) * np.log(sigmagi) * dp)) * np.exp(
524
+ -(np.log(dp) - np.log(dpgi)) ** 2 / (2 * np.log(sigmagi) ** 2))
525
+ dp = np.logspace(np.log10(lower), np.log10(upper), numberOfBins)
526
+ if all([type(x) in [list, tuple, np.ndarray] for x in [geoStdDev, geoMean]]):
527
+ # multimodal
528
+ if len(gamma) == 1 and (len(geoStdDev) == len(geoMean) > 1):
529
+ # gamma is distributed equally among modes
530
+ gamma = [1 for x in geoStdDev]
531
+ gamma = [float(x / np.sum(gamma)) for x in gamma]
532
+ ndpi = [numberOfParticles * ithPart(g, dp, dpg, sg) for g, dpg, sg in zip(gamma, geoMean, geoStdDev)]
533
+ ndp = np.sum(ndpi, axis=0)
534
+ elif len(gamma) == len(geoStdDev) == len(geoMean):
535
+ # gamma is fully specified for each mode
536
+ gamma = [float(x / np.sum(gamma)) for x in gamma]
537
+ ndpi = [numberOfParticles * ithPart(g, dp, dpg, sg) for g, dpg, sg in zip(gamma, geoMean, geoStdDev)]
538
+ ndp = np.sum(ndpi, axis=0)
539
+ else:
540
+ # user fucked up
541
+ warnings.warn("Not enough parameters to fully specify each mode.")
542
+ return None
543
+ else:
544
+ # unimodal
545
+ decomposeMultimodal = False
546
+ ndp = numberOfParticles * ithPart(1, dp, geoMean, geoStdDev)
547
+ if ndp[-1] > np.max(ndp) / 100 or ndp[0] > np.max(ndp) / 100:
548
+ warnings.warn(
549
+ "Warning: distribution may not be compact on the specified interval. Consider using a higher upper bound.")
550
+ Bext, Bsca, Babs, bigG, Bpr, Bback, Bratio = Mie_SD(m, wavelength, dp, ndp, SMPS=False)
551
+ if returnDistribution:
552
+ if decomposeMultimodal:
553
+ if asDict == True:
554
+ return dict(Bext=Bext, Bsca=Bsca, Babs=Babs, bigG=bigG, Bpr=Bpr, Bback=Bback,
555
+ Bratio=Bratio), dp, ndp, ndpi
556
+ else:
557
+ return Bext, Bsca, Babs, bigG, Bpr, Bback, Bratio, dp, ndp, ndpi
558
+ else:
559
+ if asDict == True:
560
+ return dict(Bext=Bext, Bsca=Bsca, Babs=Babs, bigG=bigG, Bpr=Bpr, Bback=Bback, Bratio=Bratio), dp, ndp
561
+ else:
562
+ return Bext, Bsca, Babs, bigG, Bpr, Bback, Bratio, dp, ndp
563
+ else:
564
+ if asDict == True:
565
+ return dict(Bext=Bext, Bsca=Bsca, Babs=Babs, bigG=bigG, Bpr=Bpr, Bback=Bback, Bratio=Bratio)
566
+ else:
567
+ return Bext, Bsca, Babs, bigG, Bpr, Bback, Bratio