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