avoca 0.15.1__tar.gz → 0.17.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.
- {avoca-0.15.1 → avoca-0.17.0}/.gitignore +2 -0
- {avoca-0.15.1 → avoca-0.17.0}/.gitlab-ci.yml +1 -1
- {avoca-0.15.1 → avoca-0.17.0}/PKG-INFO +1 -1
- {avoca-0.15.1 → avoca-0.17.0}/avoca/bindings/ebas.py +56 -45
- {avoca-0.15.1 → avoca-0.17.0}/avoca/bindings/ebas_flags.py +6 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/bindings/gcwerks.py +11 -3
- {avoca-0.15.1 → avoca-0.17.0}/avoca/flags.py +8 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/io.py +5 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/testing/utils.py +1 -1
- avoca-0.17.0/data/tests/new_NMHC_lev0.nas +116 -0
- {avoca-0.15.1 → avoca-0.17.0}/pyproject.toml +1 -1
- avoca-0.17.0/tests/bindings/gcwerks.dat +7 -0
- avoca-0.17.0/tests/bindings/gcwerks_with_flags.dat +7 -0
- avoca-0.17.0/tests/bindings/test_ebas.py +59 -0
- avoca-0.17.0/tests/bindings/test_gcwerks.py +32 -0
- {avoca-0.15.1 → avoca-0.17.0}/tests/test_io.py +8 -1
- avoca-0.15.1/tests/bindings/gcwerks.dat +0 -7
- avoca-0.15.1/tests/bindings/test_gcwerks.py +0 -11
- {avoca-0.15.1 → avoca-0.17.0}/.readthedocs.yaml +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/.vscode/settings.json +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/LICENCE.txt +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/README.md +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/__init__.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/bindings/__init__.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/bindings/gcwerks-report.conf +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/bindings/gcwerks_gui.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/bindings/nabel.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/bindings/qa_tool.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/bindings/synspec.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/export_nas.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/flagging.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/logging.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/manager.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/plots.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/qa_class/__init__.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/qa_class/abstract.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/qa_class/concs.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/qa_class/generate_classes_doc.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/qa_class/invalid.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/qa_class/rolling.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/qa_class/rt.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/qa_class/test.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/qa_class/zscore.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/requirements.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/settings.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/testing/__init__.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/testing/df.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/utils/__init__.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/utils/flags_doc.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/avoca/utils/torch_models.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/data/.avoca/config.yaml +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/data/CH0001G.20240219123300.20240307132229.online_gc.NMHC.air.16d.61mn.CH01L_Agilent_GC-MS-MEDUSA_Medusa-12_JFJ.CH01L_gc_ms.lev0.nas +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/data/tests/missing_area_cols.csv +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/data/voc_jan2jun_2023.csv +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/docs/Makefile +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/docs/make.bat +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/docs/source/bindings/ebas.md +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/docs/source/bindings/gcwerks.md +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/docs/source/bindings/index.rst +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/docs/source/bindings/qa_tool.md +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/docs/source/conf.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/docs/source/index.rst +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/docs/source/quickstart.ipynb +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/examples/config.yaml +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/examples/convert_synspec_to_gcwerks.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/examples/data_qa.ipynb +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/examples/data_qa_gcwerks.ipynb +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/examples/export_gc_werks.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/examples/export_gc_werks_secondary_peaks.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/examples/get_tanks.ipynb +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/examples/read_nas.ipynb +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/tests/bindings/test_qatool.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/tests/test_assigners.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/tests/test_flagging.py +0 -0
- {avoca-0.15.1 → avoca-0.17.0}/tests/test_manager.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: avoca
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.17.0
|
|
4
4
|
Summary: @voc@: Quality assessement of measurement data
|
|
5
5
|
Project-URL: Homepage, https://gitlab.com/empa503/atmospheric-measurements/avoca
|
|
6
6
|
Project-URL: Bug Tracker, https://gitlab.com/empa503/atmospheric-measurements/avoca/-/issues
|
|
@@ -19,6 +19,7 @@ from nilutility.datetime_helper import DatetimeInterval
|
|
|
19
19
|
|
|
20
20
|
from avoca.bindings.ebas_flags import ebas_flag_to_avoca, flags_to_ebas, nan_flags
|
|
21
21
|
from avoca.flags import QA_Flag
|
|
22
|
+
from avoca.utils import compounds_from_df
|
|
22
23
|
|
|
23
24
|
logger = logging.getLogger(__name__)
|
|
24
25
|
|
|
@@ -31,15 +32,29 @@ ebas_compname_of_var = {
|
|
|
31
32
|
ebas_compname_to_var = {v: k for k, v in ebas_compname_of_var.items()}
|
|
32
33
|
|
|
33
34
|
|
|
34
|
-
# Additional variables that can be in the dataset (not compound dependant)
|
|
35
|
-
additional_vars = [
|
|
36
|
-
"temperature",
|
|
37
|
-
"pressure",
|
|
38
|
-
]
|
|
39
|
-
|
|
40
35
|
titles = {
|
|
41
36
|
"temperature": "T_inlet",
|
|
42
37
|
"pressure": "P_inlet",
|
|
38
|
+
"volume_sample": "svol",
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
unit_of_var = {
|
|
42
|
+
"C": "pmol/mol",
|
|
43
|
+
"conc_calib": "pmol/mol",
|
|
44
|
+
"rt": "s",
|
|
45
|
+
"w": "s",
|
|
46
|
+
"area": "area_unit",
|
|
47
|
+
"temperature": "K",
|
|
48
|
+
"pressure": "hPa",
|
|
49
|
+
"volume_sample": "mL",
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
ebas_varname_of_var = {
|
|
53
|
+
"rt": "rt",
|
|
54
|
+
"w": "pw",
|
|
55
|
+
"area": "pa",
|
|
56
|
+
"conc_calib": "cal",
|
|
57
|
+
"volume_sample": "sample_volume",
|
|
43
58
|
}
|
|
44
59
|
|
|
45
60
|
|
|
@@ -51,6 +66,17 @@ class DataLevel(IntEnum):
|
|
|
51
66
|
QA_CONCS = 2
|
|
52
67
|
|
|
53
68
|
|
|
69
|
+
vars_to_export = {
|
|
70
|
+
DataLevel.AREAS: ["area", "rt", "w", "conc_calib"],
|
|
71
|
+
DataLevel.CONCS: ["C"],
|
|
72
|
+
DataLevel.QA_CONCS: ["C"],
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
# Additional variables that can be in the dataset (not compound dependant)
|
|
76
|
+
additional_vars = {
|
|
77
|
+
DataLevel.AREAS: ["volume_sample", "temperature", "pressure"],
|
|
78
|
+
}
|
|
79
|
+
valid_additional_vars = sum(additional_vars.values(), [])
|
|
54
80
|
concs_data_levels = [DataLevel.CONCS, DataLevel.QA_CONCS]
|
|
55
81
|
|
|
56
82
|
|
|
@@ -64,8 +90,8 @@ def data_level_after_qa(data_level: DataLevel) -> DataLevel:
|
|
|
64
90
|
def set_dataframe(
|
|
65
91
|
nas,
|
|
66
92
|
df_export: pd.DataFrame,
|
|
67
|
-
compounds: dict[str, str],
|
|
68
|
-
data_level: DataLevel,
|
|
93
|
+
compounds: dict[str, str] | None = None,
|
|
94
|
+
data_level: DataLevel = DataLevel.CONCS,
|
|
69
95
|
start_offset: timedelta | None = None,
|
|
70
96
|
end_offset: timedelta | None = None,
|
|
71
97
|
flag_all: list[int] = [],
|
|
@@ -108,28 +134,8 @@ def set_dataframe(
|
|
|
108
134
|
)
|
|
109
135
|
]
|
|
110
136
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
DataLevel.CONCS: ["C"],
|
|
114
|
-
DataLevel.QA_CONCS: ["C"],
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
unit_of_var = {
|
|
118
|
-
"C": "pmol/mol",
|
|
119
|
-
"conc_calib": "pmol/mol",
|
|
120
|
-
"rt": "s",
|
|
121
|
-
"w": "s",
|
|
122
|
-
"area": "area_unit",
|
|
123
|
-
"temperature": "K",
|
|
124
|
-
"pressure": "hPa",
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
ebas_varname_of_var = {
|
|
128
|
-
"rt": "rt",
|
|
129
|
-
"w": "pw",
|
|
130
|
-
"area": "pa",
|
|
131
|
-
"conc_calib": "cal",
|
|
132
|
-
}
|
|
137
|
+
if compounds is None:
|
|
138
|
+
compounds = {c: c for c in compounds_from_df(df_export)}
|
|
133
139
|
|
|
134
140
|
dict_flags_to_ebas = flags_to_ebas.copy()
|
|
135
141
|
|
|
@@ -151,12 +157,12 @@ def set_dataframe(
|
|
|
151
157
|
)
|
|
152
158
|
)
|
|
153
159
|
|
|
154
|
-
for var in additional_vars:
|
|
160
|
+
for var in additional_vars.get(data_level, []):
|
|
155
161
|
var_col = ("-", var)
|
|
156
162
|
if var_col not in df_export.columns:
|
|
157
163
|
continue
|
|
158
164
|
metadata = DataObject()
|
|
159
|
-
metadata.comp_name = var
|
|
165
|
+
metadata.comp_name = ebas_varname_of_var.get(var, var)
|
|
160
166
|
metadata.title = titles.get(var, var)
|
|
161
167
|
metadata.matrix = "instrument"
|
|
162
168
|
metadata.unit = unit_of_var[var]
|
|
@@ -233,9 +239,9 @@ def set_dataframe(
|
|
|
233
239
|
if var == "conc_calib":
|
|
234
240
|
# Set Nominal/measured=Calibration gas concentration
|
|
235
241
|
vnum = len(nas.variables) - 1
|
|
236
|
-
nas.add_var_characteristics(
|
|
237
|
-
|
|
238
|
-
)
|
|
242
|
+
# nas.add_var_characteristics(
|
|
243
|
+
# vnum, "Nominal/measured", "Calibration gas concentration"
|
|
244
|
+
# )
|
|
239
245
|
|
|
240
246
|
metadatas[sub] = metadata
|
|
241
247
|
return metadatas
|
|
@@ -327,7 +333,10 @@ def nas_to_avoca(nas: EbasNasaAmes) -> pd.DataFrame:
|
|
|
327
333
|
clean_for_df[("-", "status")] = calib_ids.astype(int)
|
|
328
334
|
continue
|
|
329
335
|
|
|
330
|
-
if comp_name
|
|
336
|
+
if comp_name == "sample_volume":
|
|
337
|
+
comp_name = "volume_sample"
|
|
338
|
+
|
|
339
|
+
if comp_name in valid_additional_vars:
|
|
331
340
|
clean_for_df[("-", comp_name)] = np.array(values, dtype=float)
|
|
332
341
|
continue
|
|
333
342
|
|
|
@@ -335,27 +344,27 @@ def nas_to_avoca(nas: EbasNasaAmes) -> pd.DataFrame:
|
|
|
335
344
|
comp_name = comp_name.split("_")
|
|
336
345
|
if len(comp_name) == 1:
|
|
337
346
|
# Can be either concentration measured or calibration
|
|
338
|
-
|
|
347
|
+
compound = comp_name[0]
|
|
339
348
|
title: str = metadata["title"]
|
|
340
349
|
if title.endswith("_cal"):
|
|
341
350
|
variable = "cal"
|
|
342
351
|
else:
|
|
343
352
|
variable = "C"
|
|
344
353
|
elif len(comp_name) == 2:
|
|
345
|
-
|
|
354
|
+
compound, variable = comp_name
|
|
346
355
|
elif len(comp_name) == 3:
|
|
347
|
-
|
|
356
|
+
compound, var_first, var_second = comp_name
|
|
348
357
|
variable = f"{var_first}_{var_second}"
|
|
349
358
|
elif len(comp_name) == 4 and comp_name[-1] == "compounds":
|
|
350
359
|
# Concentration of merged compounds
|
|
351
|
-
|
|
360
|
+
compound = "_".join(comp_name)
|
|
352
361
|
variable = "C"
|
|
353
362
|
else:
|
|
354
363
|
logger.warning(f"passing {comp_name}, could not be understood. Skipping.")
|
|
355
364
|
continue
|
|
356
365
|
|
|
357
|
-
if
|
|
358
|
-
compounds.append(
|
|
366
|
+
if compound not in compounds:
|
|
367
|
+
compounds.append(compound)
|
|
359
368
|
|
|
360
369
|
# Convert the variable name to the avoca format
|
|
361
370
|
if variable == "cal":
|
|
@@ -363,10 +372,12 @@ def nas_to_avoca(nas: EbasNasaAmes) -> pd.DataFrame:
|
|
|
363
372
|
variable = "conc_calib"
|
|
364
373
|
elif variable != "C":
|
|
365
374
|
if variable not in ebas_compname_to_var:
|
|
366
|
-
raise ValueError(
|
|
375
|
+
raise ValueError(
|
|
376
|
+
f"Variable {variable} from {comp_name=} not recognized"
|
|
377
|
+
)
|
|
367
378
|
variable = ebas_compname_to_var[variable]
|
|
368
379
|
|
|
369
|
-
clean_for_df[(
|
|
380
|
+
clean_for_df[(compound, variable)] = np.array(values, dtype=float)
|
|
370
381
|
|
|
371
382
|
flag_serie = pd.Series(
|
|
372
383
|
[
|
|
@@ -375,7 +386,7 @@ def nas_to_avoca(nas: EbasNasaAmes) -> pd.DataFrame:
|
|
|
375
386
|
],
|
|
376
387
|
dtype=int,
|
|
377
388
|
)
|
|
378
|
-
flag_col = (
|
|
389
|
+
flag_col = (compound, "flag")
|
|
379
390
|
if variable == "conc_calib":
|
|
380
391
|
# Calibration will have missing values for air smaples
|
|
381
392
|
# so we need to remove the missing values
|
|
@@ -9,6 +9,12 @@ flags_to_ebas: dict[QA_Flag, int] = {
|
|
|
9
9
|
QA_Flag.EXTREME_VALUE: 458,
|
|
10
10
|
QA_Flag.CALIBRATION: 683, # I Invalid due to calibration. Used for Level 0.
|
|
11
11
|
QA_Flag.BLANK: 684, # Invalid due to zero/span check. Used for Level 0.
|
|
12
|
+
# Invalid due to laboratory standard measurement. Level 0.
|
|
13
|
+
QA_Flag.LABORATORY_STANDARD: 688,
|
|
14
|
+
# Invalid due to working standard measurement. Level 0.
|
|
15
|
+
QA_Flag.WORKING_STANDARD: 689,
|
|
16
|
+
# Invalid due to target standard measurement. Level 0.
|
|
17
|
+
QA_Flag.TARGET_MEASUREMENT: 690,
|
|
12
18
|
QA_Flag.HEIGHT_INTEGRATION: 0, # Valid
|
|
13
19
|
QA_Flag.UNCORRELATED: 0, # Valid
|
|
14
20
|
QA_Flag.MET_OFFICE_BASELINE: 0, # Valid
|
|
@@ -90,6 +90,8 @@ flag_values = {
|
|
|
90
90
|
"F": QA_Flag.INVALIDATED_EXT,
|
|
91
91
|
# X: An X flag is an 'un-do' the flag. If there is an automatic flag by GCWerks, but I decide I want that data point still included, I have the option to set an X flag.
|
|
92
92
|
"X": ValidFlag,
|
|
93
|
+
# Nans read from pandas
|
|
94
|
+
pd.NA: QA_Flag.MISSING,
|
|
93
95
|
}
|
|
94
96
|
|
|
95
97
|
# Show the flags and the columns they are applied to
|
|
@@ -203,6 +205,11 @@ def read_gcwerks(
|
|
|
203
205
|
format=datetime_format,
|
|
204
206
|
)
|
|
205
207
|
|
|
208
|
+
if not df[("-", "volume")].isna().all():
|
|
209
|
+
df[("-", "volume_sample")] = df[("-", "volume")]
|
|
210
|
+
# Drop useless columns
|
|
211
|
+
df = df.drop(columns=[("-", "date"), ("-", "time"), ("-", "volume")])
|
|
212
|
+
|
|
206
213
|
substances = []
|
|
207
214
|
|
|
208
215
|
for col in df.columns:
|
|
@@ -224,9 +231,9 @@ def read_gcwerks(
|
|
|
224
231
|
flags: pd.Series = serie_str.str[-1]
|
|
225
232
|
if col[1] in cols_float:
|
|
226
233
|
# Remove the flag value when given
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
234
|
+
mask_flag_allowed = flags.isin(flags_allowed)
|
|
235
|
+
serie_str = serie_str.where(~mask_flag_allowed, serie_str.str[:-1])
|
|
236
|
+
|
|
230
237
|
# Convert the serie to numeric
|
|
231
238
|
df[col] = pd.to_numeric(serie_str, errors="coerce")
|
|
232
239
|
|
|
@@ -359,6 +366,7 @@ def export(
|
|
|
359
366
|
"time",
|
|
360
367
|
"type",
|
|
361
368
|
"sample",
|
|
369
|
+
"volume",
|
|
362
370
|
f"{variables_str}",
|
|
363
371
|
f"> {out_file}",
|
|
364
372
|
)
|
|
@@ -46,6 +46,14 @@ class QA_Flag(Flag):
|
|
|
46
46
|
# Invalid Values
|
|
47
47
|
INVALID_VALUES = auto()
|
|
48
48
|
|
|
49
|
+
# Target measurement
|
|
50
|
+
TARGET_MEASUREMENT = auto()
|
|
51
|
+
# Laboratory standard
|
|
52
|
+
LABORATORY_STANDARD = auto()
|
|
53
|
+
# Working standard
|
|
54
|
+
WORKING_STANDARD = auto()
|
|
55
|
+
|
|
56
|
+
|
|
49
57
|
# Flags that are considered to have missing values
|
|
50
58
|
nan_flags = [
|
|
51
59
|
QA_Flag.MISSING,
|
|
@@ -8,6 +8,11 @@ date_format = "%Y-%m-%d %H:%M:%S"
|
|
|
8
8
|
|
|
9
9
|
def to_csv(df: pd.DataFrame, path: Path, **kwargs) -> None:
|
|
10
10
|
"""Export a dataframe to a csv file."""
|
|
11
|
+
|
|
12
|
+
# Put the columsn with "-" first
|
|
13
|
+
cols = df.columns.tolist()
|
|
14
|
+
cols_sorted = sorted(cols, key=lambda x: (x[0] != "-", x))
|
|
15
|
+
df = df[cols_sorted]
|
|
11
16
|
df.to_csv(path, index=False, date_format=date_format, **kwargs)
|
|
12
17
|
|
|
13
18
|
|
|
@@ -3,7 +3,7 @@ import pandas as pd
|
|
|
3
3
|
|
|
4
4
|
def make_dt_index(df: pd.DataFrame | pd.Index) -> pd.DataFrame | pd.Index:
|
|
5
5
|
"""Create a datetime index for the dataframe."""
|
|
6
|
-
index = pd.date_range(start="2023-01-01", periods=len(df), freq="h")
|
|
6
|
+
index = pd.date_range(start="2023-01-01", periods=len(df), freq="h", unit="s")
|
|
7
7
|
if isinstance(df, pd.Index):
|
|
8
8
|
return index
|
|
9
9
|
return df.set_index(index)
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
95 1001
|
|
2
|
+
Constantin, Lionel; Vollmer, Martin K.; Reimann, Stefan
|
|
3
|
+
CH01L, Swiss Federal Laboratories for Materials Science and Technology, EMPA, Laboratory for Air Pollution, Überlandstrasse 129, , 8600, Dübendorf, Switzerland
|
|
4
|
+
Constantin, Lionel
|
|
5
|
+
ACTRIS
|
|
6
|
+
1 1
|
|
7
|
+
2024 01 01 2024 02 20
|
|
8
|
+
0
|
|
9
|
+
days from file reference point
|
|
10
|
+
19
|
|
11
|
+
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
|
|
12
|
+
99.999999 99 99.9 9.999 999999 99.99 99999.9 9999.9999 9.999 999999 99.99 99999.9 9999.99999 9.999 9999999 99.99 99999.9 999.99999 9.999
|
|
13
|
+
end_time of measurement, days from the file reference point
|
|
14
|
+
status, no unit, Status type=calibration standard, Matrix=instrument, Comment=See metadata elements "Calibration standard ID" and "Secondary standard ID"
|
|
15
|
+
sample_volume, ml, QA1 measure ID=, QA1 date=, QA1 document URL=
|
|
16
|
+
numflag, no unit
|
|
17
|
+
2-methylbutane_peak_area, area_unit
|
|
18
|
+
2-methylbutane_peak_width, s
|
|
19
|
+
2-methylbutane_retention_time, s
|
|
20
|
+
2-methylbutane, pmol/mol, Nominal/measured=Calibration gas concentration
|
|
21
|
+
numflag, no unit
|
|
22
|
+
2-methylpropane_peak_area, area_unit
|
|
23
|
+
2-methylpropane_peak_width, s
|
|
24
|
+
2-methylpropane_retention_time, s
|
|
25
|
+
2-methylpropane, pmol/mol, Nominal/measured=Calibration gas concentration
|
|
26
|
+
numflag, no unit
|
|
27
|
+
benzene_peak_area, area_unit
|
|
28
|
+
benzene_peak_width, s
|
|
29
|
+
benzene_retention_time, s
|
|
30
|
+
benzene, pmol/mol, Nominal/measured=Calibration gas concentration
|
|
31
|
+
numflag, no unit
|
|
32
|
+
0
|
|
33
|
+
62
|
|
34
|
+
Data definition: EBAS_1.1
|
|
35
|
+
Set type code: TI
|
|
36
|
+
Timezone: UTC
|
|
37
|
+
File name: CH0001G.20240219123300.20240220160444.online_gc.NMHC.air.1402mn.61mn.CH01L_Agilent_GC-MS-MEDUSA_Medusa-12_JFJ.CH01L_gc_ms.lev0.nas
|
|
38
|
+
Startdate: 20240219123300
|
|
39
|
+
Revision date: 20240220160444
|
|
40
|
+
Version: 1
|
|
41
|
+
Version description: initial revision, automatically generated, manually inspected
|
|
42
|
+
Statistics: arithmetic mean
|
|
43
|
+
Data level: 0
|
|
44
|
+
Period code: 1y
|
|
45
|
+
Resolution code: 61mn
|
|
46
|
+
Sample duration: 20mn
|
|
47
|
+
Orig. time res.: 30mn
|
|
48
|
+
Station code: CH0001G
|
|
49
|
+
Platform code: CH0001S
|
|
50
|
+
Station name: Jungfraujoch
|
|
51
|
+
Station WDCA-ID: GAWACH__JFJ
|
|
52
|
+
Station GAW-ID: JFJ
|
|
53
|
+
Station GAW-Name: Jungfraujoch
|
|
54
|
+
Station other IDs:
|
|
55
|
+
Station land use: Gravel and stone
|
|
56
|
+
Station setting: Mountain
|
|
57
|
+
Station GAW type: G
|
|
58
|
+
Station WMO region: 6
|
|
59
|
+
Station latitude: 46.547500
|
|
60
|
+
Station longitude: 7.985000
|
|
61
|
+
Station altitude: 3578.0 m
|
|
62
|
+
Measurement altitude: 3566.0 m
|
|
63
|
+
Measurement height: 7.00 m
|
|
64
|
+
Regime: IMG
|
|
65
|
+
Component: NMHC
|
|
66
|
+
Unit:
|
|
67
|
+
Matrix: air
|
|
68
|
+
Laboratory code: CH01L
|
|
69
|
+
Instrument type: online_gc
|
|
70
|
+
Instrument name: Agilent_GC-MS-MEDUSA_Medusa-12_JFJ
|
|
71
|
+
Instrument manufacturer: AGAGE+Agilent+Agilent
|
|
72
|
+
Instrument model: MEDUSA+6890N+5975B
|
|
73
|
+
Instrument serial number: Medusa-12
|
|
74
|
+
Method ref: CH01L_gc_ms
|
|
75
|
+
Standard method: SOP=ACTRIS_VOC_2014
|
|
76
|
+
Calibration scale:
|
|
77
|
+
Calibration standard ID: "Status calibration standard: 1, Manufacturer: NPL (passivated aluminum cylinder), Batch: E-223"
|
|
78
|
+
Secondary standard ID: "Status calibration standard: 2, Manufacturer: In House Aluminium cylinder (Luxfer), Batch: Referenzluft_15; Status calibration standard: 3, Manufacturer: In House Aluminium cylinder (Luxfer), Batch: Referenzluft_04"
|
|
79
|
+
Inlet type: Hat or hood
|
|
80
|
+
Inlet description:
|
|
81
|
+
Flow rate: 10.0 l/min
|
|
82
|
+
Detection limit expl.: Detection limit equals 3 times the precision
|
|
83
|
+
Measurement uncertainty expl.: "Includes reproducibility (precision) + systematic errors (accuracy). Ref:http://www.atmos-meas-tech.net/8/2715/2015/"
|
|
84
|
+
Zero/negative values code: Zero/negative impossible
|
|
85
|
+
Zero/negative values: Values below 1 pmol/mol are not reported by the instrument.
|
|
86
|
+
QA1 measure ID: ACTRIS-VOC-1
|
|
87
|
+
QA1 date: 20120101000000
|
|
88
|
+
QA1 document URL: "https://doi.org/10.5194/amt-8-2715-2015"
|
|
89
|
+
Originator: Constantin, Lionel, lionel.constantin@empa.ch, Swiss Federal Laboratories for Materials Science and Technology, EMPA, Laboratory for Air Pollution, Überlandstrasse 129, , 8600, Dübendorf, Switzerland
|
|
90
|
+
Originator: Vollmer, Martin K., martin.vollmer@empa.ch, Swiss Federal Laboratories for Materials Science and Technology, EMPA, Laboratory for Air Pollution, Überlandstrasse 129, , 8600, Dübendorf, Switzerland
|
|
91
|
+
Originator: Reimann, Stefan, stefan.reimann@empa.ch, Swiss Federal Laboratories for Materials Science and Technology, EMPA, Laboratory for Air Pollution, Überlandstrasse 129, , 8600, Dübendorf, Switzerland
|
|
92
|
+
Submitter: Constantin, Lionel, lionel.constantin@empa.ch, Swiss Federal Laboratories for Materials Science and Technology, EMPA, Laboratory for Air Pollution, Überlandstrasse 129, , 8600, Dübendorf, Switzerland
|
|
93
|
+
Acknowledgement: Request acknowledgement details from data originator
|
|
94
|
+
Comment:
|
|
95
|
+
starttime endtime cal svol flag C5H12_pa C5H12_pw C5H12_rt C5H12_cal flag C4H10_pa C4H10_pw C4H10_rt C4H10_cal flag C6H6_pa C6H6_pw C6H6_rt C6H6_cal flag
|
|
96
|
+
49.522917 49.536806 1 1.0 0.688 88741 1.83 1384.3 150.6571 0.688 40606 2.16 1286.5 114.34055 0.688 431786 1.85 1481.1 81.37975 0.688
|
|
97
|
+
49.565278 49.579167 0 1.0 0.000 61563 1.82 1384.3 9999.9999 0.000 70360 2.11 1286.5 9999.99999 0.000 454651 1.96 1481.1 999.99999 0.000
|
|
98
|
+
49.607639 49.621528 0 1.0 0.000 67381 1.84 1384.3 9999.9999 0.000 77391 2.15 1286.4 9999.99999 0.000 461898 1.95 1481.1 999.99999 0.000
|
|
99
|
+
49.687500 49.701389 2 1.0 0.689 88678 1.79 1384.3 25.2632 0.689 40694 2.15 1286.5 40.11231 0.689 430971 1.91 1481.1 42.32401 0.689
|
|
100
|
+
49.729861 49.743750 0 1.0 0.000 60136 1.78 1384.3 9999.9999 0.000 72347 2.12 1286.5 9999.99999 0.000 443753 1.95 1481.1 999.99999 0.000
|
|
101
|
+
49.772222 49.786111 0 1.0 0.000 51128 1.81 1384.3 9999.9999 0.000 62677 2.15 1286.5 9999.99999 0.000 414173 1.94 1481.1 999.99999 0.000
|
|
102
|
+
49.814583 49.828472 2 1.0 0.689 88719 1.80 1384.3 25.2632 0.689 40407 2.16 1286.5 1.11231 0.689 431761 1.92 1481.2 42.32401 0.689
|
|
103
|
+
49.856944 49.870833 0 1.0 0.000 62053 1.86 1384.3 9999.9999 0.000 69984 2.14 1286.5 9999.99999 0.000 452174 1.89 1481.1 999.99999 0.000
|
|
104
|
+
49.899306 49.913194 0 1.0 0.000 54817 1.82 1384.3 9999.9999 0.000 64974 2.20 1286.5 9999.99999 0.000 422200 1.92 1481.1 999.99999 0.000
|
|
105
|
+
49.979167 49.993056 2 1.0 0.689 87896 1.76 1384.3 25.2632 0.689 40750 2.19 1286.5 40.11231 0.689 430206 1.90 1481.2 42.32401 0.689
|
|
106
|
+
50.021528 50.035417 0 1.0 0.000 53367 1.80 1384.3 9999.9999 0.000 62509 2.14 1286.5 9999.99999 0.000 444104 1.92 1481.2 999.99999 0.000
|
|
107
|
+
50.063889 50.077778 0 1.0 0.000 50587 1.83 1384.3 9999.9999 0.000 61325 2.18 1286.5 9999.99999 0.000 428892 1.90 1481.1 999.99999 0.000
|
|
108
|
+
50.106250 50.120139 3 1.0 0.689 88477 1.84 1384.3 22.2100 0.689 40254 2.14 1286.5 51.11830 0.689 426318 1.92 1481.2 45.77210 0.689
|
|
109
|
+
50.148611 50.162500 0 1.0 0.000 52307 1.82 1384.3 9999.9999 0.000 62443 2.17 1286.5 9999.99999 0.000 434506 1.91 1481.1 999.99999 0.000
|
|
110
|
+
50.190972 50.204861 0 1.0 0.000 57199 1.83 1384.4 9999.9999 0.000 66991 2.23 1286.5 9999.99999 0.000 434542 1.93 1481.2 999.99999 0.000
|
|
111
|
+
50.270833 50.284722 3 1.0 0.689 88520 1.81 1384.3 22.2100 0.689 40429 2.17 1286.5 51.11830 0.689 428859 1.85 1481.1 45.77210 0.689
|
|
112
|
+
50.313194 50.327083 0 1.0 0.000 69188 1.89 1384.3 9999.9999 0.000 76958 2.11 1286.5 9999.99999 0.000 457871 1.95 1481.1 999.99999 0.000
|
|
113
|
+
50.355556 50.369444 0 1.0 0.000 66581 1.82 1384.4 9999.9999 0.000 76772 2.16 1286.5 9999.99999 0.000 455124 1.91 1481.2 999.99999 0.000
|
|
114
|
+
50.397917 50.411806 3 1.0 0.690 86968 1.83 1384.3 22.2100 0.690 40311 2.16 1286.5 51.11830 0.690 425819 1.90 1481.1 45.77210 0.690
|
|
115
|
+
50.440278 50.454167 0 1.0 0.000 55852 1.76 1384.3 9999.9999 0.000 68588 2.17 1286.5 9999.99999 0.000 416956 1.94 1481.2 999.99999 0.000
|
|
116
|
+
50.482639 50.496528 99 1.0 0.000 999999 99.99 99999.9 9999.9999 0.999 999999 99.99 99999.9 9999.99999 0.999 9999999 99.99 99999.9 999.99999 0.999
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Created: 6 May 21 07:53 GMT
|
|
2
|
+
- - - - methane ethane ethene propane propene
|
|
3
|
+
date time volume type area area area area area
|
|
4
|
+
210101 0025 1.0 air 1506527 187333 54226 124023 9004
|
|
5
|
+
210101 0126 1.1 air 1532954 191969 72289 124942 14789
|
|
6
|
+
210101 0226 1.0 air 1445250 175597 39373 104478 6643
|
|
7
|
+
210101 0327 0.9 air 1434459 171817 38493 99796 5926
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Created: 6 May 21 07:53 GMT
|
|
2
|
+
- - - - methane ethane ethene propane propene
|
|
3
|
+
date time volume type area area area area area
|
|
4
|
+
210101 0025 1.0 air 1506527 187333 54226 124023 9004
|
|
5
|
+
210101 0126 1.1 air nan 191969 72289 124942 14789
|
|
6
|
+
210101 0226 1.0 air 1445250H 175597 39373 104478 6643
|
|
7
|
+
210101 0327 0.9 air 1434459* 171817 38493 99796 5926
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from ebas.io.file.nasa_ames import EbasNasaAmes
|
|
2
|
+
|
|
3
|
+
from avoca.bindings.ebas import DataLevel, nas_to_avoca, set_dataframe
|
|
4
|
+
from avoca.testing import testdata_dir
|
|
5
|
+
from avoca.utils import compounds_from_df
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_read_lev0_template():
|
|
9
|
+
|
|
10
|
+
filepath = testdata_dir / "new_NMHC_lev0.nas"
|
|
11
|
+
|
|
12
|
+
nas = EbasNasaAmes()
|
|
13
|
+
nas.read(filepath)
|
|
14
|
+
|
|
15
|
+
df = nas_to_avoca(nas)
|
|
16
|
+
|
|
17
|
+
print(df.columns)
|
|
18
|
+
|
|
19
|
+
assert ("-", "start_datetime") in df.columns
|
|
20
|
+
assert ("-", "end_datetime") in df.columns
|
|
21
|
+
|
|
22
|
+
compounds = compounds_from_df(df)
|
|
23
|
+
expected_compounds = [
|
|
24
|
+
"2-methylbutane",
|
|
25
|
+
"2-methylpropane",
|
|
26
|
+
"benzene",
|
|
27
|
+
]
|
|
28
|
+
assert sorted(compounds) == sorted(expected_compounds)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_given_nas_is_valid_to_write():
|
|
32
|
+
filepath = testdata_dir / "new_NMHC_lev0.nas"
|
|
33
|
+
|
|
34
|
+
nas = EbasNasaAmes()
|
|
35
|
+
nas.read(filepath)
|
|
36
|
+
outputs_dir = filepath.with_suffix("")
|
|
37
|
+
outputs_dir.mkdir(exist_ok=True)
|
|
38
|
+
nas.write(createfiles=True, destdir=outputs_dir)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_read_and_write():
|
|
42
|
+
filepath = testdata_dir / "new_NMHC_lev0.nas"
|
|
43
|
+
|
|
44
|
+
nas = EbasNasaAmes()
|
|
45
|
+
nas.read(filepath)
|
|
46
|
+
|
|
47
|
+
df = nas_to_avoca(nas)
|
|
48
|
+
|
|
49
|
+
new_nas = EbasNasaAmes()
|
|
50
|
+
|
|
51
|
+
metadatas = set_dataframe(
|
|
52
|
+
new_nas,
|
|
53
|
+
df,
|
|
54
|
+
data_level=DataLevel.AREAS,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
outputs_dir = filepath.with_suffix("")
|
|
58
|
+
outputs_dir.mkdir(exist_ok=True)
|
|
59
|
+
new_nas.write(createfiles=True, destdir=outputs_dir)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
|
|
5
|
+
from avoca.bindings.gcwerks import read_gcwerks
|
|
6
|
+
from avoca.flags import QA_Flag
|
|
7
|
+
|
|
8
|
+
this_dir = Path(__file__).parent
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_read_gcwerks():
|
|
12
|
+
path = this_dir / "gcwerks.dat"
|
|
13
|
+
df = read_gcwerks(path)
|
|
14
|
+
assert len(df) == 4
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_read_gcwerks_with_flags():
|
|
18
|
+
path = this_dir / "gcwerks_with_flags.dat"
|
|
19
|
+
df = read_gcwerks(path)
|
|
20
|
+
assert len(df) == 4
|
|
21
|
+
|
|
22
|
+
assert df[("methane", "area")].iloc[0] == 1506527
|
|
23
|
+
assert df[("methane", "flag")].iloc[0] == 0
|
|
24
|
+
assert df[("methane", "area")].iloc[2] == 1445250
|
|
25
|
+
assert df[("methane", "flag")].iloc[2] == QA_Flag.HEIGHT_INTEGRATION.value
|
|
26
|
+
assert pd.isna(df[("methane", "area")].iloc[1])
|
|
27
|
+
assert df[("methane", "flag")].iloc[1] == QA_Flag.MISSING.value
|
|
28
|
+
assert pd.isna(df[("methane", "area")].iloc[3])
|
|
29
|
+
assert (
|
|
30
|
+
df[("methane", "flag")].iloc[3]
|
|
31
|
+
== QA_Flag.INVALIDATED_EXT.value + QA_Flag.MISSING.value
|
|
32
|
+
)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
1
3
|
from avoca import io
|
|
2
4
|
from avoca.testing import testdata_dir
|
|
3
5
|
from avoca.testing.df import simple_df
|
|
@@ -8,8 +10,13 @@ def test_from_to_csv():
|
|
|
8
10
|
io.to_csv(simple_df, "simple_df.csv")
|
|
9
11
|
# Read the dataframe
|
|
10
12
|
df = io.from_csv("simple_df.csv")
|
|
13
|
+
|
|
14
|
+
# Columns will be sorted differently
|
|
15
|
+
cols_sorted = sorted(simple_df.columns, key=lambda x: (x[0] != "-", x))
|
|
16
|
+
simple_df_sorted = simple_df[cols_sorted]
|
|
17
|
+
|
|
11
18
|
# Check if the dataframes are equal
|
|
12
|
-
|
|
19
|
+
pd.testing.assert_frame_equal(simple_df_sorted, df)
|
|
13
20
|
|
|
14
21
|
|
|
15
22
|
def test_missing_area():
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
Created: 6 May 21 07:53 GMT
|
|
2
|
-
- - - methane ethane ethene propane propene
|
|
3
|
-
date time type area area area area area
|
|
4
|
-
210101 0025 air 1506527 187333 54226 124023 9004
|
|
5
|
-
210101 0126 air 1532954 191969 72289 124942 14789
|
|
6
|
-
210101 0226 air 1445250 175597 39373 104478 6643
|
|
7
|
-
210101 0327 air 1434459 171817 38493 99796 5926
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|