pypromice 1.5.3__py3-none-any.whl → 1.7.0__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 pypromice might be problematic. Click here for more details.

Files changed (67) hide show
  1. pypromice/__init__.py +2 -0
  2. pypromice/{qc → core/qc}/github_data_issues.py +22 -13
  3. pypromice/{qc → core/qc}/percentiles/compute_thresholds.py +2 -2
  4. pypromice/{qc → core/qc}/persistence.py +22 -29
  5. pypromice/{process → core/qc}/value_clipping.py +3 -3
  6. pypromice/core/resampling.py +142 -0
  7. pypromice/core/variables/__init__.py +1 -0
  8. pypromice/core/variables/air_temperature.py +64 -0
  9. pypromice/core/variables/gps.py +221 -0
  10. pypromice/core/variables/humidity.py +111 -0
  11. pypromice/core/variables/precipitation.py +108 -0
  12. pypromice/core/variables/pressure_transducer_depth.py +79 -0
  13. pypromice/core/variables/radiation.py +422 -0
  14. pypromice/core/variables/station_boom_height.py +75 -0
  15. pypromice/core/variables/station_pose.py +375 -0
  16. pypromice/io/bufr/__init__.py +0 -0
  17. pypromice/{postprocess → io/bufr}/bufr_to_csv.py +1 -1
  18. pypromice/{postprocess → io/bufr}/create_bufr_files.py +2 -2
  19. pypromice/{postprocess → io/bufr}/get_bufr.py +6 -6
  20. pypromice/{postprocess → io/bufr}/real_time_utilities.py +3 -3
  21. pypromice/io/ingest/__init__.py +0 -0
  22. pypromice/{utilities → io/ingest}/git.py +1 -3
  23. pypromice/io/ingest/l0.py +294 -0
  24. pypromice/io/ingest/l0_repository.py +103 -0
  25. pypromice/io/ingest/toa5.py +87 -0
  26. pypromice/{process → io}/write.py +1 -1
  27. pypromice/pipeline/L0toL1.py +291 -0
  28. pypromice/pipeline/L1toL2.py +233 -0
  29. pypromice/{process → pipeline}/L2toL3.py +113 -118
  30. pypromice/pipeline/__init__.py +4 -0
  31. pypromice/{process → pipeline}/aws.py +10 -82
  32. pypromice/{process → pipeline}/get_l2.py +2 -2
  33. pypromice/{process → pipeline}/get_l2tol3.py +19 -22
  34. pypromice/{process → pipeline}/join_l2.py +31 -32
  35. pypromice/{process → pipeline}/join_l3.py +16 -14
  36. pypromice/{process → pipeline}/resample.py +75 -51
  37. pypromice/{process → pipeline}/utilities.py +0 -22
  38. pypromice/resources/file_attributes.csv +4 -4
  39. pypromice/resources/variable_aliases_GC-Net.csv +2 -2
  40. pypromice/resources/variables.csv +27 -24
  41. {pypromice-1.5.3.dist-info → pypromice-1.7.0.dist-info}/METADATA +1 -2
  42. pypromice-1.7.0.dist-info/RECORD +65 -0
  43. pypromice-1.7.0.dist-info/entry_points.txt +12 -0
  44. pypromice/get/__init__.py +0 -1
  45. pypromice/get/get.py +0 -211
  46. pypromice/get/get_promice_data.py +0 -56
  47. pypromice/process/L0toL1.py +0 -564
  48. pypromice/process/L1toL2.py +0 -824
  49. pypromice/process/__init__.py +0 -4
  50. pypromice/process/load.py +0 -161
  51. pypromice-1.5.3.dist-info/RECORD +0 -54
  52. pypromice-1.5.3.dist-info/entry_points.txt +0 -13
  53. /pypromice/{postprocess → core}/__init__.py +0 -0
  54. /pypromice/{utilities → core}/dependency_graph.py +0 -0
  55. /pypromice/{qc → core/qc}/__init__.py +0 -0
  56. /pypromice/{qc → core/qc}/percentiles/__init__.py +0 -0
  57. /pypromice/{qc → core/qc}/percentiles/outlier_detector.py +0 -0
  58. /pypromice/{qc → core/qc}/percentiles/thresholds.csv +0 -0
  59. /pypromice/{process → core/variables}/wind.py +0 -0
  60. /pypromice/{utilities → io}/__init__.py +0 -0
  61. /pypromice/{postprocess → io/bufr}/bufr_utilities.py +0 -0
  62. /pypromice/{postprocess → io/bufr}/positions_seed.csv +0 -0
  63. /pypromice/{station_configuration.py → io/bufr/station_configuration.py} +0 -0
  64. /pypromice/{postprocess → io}/make_metadata_csv.py +0 -0
  65. {pypromice-1.5.3.dist-info → pypromice-1.7.0.dist-info}/WHEEL +0 -0
  66. {pypromice-1.5.3.dist-info → pypromice-1.7.0.dist-info}/licenses/LICENSE.txt +0 -0
  67. {pypromice-1.5.3.dist-info → pypromice-1.7.0.dist-info}/top_level.txt +0 -0
@@ -3,21 +3,20 @@ import logging, sys, os, unittest
3
3
  import pandas as pd
4
4
  import xarray as xr
5
5
  from argparse import ArgumentParser
6
- from pypromice.process.L1toL2 import correctPrecip
7
- from pypromice.process.write import prepare_and_write
6
+ from pypromice.io.write import prepare_and_write
8
7
  logger = logging.getLogger(__name__)
9
8
 
10
9
  def parse_arguments_join():
11
10
  parser = ArgumentParser(description="AWS L2 joiner for merging together two L2 products, for example an L2 RAW and L2 TX data product. An hourly, daily and monthly L2 data product is outputted to the defined output path")
12
11
  parser.add_argument('-s', '--file1', type=str, required=True,
13
12
  help='Path to source L2 file, which will be preferenced in merge process')
14
- parser.add_argument('-t', '--file2', type=str, required=True,
13
+ parser.add_argument('-t', '--file2', type=str, required=True,
15
14
  help='Path to target L2 file, which will be used to fill gaps in merge process')
16
- parser.add_argument('-o', '--outpath', default=os.getcwd(), type=str, required=True,
15
+ parser.add_argument('-o', '--outpath', default=os.getcwd(), type=str, required=True,
17
16
  help='Path where to write output')
18
- parser.add_argument('-v', '--variables', default=None, type=str, required=False,
17
+ parser.add_argument('-v', '--variables', default=None, type=str, required=False,
19
18
  help='Path to variables look-up table .csv file for variable name retained'''),
20
- parser.add_argument('-m', '--metadata', default=None, type=str, required=False,
19
+ parser.add_argument('-m', '--metadata', default=None, type=str, required=False,
21
20
  help='Path to metadata table .csv file for metadata information'''),
22
21
  args = parser.parse_args()
23
22
  return args
@@ -25,7 +24,7 @@ def parse_arguments_join():
25
24
  def loadArr(infile):
26
25
  if infile.split('.')[-1].lower() == 'csv':
27
26
  df = pd.read_csv(infile, index_col=0, parse_dates=True)
28
- ds = xr.Dataset.from_dataframe(df)
27
+ ds = xr.Dataset.from_dataframe(df)
29
28
  elif infile.split('.')[-1].lower() == 'nc':
30
29
  with xr.open_dataset(infile) as ds:
31
30
  ds.load()
@@ -35,7 +34,7 @@ def loadArr(infile):
35
34
  ds[varname].encoding = {}
36
35
 
37
36
  try:
38
- name = ds.attrs['station_id']
37
+ name = ds.attrs['station_id']
39
38
  except:
40
39
  name = infile.split('/')[-1].split('.')[0].split('_hour')[0].split('_10min')[0]
41
40
  ds.attrs['station_id'] = name
@@ -46,7 +45,6 @@ def loadArr(infile):
46
45
 
47
46
  logger.info(f'{name} array loaded from {infile}')
48
47
  return ds, name
49
-
50
48
 
51
49
  def join_l2(file1,file2,outpath,variables,metadata) -> xr.Dataset:
52
50
  logging.basicConfig(
@@ -55,43 +53,44 @@ def join_l2(file1,file2,outpath,variables,metadata) -> xr.Dataset:
55
53
  stream=sys.stdout,
56
54
  )
57
55
  # Check files
58
- if os.path.isfile(file1) and os.path.isfile(file2):
56
+ if os.path.isfile(file1) and os.path.isfile(file2):
59
57
 
60
58
  # Load data arrays
61
59
  ds1, n1 = loadArr(file1)
62
- ds2, n2 = loadArr(file2)
63
-
60
+ ds2, n2 = loadArr(file2)
61
+
64
62
  # Check stations match
65
63
  if n1.lower() == n2.lower():
66
-
67
- # Merge arrays
64
+ # Merge arrays
68
65
  logger.info(f'Combining {file1} with {file2}...')
69
66
  name = n1
70
67
  all_ds = ds1.combine_first(ds2)
71
68
 
72
- # Re-calculate corrected precipitation
73
- if hasattr(all_ds, 'precip_u_cor'):
74
- if ~all_ds['precip_u_cor'].isnull().all():
75
- all_ds['precip_u_cor'], _ = correctPrecip(all_ds['precip_u'],
76
- all_ds['wspd_u'])
77
- if hasattr(all_ds, 'precip_l_cor'):
78
- if ~all_ds['precip_l_cor'].isnull().all():
79
- all_ds['precip_l_cor'], _ = correctPrecip(all_ds['precip_l'],
80
- all_ds['wspd_l'])
69
+ # combine_first works terrible for accumulated values
70
+ # we rather combine semi-accumulated precipitation in block
71
+ for var in ['precip_u', 'precip_l']:
72
+ if hasattr(all_ds, var):
73
+ if all_ds[var].notnull().any():
74
+ tx_data_no_overlap =(ds2[var]
75
+ .sel(time=slice(ds1.time.values[-1], ds2.time.values[-1]))
76
+ .isel(time=slice(1, None))) # this line prevents redundant timestamps
77
+ all_ds[var] = xr.concat(
78
+ [ds1[var], tx_data_no_overlap], dim='time'
79
+ ).sortby('time')
81
80
  else:
82
81
  logger.info(f'Mismatched station names {n1}, {n2}')
83
- exit()
84
-
85
- elif os.path.isfile(file1):
82
+ exit()
83
+
84
+ elif os.path.isfile(file1):
86
85
  ds1, name = loadArr(file1)
87
86
  logger.info(f'Only one file found {file1}...')
88
- all_ds = ds1
87
+ all_ds = ds1
89
88
 
90
89
  elif os.path.isfile(file2):
91
90
  ds2, name = loadArr(file2)
92
91
  logger.info(f'Only one file found {file2}...')
93
- all_ds = ds2
94
-
92
+ all_ds = ds2
93
+
95
94
  else:
96
95
  logger.info(f'Invalid files {file1}, {file2}')
97
96
  exit()
@@ -100,13 +99,13 @@ def join_l2(file1,file2,outpath,variables,metadata) -> xr.Dataset:
100
99
 
101
100
  # Resample to hourly, daily and monthly datasets and write to file
102
101
  prepare_and_write(all_ds, outpath, variables, metadata, resample = False)
103
-
102
+
104
103
  logger.info(f'Files saved to {os.path.join(outpath, name)}...')
105
104
  return all_ds
106
105
 
107
106
  def main():
108
107
  args = parse_arguments_join()
109
108
  _ = join_l2(args.file1, args.file2, args.outpath, args.variables, args.metadata)
110
-
111
- if __name__ == "__main__":
109
+
110
+ if __name__ == "__main__":
112
111
  main()
@@ -3,10 +3,11 @@ import json
3
3
  import logging, os, sys, toml
4
4
  from argparse import ArgumentParser
5
5
 
6
- from pypromice.utilities.git import get_commit_hash_and_check_dirty
6
+ from pypromice.io.ingest.git import get_commit_hash_and_check_dirty
7
7
 
8
8
  import pypromice.resources
9
- from pypromice.process.write import prepare_and_write
9
+ from pypromice.io.write import prepare_and_write
10
+
10
11
  import numpy as np
11
12
  import pandas as pd
12
13
  import xarray as xr
@@ -493,20 +494,21 @@ def join_l3(config_folder, site, folder_l3, folder_gcnet, outpath, variables, me
493
494
  l3_merged.z_ice_surf.to_series(), l3.z_ice_surf.to_series()
494
495
  ),
495
496
  )
496
-
497
+
497
498
  # saves attributes
498
499
  attrs = l3_merged.attrs
499
500
  # merging by time block
500
- l3_merged = xr.concat(
501
- (
502
- l3.sel(
503
- time=slice(l3.time.isel(time=0), l3_merged.time.isel(time=0))
504
- ),
505
- l3_merged,
506
- ),
507
- dim="time",
508
- )
509
-
501
+ t_start = l3.time.values[0]
502
+ t_stop = l3_merged.time.values[0]
503
+
504
+ l3_part = l3.sel(time=slice(t_start, t_stop))
505
+
506
+ # we don't want the first timestamp of l3_merged to also be in l3
507
+ if l3_part.time.values[-1] == t_stop:
508
+ l3_part = l3_part.isel(time=slice(None, -1))
509
+
510
+ l3_merged = xr.concat([l3_part, l3_merged], dim="time")
511
+
510
512
  # restauring attributes
511
513
  l3_merged.attrs = attrs
512
514
 
@@ -540,7 +542,7 @@ def join_l3(config_folder, site, folder_l3, folder_gcnet, outpath, variables, me
540
542
  if outpath is not None:
541
543
  prepare_and_write(l3_merged, outpath, v, m, "60min", nc_compression=True)
542
544
  prepare_and_write(l3_merged, outpath, v, m, "1D", nc_compression=True)
543
- prepare_and_write(l3_merged, outpath, v, m, "M", nc_compression=True)
545
+ prepare_and_write(l3_merged, outpath, v, m, "MS", nc_compression=True)
544
546
  return l3_merged, sorted_list_station_data
545
547
 
546
548
 
@@ -1,17 +1,15 @@
1
1
  #!/usr/bin/env python3
2
2
  # -*- coding: utf-8 -*-
3
- """
4
- Created on Mon Jun 10 10:58:39 2024
5
-
6
- @author: pho
7
- """
8
3
  import logging
9
4
  import numpy as np
5
+ import pandas as pd
10
6
  import xarray as xr
11
- from pypromice.process.wind import calculate_directional_wind_speed
7
+
8
+ from pypromice.core.resampling import get_completeness_mask, DEFAULT_COMPLETENESS_THRESHOLDS
9
+ from pypromice.core.variables.wind import calculate_directional_wind_speed
12
10
  logger = logging.getLogger(__name__)
13
11
 
14
- def resample_dataset(ds_h, t):
12
+ def resample_dataset(ds_h, t, completeness_thresholds=DEFAULT_COMPLETENESS_THRESHOLDS):
15
13
  '''Resample L2 AWS data, e.g. hourly to daily average. This uses pandas
16
14
  DataFrame resampling at the moment as a work-around to the xarray Dataset
17
15
  resampling. As stated, xarray resampling is a lengthy process that takes
@@ -24,8 +22,13 @@ def resample_dataset(ds_h, t):
24
22
  ds_h : xarray.Dataset
25
23
  L3 AWS dataset either at 10 min (for raw data) or hourly (for tx data)
26
24
  t : str
27
- Resample factor, same variable definition as in
25
+ Resample factor( "60min", "1D" or "MS"), same variable definition as in
28
26
  pandas.DataFrame.resample()
27
+ completeness_thresholds : Dict
28
+ A dict with, for each variable, the lower limit of completness of an
29
+ hourly/daily/monthly aggregate (nr of samples in aggregate / expected
30
+ nr of samples). Aggregates below that limit are replaced by NaNs.
31
+ Must include a "default" value used for variables not listed explicitly.
29
32
 
30
33
  Returns
31
34
  -------
@@ -33,20 +36,42 @@ def resample_dataset(ds_h, t):
33
36
  L3 AWS dataset resampled to the frequency defined by t
34
37
  '''
35
38
  # Convert dataset to DataFrame
36
- df_d = ds_h.to_dataframe()
37
-
39
+ df_h = ds_h.to_dataframe()
40
+
38
41
  # Identify non-numeric columns
39
- non_numeric_cols = df_d.select_dtypes(exclude=['number']).columns
40
-
42
+ non_numeric_cols = df_h.select_dtypes(exclude=['number']).columns
43
+
41
44
  # Log a warning and drop non-numeric columns
42
45
  if len(non_numeric_cols) > 0:
43
46
  for col in non_numeric_cols:
44
- unique_values = df_d[col].unique()
45
- logger.warning(f"Dropping column '{col}' because it is of type '{df_d[col].dtype}' and contains unique values: {unique_values}")
47
+ unique_values = df_h[col].unique()
48
+ logger.warning(f"Dropping column '{col}' because it is of type '{df_h[col].dtype}' and contains unique values: {unique_values}")
46
49
 
47
- df_d = df_d.drop(columns=non_numeric_cols)
50
+ df_h = df_h.drop(columns=non_numeric_cols)
48
51
  # Resample the DataFrame
49
- df_d = df_d.resample(t).mean()
52
+ df_resampled = df_h.resample(t).mean()
53
+
54
+ # exception for precip_u and precip_l which are semi-accumulated with some resets
55
+ # Taking the max value within the resampled time step will preserve the
56
+ # general shape of the curve
57
+ for var in ['precip_u', 'precip_l']:
58
+ if var in df_h.columns:
59
+ df_resampled[var] = df_h[var].resample(t).max()
60
+
61
+ # exception for rainfall which should be summed when aggregated into
62
+ # hourly/daily/monthly values. This ignores missing data.
63
+ for var in ['rainfall_u', 'rainfall_cor_u', 'rainfall_l', 'rainfall_cor_l']:
64
+ if var in df_h.columns:
65
+ df_resampled[var] = df_h[var].resample(t).sum()
66
+
67
+ # Apply completeness filter based on the the data frame time index
68
+ completeness_mask = get_completeness_mask(
69
+ data_frame=df_h,
70
+ resample_offset=t,
71
+ completeness_thresholds=completeness_thresholds,
72
+ )
73
+
74
+ df_resampled[~completeness_mask] = np.nan
50
75
 
51
76
  # taking the 10 min data and using it as instantaneous values:
52
77
  is_10_minutes_timestamp = (ds_h.time.diff(dim='time') / np.timedelta64(1, 's') == 600)
@@ -54,75 +79,75 @@ def resample_dataset(ds_h, t):
54
79
  cols_to_update = ['p_i', 't_i', 'rh_i', 'rh_i_wrt_ice_or_water', 'wspd_i', 'wdir_i','wspd_x_i','wspd_y_i']
55
80
  cols_origin = ['p_u', 't_u', 'rh_u', 'rh_u_wrt_ice_or_water', 'wspd_u', 'wdir_u','wspd_x_u','wspd_y_u']
56
81
  timestamp_10min = ds_h.time.where(is_10_minutes_timestamp, drop=True).to_index()
57
- timestamp_round_hour = df_d.index
82
+ timestamp_round_hour = df_resampled.index
58
83
  timestamp_to_update = timestamp_round_hour.intersection(timestamp_10min)
59
-
84
+
60
85
  for col, col_org in zip(cols_to_update, cols_origin):
61
- if col not in df_d.columns:
62
- df_d[col] = np.nan
86
+ if col not in df_resampled.columns:
87
+ df_resampled[col] = np.nan
63
88
  else:
64
89
  # if there are already instantaneous values in the dataset
65
90
  # we want to keep them as they are
66
91
  # removing timestamps where there is already t_i filled from a TX file
67
92
  missing_instantaneous = ds_h.reindex(time=timestamp_to_update)[col].isnull()
68
93
  timestamp_to_update = timestamp_to_update[missing_instantaneous]
69
- df_d.loc[timestamp_to_update, col] = ds_h.reindex(
94
+ df_resampled.loc[timestamp_to_update, col] = ds_h.reindex(
70
95
  time= timestamp_to_update
71
96
  )[col_org].values
72
97
  if col == 'p_i':
73
- df_d.loc[timestamp_to_update, col] = df_d.loc[timestamp_to_update, col].values-1000
74
-
98
+ df_resampled.loc[timestamp_to_update, col] = df_resampled.loc[timestamp_to_update, col].values-1000
75
99
 
76
100
  # recalculating wind direction from averaged directional wind speeds
77
101
  for var in ['wdir_u','wdir_l']:
78
102
  boom = var.split('_')[1]
79
- if var in df_d.columns:
80
- if ('wspd_x_'+boom in df_d.columns) & ('wspd_y_'+boom in df_d.columns):
81
- df_d[var] = _calcWindDir(df_d['wspd_x_'+boom], df_d['wspd_y_'+boom])
103
+ if var in df_resampled.columns:
104
+ if ('wspd_x_'+boom in df_resampled.columns) & ('wspd_y_'+boom in df_resampled.columns):
105
+ df_resampled[var] = _calcWindDir(df_resampled['wspd_x_'+boom], df_resampled['wspd_y_'+boom])
82
106
  else:
83
107
  logger.info(var+' in dataframe but not wspd_x_'+boom+' nor wspd_y_'+boom+', recalculating them')
84
108
  ds_h['wspd_x_'+boom], ds_h['wspd_y_'+boom] = calculate_directional_wind_speed(ds_h['wspd_'+boom], ds_h['wdir_'+boom])
85
- df_d[['wspd_x_'+boom, 'wspd_y_'+boom]] = ds_h[['wspd_x_'+boom, 'wspd_y_'+boom]].to_dataframe().resample(t).mean()
86
- df_d[var] = _calcWindDir(df_d['wspd_x_'+boom], df_d['wspd_y_'+boom])
87
-
109
+ df_resampled[['wspd_x_'+boom, 'wspd_y_'+boom]] = ds_h[['wspd_x_'+boom, 'wspd_y_'+boom]].to_dataframe().resample(t).mean()
110
+ df_resampled[var] = _calcWindDir(df_resampled['wspd_x_'+boom], df_resampled['wspd_y_'+boom])
111
+
88
112
  # recalculating relative humidity from average vapour pressure and average
89
113
  # saturation vapor pressure
90
114
  for var in ['rh_u','rh_l']:
91
115
  lvl = var.split('_')[1]
92
- if var in df_d.columns:
116
+ if var in df_resampled.columns:
93
117
  if ('t_'+lvl in ds_h.keys()):
94
118
  es_wtr, es_cor = calculateSaturationVaporPressure(ds_h['t_'+lvl])
95
119
  p_vap = ds_h[var] / 100 * es_wtr
96
-
97
- df_d[var] = (p_vap.to_series().resample(t).mean() \
120
+
121
+ df_resampled[var] = (p_vap.to_series().resample(t).mean() \
98
122
  / es_wtr.to_series().resample(t).mean())*100
99
- if var+'_wrt_ice_or_water' in df_d.keys():
100
- df_d[var+'_wrt_ice_or_water'] = (p_vap.to_series().resample(t).mean() \
123
+ if var+'_wrt_ice_or_water' in df_resampled.keys():
124
+ df_resampled[var+'_wrt_ice_or_water'] = (p_vap.to_series().resample(t).mean() \
101
125
  / es_cor.to_series().resample(t).mean())*100
102
-
126
+
103
127
  # passing each variable attribute to the ressample dataset
104
128
  vals = []
105
- for c in df_d.columns:
129
+ for c in df_resampled.columns:
106
130
  if c in ds_h.data_vars:
107
131
  vals.append(xr.DataArray(
108
- data=df_d[c], dims=['time'],
109
- coords={'time':df_d.index}, attrs=ds_h[c].attrs))
132
+ data=df_resampled[c], dims=['time'],
133
+ coords={'time':df_resampled.index}, attrs=ds_h[c].attrs))
110
134
  else:
111
135
  vals.append(xr.DataArray(
112
- data=df_d[c], dims=['time'],
113
- coords={'time':df_d.index}, attrs=None))
114
-
115
- ds_d = xr.Dataset(dict(zip(df_d.columns,vals)), attrs=ds_h.attrs)
116
- return ds_d
136
+ data=df_resampled[c], dims=['time'],
137
+ coords={'time':df_resampled.index}, attrs=None))
138
+
139
+ ds_resampled = xr.Dataset(dict(zip(df_resampled.columns,vals)), attrs=ds_h.attrs)
140
+
141
+ return ds_resampled
117
142
 
118
143
 
119
144
  def calculateSaturationVaporPressure(t, T_0=273.15, T_100=373.15, es_0=6.1071,
120
- es_100=1013.246, eps=0.622):
145
+ es_100=1013.246, eps=0.622):
121
146
  '''Calculate specific humidity
122
-
147
+
123
148
  Parameters
124
149
  ----------
125
- T_0 : float
150
+ T_0 : float
126
151
  Steam point temperature. Default is 273.15.
127
152
  T_100 : float
128
153
  Steam point temperature in Kelvin
@@ -132,14 +157,13 @@ def calculateSaturationVaporPressure(t, T_0=273.15, T_100=373.15, es_0=6.1071,
132
157
  Saturation vapour pressure at the melting point (hPa)
133
158
  es_100 : float
134
159
  Saturation vapour pressure at steam point temperature (hPa)
135
-
136
160
  Returns
137
161
  -------
138
162
  xarray.DataArray
139
163
  Saturation vapour pressure with regard to water above 0 C (hPa)
140
164
  xarray.DataArray
141
165
  Saturation vapour pressure where subfreezing timestamps are with regards to ice (hPa)
142
- '''
166
+ '''
143
167
  # Saturation vapour pressure above 0 C (hPa)
144
168
  es_wtr = 10**(-7.90298 * (T_100 / (t + T_0) - 1) + 5.02808 * np.log10(T_100 / (t + T_0))
145
169
  - 1.3816E-7 * (10**(11.344 * (1 - (t + T_0) / T_100)) - 1)
@@ -149,11 +173,11 @@ def calculateSaturationVaporPressure(t, T_0=273.15, T_100=373.15, es_0=6.1071,
149
173
  es_ice = 10**(-9.09718 * (T_0 / (t + T_0) - 1) - 3.56654
150
174
  * np.log10(T_0 / (t + T_0)) + 0.876793
151
175
  * (1 - (t + T_0) / T_0)
152
- + np.log10(es_0))
153
-
176
+ + np.log10(es_0))
177
+
154
178
  # Saturation vapour pressure (hPa)
155
179
  es_cor = xr.where(t < 0, es_ice, es_wtr)
156
-
180
+
157
181
  return es_wtr, es_cor
158
182
 
159
183
  def _calcWindDir(wspd_x, wspd_y):
@@ -44,25 +44,3 @@ def addBasicMeta(ds, vars_df):
44
44
  ds[v].attrs[c] = vars_df[c][v]
45
45
  return ds
46
46
 
47
- def populateMeta(ds, conf, skip):
48
- '''Populate L0 Dataset with metadata dictionary
49
-
50
- Parameters
51
- ----------
52
- ds : xarray.Dataset
53
- L0 dataset
54
- conf : dict
55
- Metadata dictionary
56
- skip : list
57
- List of column names to skip parsing to metadata
58
-
59
- Returns
60
- -------
61
- ds : xarray.Dataset
62
- L0 dataset with metadata populated as Dataset attributes
63
- '''
64
- # skip = ["columns", "skiprows"]
65
- for k in conf.keys():
66
- if k not in skip: ds.attrs[k] = conf[k]
67
- return ds
68
-
@@ -3,13 +3,13 @@ acknowledgements,The Programme for Monitoring of the Greenland Ice Sheet (PROMIC
3
3
  alt.axis,Z
4
4
  alt.coverage_content_type,coordinate
5
5
  gps_alt.positive,up
6
- cdm_data_type,
6
+ cdm_data_type,Station
7
7
  comment,https://doi.org/10.22008/promice/data/aws
8
8
  contributor_name,
9
9
  contributor_role,
10
10
  conventions,ACDD-1.3; CF-1.7
11
- creater_email,pho@geus.dk
12
- creater_url,https://promice.dk
11
+ creator_email,pho@geus.dk
12
+ creator_url,https://promice.dk
13
13
  creator_institution,Geological Survey of Denmark and Greenland (GEUS)
14
14
  creator_name,Penelope How
15
15
  creator_type,person
@@ -22,7 +22,7 @@ geospatial_lon_extents_match,gps_lon
22
22
  geospatial_lon_resolution,
23
23
  geospatial_lon_units,degrees_east
24
24
  geospatial_vertical_resolution,
25
- geospatial_vertical_units,EPSG:4979
25
+ geospatial_vertical_units,meters
26
26
  institution,Geological Survey of Denmark and Greenland (GEUS)
27
27
  instrument,See https://doi.org/10.5194/essd-13-3819-2021
28
28
  instrument_vocabulary,GCMD:GCMD Keywords
@@ -27,8 +27,8 @@ dlhf_u,LHF
27
27
  dlhf_l,
28
28
  dshf_u,SHF
29
29
  dshf_l,
30
- z_boom_u,HW2
31
- z_boom_l,HW1
30
+ z_boom_cor_u,HW2
31
+ z_boom_cor_l,HW1
32
32
  precip_u,
33
33
  precip_u_cor,
34
34
  precip_l,
@@ -1,18 +1,18 @@
1
- field,standard_name,long_name,units,coverage_content_type,coordinates,instantaneous_hourly,where_to_find,lo,hi,OOL,station_type,L0,L2,L3,max_decimals
1
+ field,standard_name,long_name,units,coverage_content_type,coordinates,instantaneous_hourly,where_to_find,lo,hi,dependent_variables,station_type,L0,L2,L3,max_decimals
2
2
  time,time,Time,yyyy-mm-dd HH:MM:SS,physicalMeasurement,time,,,,,,all,1,1,1,
3
3
  rec,record,Record,-,referenceInformation,time,,L0 or L2,,,,all,1,1,0,0
4
- p_u,air_pressure,Air pressure (upper boom),hPa,physicalMeasurement,time,FALSE,,650,1100,"",all,1,1,1,4
5
- p_l,air_pressure,Air pressure (lower boom),hPa,physicalMeasurement,time,FALSE,,650,1100,"",two-boom,1,1,1,4
6
- t_u,air_temperature,Air temperature (upper boom),degrees_C,physicalMeasurement,time,FALSE,,-80,40,"",all,1,1,1,4
7
- t_l,air_temperature,Air temperature (lower boom),degrees_C,physicalMeasurement,time,FALSE,,-80,40,"",two-boom,1,1,1,4
8
- rh_u,relative_humidity,Relative humidity (upper boom),%,physicalMeasurement,time,FALSE,,0,100,"",all,1,1,1,4
4
+ p_u,air_pressure,Air pressure (upper boom),hPa,physicalMeasurement,time,FALSE,,650,1100,z_pt_cor dlhf_u dshf_u,all,1,1,1,4
5
+ p_l,air_pressure,Air pressure (lower boom),hPa,physicalMeasurement,time,FALSE,,650,1100,dlhf_l dshf_l,two-boom,1,1,1,4
6
+ t_u,air_temperature,Air temperature (upper boom),degrees_C,physicalMeasurement,time,FALSE,,-80,40,z_boom_cor_l z_boom_cor_u z_stake_cor qh_u rh_u_wrt_ice_or_water dlhf_u dshf_u,all,1,1,1,4
7
+ t_l,air_temperature,Air temperature (lower boom),degrees_C,physicalMeasurement,time,FALSE,,-80,40,dlhf_l dshf_l,two-boom,1,1,1,4
8
+ rh_u,relative_humidity,Relative humidity (upper boom),%,physicalMeasurement,time,FALSE,,0,100,qh_u rh_u_wrt_ice_or_water dlhf_u dshf_u,all,1,1,1,4
9
9
  rh_u_wrt_ice_or_water,relative_humidity_with_respect_to_ice_or_water,Relative humidity (upper boom) with respect to saturation over ice in subfreezing conditions and over water otherwise,%,modelResult,time,FALSE,L2 or later,0,150,"",all,0,1,1,4
10
10
  qh_u,specific_humidity,Specific humidity (upper boom),kg/kg,modelResult,time,FALSE,L2 or later,0,100,"",all,0,1,1,4
11
- rh_l,relative_humidity,Relative humidity (lower boom),%,physicalMeasurement,time,FALSE,,0,100,"",two-boom,1,1,1,4
11
+ rh_l,relative_humidity,Relative humidity (lower boom),%,physicalMeasurement,time,FALSE,,0,100,qh_l rh_l_wrt_ice_or_water dlhf_l dshf_l,two-boom,1,1,1,4
12
12
  rh_l_wrt_ice_or_water,relative_humidity_with_respect_to_ice_or_water,Relative humidity (lower boom) with respect to saturation over ice in subfreezing conditions and over water otherwise,%,modelResult,time,FALSE,L2 or later,0,150,"",two-boom,0,1,1,4
13
13
  qh_l,specific_humidity,Specific humidity (lower boom),kg/kg,modelResult,time,FALSE,L2 or later,0,100,,two-boom,0,1,1,4
14
- wspd_u,wind_speed,Wind speed (upper boom),m s-1,physicalMeasurement,time,FALSE,,0,100,wdir_u wspd_x_u wspd_y_u,all,1,1,1,4
15
- wspd_l,wind_speed,Wind speed (lower boom),m s-1,physicalMeasurement,time,FALSE,,0,100,wdir_l wspd_x_l wspd_y_l,two-boom,1,1,1,4
14
+ wspd_u,wind_speed,Wind speed (upper boom),m s-1,physicalMeasurement,time,FALSE,,0,100,wdir_u wspd_x_u wspd_y_u rainfall_cor_u,all,1,1,1,4
15
+ wspd_l,wind_speed,Wind speed (lower boom),m s-1,physicalMeasurement,time,FALSE,,0,100,wdir_l wspd_x_l wspd_y_l rainfall_cor_l,two-boom,1,1,1,4
16
16
  wdir_u,wind_from_direction,Wind from direction (upper boom),degrees,physicalMeasurement,time,FALSE,,1,360,wspd_x_u wspd_y_u,all,1,1,1,4
17
17
  wdir_std_u,wind_from_direction_standard_deviation,Wind from direction (standard deviation),degrees,qualityInformation,time,FALSE,L0 or L2,,,,one-boom,1,1,0,4
18
18
  wdir_l,wind_from_direction,Wind from direction (lower boom),degrees,physicalMeasurement,time,FALSE,,1,360,wspd_x_l wspd_y_l,two-boom,1,1,1,4
@@ -33,23 +33,26 @@ dlhf_u,surface_downward_latent_heat_flux,Latent heat flux (upper boom),W m-2,mod
33
33
  dlhf_l,surface_downward_latent_heat_flux,Latent heat flux (lower boom),W m-2,modelResult,time,FALSE,L3 or later,,,,two-boom,0,0,1,4
34
34
  dshf_u,surface_downward_sensible_heat_flux,Sensible heat flux (upper boom),W m-2,modelResult,time,FALSE,L3 or later,,,,all,0,0,1,4
35
35
  dshf_l,surface_downward_sensible_heat_flux,Sensible heat flux (lower boom),W m-2,modelResult,time,FALSE,L3 or later,,,,two-boom,0,0,1,4
36
- z_boom_u,distance_to_surface_from_boom,Upper boom height,m,physicalMeasurement,time,TRUE,,0.3,10,"",all,1,1,1,4
36
+ z_boom_u,distance_to_surface_from_boom,Upper boom height,m,physicalMeasurement,time,TRUE,,0.3,10,z_boom_cor_u,all,1,1,1,4
37
+ z_boom_cor_u,distance_to_surface_from_boom_corrected,Upper boom height - corrected,m,modelResult,time,TRUE,,0.3,10,z_boom_u,all,1,1,1,4
37
38
  z_boom_q_u,distance_to_surface_from_boom_quality,Upper boom height (quality),-,qualityInformation,time,TRUE,L0 or L2,,,,all,1,1,0,4
38
- z_boom_l,distance_to_surface_from_boom,Lower boom height,m,physicalMeasurement,time,TRUE,,0.3,5,"",two-boom,1,1,1,4
39
+ z_boom_l,distance_to_surface_from_boom,Lower boom height,m,physicalMeasurement,time,TRUE,,0.3,5,z_boom_cor_l,two-boom,1,1,1,4
40
+ z_boom_cor_l,distance_to_surface_from_boom_corrected,Lower boom height - corrected,m,modelResult,time,TRUE,,0.3,5,z_boom_l,two-boom,1,1,1,4
39
41
  z_boom_q_l,distance_to_surface_from_boom_quality,Lower boom height (quality),-,qualityInformation,time,TRUE,L0 or L2,,,,two-boom,1,1,0,4
40
- z_stake,distance_to_surface_from_stake_assembly,Stake height,m,physicalMeasurement,time,TRUE,,0.3,8,,one-boom,1,1,1,4
42
+ z_stake,distance_to_surface_from_stake_assembly,Stake height,m,physicalMeasurement,time,TRUE,,0.3,8,z_stake_cor,one-boom,1,1,1,4
43
+ z_stake_cor,distance_to_surface_from_stake_assembly_corrected,Stake height - corrected,m,physicalMeasurement,time,TRUE,,0.3,8,z_stake,one-boom,1,1,1,4
41
44
  z_stake_q,distance_to_surface_from_stake_assembly_quality,Stake height (quality),-,qualityInformation,time,TRUE,L0 or L2,,,,one-boom,1,1,0,4
42
- z_pt,depth_of_pressure_transducer_in_ice,Depth of pressure transducer in ice,m,physicalMeasurement,time,FALSE,,0,30,"",one-boom,1,1,1,4
45
+ z_pt,depth_of_pressure_transducer_in_ice,Depth of pressure transducer in ice,m,physicalMeasurement,time,FALSE,,0,30,z_pt_cor,one-boom,1,1,1,4
43
46
  z_pt_cor,depth_of_pressure_transducer_in_ice_corrected,Depth of pressure transducer in ice - corrected,m,modelResult,time,FALSE,L2 or later,0,30,,one-boom,0,1,1,4
44
47
  z_surf_combined,height_of_surface_combined,"Surface height combined from multiple sensors, relative to ice surface height at installation",m,modelResult,time,FALSE,L3,,,,all,0,0,1,4
45
48
  z_ice_surf,height_of_ice_surface,"Ice surface height, relative to ice surface height at installation and calculated from pt_cor and z_stake",m,modelResult,time,FALSE,L3,,,,one-boom,0,0,1,4
46
49
  snow_height,height_of_snow,"Snow surface height, relative to ice surface",m,modelResult,time,FALSE,L3,0,,,one-boom,0,0,1,4
47
- precip_u,precipitation,Precipitation (upper boom) (cumulative solid & liquid),mm,physicalMeasurement,time,TRUE,,0,,"",all,1,1,1,4
48
- precip_u_cor,precipitation_corrected,Precipitation (upper boom) (cumulative solid & liquid) – corrected,mm,modelResult,time,TRUE,L2 or later,0,,,all,0,1,1,4
49
- precip_u_rate,precipitation_rate,Precipitation rate (upper boom) (cumulative solid & liquid) – corrected,mm,modelResult,time,TRUE,L2 or later,0,,,all,0,1,1,4
50
- precip_l,precipitation,Precipitation (lower boom) (cumulative solid & liquid),mm,physicalMeasurement,time,TRUE,,0,,"",two-boom,1,1,1,4
51
- precip_l_cor,precipitation_corrected,Precipitation (lower boom) (cumulative solid & liquid) – corrected,mm,modelResult,time,TRUE,L2 or later,0,,,two-boom,0,1,1,4
52
- precip_l_rate,precipitation_rate,Precipitation rate (lower boom) (cumulative solid & liquid) – corrected,mm,modelResult,time,TRUE,L2 or later,0,,,two-boom,0,1,1,4
50
+ precip_u,precipitation_raw_upper,Semi-accumulated uncorrected liquid precipitation (upper boom),mm,physicalMeasurement,time,TRUE,L0 or L2,0,,rainfall_u,all,1,1,0,4
51
+ rainfall_u,rainfall_per_timestep_uncorrected_upper,Rainfall within timestep uncorrected for undercatch (upper boom),mm,modelResult,time,FALSE,L2 or later,0,,rainfall_cor_u,all,0,1,1,4
52
+ rainfall_cor_u,rainfall_per_timestep_corrected_upper,Rainfall within timestep corrected for undercatch (upper boom),mm,modelResult,time,FALSE,L2 or later,0,,,all,0,1,1,4
53
+ precip_l,precipitation_raw_lower,Semi-accumulated uncorrected liquid precipitation (lower boom),mm,physicalMeasurement,time,TRUE,L0 or L2,0,,rainfall_l,two-boom,1,1,0,4
54
+ rainfall_l,rainfall_per_timestep_uncorrected_lower,Rainfall within timestep uncorrected for undercatch (lower boom),mm,modelResult,time,FALSE,L2 or later,0,,rainfall_cor_l,all,0,1,1,4
55
+ rainfall_cor_l,rainfall_per_timestep_corrected_lower,Rainfall within timestep corrected for undercatch (lower boom),mm,modelResult,time,FALSE,L2 or later,0,,,all,0,1,1,4
53
56
  t_i_1,ice_temperature_at_t1,Ice temperature at sensor 1,degrees_C,physicalMeasurement,time,FALSE,,-80,1,,all,1,1,1,4
54
57
  t_i_2,ice_temperature_at_t2,Ice temperature at sensor 2,degrees_C,physicalMeasurement,time,FALSE,,-80,1,,all,1,1,1,4
55
58
  t_i_3,ice_temperature_at_t3,Ice temperature at sensor 3,degrees_C,physicalMeasurement,time,FALSE,,-80,1,,all,1,1,1,4
@@ -73,8 +76,8 @@ d_t_i_9,depth_of_thermistor_9,Depth of thermistor 9,m,modelResult,time,FALSE,L3,
73
76
  d_t_i_10,depth_of_thermistor_10,Depth of thermistor 10,m,modelResult,time,FALSE,L3,-10,100,,two-boom,0,0,1,4
74
77
  d_t_i_11,depth_of_thermistor_11,Depth of thermistor 11,m,modelResult,time,FALSE,L3,-10,100,,two-boom,0,0,1,4
75
78
  t_i_10m,10m_subsurface_temperature,10 m subsurface temperature,degrees_C,modelResult,time,FALSE,L3,-70,0,,all,0,0,1,4
76
- tilt_x,platform_view_angle_x,Tilt to east,degrees,physicalMeasurement,time,FALSE,,-30,30,"",all,1,1,1,4
77
- tilt_y,platform_view_angle_y,Tilt to north,degrees,physicalMeasurement,time,FALSE,,-30,30,"",all,1,1,1,4
79
+ tilt_x,platform_view_angle_x,Tilt to east,degrees,physicalMeasurement,time,FALSE,,-30,30,dsr_cor usr_cor,all,1,1,1,4
80
+ tilt_y,platform_view_angle_y,Tilt to north,degrees,physicalMeasurement,time,FALSE,,-30,30,dsr_cor usr_cor,all,1,1,1,4
78
81
  rot,platform_azimuth_angle,Station rotation from true North,degrees,physicalMeasurement,time,FALSE,,0,360,,all,1,1,1,2
79
82
  gps_lat,gps_latitude,Latitude,degrees_north,physicalMeasurement,time,TRUE,,50,83,,all,1,1,1,6
80
83
  gps_lon,gps_longitude,Longitude,degrees_east,physicalMeasurement,time,TRUE,,5,70,,all,1,1,1,6
@@ -95,10 +98,10 @@ fan_dc_u,fan_current,Fan current (upper boom),mA,physicalMeasurement,time,TRUE,L
95
98
  fan_dc_l,fan_current,Fan current (lower boom),mA,physicalMeasurement,time,TRUE,,0,200,,two-boom,1,1,0,2
96
99
  freq_vw,frequency_of_precipitation_wire_vibration,Frequency of vibrating wire in precipitation gauge,Hz,physicalMeasurement,time,TRUE,L0 or L2,0,10000,"",,1,1,0,
97
100
  t_log,temperature_of_logger,Logger temperature,degrees_C,physicalMeasurement,time,TRUE,,-80,40,,one-boom,1,1,0,4
98
- t_rad,temperature_of_radiation_sensor,Radiation sensor temperature,degrees_C,physicalMeasurement,time,FALSE,,-80,40,"",all,1,1,1,4
101
+ t_rad,temperature_of_radiation_sensor,Radiation sensor temperature,degrees_C,physicalMeasurement,time,FALSE,,-80,40,dlr ulr,all,1,1,1,4
99
102
  p_i,air_pressure,Air pressure (instantaneous) minus 1000,hPa,physicalMeasurement,time,TRUE,,-350,100,,all,1,1,1,4
100
- t_i,air_temperature,Air temperature (instantaneous),degrees_C,physicalMeasurement,time,TRUE,,-80,40,,all,1,1,1,4
101
- rh_i,relative_humidity,Relative humidity (instantaneous),%,physicalMeasurement,time,TRUE,,0,150,"",all,1,1,1,4
103
+ t_i,air_temperature,Air temperature (instantaneous),degrees_C,physicalMeasurement,time,TRUE,,-80,40,rh_i_wrt_ice_or_water,all,1,1,1,4
104
+ rh_i,relative_humidity,Relative humidity (instantaneous),%,physicalMeasurement,time,TRUE,,0,150,rh_i_wrt_ice_or_water,all,1,1,1,4
102
105
  rh_i_wrt_ice_or_water,relative_humidity_with_respect_to_ice_or_water,Relative humidity (instantaneous) with respect to saturation over ice in subfreezing conditions and over water otherwise,%,modelResult,time,TRUE,L2 or later,0,100,,all,0,1,1,4
103
106
  wspd_i,wind_speed,Wind speed (instantaneous),m s-1,physicalMeasurement,time,TRUE,,0,100,wdir_i wspd_x_i wspd_y_i,all,1,1,1,4
104
107
  wdir_i,wind_from_direction,Wind from direction (instantaneous),degrees,physicalMeasurement,time,TRUE,,1,360,wspd_x_i wspd_y_i,all,1,1,1,4
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pypromice
3
- Version: 1.5.3
3
+ Version: 1.7.0
4
4
  Summary: PROMICE/GC-Net data processing toolbox
5
5
  Home-page: https://github.com/GEUS-Glaciology-and-Climate/pypromice
6
6
  Author: GEUS Glaciology and Climate
@@ -25,7 +25,6 @@ Requires-Dist: toml
25
25
  Requires-Dist: scipy>=1.9.0
26
26
  Requires-Dist: Bottleneck
27
27
  Requires-Dist: netcdf4
28
- Requires-Dist: pyDataverse==0.3.1
29
28
  Requires-Dist: eccodes
30
29
  Requires-Dist: scikit-learn>=1.1.0
31
30
  Dynamic: author