pypromice 1.3.2__py3-none-any.whl → 1.3.4__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.
- pypromice/postprocess/bufr_to_csv.py +11 -0
- pypromice/postprocess/bufr_utilities.py +489 -0
- pypromice/postprocess/get_bufr.py +622 -284
- pypromice/postprocess/positions_seed.csv +5 -0
- pypromice/postprocess/real_time_utilities.py +241 -0
- pypromice/postprocess/station_configurations.toml +762 -0
- pypromice/process/L0toL1.py +44 -4
- pypromice/process/value_clipping.py +6 -13
- pypromice/process/variables.csv +13 -15
- pypromice/qc/github_data_issues.py +61 -89
- {pypromice-1.3.2.dist-info → pypromice-1.3.4.dist-info}/METADATA +2 -1
- {pypromice-1.3.2.dist-info → pypromice-1.3.4.dist-info}/RECORD +16 -13
- {pypromice-1.3.2.dist-info → pypromice-1.3.4.dist-info}/WHEEL +1 -1
- {pypromice-1.3.2.dist-info → pypromice-1.3.4.dist-info}/entry_points.txt +1 -1
- pypromice/postprocess/csv2bufr.py +0 -508
- pypromice/postprocess/wmo_config.py +0 -179
- {pypromice-1.3.2.dist-info → pypromice-1.3.4.dist-info}/LICENSE.txt +0 -0
- {pypromice-1.3.2.dist-info → pypromice-1.3.4.dist-info}/top_level.txt +0 -0
pypromice/process/L0toL1.py
CHANGED
|
@@ -57,7 +57,9 @@ def toL1(L0, vars_df, T_0=273.15, tilt_threshold=-100):
|
|
|
57
57
|
ds['ulr'] = ((ds['ulr'] * 10) / ds.attrs['ulr_eng_coef']) + 5.67E-8*(ds['t_rad'] + T_0)**4
|
|
58
58
|
|
|
59
59
|
ds['z_boom_u'] = _reformatArray(ds['z_boom_u']) # Reformat boom height
|
|
60
|
-
|
|
60
|
+
|
|
61
|
+
ds['t_u_interp'] = interpTemp(ds['t_u'], vars_df)
|
|
62
|
+
ds['z_boom_u'] = ds['z_boom_u'] * ((ds['t_u_interp'] + T_0)/T_0)**0.5 # Adjust sonic ranger readings for sensitivity to air temperature
|
|
61
63
|
|
|
62
64
|
if ds['gps_lat'].dtype.kind == 'O': # Decode and reformat GPS information
|
|
63
65
|
if 'NH' in ds['gps_lat'].dropna(dim='time').values[1]:
|
|
@@ -113,7 +115,8 @@ def toL1(L0, vars_df, T_0=273.15, tilt_threshold=-100):
|
|
|
113
115
|
|
|
114
116
|
elif ds.attrs['number_of_booms']==2: # 2-boom processing
|
|
115
117
|
ds['z_boom_l'] = _reformatArray(ds['z_boom_l']) # Reformat boom height
|
|
116
|
-
ds['
|
|
118
|
+
ds['t_l_interp'] = interpTemp(ds['t_l'], vars_df)
|
|
119
|
+
ds['z_boom_l'] = ds['z_boom_l'] * ((ds['t_l_interp']+ T_0)/T_0)**0.5 # Adjust sonic ranger readings for sensitivity to air temperature
|
|
117
120
|
|
|
118
121
|
ds = clip_values(ds, vars_df)
|
|
119
122
|
for key in ['hygroclip_t_offset', 'dsr_eng_coef', 'usr_eng_coef',
|
|
@@ -169,14 +172,16 @@ def addTimeShift(ds, vars_df):
|
|
|
169
172
|
elif ds.attrs['format'] == 'STM':
|
|
170
173
|
# hourly-averaged, non-transmitted
|
|
171
174
|
# shift everything except instantaneous, any logger type
|
|
172
|
-
df_a = df_a.shift(periods=-1, freq="
|
|
175
|
+
df_a = df_a.shift(periods=-1, freq="h")
|
|
173
176
|
df_out = pd.concat([df_a, df_i], axis=1) # different columns, same datetime indices
|
|
177
|
+
df_out = df_out.sort_index()
|
|
174
178
|
elif ds.attrs['format'] == 'TX':
|
|
175
179
|
if ds.attrs['logger_type'] == 'CR1000X':
|
|
176
180
|
# v3, data is hourly all year long
|
|
177
181
|
# shift everything except instantaneous
|
|
178
182
|
df_a = df_a.shift(periods=-1, freq="H")
|
|
179
183
|
df_out = pd.concat([df_a, df_i], axis=1) # different columns, same datetime indices
|
|
184
|
+
df_out = df_out.sort_index()
|
|
180
185
|
elif ds.attrs['logger_type'] == 'CR1000':
|
|
181
186
|
# v2, data is hourly (6-hr for instantaneous) for DOY 100-300, otherwise daily at 00 UTC
|
|
182
187
|
# shift non-instantaneous hourly for DOY 100-300, else do not shift daily
|
|
@@ -186,7 +191,7 @@ def addTimeShift(ds, vars_df):
|
|
|
186
191
|
df_a_daily_2 = df_a.loc[(df_a['doy'] > 300)]
|
|
187
192
|
|
|
188
193
|
# shift the hourly ave data
|
|
189
|
-
df_a_hourly = df_a_hourly.shift(periods=-1, freq="
|
|
194
|
+
df_a_hourly = df_a_hourly.shift(periods=-1, freq="h")
|
|
190
195
|
|
|
191
196
|
# stitch everything back together
|
|
192
197
|
df_concat_u = pd.concat([df_a_daily_1, df_a_daily_2, df_a_hourly], axis=0) # same columns, different datetime indices
|
|
@@ -254,6 +259,41 @@ def getPressDepth(z_pt, p, pt_antifreeze, pt_z_factor, pt_z_coef, pt_z_p_coef):
|
|
|
254
259
|
|
|
255
260
|
return z_pt_cor, z_pt
|
|
256
261
|
|
|
262
|
+
|
|
263
|
+
def interpTemp(temp, var_configurations, max_interp=pd.Timedelta(12,'h')):
|
|
264
|
+
'''Clip and interpolate temperature dataset for use in corrections
|
|
265
|
+
|
|
266
|
+
Parameters
|
|
267
|
+
----------
|
|
268
|
+
temp : `xarray.DataArray`
|
|
269
|
+
Array of temperature data
|
|
270
|
+
vars_df : `pandas.DataFrame`
|
|
271
|
+
Dataframe to retrieve attribute hi-lo values from for temperature clipping
|
|
272
|
+
max_interp : `pandas.Timedelta`
|
|
273
|
+
Maximum time steps to interpolate across. The default is 12 hours.
|
|
274
|
+
|
|
275
|
+
Returns
|
|
276
|
+
-------
|
|
277
|
+
temp_interp : `xarray.DataArray`
|
|
278
|
+
Array of interpolatedtemperature data
|
|
279
|
+
'''
|
|
280
|
+
# Determine if upper or lower temperature array
|
|
281
|
+
var = temp.name.lower()
|
|
282
|
+
|
|
283
|
+
# Find range threshold and use it to clip measurements
|
|
284
|
+
cols = ["lo", "hi", "OOL"]
|
|
285
|
+
assert set(cols) <= set(var_configurations.columns)
|
|
286
|
+
variable_limits = var_configurations[cols].dropna(how="all")
|
|
287
|
+
temp = temp.where(temp >= variable_limits.loc[var,'lo'])
|
|
288
|
+
temp = temp.where(temp <= variable_limits.loc[var, 'hi'])
|
|
289
|
+
|
|
290
|
+
# Drop duplicates and interpolate across NaN values
|
|
291
|
+
# temp_interp = temp.drop_duplicates(dim='time', keep='first')
|
|
292
|
+
temp_interp = temp.interpolate_na(dim='time', max_gap=max_interp)
|
|
293
|
+
|
|
294
|
+
return temp_interp
|
|
295
|
+
|
|
296
|
+
|
|
257
297
|
def smoothTilt(tilt, win_size):
|
|
258
298
|
'''Smooth tilt values using a rolling window. This is translated from the
|
|
259
299
|
previous IDL/GDL smoothing algorithm:
|
|
@@ -29,22 +29,14 @@ def clip_values(
|
|
|
29
29
|
|
|
30
30
|
variable_limits = var_configurations[cols].dropna(how="all")
|
|
31
31
|
for var, row in variable_limits.iterrows():
|
|
32
|
+
|
|
32
33
|
if var not in list(ds.variables):
|
|
33
34
|
continue
|
|
34
35
|
|
|
35
|
-
if
|
|
36
|
-
ds[var] = ds[var].where(ds[var] >= row.lo
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
# Mask out invalid corrections based on uncorrected var
|
|
40
|
-
var_uncor = var.split("_cor")[0]
|
|
41
|
-
ds[var] = ds[var].where(~np.isnan(ds[var_uncor]), other=np.nan)
|
|
42
|
-
|
|
43
|
-
else:
|
|
44
|
-
if ~np.isnan(row.lo):
|
|
45
|
-
ds[var] = ds[var].where(ds[var] >= row.lo)
|
|
46
|
-
if ~np.isnan(row.hi):
|
|
47
|
-
ds[var] = ds[var].where(ds[var] <= row.hi)
|
|
36
|
+
if ~np.isnan(row.lo):
|
|
37
|
+
ds[var] = ds[var].where(ds[var] >= row.lo)
|
|
38
|
+
if ~np.isnan(row.hi):
|
|
39
|
+
ds[var] = ds[var].where(ds[var] <= row.hi)
|
|
48
40
|
|
|
49
41
|
other_vars = row.OOL
|
|
50
42
|
if isinstance(other_vars, str) and ~ds[var].isnull().all():
|
|
@@ -56,4 +48,5 @@ def clip_values(
|
|
|
56
48
|
ds[var] = ds[var].where(ds[var] >= row.lo)
|
|
57
49
|
if ~np.isnan(row.hi):
|
|
58
50
|
ds[var] = ds[var].where(ds[var] <= row.hi)
|
|
51
|
+
|
|
59
52
|
return ds
|
pypromice/process/variables.csv
CHANGED
|
@@ -5,12 +5,12 @@ p_u,air_pressure,Air pressure (upper boom),hPa,650,1100,z_pt z_pt_cor dshf_u dlh
|
|
|
5
5
|
p_l,air_pressure,Air pressure (lower boom),hPa,650,1100,dshf_l dlhf_l qh_l,two-boom,all,4,physicalMeasurement,time lat lon alt,False,
|
|
6
6
|
t_u,air_temperature,Air temperature (upper boom),degrees_C,-80,40,rh_u_cor cc dsr_cor usr_cor z_boom z_stake dshf_u dlhf_u qh_u,all,all,4,physicalMeasurement,time lat lon alt,False,
|
|
7
7
|
t_l,air_temperature,Air temperature (lower boom),degrees_C,-80,40,rh_l_cor z_boom_l dshf_l dlhf_l qh_l ,two-boom,all,4,physicalMeasurement,time lat lon alt,False,PT100 temperature at boom
|
|
8
|
-
rh_u,relative_humidity,Relative humidity (upper boom),%,0,
|
|
8
|
+
rh_u,relative_humidity,Relative humidity (upper boom),%,0,100,rh_u_cor,all,all,4,physicalMeasurement,time lat lon alt,False,
|
|
9
9
|
rh_u_cor,relative_humidity_corrected,Relative humidity (upper boom) - corrected,%,0,150,dshf_u dlhf_u qh_u,all,all,4,modelResult,time lat lon alt,False,
|
|
10
|
-
qh_u,specific_humidity,Specific humidity (upper boom)
|
|
11
|
-
rh_l,relative_humidity,Relative humidity (lower boom),%,0,
|
|
10
|
+
qh_u,specific_humidity,Specific humidity (upper boom),kg/kg,0,100,,all,all,4,modelResult,time lat lon alt,False,Derived value (L2 or later)
|
|
11
|
+
rh_l,relative_humidity,Relative humidity (lower boom),%,0,100,rh_l_cor,two-boom,all,4,physicalMeasurement,time lat lon alt,False,
|
|
12
12
|
rh_l_cor,relative_humidity_corrected,Relative humidity (lower boom) - corrected,%,0,150,dshf_l dlhf_l qh_l,two-boom,all,4,modelResult,time lat lon alt,False,
|
|
13
|
-
qh_l,specific_humidity,Specific humidity (lower boom)
|
|
13
|
+
qh_l,specific_humidity,Specific humidity (lower boom),kg/kg,0,100,,two-boom,all,4,modelResult,time lat lon alt,False,Derived value (L2 or later)
|
|
14
14
|
wspd_u,wind_speed,Wind speed (upper boom),m s-1,0,100,"wdir_u wspd_x_u wspd_y_u dshf_u dlhf_u qh_u, precip_u",all,all,4,physicalMeasurement,time lat lon alt,False,
|
|
15
15
|
wspd_l,wind_speed,Wind speed (lower boom),m s-1,0,100,"wdir_l wspd_x_l wspd_y_l dshf_l dlhf_l qh_l , precip_l",two-boom,all,4,physicalMeasurement,time lat lon alt,False,
|
|
16
16
|
wdir_u,wind_from_direction,Wind from direction (upper boom),degrees,1,360,wspd_x_u wspd_y_u,all,all,4,physicalMeasurement,time lat lon alt,False,
|
|
@@ -81,14 +81,12 @@ fan_dc_l,fan_current,Fan current (lower boom),mA,0,200,,two-boom,all,2,physicalM
|
|
|
81
81
|
freq_vw,frequency_of_precipitation_wire_vibration,Frequency of vibrating wire in precipitation gauge,Hz,0,10000,precip_u,,all,,physicalMeasurement,time lat lon alt,True,L0 only
|
|
82
82
|
t_log,temperature_of_logger,Logger temperature,degrees_C,-80,40,,one-boom,all,4,physicalMeasurement,time lat lon alt,True,LoggerTemperature(C)
|
|
83
83
|
t_rad,temperature_of_radiation_sensor,Radiation sensor temperature,degrees_C,-80,40,t_surf dlr ulr,all,all,4,physicalMeasurement,time lat lon alt,False,
|
|
84
|
-
p_i,air_pressure,Air pressure (instantaneous) minus 1000,hPa,-350,100,,all,
|
|
85
|
-
t_i,air_temperature,Air temperature (instantaneous),degrees_C,-80,40,,all,
|
|
86
|
-
rh_i,relative_humidity,Relative humidity (instantaneous),%,0,150,rh_i_cor,all,
|
|
87
|
-
rh_i_cor,relative_humidity_corrected,Relative humidity (instantaneous) – corrected,%,0,100,,all,
|
|
88
|
-
wspd_i,wind_speed,Wind speed (instantaneous),m s-1,0,100,wdir_i wspd_x_i wspd_y_i,all,
|
|
89
|
-
wdir_i,wind_from_direction,Wind from direction (instantaneous),degrees,1,360,wspd_x_i wspd_y_i,all,
|
|
90
|
-
wspd_x_i,wind_speed_from_x_direction,Wind speed from x direction (instantaneous),m s-1,-100,100,wdir_i wspd_i,all,
|
|
91
|
-
wspd_y_i,wind_speed_from_y_direction,Wind speed from y direction (instantaneous),m s-1,-100,100,wdir_i wspd_i,all,
|
|
92
|
-
msg_i,message,Message string (instantaneous),-,,,,all,
|
|
93
|
-
msg_lat,message_latitude,latitude from modem (email text),degrees_north,50,83,,all,all,6,coordinate,time lat lon alt,True,
|
|
94
|
-
msg_lon,message_longitude,longitude from modem (email text),degrees_east,-72,13,,all,all,6,coordinate,time lat lon alt,True,
|
|
84
|
+
p_i,air_pressure,Air pressure (instantaneous) minus 1000,hPa,-350,100,,all,all,4,physicalMeasurement,time lat lon alt,True,For meteorological observations
|
|
85
|
+
t_i,air_temperature,Air temperature (instantaneous),degrees_C,-80,40,,all,all,4,physicalMeasurement,time lat lon alt,True,"PT100 temperature at boom, for meteorological observations"
|
|
86
|
+
rh_i,relative_humidity,Relative humidity (instantaneous),%,0,150,rh_i_cor,all,all,4,physicalMeasurement,time lat lon alt,True,For meteorological observations
|
|
87
|
+
rh_i_cor,relative_humidity_corrected,Relative humidity (instantaneous) – corrected,%,0,100,,all,all,4,modelResult,time lat lon alt,True,For meteorological observations
|
|
88
|
+
wspd_i,wind_speed,Wind speed (instantaneous),m s-1,0,100,wdir_i wspd_x_i wspd_y_i,all,all,4,physicalMeasurement,time lat lon alt,True,For meteorological observations
|
|
89
|
+
wdir_i,wind_from_direction,Wind from direction (instantaneous),degrees,1,360,wspd_x_i wspd_y_i,all,all,4,physicalMeasurement,time lat lon alt,True,For meteorological observations
|
|
90
|
+
wspd_x_i,wind_speed_from_x_direction,Wind speed from x direction (instantaneous),m s-1,-100,100,wdir_i wspd_i,all,all,4,modelResult,time lat lon alt,True,For meteorological observations
|
|
91
|
+
wspd_y_i,wind_speed_from_y_direction,Wind speed from y direction (instantaneous),m s-1,-100,100,wdir_i wspd_i,all,all,4,modelResult,time lat lon alt,True,For meteorological observations
|
|
92
|
+
msg_i,message,Message string (instantaneous),-,,,,all,all,,qualityInformation,time lat lon alt,True,For meteorological observations
|
|
@@ -17,8 +17,7 @@ logger = logging.getLogger(__name__)
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def flagNAN(ds_in,
|
|
20
|
-
|
|
21
|
-
flag_dir='local/flags/'):
|
|
20
|
+
flag_dir='../PROMICE-AWS-data-issues/flags'):
|
|
22
21
|
'''Read flagged data from .csv file. For each variable, and downstream
|
|
23
22
|
dependents, flag as invalid (or other) if set in the flag .csv
|
|
24
23
|
|
|
@@ -26,8 +25,6 @@ def flagNAN(ds_in,
|
|
|
26
25
|
----------
|
|
27
26
|
ds_in : xr.Dataset
|
|
28
27
|
Level 0 dataset
|
|
29
|
-
flag_url : str
|
|
30
|
-
URL to directory where .csv flag files can be found
|
|
31
28
|
flag_dir : str
|
|
32
29
|
File directory where .csv flag files can be found
|
|
33
30
|
|
|
@@ -36,13 +33,10 @@ def flagNAN(ds_in,
|
|
|
36
33
|
ds : xr.Dataset
|
|
37
34
|
Level 0 data with flagged data
|
|
38
35
|
'''
|
|
39
|
-
ds = ds_in.copy()
|
|
36
|
+
ds = ds_in.copy(deep=True)
|
|
40
37
|
df = None
|
|
41
38
|
|
|
42
|
-
df = _getDF(
|
|
43
|
-
os.path.join(flag_dir, ds.attrs["station_id"] + ".csv"),
|
|
44
|
-
# download = False, # only for working on draft local flag'n'fix files
|
|
45
|
-
)
|
|
39
|
+
df = _getDF(os.path.join(flag_dir, ds.attrs["station_id"] + ".csv"))
|
|
46
40
|
|
|
47
41
|
if isinstance(df, pd.DataFrame):
|
|
48
42
|
df.t0 = pd.to_datetime(df.t0).dt.tz_localize(None)
|
|
@@ -80,8 +74,7 @@ def flagNAN(ds_in,
|
|
|
80
74
|
|
|
81
75
|
|
|
82
76
|
def adjustTime(ds,
|
|
83
|
-
|
|
84
|
-
adj_dir='local/adjustments/',
|
|
77
|
+
adj_dir='../PROMICE-AWS-data-issues/adjustments/',
|
|
85
78
|
var_list=[], skip_var=[]):
|
|
86
79
|
'''Read adjustment data from .csv file. Only applies the "time_shift" adjustment
|
|
87
80
|
|
|
@@ -89,8 +82,6 @@ def adjustTime(ds,
|
|
|
89
82
|
----------
|
|
90
83
|
ds : xr.Dataset
|
|
91
84
|
Level 0 dataset
|
|
92
|
-
adj_url : str
|
|
93
|
-
URL to directory where .csv adjustment files can be found
|
|
94
85
|
adj_dir : str
|
|
95
86
|
File directory where .csv adjustment files can be found
|
|
96
87
|
|
|
@@ -99,11 +90,10 @@ def adjustTime(ds,
|
|
|
99
90
|
ds : xr.Dataset
|
|
100
91
|
Level 0 data with flagged data
|
|
101
92
|
'''
|
|
102
|
-
ds_out = ds.copy()
|
|
93
|
+
ds_out = ds.copy(deep=True)
|
|
103
94
|
adj_info=None
|
|
104
95
|
|
|
105
|
-
adj_info = _getDF(
|
|
106
|
-
os.path.join(adj_dir, ds.attrs["station_id"] + ".csv"),)
|
|
96
|
+
adj_info = _getDF(os.path.join(adj_dir, ds.attrs["station_id"] + ".csv"))
|
|
107
97
|
|
|
108
98
|
if isinstance(adj_info, pd.DataFrame):
|
|
109
99
|
|
|
@@ -145,8 +135,7 @@ def adjustTime(ds,
|
|
|
145
135
|
|
|
146
136
|
|
|
147
137
|
def adjustData(ds,
|
|
148
|
-
|
|
149
|
-
adj_dir='local/adjustments/',
|
|
138
|
+
adj_dir='../PROMICE-AWS-data-issues/adjustments/',
|
|
150
139
|
var_list=[], skip_var=[]):
|
|
151
140
|
'''Read adjustment data from .csv file. For each variable, and downstream
|
|
152
141
|
dependents, adjust data accordingly if set in the adjustment .csv
|
|
@@ -155,8 +144,6 @@ def adjustData(ds,
|
|
|
155
144
|
----------
|
|
156
145
|
ds : xr.Dataset
|
|
157
146
|
Level 0 dataset
|
|
158
|
-
adj_url : str
|
|
159
|
-
URL to directory where .csv adjustment files can be found
|
|
160
147
|
adj_dir : str
|
|
161
148
|
File directory where .csv adjustment files can be found
|
|
162
149
|
|
|
@@ -165,24 +152,19 @@ def adjustData(ds,
|
|
|
165
152
|
ds : xr.Dataset
|
|
166
153
|
Level 0 data with flagged data
|
|
167
154
|
'''
|
|
168
|
-
ds_out = ds.copy()
|
|
155
|
+
ds_out = ds.copy(deep=True)
|
|
169
156
|
adj_info=None
|
|
170
|
-
adj_info = _getDF(
|
|
171
|
-
os.path.join(adj_dir, ds.attrs["station_id"] + ".csv"),
|
|
172
|
-
# download = False, # only for working on draft local flag'n'fix files
|
|
173
|
-
)
|
|
157
|
+
adj_info = _getDF(os.path.join(adj_dir, ds.attrs["station_id"] + ".csv"))
|
|
174
158
|
|
|
175
159
|
if isinstance(adj_info, pd.DataFrame):
|
|
176
160
|
# removing potential time shifts from the adjustment list
|
|
177
161
|
adj_info = adj_info.loc[adj_info.adjust_function != "time_shift", :]
|
|
178
162
|
|
|
179
|
-
#
|
|
180
|
-
adj_info
|
|
181
|
-
adj_info.loc[adj_info.t1.isnull(), "t1"] =
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
adj_info.t1 = pd.to_datetime(adj_info.t1).dt.tz_localize(None)
|
|
185
|
-
|
|
163
|
+
# making sure that t0 and t1 columns are object dtype then replaceing nan with None
|
|
164
|
+
adj_info[['t0','t1']] = adj_info[['t0','t1']].astype(object)
|
|
165
|
+
adj_info.loc[adj_info.t1.isnull()|(adj_info.t1==''), "t1"] = None
|
|
166
|
+
adj_info.loc[adj_info.t0.isnull()|(adj_info.t0==''), "t0"] = None
|
|
167
|
+
|
|
186
168
|
# if "*" is in the variable name then we interpret it as regex
|
|
187
169
|
selec = adj_info['variable'].str.contains('\*') & (adj_info['variable'] != "*")
|
|
188
170
|
for ind in adj_info.loc[selec, :].index:
|
|
@@ -217,104 +199,104 @@ def adjustData(ds,
|
|
|
217
199
|
adj_info.loc[var].adjust_function,
|
|
218
200
|
adj_info.loc[var].adjust_value,
|
|
219
201
|
):
|
|
220
|
-
|
|
202
|
+
# making all timestamps timezone naive (compatibility with xarray)
|
|
203
|
+
if isinstance(t0, str):
|
|
204
|
+
t0 = pd.to_datetime(t0, utc=True).tz_localize(None)
|
|
205
|
+
if isinstance(t1, str):
|
|
206
|
+
t1 = pd.to_datetime(t1, utc=True).tz_localize(None)
|
|
207
|
+
|
|
208
|
+
index_slice = dict(time=slice(t0, t1))
|
|
209
|
+
|
|
210
|
+
if len(ds_out[var].loc[index_slice].time.time) == 0:
|
|
211
|
+
logger.info("Time range does not intersect with dataset")
|
|
221
212
|
continue
|
|
213
|
+
|
|
222
214
|
logger.info(f'---> {t0} {t1} {var} {func} {val}')
|
|
215
|
+
|
|
223
216
|
if func == "add":
|
|
224
|
-
ds_out[var].loc[
|
|
217
|
+
ds_out[var].loc[index_slice] = ds_out[var].loc[index_slice].values + val
|
|
225
218
|
# flagging adjusted values
|
|
226
219
|
# if var + "_adj_flag" not in ds_out.columns:
|
|
227
220
|
# ds_out[var + "_adj_flag"] = 0
|
|
228
|
-
# msk = ds_out[var].loc[
|
|
229
|
-
# ind = ds_out[var].loc[
|
|
221
|
+
# msk = ds_out[var].loc[index_slice])].notnull()
|
|
222
|
+
# ind = ds_out[var].loc[index_slice])].loc[msk].time
|
|
230
223
|
# ds_out.loc[ind, var + "_adj_flag"] = 1
|
|
231
224
|
|
|
232
225
|
if func == "multiply":
|
|
233
|
-
ds_out[var].loc[
|
|
226
|
+
ds_out[var].loc[index_slice] = ds_out[var].loc[index_slice].values * val
|
|
234
227
|
if "DW" in var:
|
|
235
|
-
ds_out[var].loc[
|
|
228
|
+
ds_out[var].loc[index_slice] = ds_out[var].loc[index_slice] % 360
|
|
236
229
|
# flagging adjusted values
|
|
237
230
|
# if var + "_adj_flag" not in ds_out.columns:
|
|
238
231
|
# ds_out[var + "_adj_flag"] = 0
|
|
239
|
-
# msk = ds_out[var].loc[
|
|
240
|
-
# ind = ds_out[var].loc[
|
|
232
|
+
# msk = ds_out[var].loc[index_slice].notnull()
|
|
233
|
+
# ind = ds_out[var].loc[index_slice].loc[msk].time
|
|
241
234
|
# ds_out.loc[ind, var + "_adj_flag"] = 1
|
|
242
235
|
|
|
243
236
|
if func == "min_filter":
|
|
244
|
-
tmp = ds_out[var].loc[
|
|
237
|
+
tmp = ds_out[var].loc[index_slice].values
|
|
245
238
|
tmp[tmp < val] = np.nan
|
|
246
239
|
|
|
247
240
|
if func == "max_filter":
|
|
248
|
-
tmp = ds_out[var].loc[
|
|
241
|
+
tmp = ds_out[var].loc[index_slice].values
|
|
249
242
|
tmp[tmp > val] = np.nan
|
|
250
|
-
ds_out[var].loc[
|
|
243
|
+
ds_out[var].loc[index_slice] = tmp
|
|
251
244
|
|
|
252
245
|
if func == "upper_perc_filter":
|
|
253
|
-
tmp = ds_out[var].loc[
|
|
254
|
-
df_w = ds_out[var].loc[
|
|
255
|
-
df_w = ds_out[var].loc[
|
|
246
|
+
tmp = ds_out[var].loc[index_slice].copy()
|
|
247
|
+
df_w = ds_out[var].loc[index_slice].resample(time="14D").quantile(1 - val / 100)
|
|
248
|
+
df_w = ds_out[var].loc[index_slice].resample(time="14D").var()
|
|
256
249
|
for m_start, m_end in zip(df_w.time[:-2], df_w.time[1:]):
|
|
257
250
|
msk = (tmp.time >= m_start) & (tmp.time < m_end)
|
|
258
251
|
values_month = tmp.loc[msk].values
|
|
259
252
|
values_month[values_month < df_w.loc[m_start]] = np.nan
|
|
260
253
|
tmp.loc[msk] = values_month
|
|
261
254
|
|
|
262
|
-
ds_out[var].loc[
|
|
255
|
+
ds_out[var].loc[index_slice] = tmp.values
|
|
263
256
|
|
|
264
257
|
if func == "biweekly_upper_range_filter":
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
msk = tmp.time >= m_end
|
|
275
|
-
lim = df_max.loc[m_start] - val
|
|
276
|
-
values_month = tmp.loc[msk].values
|
|
277
|
-
values_month[values_month < lim] = np.nan
|
|
278
|
-
tmp.loc[msk] = values_month
|
|
279
|
-
# updating original pandas
|
|
280
|
-
ds_out[var].loc[dict(time=slice(t0, t1))] = tmp.values
|
|
258
|
+
df_max = (
|
|
259
|
+
ds_out[var].loc[index_slice].copy(deep=True)
|
|
260
|
+
.resample(time="14D",offset='7D').max()
|
|
261
|
+
.sel(time=ds_out[var].loc[index_slice].time.values, method='ffill')
|
|
262
|
+
)
|
|
263
|
+
df_max['time'] = ds_out[var].loc[index_slice].time
|
|
264
|
+
# updating original pandas
|
|
265
|
+
ds_out[var].loc[index_slice] = ds_out[var].loc[index_slice].where(ds_out[var].loc[index_slice] > df_max-val)
|
|
266
|
+
|
|
281
267
|
|
|
282
268
|
if func == "hampel_filter":
|
|
283
|
-
tmp = ds_out[var].loc[
|
|
269
|
+
tmp = ds_out[var].loc[index_slice]
|
|
284
270
|
tmp = _hampel(tmp, k=7 * 24, t0=val)
|
|
285
|
-
ds_out[var].loc[
|
|
271
|
+
ds_out[var].loc[index_slice] = tmp.values
|
|
286
272
|
|
|
287
273
|
if func == "grad_filter":
|
|
288
|
-
tmp = ds_out[var].loc[
|
|
289
|
-
msk = ds_out[var].loc[
|
|
274
|
+
tmp = ds_out[var].loc[index_slice].copy()
|
|
275
|
+
msk = ds_out[var].loc[index_slice].copy().diff()
|
|
290
276
|
tmp[np.roll(msk.abs() > val, -1)] = np.nan
|
|
291
|
-
ds_out[var].loc[
|
|
277
|
+
ds_out[var].loc[index_slice] = tmp
|
|
292
278
|
|
|
293
279
|
if "swap_with_" in func:
|
|
294
280
|
var2 = func[10:]
|
|
295
|
-
val_var = ds_out[var].loc[
|
|
296
|
-
val_var2 = ds_out[var2].loc[
|
|
297
|
-
ds_out[var2].loc[
|
|
298
|
-
ds_out[var].loc[
|
|
281
|
+
val_var = ds_out[var].loc[index_slice].values.copy()
|
|
282
|
+
val_var2 = ds_out[var2].loc[index_slice].values.copy()
|
|
283
|
+
ds_out[var2].loc[index_slice] = val_var
|
|
284
|
+
ds_out[var].loc[index_slice] = val_var2
|
|
299
285
|
|
|
300
286
|
if func == "rotate":
|
|
301
|
-
ds_out[var].loc[
|
|
287
|
+
ds_out[var].loc[index_slice] = (ds_out[var].loc[index_slice].values + val) % 360
|
|
302
288
|
|
|
303
289
|
return ds_out
|
|
304
290
|
|
|
305
291
|
|
|
306
|
-
def _getDF(
|
|
292
|
+
def _getDF(flag_file):
|
|
307
293
|
'''Get dataframe from flag or adjust file. First attempt to retrieve from
|
|
308
294
|
URL. If this fails then attempt to retrieve from local file
|
|
309
295
|
|
|
310
296
|
Parameters
|
|
311
297
|
----------
|
|
312
|
-
flag_url : str
|
|
313
|
-
URL address to file
|
|
314
298
|
flag_file : str
|
|
315
299
|
Local path to file
|
|
316
|
-
download : bool
|
|
317
|
-
Flag to download file from URL
|
|
318
300
|
|
|
319
301
|
Returns
|
|
320
302
|
-------
|
|
@@ -322,17 +304,7 @@ def _getDF(flag_url, flag_file, download=True):
|
|
|
322
304
|
Flag or adjustment dataframe
|
|
323
305
|
'''
|
|
324
306
|
|
|
325
|
-
|
|
326
|
-
if download==True:
|
|
327
|
-
os.makedirs(os.path.dirname(flag_file), exist_ok = True)
|
|
328
|
-
|
|
329
|
-
try:
|
|
330
|
-
urllib.request.urlretrieve(flag_url, flag_file)
|
|
331
|
-
logger.info(f"Downloaded a {flag_file.split('/')[-2][:-1],} file to {flag_file}")
|
|
332
|
-
except (HTTPError, URLError) as e:
|
|
333
|
-
logger.info(f"Unable to download {flag_file.split('/')[-2][:-1],} file, using local file: {flag_file}")
|
|
334
|
-
else:
|
|
335
|
-
logger.info(f"Using local {flag_file.split('/')[-2][:-1],} file: {flag_file}")
|
|
307
|
+
logger.info(f"Using file: {flag_file}")
|
|
336
308
|
|
|
337
309
|
if os.path.isfile(flag_file):
|
|
338
310
|
df = pd.read_csv(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pypromice
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.4
|
|
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
|
|
@@ -27,6 +27,7 @@ Requires-Dist: scikit-learn >=1.1.0
|
|
|
27
27
|
Requires-Dist: Bottleneck
|
|
28
28
|
Requires-Dist: netcdf4
|
|
29
29
|
Requires-Dist: pyDataverse
|
|
30
|
+
Requires-Dist: eccodes
|
|
30
31
|
|
|
31
32
|
# pypromice
|
|
32
33
|
[](https://badge.fury.io/py/pypromice) [](https://anaconda.org/conda-forge/pypromice) [](https://anaconda.org/conda-forge/pypromice) [](https://www.doi.org/10.22008/FK2/3TSBF0) [](https://doi.org/10.21105/joss.05298) [](https://pypromice.readthedocs.io/en/latest/?badge=latest)
|
|
@@ -3,10 +3,13 @@ pypromice/get/__init__.py,sha256=n2L6P9EeUsdjsHaeU7BEanBjlkCBX9csGseT8z-laew,32
|
|
|
3
3
|
pypromice/get/get.py,sha256=tPrHyllrukGotOR8PjBYJb5tcuL4S_t6WP7wvhbWkg8,7688
|
|
4
4
|
pypromice/get/get_promice_data.py,sha256=bluNCaP50iRlWBzdEOXLrSPepOQdGB7SeQLkTWiqK4c,1806
|
|
5
5
|
pypromice/postprocess/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
pypromice/postprocess/
|
|
7
|
-
pypromice/postprocess/
|
|
8
|
-
pypromice/postprocess/
|
|
9
|
-
pypromice/
|
|
6
|
+
pypromice/postprocess/bufr_to_csv.py,sha256=RQZSJ3rC5v-R76rLQf60HNhgH7JQL3WhzXGgySHUyRg,317
|
|
7
|
+
pypromice/postprocess/bufr_utilities.py,sha256=P9hAdYvW-G04cZalV5hm65S8JjZ4ppEKlHkdbzSthtI,17032
|
|
8
|
+
pypromice/postprocess/get_bufr.py,sha256=H8n-LE9KbU70FT1vPdKvd__L2runQSeZpRDCXm9RlBs,20790
|
|
9
|
+
pypromice/postprocess/positions_seed.csv,sha256=0kVCQ8UfEALdeXNYCddmwxpseRqLRudbFStqp_bZRBw,224
|
|
10
|
+
pypromice/postprocess/real_time_utilities.py,sha256=hmJJ0t_dq6nU-VjFOgnWC_hAksECy6gOUw3jblgeekQ,8710
|
|
11
|
+
pypromice/postprocess/station_configurations.toml,sha256=o_NOXTjf8KBNPSa2vQBtSZZPCymIjixTNniVvwUtltk,17025
|
|
12
|
+
pypromice/process/L0toL1.py,sha256=eQw_cJjEEOj4zOuONp1SxTSDXPG5S0SIVlac7tuSlsc,22818
|
|
10
13
|
pypromice/process/L1toL2.py,sha256=IYrZ9okxGzuJK3dfthk3C75RjsU9yNCgvELK7H41iQg,25538
|
|
11
14
|
pypromice/process/L2toL3.py,sha256=LnpxGgk1auTHLhef4JUx6iWEhraKoXCRkVsyWI2oYR4,18238
|
|
12
15
|
pypromice/process/__init__.py,sha256=xvd0I-9nIyVw4M4qjgkQ5vXYpNuKcVSkIVIROQsZDo0,147
|
|
@@ -14,10 +17,10 @@ pypromice/process/aws.py,sha256=fIQqOP3WrCBs17a4kMxXzVD-8OD3Mlagy3OxJ-ys_mw,2984
|
|
|
14
17
|
pypromice/process/get_l3.py,sha256=jwb5nO22d9Pk5I3SrijkXbTwgqnmqVdxQn0_ACMabH0,1656
|
|
15
18
|
pypromice/process/join_l3.py,sha256=aAu_7vCSVhigcU2siMOdkz7DL1iA9smImWKNQOYgS3M,4979
|
|
16
19
|
pypromice/process/metadata.csv,sha256=Zp8Z40m23ohQfzUdLT4z43uHGFvx39rODXZHpUuYn6M,7055
|
|
17
|
-
pypromice/process/value_clipping.py,sha256=
|
|
18
|
-
pypromice/process/variables.csv,sha256=
|
|
20
|
+
pypromice/process/value_clipping.py,sha256=FkBiDT_HK_BDFiVjB7NdWH-_nab7vONG9LOd2PpEBI8,1573
|
|
21
|
+
pypromice/process/variables.csv,sha256=l6yqVNWlUntnTrXm6u1nrK8ZcrwpMmb_60Hhj-xfli0,13340
|
|
19
22
|
pypromice/qc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
-
pypromice/qc/github_data_issues.py,sha256=
|
|
23
|
+
pypromice/qc/github_data_issues.py,sha256=DAu2F2HuPSYO_JICKI8-N8zGlbkVOsW6vr1qtMPfe5k,13537
|
|
21
24
|
pypromice/qc/persistence.py,sha256=TuXxbedsekR1LSBdc0V9xypvlj8mkSE3xqI-U9xqcnY,4647
|
|
22
25
|
pypromice/qc/persistence_test.py,sha256=DbltqVnnKmxV5T-UiF3AGVMXSVsbzqjYRqhVV1pAL9c,5771
|
|
23
26
|
pypromice/qc/percentiles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -42,9 +45,9 @@ pypromice/tx/get_watsontx.py,sha256=vFSuDs_vvkATe_6WCF8OLVsx7Wa-MxLATZRfP9qUZqI,
|
|
|
42
45
|
pypromice/tx/payload_formats.csv,sha256=4pClTt5qjdB4XViDY2QzuLeJY5EBkEBia0E7Y-aMLVo,7726
|
|
43
46
|
pypromice/tx/payload_types.csv,sha256=C1-xCmHytAqqAzgzPwBLWqabzWu6s6tKAd8AjVd935s,457
|
|
44
47
|
pypromice/tx/tx.py,sha256=s1ADVUwX0hoykFMSo_BDgopsIUWTJh2l7KJ05nMNmQg,33692
|
|
45
|
-
pypromice-1.3.
|
|
46
|
-
pypromice-1.3.
|
|
47
|
-
pypromice-1.3.
|
|
48
|
-
pypromice-1.3.
|
|
49
|
-
pypromice-1.3.
|
|
50
|
-
pypromice-1.3.
|
|
48
|
+
pypromice-1.3.4.dist-info/LICENSE.txt,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
|
|
49
|
+
pypromice-1.3.4.dist-info/METADATA,sha256=uCKUJ1oPZZCZqfy8X9W_QhfQIfg27pS8IMEOHHkdZnY,5096
|
|
50
|
+
pypromice-1.3.4.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
51
|
+
pypromice-1.3.4.dist-info/entry_points.txt,sha256=8CGN4oJByZuvVFt9rL8HG41F11XL2L6aSe-EPjHTkkE,352
|
|
52
|
+
pypromice-1.3.4.dist-info/top_level.txt,sha256=cBdfwgSbWDQq3a07nKRjrfmLC7jdaYXs98GG58HpTks,10
|
|
53
|
+
pypromice-1.3.4.dist-info/RECORD,,
|