pypromice 1.4.3__py3-none-any.whl → 1.5.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.
- pypromice/postprocess/bufr_utilities.py +2 -1
- pypromice/process/L1toL2.py +43 -34
- pypromice/process/L2toL3.py +221 -221
- pypromice/process/aws.py +1 -39
- pypromice/process/join_l3.py +3 -3
- pypromice/process/resample.py +6 -5
- pypromice/process/value_clipping.py +15 -14
- pypromice/process/write.py +21 -37
- pypromice/resources/variable_aliases_GC-Net.csv +2 -2
- pypromice/resources/variables.csv +33 -33
- pypromice/tx/payload_formats.csv +1 -0
- pypromice/utilities/dependency_graph.py +101 -0
- {pypromice-1.4.3.dist-info → pypromice-1.5.0.dist-info}/METADATA +7 -7
- {pypromice-1.4.3.dist-info → pypromice-1.5.0.dist-info}/RECORD +18 -17
- {pypromice-1.4.3.dist-info → pypromice-1.5.0.dist-info}/WHEEL +1 -1
- {pypromice-1.4.3.dist-info → pypromice-1.5.0.dist-info}/LICENSE.txt +0 -0
- {pypromice-1.4.3.dist-info → pypromice-1.5.0.dist-info}/entry_points.txt +0 -0
- {pypromice-1.4.3.dist-info → pypromice-1.5.0.dist-info}/top_level.txt +0 -0
|
@@ -120,7 +120,8 @@ class BUFRVariables:
|
|
|
120
120
|
)
|
|
121
121
|
# https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_B/012101
|
|
122
122
|
# Scale: 2, unit: K
|
|
123
|
-
|
|
123
|
+
# NOTE: The expected scale is 2, but our instantanous data is rounded to 1 decimal.
|
|
124
|
+
airTemperature: float = attrs.field(converter=round_converter(1))
|
|
124
125
|
# There is also a Dewpoint temperature in this template: 012103 which is currently unused.
|
|
125
126
|
# https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_B/012103
|
|
126
127
|
# Scale: 0, unit: %
|
pypromice/process/L1toL2.py
CHANGED
|
@@ -92,9 +92,9 @@ def toL2(
|
|
|
92
92
|
baseline_elevation = (ds.gps_alt.to_series().resample('MS').median()
|
|
93
93
|
.reindex(ds.time.to_series().index, method='nearest')
|
|
94
94
|
.ffill().bfill())
|
|
95
|
-
mask = (np.abs(ds.gps_alt - baseline_elevation) < 100)
|
|
95
|
+
mask = (np.abs(ds.gps_alt - baseline_elevation) < 100) | ds.gps_alt.isnull()
|
|
96
96
|
ds[['gps_alt','gps_lon', 'gps_lat']] = ds[['gps_alt','gps_lon', 'gps_lat']].where(mask)
|
|
97
|
-
|
|
97
|
+
|
|
98
98
|
# removing dlr and ulr that are missing t_rad
|
|
99
99
|
# this is done now becasue t_rad can be filtered either manually or with persistence
|
|
100
100
|
ds['dlr'] = ds.dlr.where(ds.t_rad.notnull())
|
|
@@ -102,23 +102,23 @@ def toL2(
|
|
|
102
102
|
|
|
103
103
|
# calculating realtive humidity with regard to ice
|
|
104
104
|
T_100 = _getTempK(T_0)
|
|
105
|
-
ds['
|
|
105
|
+
ds['rh_u_wrt_ice_or_water'] = adjustHumidity(ds['rh_u'], ds['t_u'],
|
|
106
106
|
T_0, T_100, ews, ei0)
|
|
107
107
|
|
|
108
108
|
if ds.attrs['number_of_booms']==2:
|
|
109
|
-
ds['
|
|
109
|
+
ds['rh_l_wrt_ice_or_water'] = adjustHumidity(ds['rh_l'], ds['t_l'],
|
|
110
110
|
T_0, T_100, ews, ei0)
|
|
111
111
|
|
|
112
112
|
if hasattr(ds,'t_i'):
|
|
113
113
|
if ~ds['t_i'].isnull().all():
|
|
114
|
-
ds['
|
|
114
|
+
ds['rh_i_wrt_ice_or_water'] = adjustHumidity(ds['rh_i'], ds['t_i'],
|
|
115
115
|
T_0, T_100, ews, ei0)
|
|
116
|
-
|
|
116
|
+
|
|
117
117
|
# Determiune cloud cover for on-ice stations
|
|
118
118
|
cc = calcCloudCoverage(ds['t_u'], T_0, eps_overcast, eps_clear, # Calculate cloud coverage
|
|
119
119
|
ds['dlr'], ds.attrs['station_id'])
|
|
120
120
|
ds['cc'] = (('time'), cc.data)
|
|
121
|
-
|
|
121
|
+
|
|
122
122
|
# Determine surface temperature
|
|
123
123
|
ds['t_surf'] = calcSurfaceTemperature(T_0, ds['ulr'], ds['dlr'], # Calculate surface temperature
|
|
124
124
|
emissivity)
|
|
@@ -136,7 +136,7 @@ def toL2(
|
|
|
136
136
|
else:
|
|
137
137
|
lat = ds['gps_lat'].mean()
|
|
138
138
|
lon = ds['gps_lon'].mean()
|
|
139
|
-
|
|
139
|
+
|
|
140
140
|
# smoothing tilt and rot
|
|
141
141
|
ds['tilt_x'] = smoothTilt(ds['tilt_x'])
|
|
142
142
|
ds['tilt_y'] = smoothTilt(ds['tilt_y'])
|
|
@@ -151,8 +151,8 @@ def toL2(
|
|
|
151
151
|
ZenithAngle_rad, ZenithAngle_deg = calcZenith(lat, Declination_rad, # Calculate zenith
|
|
152
152
|
HourAngle_rad, deg2rad,
|
|
153
153
|
rad2deg)
|
|
154
|
-
|
|
155
|
-
|
|
154
|
+
|
|
155
|
+
|
|
156
156
|
# Correct Downwelling shortwave radiation
|
|
157
157
|
DifFrac = 0.2 + 0.8 * cc
|
|
158
158
|
CorFac_all = calcCorrectionFactor(Declination_rad, phi_sensor_rad, # Calculate correction
|
|
@@ -186,9 +186,9 @@ def toL2(
|
|
|
186
186
|
TOA_crit_nopass = (ds['dsr_cor'] > (0.9 * isr_toa + 10)) # Determine filter
|
|
187
187
|
ds['dsr_cor'][TOA_crit_nopass] = np.nan # Apply filter and interpolate
|
|
188
188
|
ds['usr_cor'][TOA_crit_nopass] = np.nan
|
|
189
|
-
|
|
190
|
-
ds['dsr_cor'] = ds.dsr_cor.where(ds.dsr.notnull())
|
|
191
|
-
ds['usr_cor'] = ds.usr_cor.where(ds.usr.notnull())
|
|
189
|
+
|
|
190
|
+
ds['dsr_cor'] = ds.dsr_cor.where(ds.dsr.notnull())
|
|
191
|
+
ds['usr_cor'] = ds.usr_cor.where(ds.usr.notnull())
|
|
192
192
|
# # Check sun position
|
|
193
193
|
# sundown = ZenithAngle_deg >= 90
|
|
194
194
|
# _checkSunPos(ds, OKalbedos, sundown, sunonlowerdome, TOA_crit_nopass)
|
|
@@ -205,27 +205,33 @@ def toL2(
|
|
|
205
205
|
ds['precip_l_cor'], ds['precip_l_rate']= correctPrecip(ds['precip_l'],
|
|
206
206
|
ds['wspd_l'])
|
|
207
207
|
|
|
208
|
-
# Get directional wind speed
|
|
209
|
-
|
|
210
|
-
ds
|
|
208
|
+
get_directional_wind_speed(ds) # Get directional wind speed
|
|
209
|
+
|
|
210
|
+
ds = clip_values(ds, vars_df)
|
|
211
|
+
return ds
|
|
212
|
+
|
|
213
|
+
def get_directional_wind_speed(ds: xr.Dataset) -> xr.Dataset:
|
|
214
|
+
"""
|
|
215
|
+
Calculate directional wind speed from wind speed and direction and mutates the dataset
|
|
216
|
+
"""
|
|
217
|
+
|
|
218
|
+
ds['wdir_u'] = ds['wdir_u'].where(ds['wspd_u'] != 0)
|
|
219
|
+
ds['wspd_x_u'], ds['wspd_y_u'] = calcDirWindSpeeds(ds['wspd_u'], ds['wdir_u'])
|
|
211
220
|
|
|
212
|
-
if ds.attrs['number_of_booms']==2:
|
|
213
|
-
ds['wdir_l'] = ds['wdir_l'].where(ds['wspd_l'] != 0)
|
|
221
|
+
if ds.attrs['number_of_booms']==2:
|
|
222
|
+
ds['wdir_l'] = ds['wdir_l'].where(ds['wspd_l'] != 0)
|
|
214
223
|
ds['wspd_x_l'], ds['wspd_y_l'] = calcDirWindSpeeds(ds['wspd_l'], ds['wdir_l'])
|
|
215
224
|
|
|
216
225
|
if hasattr(ds, 'wdir_i'):
|
|
217
226
|
if ~ds['wdir_i'].isnull().all() and ~ds['wspd_i'].isnull().all():
|
|
218
|
-
ds['wdir_i'] = ds['wdir_i'].where(ds['wspd_i'] != 0)
|
|
219
|
-
ds['wspd_x_i'], ds['wspd_y_i'] = calcDirWindSpeeds(ds['wspd_i'], ds['wdir_i'])
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
ds = clip_values(ds, vars_df)
|
|
227
|
+
ds['wdir_i'] = ds['wdir_i'].where(ds['wspd_i'] != 0)
|
|
228
|
+
ds['wspd_x_i'], ds['wspd_y_i'] = calcDirWindSpeeds(ds['wspd_i'], ds['wdir_i'])
|
|
223
229
|
return ds
|
|
224
230
|
|
|
225
231
|
|
|
226
232
|
def calcDirWindSpeeds(wspd, wdir, deg2rad=np.pi/180):
|
|
227
233
|
'''Calculate directional wind speed from wind speed and direction
|
|
228
|
-
|
|
234
|
+
|
|
229
235
|
Parameters
|
|
230
236
|
----------
|
|
231
237
|
wspd : xr.Dataarray
|
|
@@ -234,16 +240,16 @@ def calcDirWindSpeeds(wspd, wdir, deg2rad=np.pi/180):
|
|
|
234
240
|
Wind direction data array
|
|
235
241
|
deg2rad : float
|
|
236
242
|
Degree to radians coefficient. The default is np.pi/180
|
|
237
|
-
|
|
243
|
+
|
|
238
244
|
Returns
|
|
239
245
|
-------
|
|
240
246
|
wspd_x : xr.Dataarray
|
|
241
247
|
Wind speed in X direction
|
|
242
248
|
wspd_y : xr.Datarray
|
|
243
249
|
Wind speed in Y direction
|
|
244
|
-
'''
|
|
250
|
+
'''
|
|
245
251
|
wspd_x = wspd * np.sin(wdir * deg2rad)
|
|
246
|
-
wspd_y = wspd * np.cos(wdir * deg2rad)
|
|
252
|
+
wspd_y = wspd * np.cos(wdir * deg2rad)
|
|
247
253
|
return wspd_x, wspd_y
|
|
248
254
|
|
|
249
255
|
|
|
@@ -328,7 +334,7 @@ def smoothTilt(da: xr.DataArray, threshold=0.2):
|
|
|
328
334
|
either X or Y smoothed tilt inclinometer measurements
|
|
329
335
|
'''
|
|
330
336
|
# we calculate the moving standard deviation over a 3-day sliding window
|
|
331
|
-
# hourly resampling is necessary to make sure the same threshold can be used
|
|
337
|
+
# hourly resampling is necessary to make sure the same threshold can be used
|
|
332
338
|
# for 10 min and hourly data
|
|
333
339
|
moving_std_gap_filled = da.to_series().resample('h').median().rolling(
|
|
334
340
|
3*24, center=True, min_periods=2
|
|
@@ -413,9 +419,12 @@ def calcTilt(tilt_x, tilt_y, deg2rad):
|
|
|
413
419
|
return phi_sensor_rad, theta_sensor_rad
|
|
414
420
|
|
|
415
421
|
|
|
416
|
-
def
|
|
417
|
-
'''
|
|
418
|
-
|
|
422
|
+
def adjustHumidity(rh, T, T_0, T_100, ews, ei0): #TODO figure out if T replicate is needed
|
|
423
|
+
'''Adjust relative humidity so that values are given with respect to
|
|
424
|
+
saturation over ice in subfreezing conditions, and with respect to
|
|
425
|
+
saturation over water (as given by the instrument) above the melting
|
|
426
|
+
point temperature. Saturation water vapors are calculated after
|
|
427
|
+
Groff & Gratch method.
|
|
419
428
|
|
|
420
429
|
Parameters
|
|
421
430
|
----------
|
|
@@ -434,7 +443,7 @@ def correctHumidity(rh, T, T_0, T_100, ews, ei0): #TODO f
|
|
|
434
443
|
|
|
435
444
|
Returns
|
|
436
445
|
-------
|
|
437
|
-
|
|
446
|
+
rh_wrt_ice_or_water : xarray.DataArray
|
|
438
447
|
Corrected relative humidity
|
|
439
448
|
'''
|
|
440
449
|
# Convert to hPa (Groff & Gratch)
|
|
@@ -452,8 +461,8 @@ def correctHumidity(rh, T, T_0, T_100, ews, ei0): #TODO f
|
|
|
452
461
|
freezing = (T < 0) & (T > -100).values
|
|
453
462
|
|
|
454
463
|
# Set to Groff & Gratch values when freezing, otherwise just rh
|
|
455
|
-
|
|
456
|
-
return
|
|
464
|
+
rh_wrt_ice_or_water = rh.where(~freezing, other = rh*(e_s_wtr / e_s_ice))
|
|
465
|
+
return rh_wrt_ice_or_water
|
|
457
466
|
|
|
458
467
|
|
|
459
468
|
def correctPrecip(precip, wspd):
|