AeroViz 0.1.0__tar.gz

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

Potentially problematic release.


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

Files changed (108) hide show
  1. aeroviz-0.1.0/AeroViz/__init__.py +15 -0
  2. aeroviz-0.1.0/AeroViz/dataProcess/Chemistry/__init__.py +63 -0
  3. aeroviz-0.1.0/AeroViz/dataProcess/Chemistry/_calculate.py +27 -0
  4. aeroviz-0.1.0/AeroViz/dataProcess/Chemistry/_isoropia.py +99 -0
  5. aeroviz-0.1.0/AeroViz/dataProcess/Chemistry/_mass_volume.py +175 -0
  6. aeroviz-0.1.0/AeroViz/dataProcess/Chemistry/_ocec.py +184 -0
  7. aeroviz-0.1.0/AeroViz/dataProcess/Chemistry/_partition.py +29 -0
  8. aeroviz-0.1.0/AeroViz/dataProcess/Chemistry/_teom.py +16 -0
  9. aeroviz-0.1.0/AeroViz/dataProcess/Optical/_IMPROVE.py +61 -0
  10. aeroviz-0.1.0/AeroViz/dataProcess/Optical/__init__.py +62 -0
  11. aeroviz-0.1.0/AeroViz/dataProcess/Optical/_absorption.py +54 -0
  12. aeroviz-0.1.0/AeroViz/dataProcess/Optical/_extinction.py +36 -0
  13. aeroviz-0.1.0/AeroViz/dataProcess/Optical/_mie.py +16 -0
  14. aeroviz-0.1.0/AeroViz/dataProcess/Optical/_mie_sd.py +143 -0
  15. aeroviz-0.1.0/AeroViz/dataProcess/Optical/_scattering.py +30 -0
  16. aeroviz-0.1.0/AeroViz/dataProcess/SizeDistr/__init__.py +61 -0
  17. aeroviz-0.1.0/AeroViz/dataProcess/SizeDistr/__merge.py +250 -0
  18. aeroviz-0.1.0/AeroViz/dataProcess/SizeDistr/_merge.py +245 -0
  19. aeroviz-0.1.0/AeroViz/dataProcess/SizeDistr/_merge_v1.py +254 -0
  20. aeroviz-0.1.0/AeroViz/dataProcess/SizeDistr/_merge_v2.py +243 -0
  21. aeroviz-0.1.0/AeroViz/dataProcess/SizeDistr/_merge_v3.py +518 -0
  22. aeroviz-0.1.0/AeroViz/dataProcess/SizeDistr/_merge_v4.py +424 -0
  23. aeroviz-0.1.0/AeroViz/dataProcess/SizeDistr/_size_distr.py +93 -0
  24. aeroviz-0.1.0/AeroViz/dataProcess/VOC/__init__.py +19 -0
  25. aeroviz-0.1.0/AeroViz/dataProcess/VOC/_potential_par.py +76 -0
  26. aeroviz-0.1.0/AeroViz/dataProcess/__init__.py +11 -0
  27. aeroviz-0.1.0/AeroViz/dataProcess/core/__init__.py +92 -0
  28. aeroviz-0.1.0/AeroViz/plot/__init__.py +7 -0
  29. aeroviz-0.1.0/AeroViz/plot/distribution/__init__.py +1 -0
  30. aeroviz-0.1.0/AeroViz/plot/distribution/distribution.py +582 -0
  31. aeroviz-0.1.0/AeroViz/plot/improve/__init__.py +1 -0
  32. aeroviz-0.1.0/AeroViz/plot/improve/improve.py +240 -0
  33. aeroviz-0.1.0/AeroViz/plot/meteorology/__init__.py +1 -0
  34. aeroviz-0.1.0/AeroViz/plot/meteorology/meteorology.py +317 -0
  35. aeroviz-0.1.0/AeroViz/plot/optical/__init__.py +2 -0
  36. aeroviz-0.1.0/AeroViz/plot/optical/aethalometer.py +77 -0
  37. aeroviz-0.1.0/AeroViz/plot/optical/optical.py +388 -0
  38. aeroviz-0.1.0/AeroViz/plot/templates/__init__.py +8 -0
  39. aeroviz-0.1.0/AeroViz/plot/templates/contour.py +47 -0
  40. aeroviz-0.1.0/AeroViz/plot/templates/corr_matrix.py +108 -0
  41. aeroviz-0.1.0/AeroViz/plot/templates/diurnal_pattern.py +42 -0
  42. aeroviz-0.1.0/AeroViz/plot/templates/event_evolution.py +65 -0
  43. aeroviz-0.1.0/AeroViz/plot/templates/koschmieder.py +156 -0
  44. aeroviz-0.1.0/AeroViz/plot/templates/metal_heatmap.py +57 -0
  45. aeroviz-0.1.0/AeroViz/plot/templates/regression.py +256 -0
  46. aeroviz-0.1.0/AeroViz/plot/templates/scatter.py +130 -0
  47. aeroviz-0.1.0/AeroViz/plot/templates/templates.py +398 -0
  48. aeroviz-0.1.0/AeroViz/plot/timeseries/__init__.py +1 -0
  49. aeroviz-0.1.0/AeroViz/plot/timeseries/timeseries.py +317 -0
  50. aeroviz-0.1.0/AeroViz/plot/utils/__init__.py +3 -0
  51. aeroviz-0.1.0/AeroViz/plot/utils/_color.py +71 -0
  52. aeroviz-0.1.0/AeroViz/plot/utils/_decorator.py +74 -0
  53. aeroviz-0.1.0/AeroViz/plot/utils/_unit.py +55 -0
  54. aeroviz-0.1.0/AeroViz/process/__init__.py +31 -0
  55. aeroviz-0.1.0/AeroViz/process/core/DataProc.py +19 -0
  56. aeroviz-0.1.0/AeroViz/process/core/SizeDist.py +90 -0
  57. aeroviz-0.1.0/AeroViz/process/core/__init__.py +4 -0
  58. aeroviz-0.1.0/AeroViz/process/method/PyMieScatt_update.py +567 -0
  59. aeroviz-0.1.0/AeroViz/process/method/__init__.py +2 -0
  60. aeroviz-0.1.0/AeroViz/process/method/mie_theory.py +258 -0
  61. aeroviz-0.1.0/AeroViz/process/method/prop.py +62 -0
  62. aeroviz-0.1.0/AeroViz/process/script/AbstractDistCalc.py +143 -0
  63. aeroviz-0.1.0/AeroViz/process/script/Chemical.py +176 -0
  64. aeroviz-0.1.0/AeroViz/process/script/IMPACT.py +49 -0
  65. aeroviz-0.1.0/AeroViz/process/script/IMPROVE.py +161 -0
  66. aeroviz-0.1.0/AeroViz/process/script/Others.py +65 -0
  67. aeroviz-0.1.0/AeroViz/process/script/PSD.py +103 -0
  68. aeroviz-0.1.0/AeroViz/process/script/PSD_dry.py +94 -0
  69. aeroviz-0.1.0/AeroViz/process/script/__init__.py +5 -0
  70. aeroviz-0.1.0/AeroViz/process/script/retrieve_RI.py +70 -0
  71. aeroviz-0.1.0/AeroViz/rawDataReader/__init__.py +68 -0
  72. aeroviz-0.1.0/AeroViz/rawDataReader/core/__init__.py +397 -0
  73. aeroviz-0.1.0/AeroViz/rawDataReader/script/AE33.py +31 -0
  74. aeroviz-0.1.0/AeroViz/rawDataReader/script/AE43.py +34 -0
  75. aeroviz-0.1.0/AeroViz/rawDataReader/script/APS_3321.py +47 -0
  76. aeroviz-0.1.0/AeroViz/rawDataReader/script/Aurora.py +38 -0
  77. aeroviz-0.1.0/AeroViz/rawDataReader/script/BC1054.py +46 -0
  78. aeroviz-0.1.0/AeroViz/rawDataReader/script/EPA_vertical.py +18 -0
  79. aeroviz-0.1.0/AeroViz/rawDataReader/script/GRIMM.py +35 -0
  80. aeroviz-0.1.0/AeroViz/rawDataReader/script/IGAC_TH.py +104 -0
  81. aeroviz-0.1.0/AeroViz/rawDataReader/script/IGAC_ZM.py +90 -0
  82. aeroviz-0.1.0/AeroViz/rawDataReader/script/MA350.py +45 -0
  83. aeroviz-0.1.0/AeroViz/rawDataReader/script/NEPH.py +57 -0
  84. aeroviz-0.1.0/AeroViz/rawDataReader/script/OCEC_LCRES.py +34 -0
  85. aeroviz-0.1.0/AeroViz/rawDataReader/script/OCEC_RES.py +28 -0
  86. aeroviz-0.1.0/AeroViz/rawDataReader/script/SMPS_TH.py +41 -0
  87. aeroviz-0.1.0/AeroViz/rawDataReader/script/SMPS_aim11.py +51 -0
  88. aeroviz-0.1.0/AeroViz/rawDataReader/script/SMPS_genr.py +51 -0
  89. aeroviz-0.1.0/AeroViz/rawDataReader/script/TEOM.py +46 -0
  90. aeroviz-0.1.0/AeroViz/rawDataReader/script/Table.py +28 -0
  91. aeroviz-0.1.0/AeroViz/rawDataReader/script/VOC_TH.py +30 -0
  92. aeroviz-0.1.0/AeroViz/rawDataReader/script/VOC_ZM.py +37 -0
  93. aeroviz-0.1.0/AeroViz/rawDataReader/script/__init__.py +22 -0
  94. aeroviz-0.1.0/AeroViz/tools/__init__.py +3 -0
  95. aeroviz-0.1.0/AeroViz/tools/database.py +94 -0
  96. aeroviz-0.1.0/AeroViz/tools/dataclassifier.py +117 -0
  97. aeroviz-0.1.0/AeroViz/tools/datareader.py +66 -0
  98. aeroviz-0.1.0/AeroViz.egg-info/PKG-INFO +117 -0
  99. aeroviz-0.1.0/AeroViz.egg-info/SOURCES.txt +106 -0
  100. aeroviz-0.1.0/AeroViz.egg-info/dependency_links.txt +1 -0
  101. aeroviz-0.1.0/AeroViz.egg-info/requires.txt +8 -0
  102. aeroviz-0.1.0/AeroViz.egg-info/top_level.txt +1 -0
  103. aeroviz-0.1.0/LICENSE +21 -0
  104. aeroviz-0.1.0/PKG-INFO +117 -0
  105. aeroviz-0.1.0/README.md +95 -0
  106. aeroviz-0.1.0/setup.cfg +4 -0
  107. aeroviz-0.1.0/setup.py +34 -0
  108. aeroviz-0.1.0/tests/test_plot.py +100 -0
@@ -0,0 +1,15 @@
1
+ # This file is used to import all the modules in the DataPlot package
2
+ from AeroViz import plot
3
+ from AeroViz.dataProcess import Optical, SizeDistr, Chemistry, VOC
4
+ from AeroViz.plot import Color, Unit, set_figure
5
+ from AeroViz.process import DataProcess
6
+ from AeroViz.rawDataReader import RawDataReader
7
+ from AeroViz.tools import DataBase, DataReader, DataClassifier
8
+
9
+ __all__ = [
10
+ 'plot',
11
+ 'Color', 'Unit', 'set_figure',
12
+ 'RawDataReader',
13
+ 'Optical', 'SizeDistr', 'Chemistry', 'VOC',
14
+ 'DataProcess', 'DataBase', 'DataReader', 'DataClassifier',
15
+ ]
@@ -0,0 +1,63 @@
1
+ from ..core import _writter, _run_process
2
+
3
+ __all__ = [
4
+
5
+ 'Chemistry',
6
+
7
+ ]
8
+
9
+
10
+ class Chemistry(_writter):
11
+
12
+ ## Reconstruction
13
+ @_run_process('Chemistry - reconstruction basic', 'reconstrc_basic')
14
+ def ReConstrc_basic(self, *df_chem, df_ref=None, df_water=None, df_density=None,
15
+ nam_lst=['NH4+', 'SO42-', 'NO3-', 'Fe', 'Na+', 'OC', 'EC']):
16
+ from ._mass_volume import _basic
17
+
18
+ out = _basic(df_chem, df_ref, df_water, df_density, nam_lst=nam_lst)
19
+
20
+ return self, out
21
+
22
+ ## Partition
23
+ @_run_process('Chemistry - Partition', 'partition')
24
+ def Partition(self, *df_chem, nam_lst=['NH4+', 'SO42-', 'NO3-', 'Cl-', 'NO2', 'HNO3', 'SO2', 'NH3', 'HCl', 'temp']):
25
+ from ._partition import _basic
26
+
27
+ out = _basic(df_chem, nam_lst=nam_lst)
28
+
29
+ return self, out
30
+
31
+ ## ISOROPIA
32
+ @_run_process('Chemistry - ISOROPIA', 'isoropia')
33
+ def ISOROPIA(self, *df_chem,
34
+ nam_lst=['Na+', 'SO42-', 'NH4+', 'NO3-', 'Cl-', 'Ca2+', 'K+', 'Mg2+', 'NH3', 'HNO3', 'HCl', 'RH',
35
+ 'temp']):
36
+ from ._isoropia import _basic
37
+
38
+ if self.path_out is None:
39
+ raise ValueError('Please Input "path_out" !!')
40
+
41
+ out = _basic(df_chem, self.path_out, nam_lst=nam_lst)
42
+
43
+ return self, out
44
+
45
+ ## OCEC
46
+ @_run_process('Chemistry - OC/EC basic', 'ocec_basic')
47
+ def OCEC_basic(self, df_lcres, df_res, df_mass=None, ocec_ratio=None, ocec_ratio_month=1, hr_lim=200,
48
+ least_square_range=(0.1, 2.5, 0.1), WISOC_OC_range=(0.2, 0.7, 0.01), ):
49
+ from ._ocec import _basic
50
+
51
+ out = _basic(df_lcres, df_res, df_mass, ocec_ratio, ocec_ratio_month, hr_lim, least_square_range,
52
+ WISOC_OC_range)
53
+
54
+ return self, out
55
+
56
+ ## TEOM
57
+ @_run_process('Chemistry - TEOM basic', 'teom_basic')
58
+ def TEOM_basic(self, df_teom, df_check=None):
59
+ from ._teom import _basic
60
+
61
+ out = _basic(df_teom, df_check)
62
+
63
+ return self, out
@@ -0,0 +1,27 @@
1
+ from pandas import concat, DataFrame
2
+
3
+ # parameter
4
+ _mol_wg = {
5
+ 'SO42-': 96.06,
6
+ 'NO3-': 62.00,
7
+ 'Cl-': 35.4,
8
+
9
+ 'Ca2+': 40.078,
10
+ 'K+': 39.098,
11
+ 'Mg2+': 24.305,
12
+ 'Na+': 22.99,
13
+ 'NH4+': 18.04,
14
+ }
15
+
16
+
17
+ # ug -> umol
18
+ def _ug2umol(_df):
19
+ _pt_ky = list(set(_df.keys()) & set(_mol_wg.keys()))
20
+ _gas_ky = list(set(_df.keys()) - set(_mol_wg.keys()) - set(['temp', 'RH']))
21
+
22
+ _par = (_df['temp'].to_frame() + 273.15) * .082
23
+
24
+ _df_pt = concat([(_df[_ky] / _mol_wg[_ky]).copy() for _ky in _pt_ky], axis=1)
25
+ _df_gas = _df[_gas_ky] / _par.values
26
+
27
+ return concat([_df_pt, _df_gas], axis=1)
@@ -0,0 +1,99 @@
1
+ from subprocess import Popen, PIPE
2
+ from pandas import date_range, concat, DataFrame, to_numeric, read_csv
3
+ from ._calculate import _ug2umol
4
+ import numpy as np
5
+
6
+ from pathlib import Path
7
+
8
+
9
+ def _basic(df_che, path_out, nam_lst):
10
+ # parameter
11
+ df_all = concat(df_che, axis=1)
12
+ index = df_all.index.copy()
13
+ df_all.columns = nam_lst
14
+
15
+ df_umol = _ug2umol(df_all)
16
+
17
+ ## output
18
+ ## Na, SO4, NH3, NO3, Cl, Ca, K, Mg, RH, TEMP
19
+ df_input = DataFrame(index=index)
20
+ df_out = DataFrame(index=index)
21
+
22
+ pth_input = path_out / '_temp_input.txt'
23
+ pth_output = path_out / '_temp_input.dat'
24
+
25
+ pth_input.unlink(missing_ok=True)
26
+ pth_output.unlink(missing_ok=True)
27
+
28
+ ## header
29
+ _header = 'Input units (0=umol/m3, 1=ug/m3)\n' + '0\n\n' + \
30
+ 'Problem type (0=forward, 1=reverse); Phase state (0=solid+liquid, 1=metastable)\n' + '0, 1\n\n' + \
31
+ 'NH4-SO4 system case\n'
32
+
33
+ ## software
34
+ path_iso = Path(__file__).parent / 'isrpia2.exe'
35
+
36
+ # make input file and output temp input (without index)
37
+ ## NH3
38
+ df_input['NH3'] = df_umol['NH4+'].fillna(0).copy() + df_umol['NH3']
39
+
40
+ ## NO3
41
+ df_input['NO3'] = df_umol['HNO3'].fillna(0).copy() + df_umol['NO3-']
42
+
43
+ ## Cl
44
+ df_input['Cl'] = df_umol['HCl'].fillna(0).copy() + df_umol['Cl-']
45
+
46
+ ## temp, RH
47
+ df_input['RH'] = df_all['RH'] / 100
48
+ df_input['TEMP'] = df_all['temp'] + 273.15
49
+
50
+ df_input[['Na', 'SO4', 'Ca', 'K', 'Mg']] = df_umol[['Na+', 'SO42-', 'Ca2+', 'K+', 'Mg2+']].copy()
51
+
52
+ df_input = df_input[['Na', 'SO4', 'NH3', 'NO3', 'Cl', 'Ca', 'K', 'Mg', 'RH', 'TEMP']].fillna('-').copy()
53
+
54
+ ## output the input data
55
+ df_input.to_csv(pth_input, index=False)
56
+ with (pth_input).open('r+', encoding='utf-8', errors='ignore') as _f:
57
+ _cont = _f.read()
58
+ _f.seek(0)
59
+
60
+ _f.write(_header)
61
+ _f.write(_cont)
62
+
63
+ # use ISOROPIA2
64
+ run = Popen([path_iso], stdin=PIPE, stdout=PIPE, stderr=PIPE)
65
+ scrn_res, run_res = run.communicate(input=str(pth_input.resolve()).encode())
66
+
67
+ # read dat file and transform to the normal name
68
+ cond_idx = df_all[['SO42-', 'NH4+', 'NO3-']].dropna().index
69
+
70
+ with (pth_output).open('r', encoding='utf-8', errors='ignore') as f:
71
+ df_res = read_csv(f, delimiter='\s+').apply(to_numeric, errors='coerce').set_index(index)
72
+
73
+ df_out['H'] = df_res['HLIQ'] / (df_res['WATER'] / 1000)
74
+
75
+ df_out.loc[cond_idx, 'pH'] = -np.log10(df_out['H'].loc[cond_idx])
76
+ df_out['pH'] = df_out['pH'].where((df_all['RH'] <= 95) & (df_all['RH'] >= 20))
77
+
78
+ cond_idx = df_out['pH'].dropna().index
79
+ df_out.loc[cond_idx, 'ALWC'] = df_res['WATER'].loc[cond_idx]
80
+
81
+ df_out[['NH3', 'HNO3', 'HCl', 'NH4+', 'NO3-', 'Cl-']] = df_res[
82
+ ['GNH3', 'GHNO3', 'GHCL', 'NH4AER', 'NO3AER', 'CLAER']]
83
+
84
+ # calculate partition
85
+ # df_out['epls_NO3-'] = df_umol['NO3-'] / (df_umol['NO3-'] + df_umol['HNO3'])
86
+ # df_out['epls_NH4+'] = df_umol['NH4+'] / (df_umol['NH4+'] + df_umol['NH3'])
87
+ # df_out['epls_Cl-'] = df_umol['Cl-'] / (df_umol['Cl-'] + df_umol['HCl'])
88
+
89
+ # remove _temp file (input and output)
90
+ pth_input.unlink(missing_ok=True)
91
+ pth_output.unlink(missing_ok=True)
92
+
93
+ # output input and output
94
+ out = {
95
+ 'input': df_input,
96
+ 'output': df_out,
97
+ }
98
+
99
+ return out
@@ -0,0 +1,175 @@
1
+ from pandas import date_range, concat, DataFrame, to_numeric
2
+
3
+
4
+ def _basic(df_che, df_ref, df_water, df_density, nam_lst):
5
+ df_all = concat(df_che, axis=1)
6
+ index = df_all.index.copy()
7
+ df_all.columns = nam_lst
8
+
9
+ ## parameter
10
+ mol_A, mol_S, mol_N = df_all['NH4+'] / 18, df_all['SO42-'] / 96, df_all['NO3-'] / 62
11
+ df_all['status'] = (mol_A) / (2 * mol_S + mol_N)
12
+
13
+ convert_nam = {'AS': 'SO42-',
14
+ 'AN': 'NO3-',
15
+ 'OM': 'OC',
16
+ 'Soil': 'Fe',
17
+ 'SS': 'Na+',
18
+ 'EC': 'EC',
19
+ }
20
+
21
+ mass_coe = {'AS': 1.375,
22
+ 'AN': 1.29,
23
+ 'OM': 1.8,
24
+ 'Soil': 28.57,
25
+ 'SS': 2.54,
26
+ 'EC': 1,
27
+ }
28
+
29
+ vol_coe = {'AS': 1.76,
30
+ 'AN': 1.73,
31
+ 'OM': 1.4,
32
+ 'Soil': 2.6,
33
+ 'SS': 2.16,
34
+ 'EC': 1.5,
35
+ }
36
+
37
+ RI_coe = {'550': {'ALWC': 1.333 + 0j,
38
+ 'AS': 1.53 + 0j,
39
+ 'AN': 1.55 + 0j,
40
+ 'OM': 1.55 + 0.0163j,
41
+ 'Soil': 1.56 + 0.006j,
42
+ 'SS': 1.54 + 0j,
43
+ 'EC': 1.80 + 0.72j,
44
+ },
45
+
46
+ ## m + kj -> m value is same as 550 current
47
+ '450': {'ALWC': 1.333 + 0j,
48
+ 'AS': 1.57 + 0j,
49
+ 'AN': 1.57 + 0j,
50
+ 'OM': 1.58 + 0.056,
51
+ 'Soil': 1.56 + 0.009j,
52
+ 'SS': 1.54 + 0j,
53
+ 'EC': 1.80 + 0.79j,
54
+ },
55
+ }
56
+
57
+ ## mass
58
+ ## NH4 Enough
59
+ df_mass = DataFrame()
60
+ df_enough = df_all.where(df_all['status'] >= 1).dropna().copy()
61
+
62
+ for _mass_nam, _coe in mass_coe.items():
63
+ df_mass[_mass_nam] = df_all[convert_nam[_mass_nam]] * _coe
64
+
65
+ ## NH4 Deficiency
66
+ defic_idx = df_all['status'] < 1
67
+
68
+ if defic_idx.any():
69
+ residual = mol_A - 2 * mol_S
70
+
71
+ ## residual > 0
72
+ _status = residual > 0
73
+ if _status.any():
74
+ _cond = _status & (residual <= mol_N)
75
+ df_mass.loc[_cond, 'AN'] = residual.loc[_cond] * 80
76
+
77
+ _cond = _status & (residual > mol_N)
78
+ df_mass.loc[_cond, 'AN'] = mol_N.loc[_cond] * 80
79
+
80
+ ## residual < 0
81
+ _status = residual <= 0
82
+ if _status.any():
83
+ df_mass.loc[_status, 'AN'] = 0
84
+
85
+ _cond = _status & (mol_A <= 2 * mol_S)
86
+ df_mass.loc[_cond, 'AS'] = mol_A.loc[_cond] / 2 * 132
87
+
88
+ _cond = _status & (mol_A > 2 * mol_S)
89
+ df_mass.loc[_cond, 'AS'] = mol_S.loc[_cond] * 132
90
+
91
+ df_mass_cal = df_mass.dropna().copy()
92
+ df_mass['total'] = df_mass.sum(axis=1, min_count=6)
93
+
94
+ qc_ratio = df_mass['total'] / df_ref
95
+ qc_cond = (qc_ratio >= 0.7) & (qc_ratio <= 1.3)
96
+
97
+ ## volume
98
+ df_vol = DataFrame()
99
+ for _vol_nam, _coe in vol_coe.items():
100
+ df_vol[_vol_nam] = df_mass_cal[_vol_nam] / _coe
101
+
102
+ if df_water is not None:
103
+ df_vol['ALWC'] = df_water
104
+ df_vol = df_vol.dropna()
105
+ df_vol['total_wet'] = df_vol.sum(axis=1, min_count=6)
106
+
107
+ df_vol['total_dry'] = df_vol[vol_coe.keys()].sum(axis=1, min_count=6)
108
+
109
+ ## density
110
+ df_vol_cal = DataFrame()
111
+ df_den_rec = df_mass['total'] / df_vol['total_dry']
112
+ if df_density is not None:
113
+ df_den_all = concat([df_all[['SO42-', 'NO3-', 'NH4+', 'EC']], df_density, df_mass['OM']], axis=1).dropna()
114
+
115
+ df_vol_cal = (df_den_all[['SO42-', 'NO3-', 'NH4+']].sum(axis=1) / 1.75) + \
116
+ df_den_all['Cl-'] / 1.52 + \
117
+ df_den_all['OM'] / 1.4 + df_den_all['EC'] / 1.77
118
+
119
+ df_den = df_den_all.sum(axis=1, min_count=6) / df_vol_cal
120
+ # df_den = df_den_all.sum(axis=1) / df_vol_cal
121
+ # df_den = df_mass['total'].loc[df_den_all.index] / df_vol_cal
122
+
123
+ ## refractive index
124
+ ri_dic = {}
125
+ for _lambda, _coe in RI_coe.items():
126
+
127
+ df_RI = DataFrame()
128
+
129
+ for _ky, _df in df_vol.items():
130
+ if 'total' in _ky: continue
131
+ df_RI[_ky] = (_df * _coe[_ky])
132
+
133
+ df_RI['RI_wet'] = None
134
+ if df_water is not None:
135
+ df_RI['RI_wet'] = (df_RI / df_vol['total_wet'].to_frame().values).sum(axis=1)
136
+
137
+ df_RI['RI_dry'] = (df_RI[vol_coe.keys()] / df_vol['total_dry'].to_frame().values).sum(axis=1)
138
+
139
+ ri_dic[f'RI_{_lambda}'] = df_RI[['RI_dry', 'RI_wet']]
140
+
141
+ ## mole and equivalent
142
+ df_eq = concat((mol_A, mol_S, mol_N, mol_A * 1, mol_S * 2, mol_N * 1), axis=1)
143
+ df_eq.columns = ['mol_NH4', 'mol_SO4', 'mol_NO3', 'eq_NH4', 'eq_SO4', 'eq_NO3', ]
144
+
145
+ ## out
146
+ out = {'mass': df_mass,
147
+ 'volume': df_vol,
148
+ 'vol_cal': df_vol_cal,
149
+ 'eq': df_eq,
150
+ 'density_mat': df_den,
151
+ 'density_rec': df_den_rec,
152
+ }
153
+ out.update(ri_dic)
154
+
155
+ for _ky, _df in out.items():
156
+ out[_ky] = _df.reindex(index).where(qc_cond)
157
+
158
+ return out
159
+
160
+
161
+ # '''
162
+
163
+
164
+ def mass_ratio(_df):
165
+ if _df['PM25'] >= _df['total_mass']:
166
+ _df['others'] = _df['PM25'] - _df['total_mass']
167
+ for _val, _species in zip(_df.values, _df.index):
168
+ _df[f'{_species}_ratio'] = _val / _df['PM25'].__round__(3)
169
+
170
+ if _df['PM25'] < _df['total_mass']:
171
+ _df['others'] = 0
172
+ for _val, _species in zip(_df.values, _df.index):
173
+ _df[f'{_species}_ratio'] = _val / _df['PM25'].__round__(3)
174
+
175
+ return _df['others':].drop(labels=['PM25_ratio', 'total_mass_ratio'])
@@ -0,0 +1,184 @@
1
+ from AeroViz.dataProcess.core import _union_index
2
+
3
+ from pandas import date_range, concat, DataFrame, to_numeric
4
+ from scipy.optimize import curve_fit
5
+ import numpy as np
6
+
7
+ __all__ = [
8
+ '_basic',
9
+ # '_ocec_ratio_cal',
10
+ ]
11
+
12
+
13
+ def _min_Rsq(_oc, _ec, _rng):
14
+ _val_mesh, _oc_mesh = np.meshgrid(_rng, _oc)
15
+ _val_mesh, _ec_mesh = np.meshgrid(_rng, _ec)
16
+
17
+ _out_table = DataFrame(_oc_mesh - _val_mesh * _ec_mesh, index=_oc.index, columns=_rng)
18
+
19
+ ## calculate R2
20
+ _r2_dic = {}
21
+ _func = lambda _x, _sl, _inte: _sl * _x + _inte
22
+ for _ocec, _out in _out_table.items():
23
+ _df = DataFrame([_out.values, _ec.values]).T.dropna()
24
+
25
+ _x, _y = _df[0], _df[1]
26
+ _opt, _ = curve_fit(_func, _x, _y)
27
+
28
+ _tss = np.sum((_y - _y.mean()) ** 2.)
29
+ _rss = np.sum((_y - _func(_x, *_opt)) ** 2.)
30
+
31
+ _r2_dic[round(_ocec, 3)] = 1. - _rss / _tss
32
+
33
+ ## get the min R2
34
+ _ratio = DataFrame(_r2_dic, index=[0]).idxmin(axis=1).values[0]
35
+
36
+ return _ratio, _out_table[_ratio]
37
+
38
+
39
+ def _ocec_ratio_cal(_nam, _lcres_splt, _hr_lim, _range_, _wisoc_range_):
40
+ ## parameter
41
+ _out = DataFrame(index=_lcres_splt.index)
42
+ (_, _oc), (_, _ec) = _lcres_splt.items()
43
+ # _oc, _ec = _lcres_splt['Thermal_OC'], _lcres_splt['Thermal_EC']
44
+
45
+ ## real data OC/EC
46
+ _ocec_ratio_real = (_oc / _ec).quantile(.5)
47
+
48
+ _out[f'OC/EC_real_{_nam}'] = _ocec_ratio_real
49
+ _out[f'POC_real_{_nam}'] = _ocec_ratio_real * _ec
50
+ _out[f'SOC_real_{_nam}'] = _oc - _out[f'POC_real_{_nam}']
51
+
52
+ ## the least R2 method
53
+ ## estimated OC/EC
54
+ if (len(_lcres_splt) <= _hr_lim):
55
+ print(f"\t\t{_lcres_splt.index[0].strftime('%Y-%m-%d %X')} to {_lcres_splt.index[-1].strftime('%Y-%m-%d %X')}")
56
+ print('\t\tPlease Modify the Values of "hour_limit" or Input Sufficient Amount of Data !!')
57
+
58
+ _out[[f'OC/EC_{_nam}', f'POC_{_nam}', f'SOC_{_nam}', f'WISOC/OC_{_nam}', f'WSOC_{_nam}',
59
+ f'WISOC_{_nam}']] = np.nan
60
+
61
+ return _out
62
+
63
+ if (len(_lcres_splt.dropna()) == 0):
64
+ _out[[f'OC/EC_{_nam}', f'POC_{_nam}', f'SOC_{_nam}', f'WISOC/OC_{_nam}', f'WSOC_{_nam}',
65
+ f'WISOC_{_nam}']] = np.nan
66
+
67
+ return _out
68
+
69
+ ## OC/EC
70
+ _ocec_ratio = False
71
+ _st, _ed, _stp = _range_
72
+
73
+ for _ in range(2):
74
+ if _ocec_ratio:
75
+ _ocec_rng = np.arange(_ocec_ratio - _stp / 2, _ocec_ratio + _stp / 2, .01).round(3)
76
+ else:
77
+ _ocec_rng = np.arange(_st, _ed + _stp, _stp).round(3)
78
+
79
+ _ocec_ratio, _soc = _min_Rsq(_oc, _ec, _ocec_rng)
80
+
81
+ ## WISOC
82
+ _st, _ed, _stp = _wisoc_range_
83
+ _wisoc_rng = (np.arange(_st, _ed + _stp, _stp) * _ocec_ratio).round(5)
84
+ _wisoc_ratio, _wsoc = _min_Rsq(_oc, _ec, _wisoc_rng)
85
+
86
+ ## out
87
+ _out[f'OC/EC_{_nam}'] = _ocec_ratio
88
+ _out[f'SOC_{_nam}'] = _soc
89
+ _out[f'POC_{_nam}'] = _oc - _out[f'SOC_{_nam}']
90
+ _out[f'WISOC/OC_{_nam}'] = _wisoc_ratio
91
+ _out[f'WSOC_{_nam}'] = _wsoc
92
+ _out[f'WISOC_{_nam}'] = _oc - _out[f'WSOC_{_nam}']
93
+
94
+ return _out[[f'OC/EC_{_nam}', f'POC_{_nam}', f'SOC_{_nam}', f'WISOC/OC_{_nam}', f'WSOC_{_nam}', f'WISOC_{_nam}',
95
+ f'OC/EC_real_{_nam}', f'POC_real_{_nam}', f'SOC_real_{_nam}']]
96
+
97
+
98
+ def _basic(_lcres, _res, _mass, _ocec_ratio, _ocec_ratio_month, _hr_lim, _range, _wisoc_range):
99
+ _lcres, _res, _mass = _union_index(_lcres, _res, _mass)
100
+
101
+ _out = {}
102
+
103
+ ## OC1, OC2, OC3, OC4, PC
104
+ _df_bsc = _res / _lcres['Sample_Volume'].to_frame().values.copy()
105
+
106
+ ## SOC, POC, OC/EC
107
+ if _ocec_ratio is not None:
108
+ try:
109
+ iter(_ocec_ratio)
110
+ except TypeError:
111
+ raise TypeError('"ocec_ratio" Only Accept a Single Value !!')
112
+
113
+ _prcs_df = DataFrame(index=_df_bsc.index)
114
+ _prcs_df['OC/EC'] = _ocec_ratio
115
+ _prcs_df['POC'] = _ocec_ratio * _lcres['Thermal_EC']
116
+ _prcs_df['SOC'] = _lcres['Thermal_OC'] - _prcs_df['POC']
117
+
118
+ else:
119
+ _df_lst = []
120
+ for _, _df in _lcres.resample(f'{_ocec_ratio_month}MS', closed='left'):
121
+ _thm_cal = _ocec_ratio_cal('thm', _df[['Thermal_OC', 'Thermal_EC']], _hr_lim, _range, _wisoc_range)
122
+ _opt_cal = _ocec_ratio_cal('opt', _df[['Optical_OC', 'Optical_EC']], _hr_lim, _range, _wisoc_range)
123
+ _df_lst.append(concat([_thm_cal, _opt_cal], axis=1))
124
+
125
+ _prcs_df = concat(_df_lst)
126
+
127
+ _df_bsc = concat((_df_bsc.copy(), _prcs_df), axis=1)
128
+
129
+ ## ratio
130
+ _df_ratio = DataFrame(index=_df_bsc.index)
131
+
132
+ for _ky, _val in _df_bsc.items():
133
+ if 'OC/EC' in _ky: continue
134
+ _df_ratio[f'{_ky}/Thermal_OC'] = _val / _lcres['Thermal_OC']
135
+ _df_ratio[f'{_ky}/Optical_OC'] = _val / _lcres['Optical_OC']
136
+
137
+ if _mass is not None:
138
+ for _ky, _val in _df_bsc.items():
139
+ _df_ratio[f'{_ky}/PM'] = _val / _mass
140
+
141
+ _df_ratio[f'Thermal_OC/PM'] = _lcres['Thermal_OC'] / _mass
142
+ _df_ratio[f'Thermal_EC/PM'] = _lcres['Thermal_EC'] / _mass
143
+
144
+ _df_ratio[f'Optical_OC/PM'] = _lcres['Optical_OC'] / _mass
145
+ _df_ratio[f'Optical_EC/PM'] = _lcres['Optical_EC'] / _mass
146
+
147
+ ## ratio status
148
+ _df_bsc = concat((_lcres, _df_bsc.copy()), axis=1)
149
+
150
+ for _ky, _df in _df_ratio.items():
151
+ _df_bsc[f'{_ky}_status'] = 'Normal'
152
+ _df_bsc[f'{_ky}_status'] = _df_bsc[f'{_ky}_status'].mask(_df > 1, 'Warning')
153
+
154
+ ## out
155
+ _out['ratio'] = _df_ratio
156
+ _out['basic'] = _df_bsc
157
+
158
+ return _out
159
+
160
+
161
+ '''
162
+ _ocec_mesh, _oc_mesh = n.meshgrid(_ocec_rng, _oc)
163
+ _ocec_mesh, _ec_mesh = n.meshgrid(_ocec_rng, _ec)
164
+
165
+ _soc_table = DataFrame(_oc_mesh-_ocec_mesh*_ec_mesh, index=_oc.index, columns=_ocec_rng)
166
+
167
+ ## calculate R2
168
+ _r2_dic = {}
169
+ _func = lambda _x, _sl, _inte : _sl*_x+_inte
170
+ for _ocec, _soc in _soc_table.items():
171
+
172
+ _df = DataFrame([_soc.values, _ec.values]).T.dropna()
173
+ _x, _y = _df[0], _df[1]
174
+
175
+ _opt, _ = curve_fit(_func, _x, _y)
176
+
177
+ _tss = n.sum((_y - _y.mean())**2.)
178
+ _rss = n.sum((_y - _func(_x, *_opt))**2.)
179
+
180
+ _r2_dic[round(_ocec,2)] = 1. - _rss / _tss
181
+
182
+ ## get the min R2
183
+ _ocec_ratio = DataFrame(_r2_dic, index=[0]).idxmin(axis=1).values[0]
184
+ # '''
@@ -0,0 +1,29 @@
1
+ from pandas import date_range, concat, DataFrame, to_numeric
2
+ from ._calculate import _ug2umol
3
+
4
+
5
+ def _basic(df_che, nam_lst):
6
+ # parameter
7
+ df_all = concat(df_che, axis=1)
8
+ index = df_all.index.copy()
9
+ df_all.columns = nam_lst
10
+
11
+ df_umol = _ug2umol(df_all)
12
+
13
+ # calculate
14
+ df_out = DataFrame(index=df_umol.index)
15
+
16
+ # df_out['NTR'] = df_umol['NH4+'] / (df_umol['NH4+'] + df_all['NH3'] / 22.4)
17
+ df_out['NTR+'] = df_umol['NH4+'] / (df_umol['NH4+'] + df_umol['NH3'])
18
+
19
+ df_out['NOR'] = df_umol['NO3-'] / (df_umol['NO3-'] + df_umol['NO2'])
20
+ df_out['NOR_2'] = (df_umol['NO3-'] + df_umol['HNO3']) / (df_umol['NO3-'] + df_umol['NO2'] + df_umol['HNO3'])
21
+
22
+ df_out['SOR'] = df_umol['SO42-'] / (df_umol['SO42-'] + df_umol['SO2'])
23
+
24
+ df_out['epls_NO3-'] = df_umol['NO3-'] / (df_umol['NO3-'] + df_umol['HNO3'])
25
+ df_out['epls_NH4+'] = df_umol['NH4+'] / (df_umol['NH4+'] + df_umol['NH3'])
26
+ df_out['epls_SO42-'] = df_out['SOR']
27
+ df_out['epls_Cl-'] = df_umol['Cl-'] / (df_umol['Cl-'] + df_umol['HCl'])
28
+
29
+ return df_out
@@ -0,0 +1,16 @@
1
+ import numpy as np
2
+
3
+
4
+ def _basic(_teom, _check):
5
+ _teom['Volatile_Fraction'] = (_teom['PM_Total'] - _teom['PM_NV']) / _teom['PM_Total']
6
+
7
+ _teom.loc[(_teom['Volatile_Fraction'] < 0) | (_teom['Volatile_Fraction'] > 1)] = n.nan
8
+
9
+ if _check is not None:
10
+ _ratio = _teom['PM_NV'] / _check
11
+ _teom['PM_Check'] = _check
12
+
13
+ _teom.loc[_teom.dropna().index, 'status'] = 'Warning'
14
+ _teom.loc[(_ratio > 0) & (_ratio < 1), 'status'] = 'Normal'
15
+
16
+ return _teom
@@ -0,0 +1,61 @@
1
+ import pickle as pkl
2
+ from pathlib import Path
3
+ import numpy as np
4
+
5
+ from pandas import date_range, concat, DataFrame, to_numeric
6
+ from AeroViz.dataProcess.core import _union_index
7
+
8
+
9
+ def _revised(_df_mass, _df_RH):
10
+ _df_mass, _df_RH = _union_index(_df_mass, _df_RH)
11
+
12
+ ## fRH
13
+ with (Path(__file__).parent / 'fRH.pkl').open('rb') as f:
14
+ _fRH = pkl.load(f)
15
+ _fRH.loc[np.nan] = np.nan
16
+
17
+ def fRH(_RH):
18
+ if _RH is not None:
19
+ _RH = _RH.mask(_RH > 95, 95).round(0)
20
+ return _fRH.loc[_RH].values.T
21
+
22
+ return 1, 1, 1, 1
23
+
24
+ ## different mode
25
+ ## mass < 20 :
26
+ ## large = mass**2/20
27
+ ## small = mass-large
28
+ ## mass >= 20 :
29
+ ## large = mass
30
+ ## small = 0
31
+ _df_mode = _df_mass[['AS', 'AN', 'OM']].copy()
32
+
33
+ _df_mass[['L_AS', 'L_AN', 'L_OM']] = _df_mode.mask(_df_mode < 20, _df_mode ** 2 / 20)
34
+ _df_mass[['S_AS', 'S_AN', 'S_OM']] = _df_mode.values - _df_mass[['L_AS', 'L_AN', 'L_OM']]
35
+
36
+ ## apply IMPROVE ccoe.
37
+ def _ext_cal(_RH=None):
38
+
39
+ _frh, _frhss, _frhs, _frhl = fRH(_RH)
40
+ _df = DataFrame(index=_df_mass.index)
41
+
42
+ _df['AS'] = 2.2 * _frhs * _df_mass['S_AS'] + 4.8 * _frhl * _df_mass['L_AS']
43
+ _df['AN'] = 2.4 * _frhs * _df_mass['S_AN'] + 5.1 * _frhl * _df_mass['L_AN']
44
+ _df['OM'] = 2.8 * _df_mass['S_OM'] + 6.1 * _frhl * _df_mass['L_OM']
45
+ _df['Soil'] = _df_mass['Soil']
46
+ _df['SS'] = 1.7 * _frhss * _df_mass['SS']
47
+ _df['EC'] = 10 * _df_mass['EC']
48
+
49
+ _df['total'] = _df.sum(axis=1)
50
+
51
+ return _df.dropna().reindex(_df_mass.index)
52
+
53
+ ## calculate
54
+ _out = {}
55
+
56
+ _out['dry'] = _ext_cal()
57
+
58
+ if _df_RH is not None:
59
+ _out['wet'] = _ext_cal(_df_RH)
60
+
61
+ return _out