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,281 @@
1
+ from ..core import Writer, run_process, deprecated
2
+
3
+ __all__ = ['Optical']
4
+
5
+
6
+ class Optical(Writer):
7
+
8
+ @run_process('Optical - scaCoe', 'scaCoe')
9
+ @deprecated(
10
+ "This method is now automatically called during file reading. Please update your code to use the pre-calculated values.")
11
+ def scaCoe(self, df_sca, instru, specified_band):
12
+ from .coefficient import _scaCoe
13
+
14
+ out = _scaCoe(df_sca, instru=instru, specified_band=[550] if specified_band is None else specified_band)
15
+
16
+ return self, out
17
+
18
+ @run_process('Optical - absCoe', 'absCoe')
19
+ @deprecated(
20
+ "This method is now automatically called during file reading. Please update your code to use the pre-calculated values.")
21
+ def absCoe(self, df_ae33, instru, specified_band):
22
+ from .coefficient import _absCoe
23
+
24
+ out = _absCoe(df_ae33, instru=instru, specified_band=[550] if specified_band is None else specified_band)
25
+
26
+ return self, out
27
+
28
+ @run_process('Optical - basic', 'opt_basic')
29
+ def basic(self, df_sca, df_abs, df_mass=None, df_no2=None, df_temp=None):
30
+ from ._extinction import _basic
31
+
32
+ out = _basic(df_sca, df_abs, df_mass, df_no2, df_temp)
33
+
34
+ return self, out
35
+
36
+ @run_process('Optical - Mie', 'Mie')
37
+ def Mie(self, df_psd, df_m, wavelength=550, psd_type='auto'):
38
+ """
39
+ Calculate optical properties from PSD using Mie theory.
40
+
41
+ Parameters
42
+ ----------
43
+ df_psd : DataFrame
44
+ Particle number size distribution.
45
+ Columns are particle diameters (nm), rows are time points.
46
+ df_m : DataFrame or Series
47
+ Complex refractive index (n + ik) for each time point.
48
+ wavelength : float, default=550
49
+ Wavelength of incident light in nm.
50
+ psd_type : str, default='auto'
51
+ Type of PSD input:
52
+ - 'dNdlogDp': Number concentration per log bin width (#/cm³)
53
+ - 'dN': Number concentration per bin (#/cm³/bin)
54
+ - 'auto': Auto-detect with warning if uncertain
55
+
56
+ Returns
57
+ -------
58
+ DataFrame
59
+ Optical coefficients with columns: ext, sca, abs (Mm⁻¹)
60
+ """
61
+ from ._mie_sd import Mie_SD
62
+
63
+ # Get valid indices (where both PSD and RI have data)
64
+ original_index = df_psd.index.copy()
65
+ valid_index = df_psd.loc[df_m.dropna().index].dropna(how='all').index
66
+
67
+ # Calculate Mie for valid data only
68
+ psd_valid = df_psd.loc[valid_index]
69
+ ri_valid = df_m.loc[valid_index]
70
+
71
+ result = Mie_SD(ri_valid.values, wavelength, psd_valid, psd_type=psd_type)
72
+
73
+ # Reindex to original index (NaN for missing)
74
+ out = result.reindex(original_index)
75
+
76
+ return self, out
77
+
78
+ @run_process('Optical - IMPROVE', 'IMPROVE')
79
+ def IMPROVE(self, df_mass, df_RH=None, method='revised', df_nh4_status=None):
80
+ """
81
+ Calculate extinction using IMPROVE equation.
82
+
83
+ Parameters
84
+ ----------
85
+ df_mass : DataFrame
86
+ Mass concentrations with columns: AS, AN, OM, Soil, SS, EC
87
+ df_RH : DataFrame, optional
88
+ Relative humidity data
89
+ method : str, default='revised'
90
+ IMPROVE version: 'revised' or 'modified'
91
+ df_nh4_status : DataFrame, optional
92
+ NH4 status from reconstruction_basic()['NH4_status'].
93
+ If provided, rows with 'Deficiency' status will be excluded.
94
+
95
+ Returns
96
+ -------
97
+ dict
98
+ Dictionary with keys:
99
+ - 'dry': Dry extinction DataFrame
100
+ - 'wet': Wet extinction DataFrame (if df_RH provided)
101
+ - 'ALWC': Water contribution (wet - dry)
102
+ - 'fRH': Hygroscopic growth factor
103
+ """
104
+ from ._IMPROVE import revised, modified
105
+
106
+ if method == 'revised':
107
+ out = revised(df_mass, df_RH, df_nh4_status)
108
+ elif method == 'modified':
109
+ out = modified(df_mass, df_RH, df_nh4_status)
110
+ else:
111
+ raise ValueError(f"method must be 'revised' or 'modified', got '{method}'")
112
+
113
+ return self, out
114
+
115
+ @run_process('Optical - gas_extinction', 'gas_ext')
116
+ def gas_extinction(self, df_no2, df_temp):
117
+ """
118
+ Calculate gas contribution to extinction.
119
+
120
+ Parameters
121
+ ----------
122
+ df_no2 : DataFrame
123
+ NO2 concentration (ppb)
124
+ df_temp : DataFrame
125
+ Ambient temperature (Celsius)
126
+
127
+ Returns
128
+ -------
129
+ DataFrame
130
+ Gas extinction with ScatteringByGas, AbsorptionByGas, ExtinctionByGas
131
+ """
132
+ from ._IMPROVE import gas_extinction as calc_gas_ext
133
+
134
+ out = calc_gas_ext(df_no2, df_temp)
135
+
136
+ return self, out
137
+
138
+ @run_process('Optical - retrieve_RI', 'retrieve_RI')
139
+ def retrieve_RI(self, df_optical, df_pnsd, dlogdp=0.014, wavelength=550):
140
+ """
141
+ Retrieve refractive index from optical and PSD measurements.
142
+
143
+ Parameters
144
+ ----------
145
+ df_optical : DataFrame
146
+ Optical data with Extinction, Scattering, Absorption columns
147
+ df_pnsd : DataFrame
148
+ Particle number size distribution data
149
+ dlogdp : float, default=0.014
150
+ Logarithmic bin width
151
+ wavelength : float, default=550
152
+ Wavelength in nm
153
+
154
+ Returns
155
+ -------
156
+ DataFrame
157
+ Retrieved refractive index with re_real and re_imaginary columns
158
+ """
159
+ from ._retrieve_RI import retrieve_RI
160
+
161
+ out = retrieve_RI(df_optical, df_pnsd, dlogdp, wavelength)
162
+
163
+ return self, out
164
+
165
+ @run_process('Optical - derived', 'derived')
166
+ def derived(self, df_sca=None, df_abs=None, df_ext=None, df_no2=None, df_o3=None,
167
+ df_ec=None, df_oc=None, df_pm1=None, df_pm25=None, df_improve=None):
168
+ """
169
+ Calculate derived optical and atmospheric parameters.
170
+
171
+ Parameters
172
+ ----------
173
+ df_sca : DataFrame, optional
174
+ Scattering coefficient (Mm-1)
175
+ df_abs : DataFrame, optional
176
+ Absorption coefficient (Mm-1)
177
+ df_ext : DataFrame, optional
178
+ Extinction coefficient (Mm-1)
179
+ df_no2 : DataFrame, optional
180
+ NO2 concentration (ppb)
181
+ df_o3 : DataFrame, optional
182
+ O3 concentration (ppb)
183
+ df_ec : DataFrame, optional
184
+ Elemental carbon (ug/m3)
185
+ df_oc : DataFrame, optional
186
+ Organic carbon (ug/m3)
187
+ df_pm1 : DataFrame, optional
188
+ PM1 (ug/m3)
189
+ df_pm25 : DataFrame, optional
190
+ PM2.5 (ug/m3)
191
+ df_improve : DataFrame, optional
192
+ IMPROVE extinction data
193
+
194
+ Returns
195
+ -------
196
+ DataFrame
197
+ Derived parameters (PG, MAC, Ox, Vis_cal, fRH_IMPR, OCEC_ratio, etc.)
198
+ """
199
+ from ._derived import derived_parameters
200
+
201
+ out = derived_parameters(
202
+ df_sca=df_sca, df_abs=df_abs, df_ext=df_ext,
203
+ df_no2=df_no2, df_o3=df_o3, df_ec=df_ec, df_oc=df_oc,
204
+ df_pm1=df_pm1, df_pm25=df_pm25, df_improve=df_improve
205
+ )
206
+
207
+ return self, out
208
+
209
+ @run_process('Optical - BrC', 'BrC')
210
+ def BrC(self, df_abs, wavelengths=None, ref_wavelength=880, aae_bc=1.0):
211
+ """
212
+ Calculate Brown Carbon (BrC) absorption by separating BC and BrC contributions.
213
+
214
+ This method uses the AAE-based separation approach:
215
+ 1. Assume Black Carbon (BC) has AAE = 1.0 (or user-specified value)
216
+ 2. Absorption at 880nm is entirely from BC (reference wavelength)
217
+ 3. Calculate BC absorption at shorter wavelengths using power law
218
+ 4. BrC absorption = Total absorption - BC absorption
219
+ 5. Calculate BrC AAE from the derived spectrum
220
+
221
+ Parameters
222
+ ----------
223
+ df_abs : DataFrame
224
+ Absorption coefficient data with columns like 'abs_370', 'abs_470',
225
+ 'abs_520', 'abs_590', 'abs_660', 'abs_880'.
226
+ Units should be Mm-1.
227
+ wavelengths : list[int], optional
228
+ Wavelengths to calculate BrC absorption for.
229
+ Default: [370, 470, 520, 590, 660]
230
+ ref_wavelength : int, default=880
231
+ Reference wavelength (nm) assumed to be purely BC absorption.
232
+ aae_bc : float, default=1.0
233
+ Absorption Ångström Exponent for Black Carbon.
234
+ Typical range: 0.8-1.1 for fresh BC.
235
+
236
+ Returns
237
+ -------
238
+ DataFrame
239
+ - abs_BC_{wl}: BC absorption at each wavelength (Mm-1)
240
+ - abs_BrC_{wl}: BrC absorption at each wavelength (Mm-1, NaN if invalid)
241
+ - BrC_fraction_{wl}: BrC contribution fraction (0-1, NaN if invalid)
242
+ - AAE_BrC: BrC Absorption Ångström Exponent (NaN if invalid)
243
+
244
+ Examples
245
+ --------
246
+ >>> from AeroViz import RawDataReader, DataProcess
247
+ >>> # Read AE33 data (has multi-wavelength absorption)
248
+ >>> ae33 = RawDataReader(instrument='AE33', path='/data/AE33',
249
+ ... start='2024-01-01', end='2024-01-31')
250
+ >>> # Calculate BrC
251
+ >>> optical = DataProcess(method='Optical')
252
+ >>> brc_result = optical.BrC(ae33)
253
+ >>> # Check valid data (non-NaN)
254
+ >>> valid_brc = brc_result['AAE_BrC'].dropna()
255
+ >>> print(valid_brc.mean())
256
+
257
+ Notes
258
+ -----
259
+ The separation assumes AAE_BC ≈ 1.0 based on Mie theory for graphitic
260
+ carbon. Real BC may have slightly different AAE depending on mixing
261
+ state and size distribution.
262
+
263
+ **Validity check**: If calculated BC absorption exceeds total absorption
264
+ at ANY wavelength, the entire row is marked as invalid (NaN for all
265
+ BrC-related values). This indicates the AAE=1 assumption is not valid.
266
+
267
+ References
268
+ ----------
269
+ - Lack & Langridge (2013), ACP 13:8321-8341
270
+ - Kirchstetter et al. (2004), JGR 109:D21208
271
+ """
272
+ from ._derived import calculate_BrC_absorption
273
+
274
+ out = calculate_BrC_absorption(
275
+ df_abs=df_abs,
276
+ wavelengths=wavelengths,
277
+ ref_wavelength=ref_wavelength,
278
+ aae_bc=aae_bc
279
+ )
280
+
281
+ return self, out