AeroViz 0.1.2__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.
- AeroViz/__init__.py +4 -4
- AeroViz/config/DEFAULT_DATA.csv +1417 -0
- AeroViz/config/DEFAULT_PNSD_DATA.csv +1417 -0
- AeroViz/dataProcess/Chemistry/__init__.py +38 -38
- AeroViz/dataProcess/Chemistry/_calculate.py +15 -15
- AeroViz/dataProcess/Chemistry/_isoropia.py +69 -68
- AeroViz/dataProcess/Chemistry/_mass_volume.py +158 -158
- AeroViz/dataProcess/Chemistry/_ocec.py +109 -109
- AeroViz/dataProcess/Chemistry/_partition.py +19 -18
- AeroViz/dataProcess/Chemistry/_teom.py +8 -11
- AeroViz/dataProcess/Optical/_IMPROVE.py +40 -39
- AeroViz/dataProcess/Optical/__init__.py +35 -35
- AeroViz/dataProcess/Optical/_absorption.py +35 -35
- AeroViz/dataProcess/Optical/_extinction.py +25 -24
- AeroViz/dataProcess/Optical/_mie.py +5 -6
- AeroViz/dataProcess/Optical/_mie_sd.py +89 -90
- AeroViz/dataProcess/Optical/_scattering.py +16 -16
- AeroViz/dataProcess/SizeDistr/__init__.py +37 -37
- AeroViz/dataProcess/SizeDistr/__merge.py +159 -158
- AeroViz/dataProcess/SizeDistr/_merge.py +155 -154
- AeroViz/dataProcess/SizeDistr/_merge_v1.py +162 -161
- AeroViz/dataProcess/SizeDistr/_merge_v2.py +153 -152
- AeroViz/dataProcess/SizeDistr/_merge_v3.py +326 -326
- AeroViz/dataProcess/SizeDistr/_merge_v4.py +272 -274
- AeroViz/dataProcess/SizeDistr/_size_distr.py +51 -51
- AeroViz/dataProcess/VOC/__init__.py +7 -7
- AeroViz/dataProcess/VOC/_potential_par.py +53 -55
- AeroViz/dataProcess/VOC/voc_par.json +464 -0
- AeroViz/dataProcess/__init__.py +4 -4
- AeroViz/dataProcess/core/__init__.py +59 -58
- AeroViz/plot/__init__.py +6 -1
- AeroViz/plot/bar.py +126 -0
- AeroViz/plot/box.py +68 -0
- AeroViz/plot/distribution/distribution.py +421 -427
- AeroViz/plot/meteorology/meteorology.py +240 -292
- AeroViz/plot/optical/__init__.py +0 -1
- AeroViz/plot/optical/optical.py +230 -230
- AeroViz/plot/pie.py +198 -0
- AeroViz/plot/regression.py +210 -0
- AeroViz/plot/scatter.py +99 -0
- AeroViz/plot/templates/__init__.py +0 -3
- AeroViz/plot/templates/contour.py +25 -25
- AeroViz/plot/templates/corr_matrix.py +86 -93
- AeroViz/plot/templates/diurnal_pattern.py +24 -24
- AeroViz/plot/templates/koschmieder.py +106 -106
- AeroViz/plot/templates/metal_heatmap.py +34 -34
- AeroViz/plot/timeseries/timeseries.py +53 -60
- AeroViz/plot/utils/__init__.py +2 -1
- AeroViz/plot/utils/_color.py +57 -57
- AeroViz/plot/utils/_unit.py +48 -48
- 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 +84 -0
- AeroViz/plot/violin.py +79 -0
- AeroViz/process/__init__.py +15 -15
- AeroViz/process/core/DataProc.py +9 -9
- AeroViz/process/core/SizeDist.py +81 -81
- AeroViz/process/method/PyMieScatt_update.py +488 -488
- AeroViz/process/method/mie_theory.py +231 -229
- AeroViz/process/method/prop.py +40 -40
- AeroViz/process/script/AbstractDistCalc.py +103 -103
- AeroViz/process/script/Chemical.py +166 -166
- AeroViz/process/script/IMPACT.py +40 -40
- AeroViz/process/script/IMPROVE.py +152 -152
- AeroViz/process/script/Others.py +45 -45
- AeroViz/process/script/PSD.py +26 -26
- AeroViz/process/script/PSD_dry.py +69 -70
- AeroViz/process/script/retrieve_RI.py +50 -51
- AeroViz/rawDataReader/__init__.py +57 -57
- AeroViz/rawDataReader/core/__init__.py +328 -326
- AeroViz/rawDataReader/script/AE33.py +18 -18
- AeroViz/rawDataReader/script/AE43.py +20 -20
- AeroViz/rawDataReader/script/APS_3321.py +30 -30
- AeroViz/rawDataReader/script/Aurora.py +23 -23
- AeroViz/rawDataReader/script/BC1054.py +40 -40
- AeroViz/rawDataReader/script/EPA_vertical.py +9 -9
- AeroViz/rawDataReader/script/GRIMM.py +21 -21
- AeroViz/rawDataReader/script/IGAC_TH.py +67 -67
- AeroViz/rawDataReader/script/IGAC_ZM.py +59 -59
- AeroViz/rawDataReader/script/MA350.py +39 -39
- AeroViz/rawDataReader/script/NEPH.py +74 -74
- AeroViz/rawDataReader/script/OCEC_LCRES.py +21 -21
- AeroViz/rawDataReader/script/OCEC_RES.py +16 -16
- AeroViz/rawDataReader/script/SMPS_TH.py +25 -25
- AeroViz/rawDataReader/script/SMPS_aim11.py +32 -32
- AeroViz/rawDataReader/script/SMPS_genr.py +31 -31
- AeroViz/rawDataReader/script/TEOM.py +28 -28
- AeroViz/rawDataReader/script/Table.py +12 -12
- AeroViz/rawDataReader/script/VOC_TH.py +16 -16
- AeroViz/rawDataReader/script/VOC_ZM.py +28 -28
- AeroViz/rawDataReader/script/__init__.py +20 -20
- AeroViz/rawDataReader/utils/config.py +161 -161
- AeroViz/tools/database.py +65 -65
- AeroViz/tools/dataclassifier.py +106 -106
- AeroViz/tools/dataprinter.py +51 -51
- AeroViz/tools/datareader.py +38 -38
- {AeroViz-0.1.2.dist-info → AeroViz-0.1.3b0.dist-info}/METADATA +5 -4
- AeroViz-0.1.3b0.dist-info/RECORD +110 -0
- AeroViz/config/__init__.py +0 -0
- AeroViz/plot/improve/__init__.py +0 -1
- AeroViz/plot/improve/improve.py +0 -240
- AeroViz/plot/optical/aethalometer.py +0 -77
- AeroViz/plot/templates/event_evolution.py +0 -65
- AeroViz/plot/templates/regression.py +0 -256
- AeroViz/plot/templates/scatter.py +0 -130
- AeroViz/plot/templates/templates.py +0 -398
- AeroViz/plot/utils/_decorator.py +0 -74
- AeroViz-0.1.2.dist-info/RECORD +0 -106
- {AeroViz-0.1.2.dist-info → AeroViz-0.1.3b0.dist-info}/LICENSE +0 -0
- {AeroViz-0.1.2.dist-info → AeroViz-0.1.3b0.dist-info}/WHEEL +0 -0
- {AeroViz-0.1.2.dist-info → AeroViz-0.1.3b0.dist-info}/top_level.txt +0 -0
|
@@ -1,27 +1,25 @@
|
|
|
1
1
|
# from ContainerHandle.dataProcess.utils import _union_index
|
|
2
2
|
|
|
3
|
+
import warnings
|
|
3
4
|
from datetime import datetime as dtm
|
|
5
|
+
from functools import partial
|
|
6
|
+
from multiprocessing import Pool, cpu_count
|
|
4
7
|
|
|
5
8
|
import numpy as np
|
|
6
9
|
from pandas import DataFrame, concat, DatetimeIndex
|
|
7
10
|
# from scipy.interpolate import interp1d
|
|
8
11
|
from scipy.interpolate import UnivariateSpline as unvpline, interp1d
|
|
9
12
|
|
|
10
|
-
from multiprocessing import Pool, cpu_count
|
|
11
|
-
from functools import partial
|
|
12
|
-
|
|
13
|
-
import warnings
|
|
14
|
-
|
|
15
13
|
warnings.filterwarnings("ignore")
|
|
16
14
|
|
|
17
15
|
__all__ = ['_merge_SMPS_APS']
|
|
18
16
|
|
|
19
17
|
|
|
20
18
|
def _powerlaw_fit(_coeA, _coeB, _aps, _idx, _factor):
|
|
21
|
-
|
|
19
|
+
# breakpoint()
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
_smps_fit_df = _coeA * (_aps.keys().values / _factor) ** _coeB
|
|
22
|
+
return DataFrame(((_smps_fit_df.copy() - _aps.copy()) ** 2).sum(axis=1), columns=[_idx])
|
|
25
23
|
|
|
26
24
|
|
|
27
25
|
## Calculate S2
|
|
@@ -31,394 +29,394 @@ def _powerlaw_fit(_coeA, _coeB, _aps, _idx, _factor):
|
|
|
31
29
|
## return : S2
|
|
32
30
|
# def _S2_calculate_dN(_smps, _aps):
|
|
33
31
|
def _powerlaw_fit_dN(_smps, _aps, _alg_type):
|
|
34
|
-
|
|
32
|
+
print(f"\t\t\t{dtm.now().strftime('%m/%d %X')} : \033[92moverlap range fitting : {_alg_type}\033[0m")
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
## overlap fitting
|
|
35
|
+
## parmeter
|
|
36
|
+
_dt_indx = _smps.index
|
|
39
37
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
## use SMPS data apply power law fitting
|
|
39
|
+
## y = Ax^B, A = e**coefa, B = coefb, x = logx, y = logy
|
|
40
|
+
## ref : http://mathworld.wolfram.com/LeastSquaresFittingPowerLaw.html
|
|
41
|
+
## power law fit to SMPS num conc at upper bins to log curve
|
|
44
42
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
## coefficient A, B
|
|
44
|
+
_smps_qc_cond = ((_smps != 0) & np.isfinite(_smps))
|
|
45
|
+
_smps_qc = _smps.where(_smps_qc_cond)
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
_size = _smps_qc_cond.sum(axis=1)
|
|
48
|
+
_size = _size.where(_size != 0.).copy()
|
|
51
49
|
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
_logx, _logy = np.log(_smps_qc.keys()._data.astype(float)), np.log(_smps_qc)
|
|
51
|
+
_x, _y, _xy, _xx = _logx.sum(), _logy.sum(axis=1), (_logx * _logy).sum(axis=1), (_logx ** 2).sum()
|
|
54
52
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
_coeB = ((_size * _xy - _x * _y) / (_size * _xx - _x ** 2.))
|
|
54
|
+
_coeA = np.exp((_y - _coeB * _x) / _size).values.reshape(-1, 1)
|
|
55
|
+
_coeB = _coeB.values.reshape(-1, 1)
|
|
58
56
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
## rebuild shift smps data by coe. A, B
|
|
58
|
+
## x_shift = (y_ori/A)**(1/B)
|
|
59
|
+
_aps_shift_x = (_aps / _coeA) ** (1 / _coeB)
|
|
60
|
+
_aps_shift_x = _aps_shift_x.where(np.isfinite(_aps_shift_x))
|
|
63
61
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
## the least squares of diameter
|
|
63
|
+
## the shift factor which the closest to 1
|
|
64
|
+
_shift_val = np.arange(0.3, 3.05, .05) ** .5
|
|
65
|
+
# _shift_val = np.arange(0.9, 1.805, .005)**.5
|
|
68
66
|
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
_shift_factor = DataFrame(columns=range(_shift_val.size), index=_aps_shift_x.index)
|
|
68
|
+
_shift_factor.loc[:, :] = _shift_val
|
|
71
69
|
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
# _dropna_idx = _shift_factor.dropna(how='all').index.copy()
|
|
71
|
+
_dropna_idx = _aps_shift_x.dropna(how='all').index.copy()
|
|
74
72
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
## use the target function to get the similar aps and smps bin
|
|
74
|
+
## S2 = sum( (smps_fit_line(dia) - aps(dia*shift_factor) )**2 )
|
|
75
|
+
## assumption : the same diameter between smps and aps should get the same conc.
|
|
78
76
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
## be sure they art in log value
|
|
78
|
+
_S2 = DataFrame(index=_aps_shift_x.index)
|
|
79
|
+
_dia_table = DataFrame(np.full(_aps_shift_x.shape, _aps_shift_x.keys()),
|
|
80
|
+
columns=_aps_shift_x.keys(), index=_aps_shift_x.index)
|
|
83
81
|
|
|
84
|
-
|
|
82
|
+
pool = Pool(cpu_count())
|
|
85
83
|
|
|
86
|
-
|
|
84
|
+
_S2 = pool.starmap(partial(_powerlaw_fit, _coeA, _coeB, _aps), list(enumerate(_shift_val)))
|
|
87
85
|
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
pool.close()
|
|
87
|
+
pool.join()
|
|
90
88
|
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
S2 = concat(_S2, axis=1)[np.arange(_shift_val.size)]
|
|
90
|
+
# S2 /= S2.max(axis=1).to_frame().values
|
|
93
91
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
shift_factor_dN = DataFrame(
|
|
93
|
+
_shift_factor.loc[_dropna_idx].values[range(len(_dropna_idx)), S2.loc[_dropna_idx].idxmin(axis=1).values],
|
|
94
|
+
index=_dropna_idx).reindex(_dt_indx).astype(float)
|
|
97
95
|
|
|
98
|
-
|
|
96
|
+
shift_factor_dN = shift_factor_dN.mask((shift_factor_dN ** 2 < 0.6) | (shift_factor_dN ** 2 > 2.6))
|
|
99
97
|
|
|
100
|
-
|
|
98
|
+
return shift_factor_dN
|
|
101
99
|
|
|
102
100
|
|
|
103
101
|
def _corr_fc(_aps_dia, _smps_dia, _smps_dn, _aps_dn, _smooth, _idx, _sh):
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
ds_fc = lambda _dt: _dt * _dt.index ** 2 * np.pi
|
|
103
|
+
dv_fc = lambda _dt: _dt * _dt.index ** 3 * np.pi / 6
|
|
106
104
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
_aps_sh = _aps_dia / _sh
|
|
106
|
+
_aps_sh_inp = _aps_sh.where((_aps_sh >= 500) & (_aps_sh <= 1500.)).copy()
|
|
107
|
+
_aps_sh_corr = _aps_sh.where((_aps_sh >= _smps_dia[-1]) & (_aps_sh <= 1500.)).copy()
|
|
110
108
|
|
|
111
|
-
|
|
109
|
+
corr_x = np.append(_smps_dia, _aps_sh_corr.dropna())
|
|
112
110
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
input_x = np.append(_smps_dia, _aps_sh_inp.dropna())
|
|
112
|
+
input_y = concat([_smps_dn, _aps_dn.iloc[:, ~np.isnan(_aps_sh_inp)]], axis=1)
|
|
113
|
+
input_y.columns = input_x
|
|
116
114
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
115
|
+
input_x.sort()
|
|
116
|
+
input_y = input_y[input_x]
|
|
117
|
+
corr_y = input_y[corr_x]
|
|
120
118
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
119
|
+
S2_lst = []
|
|
120
|
+
for (_tm, _inp_y_dn), (_tm, _cor_y_dn) in zip(input_y.dropna(how='all').iterrows(),
|
|
121
|
+
corr_y.dropna(how='all').iterrows()):
|
|
122
|
+
## corr(spec_data, spec_spline)
|
|
123
|
+
_spl_dt = [unvpline(input_x, _inp_y, s=_smooth)(corr_x) for _inp_y in
|
|
124
|
+
[_inp_y_dn, ds_fc(_inp_y_dn), dv_fc(_inp_y_dn)]]
|
|
125
|
+
_cor_dt = [_cor_y_dn, ds_fc(_cor_y_dn), dv_fc(_cor_y_dn)]
|
|
128
126
|
|
|
129
|
-
|
|
127
|
+
_cor_all = sum([np.corrcoef(_cor, _spl)[0, 1] for _cor, _spl in zip(_cor_dt, _spl_dt)])
|
|
130
128
|
|
|
131
|
-
|
|
129
|
+
S2_lst.append((3 - _cor_all) / 3)
|
|
132
130
|
|
|
133
|
-
|
|
131
|
+
return DataFrame(S2_lst, columns=[_idx])
|
|
134
132
|
|
|
135
133
|
|
|
136
134
|
# def _S2_calculate_dSdV(_smps, _aps, _shft_dn, _S2, smps_ori, aps_ori):
|
|
137
135
|
# def _S2_calculate_dSdV(_smps, _aps, smps_ori=None):
|
|
138
136
|
def _corr_with_dNdSdV(_smps, _aps, _alg_type):
|
|
139
|
-
|
|
137
|
+
print(f"\t\t\t{dtm.now().strftime('%m/%d %X')} : \033[92moverlap range correlation : {_alg_type}\033[0m")
|
|
140
138
|
|
|
141
|
-
|
|
142
|
-
|
|
139
|
+
_smps_dia = _smps.keys().astype(float)
|
|
140
|
+
_aps_dia = _aps.keys().astype(float)
|
|
143
141
|
|
|
144
|
-
|
|
145
|
-
|
|
142
|
+
all_index = _smps.index.copy()
|
|
143
|
+
qc_index = DatetimeIndex(set(_smps.dropna(how='all').index) & set(_aps.dropna(how='all').index)).sort_values()
|
|
146
144
|
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
_smps_dn = _smps.loc[qc_index].copy()
|
|
146
|
+
_aps_dn = _aps.loc[qc_index].copy()
|
|
149
147
|
|
|
150
|
-
|
|
151
|
-
|
|
148
|
+
ds_fc = lambda _dt: _dt * _dt.index ** 2 * np.pi
|
|
149
|
+
dv_fc = lambda _dt: _dt * _dt.index ** 3 * np.pi / 6
|
|
152
150
|
|
|
153
|
-
|
|
154
|
-
|
|
151
|
+
_std_bin = np.geomspace(11.8, 19810, 230)
|
|
152
|
+
_merge_bin = _std_bin[(_std_bin >= _smps_dia[-1]) & (_std_bin < 1500)].copy()
|
|
155
153
|
|
|
156
|
-
|
|
154
|
+
_smooth = 50
|
|
157
155
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
156
|
+
_shift_val = np.arange(0.5, 2.605, .005) ** .5
|
|
157
|
+
_shift_val = np.arange(0.9, 2.01, .01) ** .5
|
|
158
|
+
_shift_val = np.arange(0.9, 2.65, .05) ** .5
|
|
161
159
|
|
|
162
|
-
|
|
163
|
-
|
|
160
|
+
## spline fitting with shift aps and smps
|
|
161
|
+
pool = Pool(cpu_count())
|
|
164
162
|
|
|
165
|
-
|
|
166
|
-
|
|
163
|
+
S2_lst = pool.starmap(partial(_corr_fc, _aps_dia, _smps_dia, _smps_dn, _aps_dn, _smooth),
|
|
164
|
+
list(enumerate(_shift_val)))
|
|
167
165
|
|
|
168
|
-
|
|
169
|
-
|
|
166
|
+
pool.close()
|
|
167
|
+
pool.join()
|
|
170
168
|
|
|
171
|
-
|
|
172
|
-
|
|
169
|
+
S2_table = concat(S2_lst, axis=1).set_index(qc_index)[np.arange(_shift_val.size)].astype(float).dropna()
|
|
170
|
+
min_shft = S2_table.idxmin(axis=1).values
|
|
173
171
|
|
|
174
|
-
|
|
172
|
+
return DataFrame(_shift_val[min_shft.astype(int)], index=S2_table.index).astype(float).reindex(_smps.index)
|
|
175
173
|
|
|
176
174
|
|
|
177
175
|
## Create merge data
|
|
178
176
|
## shift all smps bin and remove the aps bin which smaller than the latest old smps bin
|
|
179
177
|
## Return : merge bins, merge data, density
|
|
180
178
|
def _merge_data(_smps_ori, _aps_ori, _shift_ori, _smps_lb, _aps_hb, _shift_mode, _alg_type):
|
|
181
|
-
|
|
179
|
+
print(f"\t\t\t{dtm.now().strftime('%m/%d %X')} : \033[92mcreate merge data : {_shift_mode} and {_alg_type}\033[0m")
|
|
182
180
|
|
|
183
|
-
|
|
184
|
-
|
|
181
|
+
_ori_idx = _smps_ori.index.copy()
|
|
182
|
+
# _merge_idx = _smps_ori.loc[_aps_ori.dropna(how='all').index].dropna(how='all').index
|
|
185
183
|
|
|
186
|
-
|
|
187
|
-
|
|
184
|
+
_corr_aps_cond = _aps_ori.keys() < 700
|
|
185
|
+
_corr_aps_ky = _aps_ori.keys()[_corr_aps_cond]
|
|
188
186
|
|
|
189
|
-
|
|
190
|
-
|
|
187
|
+
_merge_idx = DatetimeIndex(set(_smps_ori.dropna(how='all').index) & set(_aps_ori.dropna(how='all').index) &
|
|
188
|
+
set(_shift_ori.dropna(how='all').index)).sort_values()
|
|
191
189
|
|
|
192
|
-
|
|
190
|
+
_smps, _aps, _shift = _smps_ori.loc[_merge_idx], _aps_ori.loc[_merge_idx], _shift_ori.loc[_merge_idx].values
|
|
193
191
|
|
|
194
|
-
|
|
195
|
-
|
|
192
|
+
## parameter
|
|
193
|
+
_smps_key, _aps_key = _smps.keys()._data.astype(float), _aps.keys()._data.astype(float)
|
|
196
194
|
|
|
197
|
-
|
|
198
|
-
|
|
195
|
+
_cntr = 1000
|
|
196
|
+
_bin_lb = _smps_key[-1]
|
|
199
197
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
198
|
+
## make shift bins
|
|
199
|
+
_smps_bin = np.full(_smps.shape, _smps_key)
|
|
200
|
+
_aps_bin = np.full(_aps.shape, _aps_key)
|
|
203
201
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
202
|
+
_std_bin = np.geomspace(_smps_key[0], _aps_key[-1], 230)
|
|
203
|
+
_std_bin_merge = _std_bin[(_std_bin < _cntr) & (_std_bin > _bin_lb)]
|
|
204
|
+
_std_bin_inte1 = _std_bin[_std_bin <= _bin_lb]
|
|
205
|
+
_std_bin_inte2 = _std_bin[_std_bin >= _cntr]
|
|
208
206
|
|
|
209
|
-
|
|
210
|
-
|
|
207
|
+
if _shift_mode == 'mobility':
|
|
208
|
+
_aps_bin /= _shift
|
|
211
209
|
|
|
212
|
-
|
|
213
|
-
|
|
210
|
+
elif _shift_mode == 'aerodynamic':
|
|
211
|
+
_smps_bin *= _shift
|
|
214
212
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
213
|
+
## merge
|
|
214
|
+
_merge_lst, _corr_lst = [], []
|
|
215
|
+
for _bin_smps, _bin_aps, _dt_smps, _dt_aps, _sh in zip(_smps_bin, _aps_bin, _smps.values, _aps.values, _shift):
|
|
216
|
+
## keep complete smps bins and data
|
|
217
|
+
## remove the aps bin data lower than smps bin
|
|
218
|
+
_condi = _bin_aps >= _bin_smps[-1]
|
|
221
219
|
|
|
222
|
-
|
|
223
|
-
|
|
220
|
+
_merge_bin = np.hstack((_bin_smps, _bin_aps[_condi]))
|
|
221
|
+
_merge_dt = np.hstack((_dt_smps, _dt_aps[_condi]))
|
|
224
222
|
|
|
225
|
-
|
|
223
|
+
_merge_fit_loc = (_merge_bin < 1500) & (_merge_bin > _smps_lb)
|
|
226
224
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
225
|
+
## coeA and coeB
|
|
226
|
+
_unvpl_fc = unvpline(np.log(_merge_bin[_merge_fit_loc]), np.log(_merge_dt[_merge_fit_loc]), s=50)
|
|
227
|
+
_inte_fc = interp1d(_merge_bin, _merge_dt, kind='linear', fill_value='extrapolate')
|
|
230
228
|
|
|
231
|
-
|
|
232
|
-
|
|
229
|
+
_merge_dt_fit = np.hstack((_inte_fc(_std_bin_inte1), np.exp(_unvpl_fc(np.log(_std_bin_merge))),
|
|
230
|
+
_inte_fc(_std_bin_inte2)))
|
|
233
231
|
|
|
234
|
-
|
|
235
|
-
|
|
232
|
+
_merge_lst.append(_merge_dt_fit)
|
|
233
|
+
_corr_lst.append(interp1d(_std_bin, _merge_dt_fit)(_bin_aps[_corr_aps_cond]))
|
|
236
234
|
|
|
237
|
-
|
|
238
|
-
|
|
235
|
+
_df_merge = DataFrame(_merge_lst, columns=_std_bin, index=_merge_idx)
|
|
236
|
+
_df_merge = _df_merge.mask(_df_merge < 0)
|
|
239
237
|
|
|
240
|
-
|
|
238
|
+
_df_corr = DataFrame(_corr_lst, columns=_corr_aps_ky, index=_merge_idx) / _aps_ori.loc[_merge_idx, _corr_aps_ky]
|
|
241
239
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
240
|
+
## process output df
|
|
241
|
+
## average, align with index
|
|
242
|
+
def _out_df(*_df_arg, **_df_kwarg):
|
|
243
|
+
_df = DataFrame(*_df_arg, **_df_kwarg).reindex(_ori_idx)
|
|
244
|
+
_df.index.name = 'time'
|
|
245
|
+
return _df
|
|
248
246
|
|
|
249
|
-
|
|
247
|
+
return _out_df(_df_merge), _out_df(_shift_ori ** 2), _out_df(_df_corr)
|
|
250
248
|
|
|
251
249
|
|
|
252
250
|
def _fitness_func(psd, rho, pm25):
|
|
253
|
-
|
|
254
|
-
|
|
251
|
+
psd_pm25 = psd[psd.keys()[psd.keys().values <= 2500]] * np.diff(np.log10(psd.keys())).mean()
|
|
252
|
+
rho_pm25 = pm25 / (psd_pm25 * np.pi * psd_pm25.keys().values ** 3 / 6 * 1e-9).sum(axis=1, min_count=1)
|
|
255
253
|
|
|
256
|
-
|
|
254
|
+
return (rho['density'] - rho_pm25) ** 2
|
|
257
255
|
|
|
258
256
|
|
|
259
257
|
def merge_SMPS_APS(df_smps, df_aps, df_pm25, aps_unit='um', smps_overlap_lowbound=500, aps_fit_highbound=1000,
|
|
260
|
-
|
|
261
|
-
|
|
258
|
+
dndsdv_alg=True, times_range=(0.8, 1.25, .05)):
|
|
259
|
+
# merge_data, merge_data_dn, merge_data_dsdv, merge_data_cor_dn, density, density_dn, density_dsdv, density_cor_dn = [DataFrame([np.nan])] * 8
|
|
262
260
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
261
|
+
## set to the same units
|
|
262
|
+
smps, aps = df_smps.copy(), df_aps.copy()
|
|
263
|
+
smps.columns = smps.keys().to_numpy(float)
|
|
264
|
+
aps.columns = aps.keys().to_numpy(float)
|
|
267
265
|
|
|
268
|
-
|
|
269
|
-
|
|
266
|
+
if aps_unit == 'um':
|
|
267
|
+
aps.columns = aps.keys() * 1e3
|
|
270
268
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
269
|
+
fitness_typ = dict(dn=[], cor_dn=[], dndsdv=[], cor_dndsdv=[])
|
|
270
|
+
shift_typ = dict(dn=[], cor_dn=[], dndsdv=[], cor_dndsdv=[])
|
|
271
|
+
oth_typ = dict()
|
|
274
272
|
|
|
275
|
-
|
|
276
|
-
|
|
273
|
+
times_ary = np.arange(*times_range).round(4)
|
|
274
|
+
# times_ary = np.arange(*(0.8, 0.9, .05)).round(4)
|
|
277
275
|
|
|
278
|
-
|
|
276
|
+
for times in times_ary:
|
|
279
277
|
|
|
280
|
-
|
|
278
|
+
print(f"\t\t{dtm.now().strftime('%m/%d %X')} : \033[92mSMPS times value : {times}\033[0m")
|
|
281
279
|
|
|
282
|
-
|
|
283
|
-
|
|
280
|
+
aps_input = aps.copy()
|
|
281
|
+
aps_over = aps_input.loc[:, (aps.keys() > 700) & (aps.keys() < 1000)].copy()
|
|
284
282
|
|
|
285
|
-
|
|
286
|
-
|
|
283
|
+
smps_input = (smps * times).copy()
|
|
284
|
+
smps_over = smps_input[smps.keys()[smps.keys() > 500]].copy()
|
|
287
285
|
|
|
288
|
-
|
|
286
|
+
for _count in range(2):
|
|
289
287
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
288
|
+
## shift data calculate
|
|
289
|
+
## original
|
|
290
|
+
if _count == 0:
|
|
291
|
+
alg_type = 'dn'
|
|
292
|
+
shift = _powerlaw_fit_dN(smps_over, aps_over, alg_type)
|
|
295
293
|
|
|
296
|
-
|
|
297
|
-
|
|
294
|
+
if dndsdv_alg:
|
|
295
|
+
shift_dsdv = _corr_with_dNdSdV(smps_over, aps_over, 'dndsdv').mask(shift.isna())
|
|
298
296
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
297
|
+
## aps correct
|
|
298
|
+
else:
|
|
299
|
+
alg_type = 'cor_dndsdv'
|
|
300
|
+
shift_cor = _powerlaw_fit_dN(smps_over, aps_over, 'cor_dn')
|
|
303
301
|
|
|
304
|
-
|
|
305
|
-
|
|
302
|
+
if dndsdv_alg:
|
|
303
|
+
shift = _corr_with_dNdSdV(smps_over, aps_over, alg_type).mask(shift_cor.isna())
|
|
306
304
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
305
|
+
## merge aps and smps
|
|
306
|
+
## 1. power law fit (dn) -> return dn data and aps correct factor
|
|
307
|
+
## 2. correaltion with dn, ds, dv -> return corrected dn_ds_dv data
|
|
308
|
+
if (alg_type == 'dn') | dndsdv_alg:
|
|
309
|
+
merge_arg = (smps_input, aps_input, shift, smps_overlap_lowbound, aps_fit_highbound)
|
|
312
310
|
|
|
313
|
-
|
|
314
|
-
|
|
311
|
+
merge_data, density, _corr = _merge_data(*merge_arg, 'mobility', _alg_type=alg_type)
|
|
312
|
+
density.columns = ['density']
|
|
315
313
|
|
|
316
|
-
|
|
317
|
-
|
|
314
|
+
fitness_typ[alg_type].append(_fitness_func(merge_data, density, df_pm25))
|
|
315
|
+
shift_typ[alg_type].append(shift[0])
|
|
318
316
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
317
|
+
## without aps correct
|
|
318
|
+
if _count == 0:
|
|
319
|
+
## merge aps and smps
|
|
320
|
+
## dn_ds_dv data
|
|
321
|
+
if dndsdv_alg:
|
|
322
|
+
alg_type = 'dndsdv'
|
|
323
|
+
merge_arg = (smps_input, aps_input, shift_dsdv, smps_overlap_lowbound, aps_fit_highbound)
|
|
326
324
|
|
|
327
|
-
|
|
328
|
-
|
|
325
|
+
merge_data_dsdv, density_dsdv, _ = _merge_data(*merge_arg, 'mobility', _alg_type=alg_type)
|
|
326
|
+
density_dsdv.columns = ['density']
|
|
329
327
|
|
|
330
|
-
|
|
331
|
-
|
|
328
|
+
fitness_typ[alg_type].append(_fitness_func(merge_data_dsdv, density_dsdv, df_pm25))
|
|
329
|
+
shift_typ[alg_type].append(shift_dsdv[0])
|
|
332
330
|
|
|
333
|
-
|
|
334
|
-
|
|
331
|
+
## dn data
|
|
332
|
+
merge_data_dn, density_dn = merge_data.copy(), density.copy()
|
|
335
333
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
334
|
+
## correct aps data
|
|
335
|
+
corr = _corr.resample('1d').mean().reindex(smps.index).ffill()
|
|
336
|
+
corr = corr.mask(corr < 1, 1)
|
|
339
337
|
|
|
340
|
-
|
|
341
|
-
|
|
338
|
+
aps_input.loc[:, corr.keys()] *= corr
|
|
339
|
+
aps_over = aps_input.copy()
|
|
342
340
|
|
|
343
341
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
342
|
+
## with aps correct
|
|
343
|
+
else:
|
|
344
|
+
## merge aps and smps
|
|
345
|
+
## dn data
|
|
346
|
+
alg_type = 'cor_dn'
|
|
347
|
+
merge_arg = (smps_input, aps_input, shift_cor, smps_overlap_lowbound, aps_fit_highbound)
|
|
350
348
|
|
|
351
|
-
|
|
352
|
-
|
|
349
|
+
merge_data_cor_dn, density_cor_dn, _ = _merge_data(*merge_arg, 'mobility', _alg_type=alg_type)
|
|
350
|
+
density_cor_dn.columns = ['density']
|
|
353
351
|
|
|
354
|
-
|
|
355
|
-
|
|
352
|
+
fitness_typ[alg_type].append(_fitness_func(merge_data_cor_dn, density_cor_dn, df_pm25))
|
|
353
|
+
shift_typ[alg_type].append(shift_cor[0])
|
|
356
354
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
355
|
+
## get times value and shift value
|
|
356
|
+
out_dic = {}
|
|
357
|
+
for (_typ, _lst), (_typ, _shft) in zip(fitness_typ.items(), shift_typ.items()):
|
|
358
|
+
oth_typ[_typ] = None
|
|
359
|
+
if len(_lst) == 0: continue
|
|
362
360
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
361
|
+
df_times_min = concat(_lst, axis=1, keys=range(len(_lst))).idxmin(axis=1).dropna().astype(int)
|
|
362
|
+
df_shift = concat(_shft, axis=1, keys=times_ary.tolist()).loc[df_times_min.index].values[
|
|
363
|
+
range(len(df_times_min.index)), df_times_min.values]
|
|
366
364
|
|
|
367
|
-
|
|
368
|
-
|
|
365
|
+
oth_typ[_typ] = DataFrame(np.array([df_shift, times_ary[df_times_min.values]]).T,
|
|
366
|
+
index=df_times_min.index, columns=['shift', 'times']).reindex(smps.index)
|
|
369
367
|
|
|
370
|
-
|
|
371
|
-
|
|
368
|
+
## re-calculate merge_data
|
|
369
|
+
alg_type = ['dn', 'cor_dn', 'dndsdv', 'cor_dndsdv'] if dndsdv_alg else ['dn', 'cor_dn']
|
|
372
370
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
371
|
+
out_dic = {}
|
|
372
|
+
den_lst, times_lst = [], []
|
|
373
|
+
for _typ in alg_type:
|
|
374
|
+
print(f"\t\t{dtm.now().strftime('%m/%d %X')} : \033[92mre-caculate merge data with times: {_typ}\033[0m")
|
|
375
|
+
typ = oth_typ[_typ]
|
|
376
|
+
smps_input = smps.copy() * typ['times'].to_frame().values
|
|
379
377
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
378
|
+
corr_typ = corr if 'cor' in _typ else 1
|
|
379
|
+
aps_input = aps.copy()
|
|
380
|
+
aps_input.loc[:, corr.keys()] *= corr_typ
|
|
383
381
|
|
|
384
|
-
|
|
382
|
+
merge_arg = (smps_input, aps_input, typ['shift'].to_frame(), smps_overlap_lowbound, aps_fit_highbound)
|
|
385
383
|
|
|
386
|
-
|
|
387
|
-
|
|
384
|
+
merge_data, density, _corr = _merge_data(*merge_arg, 'mobility', _alg_type=_typ)
|
|
385
|
+
density.columns = ['density']
|
|
388
386
|
|
|
389
|
-
|
|
387
|
+
out_dic[f'data_{_typ}'] = merge_data
|
|
390
388
|
|
|
391
|
-
|
|
392
|
-
|
|
389
|
+
den_lst.append(density)
|
|
390
|
+
times_lst.append(typ['times'])
|
|
393
391
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
392
|
+
out_rho = concat(den_lst, axis=1)
|
|
393
|
+
out_times = concat(times_lst, axis=1)
|
|
394
|
+
out_rho.columns = alg_type
|
|
395
|
+
out_times.columns = alg_type
|
|
398
396
|
|
|
399
|
-
|
|
397
|
+
# breakpoint()
|
|
400
398
|
|
|
401
|
-
|
|
402
|
-
|
|
399
|
+
## out
|
|
400
|
+
out_dic.update(dict(density=out_rho, times=out_times))
|
|
403
401
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
402
|
+
# out_dic = {
|
|
403
|
+
# 'data_cor_dndsdv' : merge_data,
|
|
404
|
+
# 'data_dn' : merge_data_dn,
|
|
405
|
+
# 'data_dndsdv' : merge_data_dsdv,
|
|
406
|
+
# 'data_cor_dn' : merge_data_cor_dn,
|
|
409
407
|
|
|
410
|
-
|
|
408
|
+
# 'density' : out_rho,
|
|
411
409
|
|
|
412
|
-
|
|
410
|
+
# 'data_all_aer' : merge_data_aer,
|
|
413
411
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
412
|
+
# 'density_cor_dndsdv' : density,
|
|
413
|
+
# 'density_dn' : density_dn,
|
|
414
|
+
# 'density_dndsdv' : density_dsdv,
|
|
415
|
+
# 'density_cor_dn' : density_cor_dn,
|
|
416
|
+
# }
|
|
419
417
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
418
|
+
## process data
|
|
419
|
+
for _nam, _df in out_dic.items():
|
|
420
|
+
out_dic[_nam] = _df.reindex(smps.index).copy()
|
|
423
421
|
|
|
424
|
-
|
|
422
|
+
return out_dic
|