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.
- AeroViz/__init__.py +13 -0
- AeroViz/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/data/DEFAULT_DATA.csv +1417 -0
- AeroViz/data/DEFAULT_PNSD_DATA.csv +1417 -0
- AeroViz/data/hysplit_example_data.txt +101 -0
- AeroViz/dataProcess/Chemistry/__init__.py +149 -0
- AeroViz/dataProcess/Chemistry/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/dataProcess/Chemistry/_calculate.py +557 -0
- AeroViz/dataProcess/Chemistry/_isoropia.py +150 -0
- AeroViz/dataProcess/Chemistry/_mass_volume.py +487 -0
- AeroViz/dataProcess/Chemistry/_ocec.py +172 -0
- AeroViz/dataProcess/Chemistry/isrpia.cnf +21 -0
- AeroViz/dataProcess/Chemistry/isrpia2.exe +0 -0
- AeroViz/dataProcess/Optical/PyMieScatt_update.py +577 -0
- AeroViz/dataProcess/Optical/_IMPROVE.py +452 -0
- AeroViz/dataProcess/Optical/__init__.py +281 -0
- AeroViz/dataProcess/Optical/__pycache__/PyMieScatt_update.cpython-312.pyc +0 -0
- AeroViz/dataProcess/Optical/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/dataProcess/Optical/__pycache__/mie_theory.cpython-312.pyc +0 -0
- AeroViz/dataProcess/Optical/_derived.py +518 -0
- AeroViz/dataProcess/Optical/_extinction.py +123 -0
- AeroViz/dataProcess/Optical/_mie_sd.py +912 -0
- AeroViz/dataProcess/Optical/_retrieve_RI.py +243 -0
- AeroViz/dataProcess/Optical/coefficient.py +72 -0
- AeroViz/dataProcess/Optical/fRH.pkl +0 -0
- AeroViz/dataProcess/Optical/mie_theory.py +260 -0
- AeroViz/dataProcess/README.md +271 -0
- AeroViz/dataProcess/SizeDistr/__init__.py +245 -0
- AeroViz/dataProcess/SizeDistr/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/dataProcess/SizeDistr/__pycache__/_size_dist.cpython-312.pyc +0 -0
- AeroViz/dataProcess/SizeDistr/_size_dist.py +810 -0
- AeroViz/dataProcess/SizeDistr/merge/README.md +93 -0
- AeroViz/dataProcess/SizeDistr/merge/__init__.py +20 -0
- AeroViz/dataProcess/SizeDistr/merge/_merge_v0.py +251 -0
- AeroViz/dataProcess/SizeDistr/merge/_merge_v0_1.py +246 -0
- AeroViz/dataProcess/SizeDistr/merge/_merge_v1.py +255 -0
- AeroViz/dataProcess/SizeDistr/merge/_merge_v2.py +244 -0
- AeroViz/dataProcess/SizeDistr/merge/_merge_v3.py +518 -0
- AeroViz/dataProcess/SizeDistr/merge/_merge_v4.py +422 -0
- AeroViz/dataProcess/SizeDistr/prop.py +62 -0
- AeroViz/dataProcess/VOC/__init__.py +14 -0
- AeroViz/dataProcess/VOC/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/dataProcess/VOC/_potential_par.py +108 -0
- AeroViz/dataProcess/VOC/support_voc.json +446 -0
- AeroViz/dataProcess/__init__.py +66 -0
- AeroViz/dataProcess/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/dataProcess/core/__init__.py +272 -0
- AeroViz/dataProcess/core/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/mcp_server.py +352 -0
- AeroViz/plot/__init__.py +13 -0
- AeroViz/plot/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/plot/__pycache__/bar.cpython-312.pyc +0 -0
- AeroViz/plot/__pycache__/box.cpython-312.pyc +0 -0
- AeroViz/plot/__pycache__/pie.cpython-312.pyc +0 -0
- AeroViz/plot/__pycache__/radar.cpython-312.pyc +0 -0
- AeroViz/plot/__pycache__/regression.cpython-312.pyc +0 -0
- AeroViz/plot/__pycache__/scatter.cpython-312.pyc +0 -0
- AeroViz/plot/__pycache__/violin.cpython-312.pyc +0 -0
- AeroViz/plot/bar.py +126 -0
- AeroViz/plot/box.py +69 -0
- AeroViz/plot/distribution/__init__.py +1 -0
- AeroViz/plot/distribution/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/plot/distribution/__pycache__/distribution.cpython-312.pyc +0 -0
- AeroViz/plot/distribution/distribution.py +576 -0
- AeroViz/plot/meteorology/CBPF.py +295 -0
- AeroViz/plot/meteorology/__init__.py +3 -0
- AeroViz/plot/meteorology/__pycache__/CBPF.cpython-312.pyc +0 -0
- AeroViz/plot/meteorology/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/plot/meteorology/__pycache__/hysplit.cpython-312.pyc +0 -0
- AeroViz/plot/meteorology/__pycache__/wind_rose.cpython-312.pyc +0 -0
- AeroViz/plot/meteorology/hysplit.py +93 -0
- AeroViz/plot/meteorology/wind_rose.py +77 -0
- AeroViz/plot/optical/__init__.py +1 -0
- AeroViz/plot/optical/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/plot/optical/__pycache__/optical.cpython-312.pyc +0 -0
- AeroViz/plot/optical/optical.py +388 -0
- AeroViz/plot/pie.py +210 -0
- AeroViz/plot/radar.py +184 -0
- AeroViz/plot/regression.py +200 -0
- AeroViz/plot/scatter.py +174 -0
- AeroViz/plot/templates/__init__.py +6 -0
- AeroViz/plot/templates/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/plot/templates/__pycache__/ammonium_rich.cpython-312.pyc +0 -0
- AeroViz/plot/templates/__pycache__/contour.cpython-312.pyc +0 -0
- AeroViz/plot/templates/__pycache__/corr_matrix.cpython-312.pyc +0 -0
- AeroViz/plot/templates/__pycache__/diurnal_pattern.cpython-312.pyc +0 -0
- AeroViz/plot/templates/__pycache__/koschmieder.cpython-312.pyc +0 -0
- AeroViz/plot/templates/__pycache__/metal_heatmap.cpython-312.pyc +0 -0
- AeroViz/plot/templates/ammonium_rich.py +34 -0
- AeroViz/plot/templates/contour.py +47 -0
- AeroViz/plot/templates/corr_matrix.py +267 -0
- AeroViz/plot/templates/diurnal_pattern.py +61 -0
- AeroViz/plot/templates/koschmieder.py +95 -0
- AeroViz/plot/templates/metal_heatmap.py +164 -0
- AeroViz/plot/timeseries/__init__.py +2 -0
- AeroViz/plot/timeseries/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/plot/timeseries/__pycache__/template.cpython-312.pyc +0 -0
- AeroViz/plot/timeseries/__pycache__/timeseries.cpython-312.pyc +0 -0
- AeroViz/plot/timeseries/template.py +47 -0
- AeroViz/plot/timeseries/timeseries.py +446 -0
- AeroViz/plot/utils/__init__.py +4 -0
- AeroViz/plot/utils/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/plot/utils/__pycache__/_color.cpython-312.pyc +0 -0
- AeroViz/plot/utils/__pycache__/_unit.cpython-312.pyc +0 -0
- AeroViz/plot/utils/__pycache__/plt_utils.cpython-312.pyc +0 -0
- AeroViz/plot/utils/__pycache__/sklearn_utils.cpython-312.pyc +0 -0
- AeroViz/plot/utils/_color.py +71 -0
- AeroViz/plot/utils/_unit.py +55 -0
- AeroViz/plot/utils/fRH.json +390 -0
- AeroViz/plot/utils/plt_utils.py +92 -0
- AeroViz/plot/utils/sklearn_utils.py +49 -0
- AeroViz/plot/utils/units.json +89 -0
- AeroViz/plot/violin.py +80 -0
- AeroViz/rawDataReader/FLOW.md +138 -0
- AeroViz/rawDataReader/__init__.py +220 -0
- AeroViz/rawDataReader/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/config/__init__.py +0 -0
- AeroViz/rawDataReader/config/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/config/__pycache__/supported_instruments.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/config/supported_instruments.py +135 -0
- AeroViz/rawDataReader/core/__init__.py +658 -0
- AeroViz/rawDataReader/core/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/core/__pycache__/logger.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/core/__pycache__/pre_process.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/core/__pycache__/qc.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/core/__pycache__/report.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/core/logger.py +171 -0
- AeroViz/rawDataReader/core/pre_process.py +308 -0
- AeroViz/rawDataReader/core/qc.py +961 -0
- AeroViz/rawDataReader/core/report.py +579 -0
- AeroViz/rawDataReader/script/AE33.py +173 -0
- AeroViz/rawDataReader/script/AE43.py +151 -0
- AeroViz/rawDataReader/script/APS.py +339 -0
- AeroViz/rawDataReader/script/Aurora.py +191 -0
- AeroViz/rawDataReader/script/BAM1020.py +90 -0
- AeroViz/rawDataReader/script/BC1054.py +161 -0
- AeroViz/rawDataReader/script/EPA.py +79 -0
- AeroViz/rawDataReader/script/GRIMM.py +68 -0
- AeroViz/rawDataReader/script/IGAC.py +140 -0
- AeroViz/rawDataReader/script/MA350.py +179 -0
- AeroViz/rawDataReader/script/Minion.py +218 -0
- AeroViz/rawDataReader/script/NEPH.py +199 -0
- AeroViz/rawDataReader/script/OCEC.py +173 -0
- AeroViz/rawDataReader/script/Q-ACSM.py +12 -0
- AeroViz/rawDataReader/script/SMPS.py +389 -0
- AeroViz/rawDataReader/script/TEOM.py +181 -0
- AeroViz/rawDataReader/script/VOC.py +106 -0
- AeroViz/rawDataReader/script/Xact.py +244 -0
- AeroViz/rawDataReader/script/__init__.py +28 -0
- AeroViz/rawDataReader/script/__pycache__/AE33.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/AE43.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/APS.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/Aurora.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/BAM1020.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/BC1054.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/EPA.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/GRIMM.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/IGAC.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/MA350.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/Minion.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/NEPH.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/OCEC.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/Q-ACSM.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/SMPS.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/TEOM.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/VOC.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/Xact.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/tools/__init__.py +2 -0
- AeroViz/tools/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/tools/__pycache__/database.cpython-312.pyc +0 -0
- AeroViz/tools/__pycache__/dataclassifier.cpython-312.pyc +0 -0
- AeroViz/tools/database.py +95 -0
- AeroViz/tools/dataclassifier.py +117 -0
- AeroViz/tools/dataprinter.py +58 -0
- aeroviz-0.1.21.dist-info/METADATA +294 -0
- aeroviz-0.1.21.dist-info/RECORD +180 -0
- aeroviz-0.1.21.dist-info/WHEEL +5 -0
- aeroviz-0.1.21.dist-info/licenses/LICENSE +21 -0
- aeroviz-0.1.21.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# AeroViz DataProcess Module
|
|
2
|
+
|
|
3
|
+
數據處理模組,提供氣膠數據的計算與分析功能。
|
|
4
|
+
|
|
5
|
+
## 模組結構
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
dataProcess/
|
|
9
|
+
├── __init__.py # DataProcess 工廠函數
|
|
10
|
+
├── core/ # 共用工具 (Writer, run_process, validate_inputs)
|
|
11
|
+
├── Chemistry/ # 化學成分處理
|
|
12
|
+
├── Optical/ # 光學特性處理
|
|
13
|
+
├── SizeDistr/ # 粒徑分布處理
|
|
14
|
+
└── VOC/ # 揮發性有機物處理
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 快速開始
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from AeroViz.dataProcess import DataProcess
|
|
22
|
+
|
|
23
|
+
# 建立處理器
|
|
24
|
+
dp = DataProcess(method='SizeDistr', path_out=Path('./output'))
|
|
25
|
+
|
|
26
|
+
# 或直接導入類
|
|
27
|
+
from AeroViz.dataProcess.SizeDistr import SizeDist
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## SizeDistr 模組
|
|
33
|
+
|
|
34
|
+
粒徑分布數據處理。
|
|
35
|
+
|
|
36
|
+
### 結構
|
|
37
|
+
```
|
|
38
|
+
SizeDistr/
|
|
39
|
+
├── __init__.py # SizeDistr (Writer 入口)
|
|
40
|
+
├── _size_dist.py # SizeDist 核心類
|
|
41
|
+
├── prop.py # 統計計算函數
|
|
42
|
+
└── merge/ # SMPS-APS 合併演算法 (v0-v4)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### SizeDist 類
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from AeroViz.dataProcess.SizeDistr import SizeDist
|
|
49
|
+
|
|
50
|
+
# 建立物件
|
|
51
|
+
psd = SizeDist(df_pnsd, state='dlogdp', weighting='n')
|
|
52
|
+
|
|
53
|
+
# 屬性
|
|
54
|
+
psd.data # DataFrame - 原始數據
|
|
55
|
+
psd.dp # ndarray - 粒徑陣列 (nm)
|
|
56
|
+
psd.dlogdp # ndarray - 對數間距
|
|
57
|
+
psd.index # DatetimeIndex - 時間索引
|
|
58
|
+
|
|
59
|
+
# 分布轉換
|
|
60
|
+
psd.to_surface() # 表面積分布 (dS/dlogDp)
|
|
61
|
+
psd.to_volume() # 體積分布 (dV/dlogDp)
|
|
62
|
+
psd.to_extinction(df_RI) # 消光分布 (Mie 理論)
|
|
63
|
+
psd.to_dry(df_gRH) # 乾燥分布 (吸濕校正)
|
|
64
|
+
|
|
65
|
+
# 統計計算
|
|
66
|
+
psd.properties() # GMD, GSD, mode, contribution
|
|
67
|
+
psd.mode_statistics() # 各模態統計 (Nucleation/Aitken/Accumulation/Coarse)
|
|
68
|
+
|
|
69
|
+
# 應用
|
|
70
|
+
psd.lung_deposition() # ICRP 66 肺沉積模型
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### SizeDistr 入口方法
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
dp = DataProcess('SizeDistr', Path('./output'))
|
|
77
|
+
|
|
78
|
+
# 基本處理
|
|
79
|
+
dp.basic(df)
|
|
80
|
+
|
|
81
|
+
# SMPS-APS 合併
|
|
82
|
+
dp.merge_SMPS_APS(df_smps, df_aps) # v1
|
|
83
|
+
dp.merge_SMPS_APS_v2(df_smps, df_aps) # v2
|
|
84
|
+
dp.merge_SMPS_APS_v3(df_smps, df_aps) # v3 (multiprocessing)
|
|
85
|
+
dp.merge_SMPS_APS_v4(df_smps, df_aps, df_pm25) # v4 (PM2.5 校正)
|
|
86
|
+
|
|
87
|
+
# 分布計算
|
|
88
|
+
dp.distributions(df_pnsd)
|
|
89
|
+
dp.dry_psd(df_pnsd, df_gRH)
|
|
90
|
+
dp.extinction_distribution(df_pnsd, df_RI)
|
|
91
|
+
dp.extinction_full(df_pnsd, df_RI)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Chemistry 模組
|
|
97
|
+
|
|
98
|
+
化學成分數據處理。
|
|
99
|
+
|
|
100
|
+
### 結構
|
|
101
|
+
```
|
|
102
|
+
Chemistry/
|
|
103
|
+
├── __init__.py # Chemistry (Writer 入口)
|
|
104
|
+
├── _mass_volume.py # 質量重建、體積計算、折射率
|
|
105
|
+
├── _calculate.py # 衍生參數、氣粒分配比
|
|
106
|
+
├── _ocec.py # OC/EC 比值計算
|
|
107
|
+
└── _isoropia.py # ISORROPIA 熱力學模型
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Chemistry 入口方法
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
dp = DataProcess('Chemistry', Path('./output'))
|
|
114
|
+
|
|
115
|
+
# 質量重建
|
|
116
|
+
dp.reconstruction_basic(df_chem) # 基本重建 (AS, AN, OM, Soil, SS, EC)
|
|
117
|
+
dp.reconstruction_full(df_chem) # 完整重建 (含 ite,ite_ox)
|
|
118
|
+
|
|
119
|
+
# 體積與折射率
|
|
120
|
+
dp.volume_RI(df_chem) # 體積分率 + 折射率計算
|
|
121
|
+
dp.kappa(df_chem, df_RH) # κ-Köhler 吸濕參數
|
|
122
|
+
|
|
123
|
+
# 衍生參數
|
|
124
|
+
dp.derived(df_chem) # 衍生化學參數
|
|
125
|
+
dp.partition_ratios(df_chem) # 氣粒分配比 (SOR, NOR, NTR, epsilon)
|
|
126
|
+
|
|
127
|
+
# OC/EC
|
|
128
|
+
dp.ocec_ratio(df_ocec) # OC/EC 比值分析
|
|
129
|
+
|
|
130
|
+
# ISORROPIA
|
|
131
|
+
dp.ISORROPIA(df_chem) # 熱力學平衡計算
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 輸出欄位說明
|
|
135
|
+
|
|
136
|
+
**質量重建:**
|
|
137
|
+
| 欄位 | 說明 |
|
|
138
|
+
|------|------|
|
|
139
|
+
| AS | 硫酸銨 (μg/m³) |
|
|
140
|
+
| AN | 硝酸銨 (μg/m³) |
|
|
141
|
+
| OM | 有機物 (μg/m³) |
|
|
142
|
+
| Soil | 土壤塵 (μg/m³) |
|
|
143
|
+
| SS | 海鹽 (μg/m³) |
|
|
144
|
+
| EC | 元素碳 (μg/m³) |
|
|
145
|
+
| PM25_rc | 重建 PM2.5 (μg/m³) |
|
|
146
|
+
|
|
147
|
+
**氣粒分配比:**
|
|
148
|
+
| 欄位 | 說明 |
|
|
149
|
+
|------|------|
|
|
150
|
+
| SOR | 硫氧化比 SO₄²⁻/(SO₄²⁻+SO₂) |
|
|
151
|
+
| NOR | 氮氧化比 NO₃⁻/(NO₃⁻+NO₂) |
|
|
152
|
+
| epsilon_ite | 硝酸鹽分配係數 |
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Optical 模組
|
|
157
|
+
|
|
158
|
+
光學特性數據處理。
|
|
159
|
+
|
|
160
|
+
### 結構
|
|
161
|
+
```
|
|
162
|
+
Optical/
|
|
163
|
+
├── __init__.py # Optical (Writer 入口)
|
|
164
|
+
├── _IMPROVE.py # IMPROVE 消光方程
|
|
165
|
+
├── _mie.py # Mie 理論計算
|
|
166
|
+
├── _retrieve_RI.py # 折射率反演
|
|
167
|
+
├── _derived.py # 衍生光學參數
|
|
168
|
+
├── mie_theory.py # Mie 混合模式
|
|
169
|
+
└── coefficient.py # 散射/吸收係數
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Optical 入口方法
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
dp = DataProcess('Optical', Path('./output'))
|
|
176
|
+
|
|
177
|
+
# 消光計算
|
|
178
|
+
dp.basic(df_sca, df_abs) # 基本消光特性
|
|
179
|
+
dp.IMPROVE(df_mass, df_RH) # IMPROVE 方程 (revised/modified)
|
|
180
|
+
dp.gas_extinction(df_no2, df_temp) # 氣體消光貢獻
|
|
181
|
+
|
|
182
|
+
# Mie 計算
|
|
183
|
+
dp.Mie(df_psd, df_m) # Mie 理論消光
|
|
184
|
+
|
|
185
|
+
# 折射率反演
|
|
186
|
+
dp.retrieve_RI(df_optical, df_pnsd) # 從光學+PSD 反演折射率
|
|
187
|
+
|
|
188
|
+
# 衍生參數
|
|
189
|
+
dp.derived(df_sca, df_abs, ...) # PG, MAC, Ox, 能見度等
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### IMPROVE 輸出
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
result = dp.IMPROVE(df_mass, df_RH, method='revised')
|
|
196
|
+
|
|
197
|
+
result['dry'] # 乾燥消光 DataFrame
|
|
198
|
+
result['wet'] # 濕消光 DataFrame (含 ALWC)
|
|
199
|
+
result['ALWC'] # 液態水貢獻
|
|
200
|
+
result['fRH'] # 吸濕成長因子
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## VOC 模組
|
|
206
|
+
|
|
207
|
+
揮發性有機物數據處理。
|
|
208
|
+
|
|
209
|
+
### VOC 入口方法
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
dp = DataProcess('VOC', Path('./output'))
|
|
213
|
+
|
|
214
|
+
dp.potential(df_voc) # 臭氧生成潛勢 (OFP, SOAP)
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## 共用功能
|
|
220
|
+
|
|
221
|
+
### Writer 基類
|
|
222
|
+
|
|
223
|
+
所有處理模組繼承自 `Writer`,提供:
|
|
224
|
+
- 自動輸出 CSV/Excel
|
|
225
|
+
- 處理進度顯示
|
|
226
|
+
- 錯誤處理
|
|
227
|
+
|
|
228
|
+
### run_process 裝飾器
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
@run_process('處理名稱', '輸出檔名')
|
|
232
|
+
def method(self, ...):
|
|
233
|
+
...
|
|
234
|
+
return self, output_data
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### validate_inputs 驗證器
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
from AeroViz.dataProcess.core import validate_inputs
|
|
241
|
+
|
|
242
|
+
validate_inputs(df, ['SO42-', 'NO3-'], 'Chemistry', COLUMN_DESCRIPTIONS)
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## 資料格式要求
|
|
248
|
+
|
|
249
|
+
### 通用格式
|
|
250
|
+
- **Index**: `DatetimeIndex` (時間索引)
|
|
251
|
+
- **Columns**: 依模組需求
|
|
252
|
+
|
|
253
|
+
### SizeDist 格式
|
|
254
|
+
```python
|
|
255
|
+
# 欄位為粒徑值 (nm)
|
|
256
|
+
df.columns = [11.8, 13.6, 15.7, ..., 523.3]
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Chemistry 格式
|
|
260
|
+
```python
|
|
261
|
+
# 化學成分欄位
|
|
262
|
+
required = ['SO42-', 'NO3-', 'Cl-', 'Na+', 'NH4+', 'K+', 'Mg2+', 'Ca2+',
|
|
263
|
+
'OC', 'EC', 'Al', 'Fe', 'Ti', 'PM25']
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Optical 格式
|
|
267
|
+
```python
|
|
268
|
+
# 散射/吸收係數
|
|
269
|
+
df_sca.columns = ['G_550', 'R_700', 'B_450'] # Mm⁻¹
|
|
270
|
+
df_abs.columns = ['Abs_880'] # Mm⁻¹
|
|
271
|
+
```
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
from ..core import Writer, run_process
|
|
2
|
+
|
|
3
|
+
from ._size_dist import SizeDist
|
|
4
|
+
|
|
5
|
+
__all__ = ['SizeDistr', 'SizeDist']
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SizeDistr(Writer):
|
|
9
|
+
|
|
10
|
+
# basic
|
|
11
|
+
@run_process('SizeDistr - basic', 'distr_basic')
|
|
12
|
+
def basic(self, df, hybrid_bin_start_loc=None, unit='nm', bin_range=(0, 20000), input_type='norm'):
|
|
13
|
+
"""
|
|
14
|
+
Process particle size distribution data.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
df : DataFrame
|
|
19
|
+
Raw particle size distribution data.
|
|
20
|
+
hybrid_bin_start_loc : int, optional
|
|
21
|
+
Column index where bin spacing changes (for hybrid instruments).
|
|
22
|
+
unit : {'nm', 'um'}, default='nm'
|
|
23
|
+
Unit of particle diameter.
|
|
24
|
+
bin_range : tuple, default=(0, 20000)
|
|
25
|
+
Size range to include (min, max).
|
|
26
|
+
input_type : {'norm', 'raw'}, default='norm'
|
|
27
|
+
Whether input is normalized (dN/dlogDp) or raw (dN).
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
dict
|
|
32
|
+
Distributions and statistics for each size mode.
|
|
33
|
+
"""
|
|
34
|
+
import numpy as np
|
|
35
|
+
|
|
36
|
+
# Prepare data
|
|
37
|
+
data = df.copy()
|
|
38
|
+
data.columns = data.keys().to_numpy(float)
|
|
39
|
+
|
|
40
|
+
# Filter by size range
|
|
41
|
+
cols = data.keys()[(data.keys() >= bin_range[0]) & (data.keys() <= bin_range[-1])]
|
|
42
|
+
data = data[cols].copy()
|
|
43
|
+
|
|
44
|
+
dp = data.keys().to_numpy()
|
|
45
|
+
|
|
46
|
+
# Calculate dlogdp
|
|
47
|
+
if hybrid_bin_start_loc is None:
|
|
48
|
+
dlog_dp = np.full(dp.size, np.diff(np.log10(dp)).mean())
|
|
49
|
+
else:
|
|
50
|
+
dlog_dp = np.ones(dp.size)
|
|
51
|
+
dlog_dp[:hybrid_bin_start_loc] = np.diff(np.log10(dp[:hybrid_bin_start_loc])).mean()
|
|
52
|
+
dlog_dp[hybrid_bin_start_loc:] = np.diff(np.log10(dp[hybrid_bin_start_loc:])).mean()
|
|
53
|
+
|
|
54
|
+
# Handle normalization
|
|
55
|
+
if input_type == 'norm':
|
|
56
|
+
data_norm = data
|
|
57
|
+
else:
|
|
58
|
+
data_norm = data / dlog_dp
|
|
59
|
+
|
|
60
|
+
# Create SizeDist and calculate
|
|
61
|
+
psd = SizeDist(data_norm, state='dlogdp', weighting='n')
|
|
62
|
+
psd.dlogdp = dlog_dp
|
|
63
|
+
|
|
64
|
+
out = psd.mode_statistics(unit=unit)
|
|
65
|
+
|
|
66
|
+
# Rename for backward compatibility
|
|
67
|
+
out['other'] = out.pop('statistics')
|
|
68
|
+
|
|
69
|
+
return self, out
|
|
70
|
+
|
|
71
|
+
# merge
|
|
72
|
+
@run_process('SizeDistr - merge_SMPS_APS_v4', 'distr_merge')
|
|
73
|
+
def merge_SMPS_APS_v4(self, df_smps, df_aps, df_pm25, aps_unit='um',
|
|
74
|
+
smps_overlap_lowbound=500, aps_fit_highbound=1000, dndsdv_alg=True,
|
|
75
|
+
times_range=(0.8, 1.25, .05)):
|
|
76
|
+
from .merge import merge_v4
|
|
77
|
+
|
|
78
|
+
out = merge_v4(df_smps, df_aps, df_pm25, aps_unit, smps_overlap_lowbound, aps_fit_highbound, dndsdv_alg,
|
|
79
|
+
times_range)
|
|
80
|
+
|
|
81
|
+
return self, out
|
|
82
|
+
|
|
83
|
+
# merge
|
|
84
|
+
@run_process('SizeDistr - merge_SMPS_APS_v3', 'distr_merge')
|
|
85
|
+
def merge_SMPS_APS_v3(self, df_smps, df_aps, aps_unit='um',
|
|
86
|
+
smps_overlap_lowbound=500, aps_fit_highbound=1000, dndsdv_alg=True):
|
|
87
|
+
from .merge import merge_v3
|
|
88
|
+
|
|
89
|
+
out = merge_v3(df_smps, df_aps, aps_unit, smps_overlap_lowbound, aps_fit_highbound, dndsdv_alg)
|
|
90
|
+
|
|
91
|
+
return self, out
|
|
92
|
+
|
|
93
|
+
# merge
|
|
94
|
+
@run_process('SizeDistr - merge_SMPS_APS_v2', 'distr_merge')
|
|
95
|
+
def merge_SMPS_APS_v2(self, df_smps, df_aps, aps_unit='um',
|
|
96
|
+
smps_overlap_lowbound=500, aps_fit_highbound=1000):
|
|
97
|
+
from .merge import merge_v2
|
|
98
|
+
|
|
99
|
+
out = merge_v2(df_smps, df_aps, aps_unit, smps_overlap_lowbound, aps_fit_highbound)
|
|
100
|
+
|
|
101
|
+
return self, out
|
|
102
|
+
|
|
103
|
+
# merge
|
|
104
|
+
@run_process('SizeDistr - merge_SMPS_APS_v1', 'distr_merge')
|
|
105
|
+
def merge_SMPS_APS(self, df_smps, df_aps, aps_unit='um', shift_mode='mobility',
|
|
106
|
+
smps_overlap_lowbound=523, aps_fit_highbound=800):
|
|
107
|
+
from .merge import merge_v1
|
|
108
|
+
|
|
109
|
+
out = merge_v1(df_smps, df_aps, aps_unit, shift_mode, smps_overlap_lowbound, aps_fit_highbound)
|
|
110
|
+
|
|
111
|
+
return self, out
|
|
112
|
+
|
|
113
|
+
# Distribution calculations
|
|
114
|
+
@run_process('SizeDistr - distributions', 'distr_calc')
|
|
115
|
+
def distributions(self, df_pnsd):
|
|
116
|
+
"""
|
|
117
|
+
Calculate number, surface, and volume distributions with properties.
|
|
118
|
+
|
|
119
|
+
Parameters
|
|
120
|
+
----------
|
|
121
|
+
df_pnsd : DataFrame
|
|
122
|
+
Particle number size distribution data.
|
|
123
|
+
|
|
124
|
+
Returns
|
|
125
|
+
-------
|
|
126
|
+
dict
|
|
127
|
+
Dictionary with 'number', 'surface', 'volume', and 'properties' DataFrames.
|
|
128
|
+
"""
|
|
129
|
+
from pandas import concat
|
|
130
|
+
|
|
131
|
+
psd = SizeDist(df_pnsd, weighting='n')
|
|
132
|
+
|
|
133
|
+
number = psd.data
|
|
134
|
+
surface = psd.to_surface()
|
|
135
|
+
volume = psd.to_volume()
|
|
136
|
+
|
|
137
|
+
# Calculate properties for each distribution type
|
|
138
|
+
props_n = psd.properties()
|
|
139
|
+
props_s = SizeDist(surface, weighting='s').properties()
|
|
140
|
+
props_v = SizeDist(volume, weighting='v').properties()
|
|
141
|
+
|
|
142
|
+
out = {
|
|
143
|
+
'number': number,
|
|
144
|
+
'surface': surface,
|
|
145
|
+
'volume': volume,
|
|
146
|
+
'properties': concat([props_n, props_s, props_v], axis=1)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return self, out
|
|
150
|
+
|
|
151
|
+
# Dry PSD
|
|
152
|
+
@run_process('SizeDistr - dry_psd', 'distr_dry')
|
|
153
|
+
def dry_psd(self, df_pnsd, df_gRH, uniform=True):
|
|
154
|
+
"""
|
|
155
|
+
Convert ambient PSD to dry PSD.
|
|
156
|
+
|
|
157
|
+
Parameters
|
|
158
|
+
----------
|
|
159
|
+
df_pnsd : DataFrame
|
|
160
|
+
Particle number size distribution data.
|
|
161
|
+
df_gRH : DataFrame
|
|
162
|
+
DataFrame with 'gRH' column (growth factor).
|
|
163
|
+
uniform : bool, default=True
|
|
164
|
+
Whether to apply uniform growth factor.
|
|
165
|
+
|
|
166
|
+
Returns
|
|
167
|
+
-------
|
|
168
|
+
DataFrame
|
|
169
|
+
Dry particle size distribution.
|
|
170
|
+
"""
|
|
171
|
+
psd = SizeDist(df_pnsd)
|
|
172
|
+
out = psd.to_dry(df_gRH, uniform=uniform)
|
|
173
|
+
|
|
174
|
+
return self, out
|
|
175
|
+
|
|
176
|
+
# Extinction distribution
|
|
177
|
+
@run_process('SizeDistr - extinction', 'distr_ext')
|
|
178
|
+
def extinction_distribution(self, df_pnsd, df_RI, method='internal', result_type='extinction'):
|
|
179
|
+
"""
|
|
180
|
+
Calculate extinction distribution using Mie theory.
|
|
181
|
+
|
|
182
|
+
Parameters
|
|
183
|
+
----------
|
|
184
|
+
df_pnsd : DataFrame
|
|
185
|
+
Particle number size distribution (dN/dlogDp).
|
|
186
|
+
df_RI : DataFrame
|
|
187
|
+
Refractive index data (n, k columns).
|
|
188
|
+
method : {'internal', 'external', 'core_shell', 'sensitivity'}, default='internal'
|
|
189
|
+
Mixing method for Mie calculation.
|
|
190
|
+
result_type : {'extinction', 'scattering', 'absorption'}, default='extinction'
|
|
191
|
+
Type of optical property.
|
|
192
|
+
|
|
193
|
+
Returns
|
|
194
|
+
-------
|
|
195
|
+
dict
|
|
196
|
+
- 'distribution': Extinction size distribution (Mm⁻¹)
|
|
197
|
+
- 'properties': Statistical properties (GMD, GSD, mode)
|
|
198
|
+
"""
|
|
199
|
+
psd = SizeDist(df_pnsd)
|
|
200
|
+
ext_dist = psd.to_extinction(df_RI, method=method, result_type=result_type)
|
|
201
|
+
ext_props = SizeDist(ext_dist, weighting=f'ext_{method[:2]}').properties()
|
|
202
|
+
|
|
203
|
+
out = {
|
|
204
|
+
'distribution': ext_dist,
|
|
205
|
+
'properties': ext_props
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return self, out
|
|
209
|
+
|
|
210
|
+
# Full extinction analysis (internal + external)
|
|
211
|
+
@run_process('SizeDistr - extinction_full', 'distr_ext_full')
|
|
212
|
+
def extinction_full(self, df_pnsd, df_RI, result_type='extinction'):
|
|
213
|
+
"""
|
|
214
|
+
Calculate extinction using both internal and external mixing.
|
|
215
|
+
|
|
216
|
+
Parameters
|
|
217
|
+
----------
|
|
218
|
+
df_pnsd : DataFrame
|
|
219
|
+
Particle number size distribution (dN/dlogDp).
|
|
220
|
+
df_RI : DataFrame
|
|
221
|
+
Refractive index data with volume ratios.
|
|
222
|
+
result_type : {'extinction', 'scattering', 'absorption'}, default='extinction'
|
|
223
|
+
Type of optical property.
|
|
224
|
+
|
|
225
|
+
Returns
|
|
226
|
+
-------
|
|
227
|
+
dict
|
|
228
|
+
- 'internal': Internal mixing distribution
|
|
229
|
+
- 'external': External mixing distribution
|
|
230
|
+
- 'properties_internal': Internal properties
|
|
231
|
+
- 'properties_external': External properties
|
|
232
|
+
"""
|
|
233
|
+
psd = SizeDist(df_pnsd)
|
|
234
|
+
|
|
235
|
+
ext_internal = psd.to_extinction(df_RI, method='internal', result_type=result_type)
|
|
236
|
+
ext_external = psd.to_extinction(df_RI, method='external', result_type=result_type)
|
|
237
|
+
|
|
238
|
+
out = {
|
|
239
|
+
'internal': ext_internal,
|
|
240
|
+
'external': ext_external,
|
|
241
|
+
'properties_internal': SizeDist(ext_internal, weighting='ext_in').properties(),
|
|
242
|
+
'properties_external': SizeDist(ext_external, weighting='ext_ex').properties()
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return self, out
|
|
Binary file
|
|
Binary file
|