grdwindinversion 0.3.3__py3-none-any.whl → 0.3.5__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.
- grdwindinversion/__init__.py +1 -1
- grdwindinversion/gradientFeatures.py +204 -138
- grdwindinversion/inversion.py +714 -422
- grdwindinversion/load_config.py +10 -7
- grdwindinversion/main.py +71 -28
- grdwindinversion/utils.py +22 -16
- grdwindinversion/utils_memory.py +20 -22
- {grdwindinversion-0.3.3.dist-info → grdwindinversion-0.3.5.dist-info}/METADATA +2 -2
- grdwindinversion-0.3.5.dist-info/RECORD +22 -0
- {grdwindinversion-0.3.3.dist-info → grdwindinversion-0.3.5.dist-info}/WHEEL +1 -1
- grdwindinversion-0.3.3.dist-info/RECORD +0 -22
- {grdwindinversion-0.3.3.dist-info → grdwindinversion-0.3.5.dist-info}/AUTHORS.rst +0 -0
- {grdwindinversion-0.3.3.dist-info → grdwindinversion-0.3.5.dist-info}/LICENSE +0 -0
- {grdwindinversion-0.3.3.dist-info → grdwindinversion-0.3.5.dist-info}/entry_points.txt +0 -0
- {grdwindinversion-0.3.3.dist-info → grdwindinversion-0.3.5.dist-info}/top_level.txt +0 -0
grdwindinversion/inversion.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
# To place here in the code to not have errors with cv2.
|
|
2
|
+
# if placed in main => error ..
|
|
1
3
|
import tempfile
|
|
2
4
|
import traceback
|
|
3
|
-
|
|
4
5
|
import xsar
|
|
5
6
|
import xsarsea
|
|
6
7
|
from xsarsea import windspeed
|
|
@@ -9,17 +10,28 @@ import xarray as xr
|
|
|
9
10
|
import numpy as np
|
|
10
11
|
import sys
|
|
11
12
|
import datetime
|
|
12
|
-
import os
|
|
13
13
|
import yaml
|
|
14
14
|
from scipy.ndimage import binary_dilation
|
|
15
|
-
|
|
16
15
|
import re
|
|
17
16
|
import string
|
|
18
|
-
import os
|
|
19
17
|
from grdwindinversion.utils import check_incidence_range, get_pol_ratio_name, timing
|
|
20
18
|
from grdwindinversion.load_config import getConf
|
|
21
|
-
# optional debug messages
|
|
22
19
|
import logging
|
|
20
|
+
import os
|
|
21
|
+
|
|
22
|
+
os.environ["OMP_NUM_THREADS"] = "1"
|
|
23
|
+
os.environ["OPENBLAS_NUM_THREADS"] = "1"
|
|
24
|
+
os.environ["MKL_NUM_THREADS"] = "1"
|
|
25
|
+
os.environ["VECLIB_MAXIMUM_THREADS"] = "1"
|
|
26
|
+
os.environ["NUMEXPR_NUM_THREADS"] = "1"
|
|
27
|
+
try:
|
|
28
|
+
import cv2
|
|
29
|
+
except:
|
|
30
|
+
import cv2
|
|
31
|
+
cv2.setNumThreads(1)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# optional debug messages
|
|
23
35
|
logger = logging.getLogger('grdwindinversion.inversion')
|
|
24
36
|
logger.addHandler(logging.NullHandler())
|
|
25
37
|
|
|
@@ -38,25 +50,28 @@ def getSensorMetaDataset(filename):
|
|
|
38
50
|
tuple
|
|
39
51
|
sensor name, sensor long name, meta function, dataset function
|
|
40
52
|
"""
|
|
41
|
-
if
|
|
53
|
+
if "S1A" in filename:
|
|
42
54
|
return "S1A", "SENTINEL-1 A", xsar.Sentinel1Meta, xsar.Sentinel1Dataset
|
|
43
|
-
elif
|
|
55
|
+
elif "S1B" in filename:
|
|
44
56
|
return "S1B", "SENTINEL-1 B", xsar.Sentinel1Meta, xsar.Sentinel1Dataset
|
|
45
|
-
elif
|
|
57
|
+
elif "RS2" in filename:
|
|
46
58
|
return "RS2", "RADARSAT-2", xsar.RadarSat2Meta, xsar.RadarSat2Dataset
|
|
47
|
-
elif
|
|
59
|
+
elif "RCM1" in filename:
|
|
48
60
|
return "RCM", "RADARSAT Constellation 1", xsar.RcmMeta, xsar.RcmDataset
|
|
49
|
-
elif
|
|
61
|
+
elif "RCM2" in filename:
|
|
50
62
|
return "RCM", "RADARSAT Constellation 2", xsar.RcmMeta, xsar.RcmDataset
|
|
51
|
-
elif
|
|
63
|
+
elif "RCM3" in filename:
|
|
52
64
|
return "RCM", "RADARSAT Constellation 3", xsar.RcmMeta, xsar.RcmDataset
|
|
53
65
|
|
|
54
66
|
else:
|
|
55
67
|
raise ValueError(
|
|
56
|
-
"must be S1A|S1B|RS2|RCM1|RCM2|RCM3, got filename %s" % filename
|
|
68
|
+
"must be S1A|S1B|RS2|RCM1|RCM2|RCM3, got filename %s" % filename
|
|
69
|
+
)
|
|
57
70
|
|
|
58
71
|
|
|
59
|
-
def getOutputName(
|
|
72
|
+
def getOutputName(
|
|
73
|
+
input_file, outdir, sensor, meta_start_date, meta_stop_date, subdir=True
|
|
74
|
+
):
|
|
60
75
|
"""
|
|
61
76
|
Create output filename for L2-GRD product
|
|
62
77
|
|
|
@@ -81,40 +96,65 @@ def getOutputName(input_file, outdir, sensor, meta_start_date, meta_stop_date, s
|
|
|
81
96
|
basename = os.path.basename(input_file)
|
|
82
97
|
basename_match = basename
|
|
83
98
|
|
|
84
|
-
if sensor ==
|
|
99
|
+
if sensor == "S1A" or sensor == "S1B":
|
|
85
100
|
regex = re.compile(
|
|
86
|
-
"(...)_(..)_(...)(.)_(.)(.)(..)_(........T......)_(........T......)_(......)_(......)_(....).SAFE"
|
|
101
|
+
"(...)_(..)_(...)(.)_(.)(.)(..)_(........T......)_(........T......)_(......)_(......)_(....).SAFE"
|
|
102
|
+
)
|
|
87
103
|
template = string.Template(
|
|
88
|
-
"${MISSIONID}_${BEAM}_${PRODUCT}${RESOLUTION}_${LEVEL}${CLASS}${POL}_${STARTDATE}_${STOPDATE}_${ORBIT}_${TAKEID}_${PRODID}.SAFE"
|
|
104
|
+
"${MISSIONID}_${BEAM}_${PRODUCT}${RESOLUTION}_${LEVEL}${CLASS}${POL}_${STARTDATE}_${STOPDATE}_${ORBIT}_${TAKEID}_${PRODID}.SAFE"
|
|
105
|
+
)
|
|
89
106
|
match = regex.match(basename_match)
|
|
90
107
|
if not match:
|
|
91
108
|
raise AttributeError(
|
|
92
|
-
f"S1 file {basename_match} does not match the expected pattern"
|
|
109
|
+
f"S1 file {basename_match} does not match the expected pattern"
|
|
110
|
+
)
|
|
93
111
|
|
|
94
|
-
|
|
112
|
+
(
|
|
113
|
+
MISSIONID,
|
|
114
|
+
BEAM,
|
|
115
|
+
PRODUCT,
|
|
116
|
+
RESOLUTION,
|
|
117
|
+
LEVEL,
|
|
118
|
+
CLASS,
|
|
119
|
+
POL,
|
|
120
|
+
STARTDATE,
|
|
121
|
+
STOPDATE,
|
|
122
|
+
ORBIT,
|
|
123
|
+
TAKEID,
|
|
124
|
+
PRODID,
|
|
125
|
+
) = match.groups()
|
|
95
126
|
new_format = f"{MISSIONID.lower()}-{BEAM.lower()}-owi-xx-{STARTDATE.lower()}-{STOPDATE.lower()}-{ORBIT}-{TAKEID}.nc"
|
|
96
|
-
elif sensor ==
|
|
127
|
+
elif sensor == "RS2":
|
|
97
128
|
regex = re.compile(
|
|
98
|
-
"(RS2)_OK([0-9]+)_PK([0-9]+)_DK([0-9]+)_(....)_(........)_(......)_(.._?.?.?)_(S.F)"
|
|
129
|
+
"(RS2)_OK([0-9]+)_PK([0-9]+)_DK([0-9]+)_(....)_(........)_(......)_(.._?.?.?)_(S.F)"
|
|
130
|
+
)
|
|
99
131
|
template = string.Template(
|
|
100
|
-
"${MISSIONID}_OK${DATA1}_PK${DATA2}_DK${DATA3}_${DATA4}_${DATE}_${TIME}_${POLARIZATION}_${LAST}"
|
|
132
|
+
"${MISSIONID}_OK${DATA1}_PK${DATA2}_DK${DATA3}_${DATA4}_${DATE}_${TIME}_${POLARIZATION}_${LAST}"
|
|
133
|
+
)
|
|
101
134
|
match = regex.match(basename_match)
|
|
102
135
|
if not match:
|
|
103
136
|
raise AttributeError(
|
|
104
|
-
f"RC2 file {basename_match} does not match the expected pattern"
|
|
137
|
+
f"RC2 file {basename_match} does not match the expected pattern"
|
|
138
|
+
)
|
|
105
139
|
|
|
106
|
-
MISSIONID, DATA1, DATA2, DATA3, DATA4, DATE, TIME, POLARIZATION, LAST =
|
|
140
|
+
MISSIONID, DATA1, DATA2, DATA3, DATA4, DATE, TIME, POLARIZATION, LAST = (
|
|
141
|
+
match.groups()
|
|
142
|
+
)
|
|
107
143
|
new_format = f"{MISSIONID.lower()}--owi-xx-{meta_start_date.lower()}-{meta_stop_date.lower()}-_____-_____.nc"
|
|
108
|
-
elif sensor ==
|
|
144
|
+
elif sensor == "RCM":
|
|
109
145
|
|
|
110
146
|
regex = re.compile(
|
|
111
|
-
r"(RCM[0-9])_OK([0-9]+)_PK([0-9]+)_([0-9]+)_([A-Z0-9]+)_(\d{8})_(\d{6})_([A-Z]{2}(?:_[A-Z]{2})?)_([A-Z]+)$"
|
|
147
|
+
r"(RCM[0-9])_OK([0-9]+)_PK([0-9]+)_([0-9]+)_([A-Z0-9]+)_(\d{8})_(\d{6})_([A-Z]{2}(?:_[A-Z]{2})?)_([A-Z]+)$"
|
|
148
|
+
)
|
|
112
149
|
match = regex.match(basename_match)
|
|
113
150
|
if not match:
|
|
114
151
|
raise AttributeError(
|
|
115
|
-
f"RCM file {basename_match} does not match the expected pattern"
|
|
152
|
+
f"RCM file {basename_match} does not match the expected pattern"
|
|
153
|
+
)
|
|
116
154
|
|
|
117
|
-
MISSIONID, DATA1, DATA2, DATA3, BEAM, DATE, TIME, POLARIZATION, PRODUCT =
|
|
155
|
+
MISSIONID, DATA1, DATA2, DATA3, BEAM, DATE, TIME, POLARIZATION, PRODUCT = (
|
|
156
|
+
match.groups()
|
|
157
|
+
)
|
|
118
158
|
new_format = f"{MISSIONID.lower()}-{BEAM.lower()}-owi-xx-{meta_start_date.lower()}-{meta_stop_date.lower()}-_____-_____.nc"
|
|
119
159
|
|
|
120
160
|
else:
|
|
@@ -128,7 +168,7 @@ def getOutputName(input_file, outdir, sensor, meta_start_date, meta_stop_date, s
|
|
|
128
168
|
return out_file
|
|
129
169
|
|
|
130
170
|
|
|
131
|
-
def getAncillary(meta, ancillary_name=
|
|
171
|
+
def getAncillary(meta, ancillary_name="ecmwf"):
|
|
132
172
|
"""
|
|
133
173
|
Map ancillary wind from ECMWF or ERA5.
|
|
134
174
|
This function is used to check if the model files are available and to map the model to the SAR data.
|
|
@@ -143,28 +183,34 @@ def getAncillary(meta, ancillary_name='ecmwf'):
|
|
|
143
183
|
map model to SAR data
|
|
144
184
|
"""
|
|
145
185
|
|
|
146
|
-
if ancillary_name ==
|
|
186
|
+
if ancillary_name == "ecmwf":
|
|
147
187
|
|
|
148
|
-
logging.debug(
|
|
149
|
-
ec01 = getConf()[
|
|
150
|
-
ec0125 = getConf()[
|
|
151
|
-
logging.debug(
|
|
152
|
-
meta.set_raster(
|
|
153
|
-
meta.set_raster(
|
|
188
|
+
logging.debug("conf: %s", getConf())
|
|
189
|
+
ec01 = getConf()["ecmwf_0100_1h"]
|
|
190
|
+
ec0125 = getConf()["ecmwf_0125_1h"]
|
|
191
|
+
logging.debug("ec01 : %s", ec01)
|
|
192
|
+
meta.set_raster("ecmwf_0100_1h", ec01)
|
|
193
|
+
meta.set_raster("ecmwf_0125_1h", ec0125)
|
|
154
194
|
|
|
155
195
|
map_model = None
|
|
156
196
|
# only keep best ecmwf (FIXME: it's hacky, and xsar should provide a better method to handle this)
|
|
157
|
-
for ecmwf_name in [
|
|
197
|
+
for ecmwf_name in ["ecmwf_0125_1h", "ecmwf_0100_1h"]:
|
|
158
198
|
ecmwf_infos = meta.rasters.loc[ecmwf_name]
|
|
159
199
|
try:
|
|
160
|
-
ecmwf_file = ecmwf_infos[
|
|
161
|
-
|
|
162
|
-
|
|
200
|
+
ecmwf_file = ecmwf_infos["get_function"](
|
|
201
|
+
ecmwf_infos["resource"],
|
|
202
|
+
date=datetime.datetime.strptime(
|
|
203
|
+
meta.start_date, "%Y-%m-%d %H:%M:%S.%f"
|
|
204
|
+
),
|
|
205
|
+
)[1]
|
|
163
206
|
# temporary for RCM issue https://github.com/umr-lops/xarray-safe-rcm/issues/34
|
|
164
207
|
except Exception as e:
|
|
165
|
-
ecmwf_file = ecmwf_infos[
|
|
166
|
-
|
|
167
|
-
|
|
208
|
+
ecmwf_file = ecmwf_infos["get_function"](
|
|
209
|
+
ecmwf_infos["resource"],
|
|
210
|
+
date=datetime.datetime.strptime(
|
|
211
|
+
meta.start_date, "%Y-%m-%d %H:%M:%S"
|
|
212
|
+
),
|
|
213
|
+
)[1]
|
|
168
214
|
if not os.path.isfile(ecmwf_file):
|
|
169
215
|
# temporary
|
|
170
216
|
# if repro does not exist we look at not repro folder (only one will exist after)
|
|
@@ -191,41 +237,58 @@ def getAncillary(meta, ancillary_name='ecmwf'):
|
|
|
191
237
|
"""
|
|
192
238
|
meta.rasters = meta.rasters.drop([ecmwf_name])
|
|
193
239
|
else:
|
|
194
|
-
map_model = {
|
|
195
|
-
|
|
240
|
+
map_model = {
|
|
241
|
+
"%s_%s" % (ecmwf_name, uv): "model_%s" % uv for uv in ["U10", "V10"]
|
|
242
|
+
}
|
|
196
243
|
|
|
197
244
|
return map_model
|
|
198
245
|
|
|
199
|
-
elif ancillary_name ==
|
|
246
|
+
elif ancillary_name == "era5":
|
|
200
247
|
era5_name = "era5_0250_1h"
|
|
201
|
-
logging.debug(
|
|
248
|
+
logging.debug("conf: %s", getConf())
|
|
202
249
|
era0250 = getConf()[era5_name]
|
|
203
|
-
logging.debug(
|
|
250
|
+
logging.debug("%s : %s", (era5_name, era0250))
|
|
204
251
|
meta.set_raster(era5_name, era0250)
|
|
205
252
|
|
|
206
253
|
era5_infos = meta.rasters.loc[era5_name]
|
|
207
254
|
try:
|
|
208
|
-
era5_file = era5_infos[
|
|
209
|
-
|
|
210
|
-
|
|
255
|
+
era5_file = era5_infos["get_function"](
|
|
256
|
+
era5_infos["resource"],
|
|
257
|
+
date=datetime.datetime.strptime(
|
|
258
|
+
meta.start_date, "%Y-%m-%d %H:%M:%S.%f"
|
|
259
|
+
),
|
|
260
|
+
)[1]
|
|
211
261
|
except Exception as e:
|
|
212
|
-
era5_file = era5_infos[
|
|
213
|
-
|
|
214
|
-
|
|
262
|
+
era5_file = era5_infos["get_function"](
|
|
263
|
+
era5_infos["resource"],
|
|
264
|
+
date=datetime.datetime.strptime(
|
|
265
|
+
meta.start_date, "%Y-%m-%d %H:%M:%S"),
|
|
266
|
+
)[1]
|
|
215
267
|
if not os.path.isfile(era5_file):
|
|
216
268
|
raise ValueError(f"era5 file {era5_file} not found")
|
|
217
269
|
|
|
218
|
-
map_model = {
|
|
219
|
-
|
|
270
|
+
map_model = {
|
|
271
|
+
"%s_%s" % (era5_name, uv): "model_%s" % uv for uv in ["U10", "V10"]
|
|
272
|
+
}
|
|
220
273
|
return map_model
|
|
221
274
|
|
|
222
275
|
else:
|
|
223
|
-
raise ValueError(
|
|
224
|
-
|
|
276
|
+
raise ValueError(
|
|
277
|
+
"ancillary_name must be ecmwf/era5, got %s" % ancillary_name)
|
|
225
278
|
|
|
226
279
|
|
|
227
280
|
@timing(logger=logger.debug)
|
|
228
|
-
def inverse(
|
|
281
|
+
def inverse(
|
|
282
|
+
dual_pol,
|
|
283
|
+
inc,
|
|
284
|
+
sigma0,
|
|
285
|
+
sigma0_dual,
|
|
286
|
+
ancillary_wind,
|
|
287
|
+
dsig_cr,
|
|
288
|
+
model_co,
|
|
289
|
+
model_cross,
|
|
290
|
+
**kwargs,
|
|
291
|
+
):
|
|
229
292
|
"""
|
|
230
293
|
Invert sigma0 to retrieve wind using model (lut or gmf).
|
|
231
294
|
|
|
@@ -263,14 +326,19 @@ def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_c
|
|
|
263
326
|
"""
|
|
264
327
|
logging.debug("inversion")
|
|
265
328
|
|
|
266
|
-
list_mods =
|
|
267
|
-
|
|
329
|
+
list_mods = (
|
|
330
|
+
windspeed.available_models().index.tolist()
|
|
331
|
+
+ windspeed.available_models().alias.tolist()
|
|
332
|
+
+ [None]
|
|
333
|
+
)
|
|
268
334
|
if model_co not in list_mods:
|
|
269
335
|
raise ValueError(
|
|
270
|
-
f"model_co {model_co} not in windspeed.available_models() : not going further"
|
|
336
|
+
f"model_co {model_co} not in windspeed.available_models() : not going further"
|
|
337
|
+
)
|
|
271
338
|
if model_cross not in list_mods:
|
|
272
339
|
raise ValueError(
|
|
273
|
-
f"model_cross {model_cross} not in windspeed.available_models() : not going further"
|
|
340
|
+
f"model_cross {model_cross} not in windspeed.available_models() : not going further"
|
|
341
|
+
)
|
|
274
342
|
|
|
275
343
|
winds = windspeed.invert_from_model(
|
|
276
344
|
inc,
|
|
@@ -279,7 +347,8 @@ def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_c
|
|
|
279
347
|
ancillary_wind=ancillary_wind,
|
|
280
348
|
dsig_cr=dsig_cr,
|
|
281
349
|
model=(model_co, model_cross),
|
|
282
|
-
**kwargs
|
|
350
|
+
**kwargs,
|
|
351
|
+
)
|
|
283
352
|
|
|
284
353
|
if dual_pol:
|
|
285
354
|
wind_co, wind_dual = winds
|
|
@@ -289,7 +358,8 @@ def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_c
|
|
|
289
358
|
sigma0_dual.values,
|
|
290
359
|
dsig_cr=dsig_cr.values,
|
|
291
360
|
model=model_cross,
|
|
292
|
-
**kwargs
|
|
361
|
+
**kwargs,
|
|
362
|
+
)
|
|
293
363
|
|
|
294
364
|
return wind_co, wind_dual, wind_cross
|
|
295
365
|
else:
|
|
@@ -321,38 +391,42 @@ def makeL2asOwi(xr_dataset, config):
|
|
|
321
391
|
--------
|
|
322
392
|
"""
|
|
323
393
|
|
|
324
|
-
xr_dataset = xr_dataset.rename(
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
394
|
+
xr_dataset = xr_dataset.rename(
|
|
395
|
+
{
|
|
396
|
+
"longitude": "owiLon",
|
|
397
|
+
"latitude": "owiLat",
|
|
398
|
+
"incidence": "owiIncidenceAngle",
|
|
399
|
+
"elevation": "owiElevationAngle",
|
|
400
|
+
"ground_heading": "owiHeading",
|
|
401
|
+
"land_mask": "owiLandFlag",
|
|
402
|
+
"mask": "owiMask",
|
|
403
|
+
"windspeed_co": "owiWindSpeed_co",
|
|
404
|
+
"winddir_co": "owiWindDirection_co",
|
|
405
|
+
"ancillary_wind_speed": "owiAncillaryWindSpeed",
|
|
406
|
+
"ancillary_wind_direction": "owiAncillaryWindDirection",
|
|
407
|
+
"sigma0_detrend": "owiNrcs_detrend",
|
|
408
|
+
}
|
|
409
|
+
)
|
|
338
410
|
|
|
339
411
|
if "offboresight" in xr_dataset:
|
|
340
412
|
xr_dataset = xr_dataset.rename(
|
|
341
413
|
{"offboresight": "owiOffboresightAngle"})
|
|
342
414
|
|
|
343
415
|
if config["add_nrcs_model"]:
|
|
344
|
-
xr_dataset = xr_dataset.rename(
|
|
345
|
-
{"ancillary_nrcs": "owiAncillaryNrcs"})
|
|
416
|
+
xr_dataset = xr_dataset.rename({"ancillary_nrcs": "owiAncillaryNrcs"})
|
|
346
417
|
xr_dataset.owiAncillaryNrcs.attrs["units"] = "m^2 / m^2"
|
|
347
|
-
xr_dataset.owiAncillaryNrcs.attrs[
|
|
348
|
-
|
|
418
|
+
xr_dataset.owiAncillaryNrcs.attrs["long_name"] = (
|
|
419
|
+
f"Ancillary Normalized Radar Cross Section - simulated from {config['l2_params']['copol_gmf']} & ancillary wind"
|
|
420
|
+
)
|
|
349
421
|
|
|
350
422
|
if config["l2_params"]["dual_pol"]:
|
|
351
423
|
xr_dataset = xr_dataset.rename(
|
|
352
|
-
{"ancillary_nrcs_cross": "owiAncillaryNrcs_cross"}
|
|
424
|
+
{"ancillary_nrcs_cross": "owiAncillaryNrcs_cross"}
|
|
425
|
+
)
|
|
353
426
|
xr_dataset.owiAncillaryNrcs_cross.attrs["units"] = "m^2 / m^2"
|
|
354
|
-
xr_dataset.owiAncillaryNrcs_cross.attrs[
|
|
355
|
-
|
|
427
|
+
xr_dataset.owiAncillaryNrcs_cross.attrs["long_name"] = (
|
|
428
|
+
f"Ancillary Normalized Radar Cross Section - simulated from {config['l2_params']['crosspol_gmf']} & ancillary wind"
|
|
429
|
+
)
|
|
356
430
|
|
|
357
431
|
xr_dataset.owiLon.attrs["units"] = "degrees_east"
|
|
358
432
|
xr_dataset.owiLon.attrs["long_name"] = "Longitude at wind cell center"
|
|
@@ -363,146 +437,196 @@ def makeL2asOwi(xr_dataset, config):
|
|
|
363
437
|
xr_dataset.owiLat.attrs["standard_name"] = "latitude"
|
|
364
438
|
|
|
365
439
|
xr_dataset.owiIncidenceAngle.attrs["units"] = "degrees"
|
|
366
|
-
xr_dataset.owiIncidenceAngle.attrs["long_name"] =
|
|
440
|
+
xr_dataset.owiIncidenceAngle.attrs["long_name"] = (
|
|
441
|
+
"Incidence angle at wind cell center"
|
|
442
|
+
)
|
|
367
443
|
xr_dataset.owiIncidenceAngle.attrs["standard_name"] = "incidence"
|
|
368
444
|
|
|
369
445
|
xr_dataset.owiElevationAngle.attrs["units"] = "degrees"
|
|
370
|
-
xr_dataset.owiElevationAngle.attrs["long_name"] =
|
|
446
|
+
xr_dataset.owiElevationAngle.attrs["long_name"] = (
|
|
447
|
+
"Elevation angle at wind cell center"
|
|
448
|
+
)
|
|
371
449
|
xr_dataset.owiElevationAngle.attrs["standard_name"] = "elevation"
|
|
372
450
|
|
|
373
|
-
xr_dataset[
|
|
374
|
-
pol=config["l2_params"]["copol"]
|
|
451
|
+
xr_dataset["owiNrcs"] = xr_dataset["sigma0_ocean"].sel(
|
|
452
|
+
pol=config["l2_params"]["copol"]
|
|
453
|
+
)
|
|
375
454
|
xr_dataset.owiNrcs.attrs = xr_dataset.sigma0_ocean.attrs
|
|
376
|
-
xr_dataset.owiNrcs.attrs[
|
|
377
|
-
xr_dataset.owiNrcs.attrs[
|
|
378
|
-
xr_dataset.owiNrcs.attrs[
|
|
455
|
+
xr_dataset.owiNrcs.attrs["units"] = "m^2 / m^2"
|
|
456
|
+
xr_dataset.owiNrcs.attrs["long_name"] = "Normalized Radar Cross Section"
|
|
457
|
+
xr_dataset.owiNrcs.attrs["definition"] = "owiNrcs_no_noise_correction - owiNesz"
|
|
379
458
|
|
|
380
|
-
xr_dataset[
|
|
381
|
-
pol=config["l2_params"]["copol"]
|
|
459
|
+
xr_dataset["owiMask_Nrcs"] = xr_dataset["sigma0_mask"].sel(
|
|
460
|
+
pol=config["l2_params"]["copol"]
|
|
461
|
+
)
|
|
382
462
|
xr_dataset.owiMask_Nrcs.attrs = xr_dataset.sigma0_mask.attrs
|
|
383
463
|
|
|
384
464
|
# NESZ & DSIG
|
|
385
465
|
xr_dataset = xr_dataset.assign(
|
|
386
|
-
owiNesz=(
|
|
387
|
-
|
|
388
|
-
|
|
466
|
+
owiNesz=(
|
|
467
|
+
["line", "sample"],
|
|
468
|
+
xr_dataset.nesz.sel(pol=config["l2_params"]["copol"]).values,
|
|
469
|
+
)
|
|
470
|
+
)
|
|
471
|
+
xr_dataset.owiNesz.attrs["units"] = "m^2 / m^2"
|
|
472
|
+
xr_dataset.owiNesz.attrs["long_name"] = "Noise Equivalent SigmaNaught"
|
|
389
473
|
|
|
390
|
-
xr_dataset[
|
|
391
|
-
pol=config["l2_params"]["copol"]
|
|
474
|
+
xr_dataset["owiNrcs_no_noise_correction"] = xr_dataset["sigma0_ocean_raw"].sel(
|
|
475
|
+
pol=config["l2_params"]["copol"]
|
|
476
|
+
)
|
|
392
477
|
xr_dataset.owiNrcs_no_noise_correction.attrs = xr_dataset.sigma0_ocean_raw.attrs
|
|
393
|
-
xr_dataset.owiNrcs_no_noise_correction.attrs[
|
|
394
|
-
xr_dataset.owiNrcs_no_noise_correction.attrs[
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
478
|
+
xr_dataset.owiNrcs_no_noise_correction.attrs["units"] = "m^2 / m^2"
|
|
479
|
+
xr_dataset.owiNrcs_no_noise_correction.attrs["long_name"] = (
|
|
480
|
+
"Normalized Radar Cross Section ; no noise correction applied"
|
|
481
|
+
)
|
|
482
|
+
xr_dataset.owiNrcs_no_noise_correction.attrs["comment"] = (
|
|
483
|
+
"owiNrcs_no_noise_correction ; no recalibration"
|
|
484
|
+
)
|
|
398
485
|
|
|
399
|
-
if
|
|
400
|
-
xr_dataset = xr_dataset.rename(
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
486
|
+
if "swath_number" in xr_dataset:
|
|
487
|
+
xr_dataset = xr_dataset.rename(
|
|
488
|
+
{
|
|
489
|
+
"swath_number": "owiSwathNumber",
|
|
490
|
+
"swath_number_flag": "owiSwathNumberFlag",
|
|
491
|
+
}
|
|
492
|
+
)
|
|
404
493
|
|
|
405
494
|
xr_dataset["owiSwathNumber"].attrs["standart_name"] = "swath number"
|
|
406
495
|
|
|
407
496
|
# sigma0_raw__corrected cross
|
|
408
497
|
if "sigma0_raw__corrected" in xr_dataset:
|
|
409
|
-
xr_dataset[
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs[
|
|
416
|
-
|
|
498
|
+
xr_dataset["owiNrcs_no_noise_correction_recalibrated"] = xr_dataset[
|
|
499
|
+
"sigma0_raw__corrected"
|
|
500
|
+
].sel(pol=config["l2_params"]["copol"])
|
|
501
|
+
xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs = (
|
|
502
|
+
xr_dataset.sigma0_raw__corrected.attrs
|
|
503
|
+
)
|
|
504
|
+
xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs["units"] = "m^2 / m^2"
|
|
505
|
+
xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs["long_name"] = (
|
|
506
|
+
"Normalized Radar Cross Section, no noise correction applied"
|
|
507
|
+
)
|
|
508
|
+
xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs["comment"] = (
|
|
509
|
+
"owiNrcs_no_noise_correction ; recalibrated with kersten method"
|
|
510
|
+
)
|
|
417
511
|
|
|
418
|
-
xr_dataset.owiNrcs.attrs[
|
|
512
|
+
xr_dataset.owiNrcs.attrs["definition"] = (
|
|
513
|
+
"owiNrcs_no_noise_correction_recalibrated - owiNesz"
|
|
514
|
+
)
|
|
419
515
|
|
|
420
516
|
if config["l2_params"]["dual_pol"]:
|
|
421
|
-
|
|
422
517
|
xr_dataset = xr_dataset.rename({
|
|
423
518
|
'dsig_cross': 'owiDsig_cross',
|
|
424
519
|
'winddir_cross': 'owiWindDirection_cross',
|
|
425
520
|
'winddir_dual': 'owiWindDirection',
|
|
426
521
|
'windspeed_cross': 'owiWindSpeed_cross',
|
|
427
522
|
'windspeed_dual': 'owiWindSpeed',
|
|
428
|
-
'sigma0_detrend_cross': 'owiNrcs_detrend_cross'
|
|
523
|
+
'sigma0_detrend_cross': 'owiNrcs_detrend_cross',
|
|
524
|
+
'nesz_cross_flattened': 'owiNesz_cross_flattened'
|
|
429
525
|
})
|
|
430
526
|
|
|
431
|
-
if config["apply_flattening"]:
|
|
432
|
-
xr_dataset = xr_dataset.rename({
|
|
433
|
-
'nesz_cross_flattened': 'owiNesz_cross_flattened',
|
|
434
|
-
})
|
|
435
|
-
|
|
436
527
|
# nrcs cross
|
|
437
|
-
xr_dataset[
|
|
438
|
-
pol=config["l2_params"]["crosspol"]
|
|
528
|
+
xr_dataset["owiNrcs_cross"] = xr_dataset["sigma0_ocean"].sel(
|
|
529
|
+
pol=config["l2_params"]["crosspol"]
|
|
530
|
+
)
|
|
439
531
|
|
|
440
|
-
xr_dataset.owiNrcs_cross.attrs[
|
|
441
|
-
xr_dataset.owiNrcs_cross.attrs[
|
|
442
|
-
xr_dataset.owiNrcs_cross.attrs[
|
|
532
|
+
xr_dataset.owiNrcs_cross.attrs["units"] = "m^2 / m^2"
|
|
533
|
+
xr_dataset.owiNrcs_cross.attrs["long_name"] = "Normalized Radar Cross Section"
|
|
534
|
+
xr_dataset.owiNrcs_cross.attrs["definition"] = (
|
|
535
|
+
"owiNrcs_cross_no_noise_correction - owiNesz_cross"
|
|
536
|
+
)
|
|
443
537
|
|
|
444
|
-
xr_dataset[
|
|
445
|
-
pol=config["l2_params"]["crosspol"]
|
|
538
|
+
xr_dataset["owiMask_Nrcs_cross"] = xr_dataset["sigma0_mask"].sel(
|
|
539
|
+
pol=config["l2_params"]["crosspol"]
|
|
540
|
+
)
|
|
446
541
|
xr_dataset.owiMask_Nrcs_cross.attrs = xr_dataset.sigma0_mask.attrs
|
|
447
542
|
|
|
448
543
|
# nesz cross
|
|
449
|
-
xr_dataset = xr_dataset.assign(
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
544
|
+
xr_dataset = xr_dataset.assign(
|
|
545
|
+
owiNesz_cross=(
|
|
546
|
+
["line", "sample"],
|
|
547
|
+
xr_dataset.nesz.sel(
|
|
548
|
+
pol=config["l2_params"]["crosspol"]).values,
|
|
549
|
+
)
|
|
550
|
+
) # no flattening
|
|
551
|
+
xr_dataset.owiNesz_cross.attrs["units"] = "m^2 / m^2"
|
|
552
|
+
xr_dataset.owiNesz_cross.attrs["long_name"] = "Noise Equivalent SigmaNaught"
|
|
453
553
|
|
|
454
|
-
xr_dataset[
|
|
455
|
-
|
|
554
|
+
xr_dataset.owiNesz_cross_flattened.attrs["units"] = "m^2 / m^2"
|
|
555
|
+
xr_dataset.owiNesz_cross_flattened.attrs["long_name"] = "Noise Equivalent SigmaNaught"
|
|
456
556
|
|
|
457
|
-
xr_dataset
|
|
458
|
-
|
|
459
|
-
|
|
557
|
+
xr_dataset["owiNrcs_cross_no_noise_correction"] = xr_dataset[
|
|
558
|
+
"sigma0_ocean_raw"
|
|
559
|
+
].sel(pol=config["l2_params"]["crosspol"])
|
|
560
|
+
|
|
561
|
+
xr_dataset.owiNrcs_cross_no_noise_correction.attrs["units"] = "m^2 / m^2"
|
|
562
|
+
xr_dataset.owiNrcs_cross_no_noise_correction.attrs["long_name"] = (
|
|
563
|
+
"Normalized Radar Cross Section, no noise correction applied"
|
|
564
|
+
)
|
|
460
565
|
|
|
461
566
|
# sigma0_raw__corrected cross
|
|
462
567
|
if "sigma0_raw__corrected" in xr_dataset:
|
|
463
|
-
xr_dataset[
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs
|
|
568
|
+
xr_dataset["owiNrcs_cross_no_noise_correction_recalibrated"] = xr_dataset[
|
|
569
|
+
"sigma0_raw__corrected"
|
|
570
|
+
].sel(pol=config["l2_params"]["crosspol"])
|
|
571
|
+
xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs = (
|
|
572
|
+
xr_dataset.sigma0_raw__corrected.attrs
|
|
573
|
+
)
|
|
574
|
+
xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs["units"] = (
|
|
575
|
+
"m^2 / m^2"
|
|
576
|
+
)
|
|
467
577
|
xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs[
|
|
468
|
-
|
|
578
|
+
"long_name"
|
|
579
|
+
] = "Normalized Radar Cross Section ; no noise correction applied"
|
|
469
580
|
xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs[
|
|
470
|
-
|
|
581
|
+
"comment"
|
|
582
|
+
] = "owiNrcs_cross_no_noise_correction ; recalibrated with kersten method"
|
|
471
583
|
|
|
472
|
-
xr_dataset.owiNrcs_cross.attrs[
|
|
584
|
+
xr_dataset.owiNrcs_cross.attrs["definition"] = (
|
|
585
|
+
"owiNrcs_cross_no_noise_correction_recalibrated - owiNesz_cross"
|
|
586
|
+
)
|
|
473
587
|
|
|
474
588
|
if config["add_gradientsfeatures"]:
|
|
475
|
-
xr_dataset = xr_dataset.rename({
|
|
476
|
-
'heterogeneity_mask': 'owiWindFilter'
|
|
477
|
-
})
|
|
589
|
+
xr_dataset = xr_dataset.rename({"heterogeneity_mask": "owiWindFilter"})
|
|
478
590
|
else:
|
|
479
|
-
xr_dataset[
|
|
480
|
-
xr_dataset[
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
xr_dataset[
|
|
485
|
-
|
|
591
|
+
xr_dataset["owiWindFilter"] = xr.full_like(xr_dataset.owiNrcs, 0)
|
|
592
|
+
xr_dataset["owiWindFilter"].attrs[
|
|
593
|
+
"long_name"
|
|
594
|
+
] = "Quality flag taking into account the local heterogeneity"
|
|
595
|
+
xr_dataset["owiWindFilter"].attrs["valid_range"] = np.array([0, 3])
|
|
596
|
+
xr_dataset["owiWindFilter"].attrs["flag_values"] = np.array([
|
|
597
|
+
0, 1, 2, 3])
|
|
598
|
+
xr_dataset["owiWindFilter"].attrs[
|
|
599
|
+
"flag_meanings"
|
|
600
|
+
] = "homogeneous_NRCS, heterogeneous_from_co-polarization_NRCS, heterogeneous_from_cross-polarization_NRCS, heterogeneous_from_dual-polarization_NRCS"
|
|
486
601
|
|
|
487
602
|
# other variables
|
|
488
603
|
|
|
489
|
-
xr_dataset[
|
|
490
|
-
xr_dataset[
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
xr_dataset[
|
|
494
|
-
|
|
495
|
-
xr_dataset[
|
|
496
|
-
xr_dataset[
|
|
604
|
+
xr_dataset["owiWindQuality"] = xr.full_like(xr_dataset.owiNrcs, 0)
|
|
605
|
+
xr_dataset["owiWindQuality"].attrs[
|
|
606
|
+
"long_name"
|
|
607
|
+
] = "Quality flag taking into account the consistency_between_wind_inverted_and_NRCS_and_Doppler_measured"
|
|
608
|
+
xr_dataset["owiWindQuality"].attrs["valid_range"] = np.array([0, 3])
|
|
609
|
+
xr_dataset["owiWindQuality"].attrs["flag_values"] = np.array([0, 1, 2, 3])
|
|
610
|
+
xr_dataset["owiWindQuality"].attrs["flag_meanings"] = "good medium low poor"
|
|
611
|
+
xr_dataset["owiWindQuality"].attrs["comment"] = "NOT COMPUTED YET"
|
|
497
612
|
|
|
498
613
|
xr_dataset = xr_dataset.rename(
|
|
499
614
|
{"line": "owiAzSize", "sample": "owiRaSize"})
|
|
500
615
|
|
|
501
616
|
xr_dataset = xr_dataset.drop_vars(
|
|
502
|
-
[
|
|
503
|
-
|
|
617
|
+
[
|
|
618
|
+
"sigma0_ocean",
|
|
619
|
+
"sigma0",
|
|
620
|
+
"sigma0_ocean_raw",
|
|
621
|
+
"sigma0_raw",
|
|
622
|
+
"ancillary_wind",
|
|
623
|
+
"nesz",
|
|
624
|
+
"spatial_ref",
|
|
625
|
+
]
|
|
626
|
+
)
|
|
627
|
+
if "sigma0_raw__corrected" in xr_dataset:
|
|
504
628
|
xr_dataset = xr_dataset.drop_vars(["sigma0_raw__corrected"])
|
|
505
|
-
xr_dataset = xr_dataset.drop_dims([
|
|
629
|
+
xr_dataset = xr_dataset.drop_dims(["pol"])
|
|
506
630
|
|
|
507
631
|
table_fillValue = {
|
|
508
632
|
"owiWindQuality": -1,
|
|
@@ -521,17 +645,24 @@ def makeL2asOwi(xr_dataset, config):
|
|
|
521
645
|
for var in list(set(xr_dataset.coords.keys()) | set(xr_dataset.keys())):
|
|
522
646
|
encoding[var] = {}
|
|
523
647
|
try:
|
|
524
|
-
encoding[var].update({
|
|
648
|
+
encoding[var].update({"_FillValue": table_fillValue[var]})
|
|
525
649
|
except:
|
|
526
|
-
if
|
|
527
|
-
encoding[var].update({
|
|
650
|
+
if var in ["owiWindSpeed_co", "owiWindSpeed_cross", "owiWindSpeed"]:
|
|
651
|
+
encoding[var].update({"_FillValue": -9999.0})
|
|
528
652
|
else:
|
|
529
|
-
encoding[var].update({
|
|
653
|
+
encoding[var].update({"_FillValue": None})
|
|
530
654
|
|
|
531
655
|
return xr_dataset, encoding
|
|
532
656
|
|
|
533
657
|
|
|
534
|
-
def preprocess(
|
|
658
|
+
def preprocess(
|
|
659
|
+
filename,
|
|
660
|
+
outdir,
|
|
661
|
+
config_path,
|
|
662
|
+
overwrite=False,
|
|
663
|
+
add_gradientsfeatures=False,
|
|
664
|
+
resolution="1000m",
|
|
665
|
+
):
|
|
535
666
|
"""
|
|
536
667
|
Main function to generate L2 product.
|
|
537
668
|
|
|
@@ -558,11 +689,8 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_gradientsfeat
|
|
|
558
689
|
filename)
|
|
559
690
|
|
|
560
691
|
if os.path.exists(config_path):
|
|
561
|
-
with open(config_path,
|
|
562
|
-
config_base = yaml.load(
|
|
563
|
-
file,
|
|
564
|
-
Loader=yaml.FullLoader
|
|
565
|
-
)
|
|
692
|
+
with open(config_path, "r") as file:
|
|
693
|
+
config_base = yaml.load(file, Loader=yaml.FullLoader)
|
|
566
694
|
try:
|
|
567
695
|
# check if sensor is in the config
|
|
568
696
|
config = config_base[sensor]
|
|
@@ -570,15 +698,20 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_gradientsfeat
|
|
|
570
698
|
raise KeyError("sensor %s not in this config" % sensor)
|
|
571
699
|
else:
|
|
572
700
|
raise FileNotFoundError(
|
|
573
|
-
|
|
701
|
+
"config_path do not exists, got %s " % config_path)
|
|
574
702
|
|
|
575
703
|
recalibration = config["recalibration"]
|
|
576
704
|
meta = fct_meta(filename)
|
|
577
705
|
|
|
578
706
|
# si une des deux n'est pas VV VH HH HV on ne fait rien
|
|
579
|
-
if not all([pol in ["VV", "VH", "HH", "HV"] for pol in meta.pols.split(
|
|
707
|
+
if not all([pol in ["VV", "VH", "HH", "HV"] for pol in meta.pols.split(" ")]):
|
|
580
708
|
raise ValueError(f"Polarisation non gérée : meta.pols = {meta.pols}")
|
|
581
709
|
|
|
710
|
+
overwrite_cfg = config_base.get("overwrite", None)
|
|
711
|
+
# If overwrite is specified in config, it will overwrite the value given as argument (which defaults to False)
|
|
712
|
+
if overwrite_cfg is not None:
|
|
713
|
+
overwrite = overwrite_cfg
|
|
714
|
+
|
|
582
715
|
no_subdir_cfg = config_base.get("no_subdir", False)
|
|
583
716
|
config["no_subdir"] = no_subdir_cfg
|
|
584
717
|
|
|
@@ -587,39 +720,53 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_gradientsfeat
|
|
|
587
720
|
else:
|
|
588
721
|
winddir_convention = "meteorological"
|
|
589
722
|
logging.warning(
|
|
590
|
-
f'Using meteorological convention because "winddir_convention" was not found in config.'
|
|
723
|
+
f'Using meteorological convention because "winddir_convention" was not found in config.'
|
|
724
|
+
)
|
|
591
725
|
config["winddir_convention"] = winddir_convention
|
|
592
726
|
|
|
593
727
|
if "add_gradientsfeatures" in config_base:
|
|
594
728
|
add_gradientsfeatures = config_base["add_gradientsfeatures"]
|
|
595
729
|
else:
|
|
596
730
|
add_gradientsfeatures = False
|
|
597
|
-
logging.warning(
|
|
598
|
-
f'Not computing gradients by default')
|
|
731
|
+
logging.warning(f"Not computing gradients by default")
|
|
599
732
|
config["add_gradientsfeatures"] = add_gradientsfeatures
|
|
600
733
|
|
|
601
734
|
if "add_nrcs_model" in config_base:
|
|
602
735
|
add_nrcs_model = config_base["add_nrcs_model"]
|
|
603
736
|
add_nrcs_model = False
|
|
604
737
|
logging.warning(
|
|
605
|
-
f
|
|
606
|
-
)
|
|
738
|
+
f"Force add_nrcs_model to be false, before fixing an issue")
|
|
607
739
|
else:
|
|
608
740
|
add_nrcs_model = False
|
|
609
|
-
logging.warning(
|
|
610
|
-
f'Not computing nrcs from model by default')
|
|
741
|
+
logging.warning(f"Not computing nrcs from model by default")
|
|
611
742
|
config["add_nrcs_model"] = add_nrcs_model
|
|
612
743
|
|
|
613
744
|
# creating a dictionnary of parameters
|
|
614
745
|
config["l2_params"] = {}
|
|
615
746
|
|
|
616
|
-
meta_start_date =
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
747
|
+
meta_start_date = (
|
|
748
|
+
meta.start_date.split(".")[0]
|
|
749
|
+
.replace("-", "")
|
|
750
|
+
.replace(":", "")
|
|
751
|
+
.replace(" ", "t")
|
|
752
|
+
.replace("Z", "")
|
|
753
|
+
)
|
|
754
|
+
meta_stop_date = (
|
|
755
|
+
meta.stop_date.split(".")[0]
|
|
756
|
+
.replace("-", "")
|
|
757
|
+
.replace(":", "")
|
|
758
|
+
.replace(" ", "t")
|
|
759
|
+
.replace("Z", "")
|
|
760
|
+
)
|
|
620
761
|
|
|
621
|
-
out_file = getOutputName(
|
|
622
|
-
|
|
762
|
+
out_file = getOutputName(
|
|
763
|
+
filename,
|
|
764
|
+
outdir,
|
|
765
|
+
sensor,
|
|
766
|
+
meta_start_date,
|
|
767
|
+
meta_stop_date,
|
|
768
|
+
subdir=not no_subdir_cfg,
|
|
769
|
+
)
|
|
623
770
|
|
|
624
771
|
if os.path.exists(out_file) and overwrite is False:
|
|
625
772
|
raise FileExistsError("outfile %s already exists" % out_file)
|
|
@@ -628,37 +775,48 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_gradientsfeat
|
|
|
628
775
|
map_model = getAncillary(meta, ancillary_name)
|
|
629
776
|
if map_model is None:
|
|
630
777
|
raise Exception(
|
|
631
|
-
f"the weather model is not set `map_model` is None -> you probably don't have access to {ancillary_name} archive"
|
|
778
|
+
f"the weather model is not set `map_model` is None -> you probably don't have access to {ancillary_name} archive"
|
|
779
|
+
)
|
|
632
780
|
|
|
633
781
|
try:
|
|
634
|
-
if (
|
|
782
|
+
if (recalibration) & ("SENTINEL" in sensor_longname):
|
|
635
783
|
logging.info(
|
|
636
|
-
f
|
|
784
|
+
f"recalibration is {recalibration} : Kersten formula is applied"
|
|
785
|
+
)
|
|
637
786
|
xsar_dataset = fct_dataset(
|
|
638
|
-
meta, resolution=resolution, recalibration=recalibration
|
|
639
|
-
|
|
640
|
-
xr_dataset =
|
|
641
|
-
|
|
787
|
+
meta, resolution=resolution, recalibration=recalibration
|
|
788
|
+
)
|
|
789
|
+
xr_dataset = xsar_dataset.datatree["measurement"].to_dataset()
|
|
790
|
+
xr_dataset = xr_dataset.merge(
|
|
791
|
+
xsar_dataset.datatree["recalibration"].to_dataset()[
|
|
792
|
+
["swath_number", "swath_number_flag", "sigma0_raw__corrected"]
|
|
793
|
+
]
|
|
794
|
+
)
|
|
642
795
|
|
|
643
796
|
else:
|
|
644
797
|
logging.info(
|
|
645
|
-
f
|
|
646
|
-
|
|
798
|
+
f"recalibration is {recalibration} : Kersten formula is not applied"
|
|
799
|
+
)
|
|
800
|
+
if "SENTINEL" in sensor_longname:
|
|
647
801
|
xsar_dataset = fct_dataset(
|
|
648
|
-
meta, resolution=resolution, recalibration=recalibration
|
|
649
|
-
|
|
650
|
-
xr_dataset =
|
|
651
|
-
|
|
802
|
+
meta, resolution=resolution, recalibration=recalibration
|
|
803
|
+
)
|
|
804
|
+
xr_dataset = xsar_dataset.datatree["measurement"].to_dataset()
|
|
805
|
+
xr_dataset = xr_dataset.merge(
|
|
806
|
+
xsar_dataset.datatree["recalibration"].to_dataset()[
|
|
807
|
+
["swath_number", "swath_number_flag"]
|
|
808
|
+
]
|
|
809
|
+
)
|
|
652
810
|
|
|
653
811
|
else:
|
|
654
812
|
xsar_dataset = fct_dataset(meta, resolution=resolution)
|
|
655
|
-
xr_dataset = xsar_dataset.datatree[
|
|
813
|
+
xr_dataset = xsar_dataset.datatree["measurement"].to_dataset()
|
|
656
814
|
|
|
657
815
|
xr_dataset = xr_dataset.rename(map_model)
|
|
658
816
|
xr_dataset.attrs = xsar_dataset.dataset.attrs
|
|
659
817
|
|
|
660
818
|
except Exception as e:
|
|
661
|
-
logging.info(
|
|
819
|
+
logging.info("%s", traceback.format_exc())
|
|
662
820
|
logging.error(e)
|
|
663
821
|
sys.exit(-1)
|
|
664
822
|
|
|
@@ -676,22 +834,24 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_gradientsfeat
|
|
|
676
834
|
else:
|
|
677
835
|
dual_pol = False
|
|
678
836
|
|
|
679
|
-
if
|
|
680
|
-
copol =
|
|
681
|
-
crosspol =
|
|
682
|
-
copol_gmf =
|
|
683
|
-
crosspol_gmf =
|
|
837
|
+
if "VV" in xr_dataset.pol.values:
|
|
838
|
+
copol = "VV"
|
|
839
|
+
crosspol = "VH"
|
|
840
|
+
copol_gmf = "VV"
|
|
841
|
+
crosspol_gmf = "VH"
|
|
684
842
|
else:
|
|
685
|
-
logging.warning(
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
843
|
+
logging.warning(
|
|
844
|
+
"for now this processor does not support entirely HH+HV acquisitions\n "
|
|
845
|
+
"it wont crash but it will use HH+VH GMF for wind inversion -> wrong hypothesis\n "
|
|
846
|
+
"!! dual WIND SPEED IS NOT USABLE !! But co WIND SPEED IS USABLE !!"
|
|
847
|
+
)
|
|
848
|
+
copol = "HH"
|
|
849
|
+
crosspol = "HV"
|
|
850
|
+
copol_gmf = "HH"
|
|
851
|
+
crosspol_gmf = "VH"
|
|
692
852
|
|
|
693
|
-
model_co = config["GMF_"+copol_gmf+"_NAME"]
|
|
694
|
-
model_cross = config["GMF_"+crosspol_gmf+"_NAME"]
|
|
853
|
+
model_co = config["GMF_" + copol_gmf + "_NAME"]
|
|
854
|
+
model_cross = config["GMF_" + crosspol_gmf + "_NAME"]
|
|
695
855
|
|
|
696
856
|
# register paramaters in config
|
|
697
857
|
config["l2_params"]["dual_pol"] = dual_pol
|
|
@@ -710,16 +870,37 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_gradientsfeat
|
|
|
710
870
|
if len(nc_luts) > 0:
|
|
711
871
|
windspeed.register_nc_luts(getConf()["nc_luts_path"])
|
|
712
872
|
|
|
713
|
-
if
|
|
873
|
+
if model_co == "gmf_cmod7":
|
|
714
874
|
windspeed.register_cmod7(getConf()["lut_cmod7_path"])
|
|
715
875
|
# Step 2 - clean and prepare dataset
|
|
716
876
|
|
|
717
877
|
# variables to not keep in the L2
|
|
718
|
-
black_list = [
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
878
|
+
black_list = [
|
|
879
|
+
"digital_number",
|
|
880
|
+
"gamma0_raw",
|
|
881
|
+
"negz",
|
|
882
|
+
"azimuth_time",
|
|
883
|
+
"slant_range_time",
|
|
884
|
+
"velocity",
|
|
885
|
+
"range_ground_spacing",
|
|
886
|
+
"gamma0",
|
|
887
|
+
"time",
|
|
888
|
+
"nd_co",
|
|
889
|
+
"nd_cr",
|
|
890
|
+
"gamma0_lut",
|
|
891
|
+
"sigma0_lut",
|
|
892
|
+
"noise_lut_range",
|
|
893
|
+
"lineSpacing",
|
|
894
|
+
"sampleSpacing",
|
|
895
|
+
"noise_lut",
|
|
896
|
+
"noise_lut_azi",
|
|
897
|
+
"nebz",
|
|
898
|
+
"beta0_raw",
|
|
899
|
+
"lines_flipped",
|
|
900
|
+
"samples_flipped",
|
|
901
|
+
"altitude",
|
|
902
|
+
"beta0",
|
|
903
|
+
]
|
|
723
904
|
variables = list(set(xr_dataset) - set(black_list))
|
|
724
905
|
xr_dataset = xr_dataset[variables]
|
|
725
906
|
|
|
@@ -746,122 +927,191 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_gradientsfeat
|
|
|
746
927
|
# TOREMOVE
|
|
747
928
|
if "offboresight" in xr_dataset:
|
|
748
929
|
xr_dataset.offboresight.attrs["units"] = "degrees"
|
|
749
|
-
xr_dataset.offboresight.attrs["long_name"] =
|
|
930
|
+
xr_dataset.offboresight.attrs["long_name"] = (
|
|
931
|
+
"Offboresight angle at wind cell center"
|
|
932
|
+
)
|
|
750
933
|
xr_dataset.elevation.attrs["standard_name"] = "offboresight"
|
|
751
934
|
|
|
752
935
|
# masks (no ice / no_valid)
|
|
753
|
-
xr_dataset.land_mask.values = binary_dilation(
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
xr_dataset.land_mask.attrs[
|
|
936
|
+
xr_dataset.land_mask.values = binary_dilation(
|
|
937
|
+
xr_dataset["land_mask"].values.astype("uint8"),
|
|
938
|
+
structure=np.ones((3, 3), np.uint8),
|
|
939
|
+
iterations=3,
|
|
940
|
+
)
|
|
941
|
+
xr_dataset.land_mask.attrs["long_name"] = "Mask of data"
|
|
942
|
+
xr_dataset.land_mask.attrs["valid_range"] = np.array([0, 1])
|
|
943
|
+
xr_dataset.land_mask.attrs["flag_values"] = np.array([0, 1])
|
|
944
|
+
xr_dataset.land_mask.attrs["flag_meanings"] = "valid no_valid"
|
|
759
945
|
|
|
760
946
|
logging.debug("mask is a copy of land_mask")
|
|
761
947
|
|
|
762
|
-
xr_dataset[
|
|
948
|
+
xr_dataset["mask"] = xr.DataArray(xr_dataset.land_mask)
|
|
763
949
|
xr_dataset.mask.attrs = {}
|
|
764
|
-
xr_dataset.mask.attrs[
|
|
765
|
-
xr_dataset.mask.attrs[
|
|
766
|
-
xr_dataset.mask.attrs[
|
|
767
|
-
xr_dataset.mask.attrs[
|
|
950
|
+
xr_dataset.mask.attrs["long_name"] = "Mask of data"
|
|
951
|
+
xr_dataset.mask.attrs["valid_range"] = np.array([0, 3])
|
|
952
|
+
xr_dataset.mask.attrs["flag_values"] = np.array([0, 1, 2, 3])
|
|
953
|
+
xr_dataset.mask.attrs["flag_meanings"] = "valid land ice no_valid"
|
|
768
954
|
|
|
769
955
|
# ancillary
|
|
770
|
-
xr_dataset[
|
|
771
|
-
90. - np.rad2deg(np.arctan2(xr_dataset.model_V10,
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
xr_dataset[
|
|
778
|
-
xr_dataset[
|
|
779
|
-
|
|
780
|
-
xr_dataset[
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
xr_dataset[
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
xr_dataset[
|
|
792
|
-
|
|
793
|
-
xr_dataset[
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
956
|
+
xr_dataset["ancillary_wind_direction"] = (
|
|
957
|
+
90.0 - np.rad2deg(np.arctan2(xr_dataset.model_V10,
|
|
958
|
+
xr_dataset.model_U10)) + 180
|
|
959
|
+
) % 360
|
|
960
|
+
|
|
961
|
+
xr_dataset["ancillary_wind_direction"] = xr.where(
|
|
962
|
+
xr_dataset["mask"], np.nan, xr_dataset["ancillary_wind_direction"]
|
|
963
|
+
).transpose(*xr_dataset["ancillary_wind_direction"].dims)
|
|
964
|
+
xr_dataset["ancillary_wind_direction"].attrs = {}
|
|
965
|
+
xr_dataset["ancillary_wind_direction"].attrs["units"] = "degrees_north"
|
|
966
|
+
xr_dataset["ancillary_wind_direction"].attrs[
|
|
967
|
+
"long_name"
|
|
968
|
+
] = f"{ancillary_name} wind direction in meteorological convention (clockwise, from), ex: 0°=from north, 90°=from east"
|
|
969
|
+
xr_dataset["ancillary_wind_direction"].attrs["standart_name"] = "wind_direction"
|
|
970
|
+
|
|
971
|
+
xr_dataset["ancillary_wind_speed"] = np.sqrt(
|
|
972
|
+
xr_dataset["model_U10"] ** 2 + xr_dataset["model_V10"] ** 2
|
|
973
|
+
)
|
|
974
|
+
xr_dataset["ancillary_wind_speed"] = xr.where(
|
|
975
|
+
xr_dataset["mask"], np.nan, xr_dataset["ancillary_wind_speed"]
|
|
976
|
+
).transpose(*xr_dataset["ancillary_wind_speed"].dims)
|
|
977
|
+
xr_dataset["ancillary_wind_speed"].attrs = {}
|
|
978
|
+
xr_dataset["ancillary_wind_speed"].attrs["units"] = "m s^-1"
|
|
979
|
+
xr_dataset["ancillary_wind_speed"].attrs[
|
|
980
|
+
"long_name"
|
|
981
|
+
] = f"{ancillary_name} wind speed"
|
|
982
|
+
xr_dataset["ancillary_wind_speed"].attrs["standart_name"] = "wind_speed"
|
|
983
|
+
|
|
984
|
+
xr_dataset["ancillary_wind"] = xr.where(
|
|
985
|
+
xr_dataset["mask"],
|
|
986
|
+
np.nan,
|
|
987
|
+
(
|
|
988
|
+
xr_dataset.ancillary_wind_speed
|
|
989
|
+
* np.exp(
|
|
990
|
+
1j
|
|
991
|
+
* xsarsea.dir_meteo_to_sample(
|
|
992
|
+
xr_dataset.ancillary_wind_direction, xr_dataset.ground_heading
|
|
993
|
+
)
|
|
994
|
+
)
|
|
995
|
+
),
|
|
996
|
+
).transpose(*xr_dataset["ancillary_wind_speed"].dims)
|
|
997
|
+
|
|
998
|
+
xr_dataset.attrs["ancillary_source"] = (
|
|
999
|
+
xr_dataset["model_U10"].attrs["history"].split("decoded: ")[1].strip()
|
|
1000
|
+
)
|
|
1001
|
+
xr_dataset = xr_dataset.drop_vars(["model_U10", "model_V10"])
|
|
800
1002
|
|
|
801
1003
|
# nrcs processing
|
|
802
|
-
xr_dataset[
|
|
803
|
-
|
|
804
|
-
|
|
1004
|
+
xr_dataset["sigma0_ocean"] = xr.where(
|
|
1005
|
+
xr_dataset["mask"], np.nan, xr_dataset["sigma0"]
|
|
1006
|
+
).transpose(*xr_dataset["sigma0"].dims)
|
|
1007
|
+
xr_dataset["sigma0_ocean"].attrs = xr_dataset["sigma0"].attrs
|
|
805
1008
|
# we forced it to 1e-15
|
|
806
|
-
xr_dataset[
|
|
1009
|
+
xr_dataset["sigma0_ocean"].attrs[
|
|
1010
|
+
"comment"
|
|
1011
|
+
] = "clipped, no values <=0 ; 1e-15 instread"
|
|
807
1012
|
|
|
808
1013
|
# rajout d'un mask pour les valeurs <=0:
|
|
809
|
-
xr_dataset[
|
|
810
|
-
xr_dataset[
|
|
811
|
-
xr_dataset
|
|
812
|
-
xr_dataset.sigma0_mask.attrs[
|
|
813
|
-
xr_dataset.sigma0_mask.attrs[
|
|
814
|
-
xr_dataset[
|
|
815
|
-
|
|
1014
|
+
xr_dataset["sigma0_mask"] = xr.where(
|
|
1015
|
+
xr_dataset["sigma0_ocean"] <= 0, 1, 0
|
|
1016
|
+
).transpose(*xr_dataset["sigma0"].dims)
|
|
1017
|
+
xr_dataset.sigma0_mask.attrs["valid_range"] = np.array([0, 1])
|
|
1018
|
+
xr_dataset.sigma0_mask.attrs["flag_values"] = np.array([0, 1])
|
|
1019
|
+
xr_dataset.sigma0_mask.attrs["flag_meanings"] = "valid no_valid"
|
|
1020
|
+
xr_dataset["sigma0_ocean"] = xr.where(
|
|
1021
|
+
xr_dataset["sigma0_ocean"] <= 0, 1e-15, xr_dataset["sigma0_ocean"]
|
|
1022
|
+
)
|
|
816
1023
|
|
|
817
|
-
xr_dataset[
|
|
818
|
-
|
|
1024
|
+
xr_dataset["sigma0_ocean_raw"] = xr.where(
|
|
1025
|
+
xr_dataset["mask"], np.nan, xr_dataset["sigma0_raw"]
|
|
1026
|
+
).transpose(*xr_dataset["sigma0_raw"].dims)
|
|
819
1027
|
|
|
820
|
-
xr_dataset[
|
|
1028
|
+
xr_dataset["sigma0_ocean_raw"].attrs = xr_dataset["sigma0_raw"].attrs
|
|
821
1029
|
|
|
822
|
-
xr_dataset[
|
|
823
|
-
xr_dataset.sigma0.sel(pol=copol), xr_dataset.incidence, model=model_co
|
|
1030
|
+
xr_dataset["sigma0_detrend"] = xsarsea.sigma0_detrend(
|
|
1031
|
+
xr_dataset.sigma0.sel(pol=copol), xr_dataset.incidence, model=model_co
|
|
1032
|
+
)
|
|
824
1033
|
|
|
825
1034
|
# processing
|
|
826
1035
|
if dual_pol:
|
|
827
1036
|
|
|
828
1037
|
xr_dataset['sigma0_detrend_cross'] = xsarsea.sigma0_detrend(
|
|
829
1038
|
xr_dataset.sigma0.sel(pol=crosspol), xr_dataset.incidence, model=model_cross)
|
|
1039
|
+
|
|
1040
|
+
xr_dataset = xr_dataset.assign(nesz_cross_flattened=(
|
|
1041
|
+
['line', 'sample'], windspeed.nesz_flattening(xr_dataset.nesz.sel(pol=crosspol), xr_dataset.incidence).data))
|
|
1042
|
+
|
|
1043
|
+
xr_dataset['nesz_cross_flattened'].attrs[
|
|
1044
|
+
"comment"] = 'nesz has been flattened using windspeed.nesz_flattening'
|
|
1045
|
+
|
|
830
1046
|
if config["apply_flattening"]:
|
|
831
|
-
xr_dataset = xr_dataset.assign(nesz_cross_flattened=(
|
|
832
|
-
['line', 'sample'], windspeed.nesz_flattening(xr_dataset.nesz.sel(pol=crosspol), xr_dataset.incidence).data))
|
|
833
|
-
xr_dataset['nesz_cross_flattened'].attrs[
|
|
834
|
-
"comment"] = 'nesz has been flattened using windspeed.nesz_flattening'
|
|
835
1047
|
# dsig
|
|
836
|
-
xr_dataset["dsig_cross"] = windspeed.get_dsig(
|
|
837
|
-
|
|
1048
|
+
xr_dataset["dsig_cross"] = windspeed.get_dsig(
|
|
1049
|
+
config["dsig_" + crosspol_gmf + "_NAME"],
|
|
1050
|
+
xr_dataset.incidence,
|
|
1051
|
+
xr_dataset["sigma0_ocean"].sel(pol=crosspol),
|
|
1052
|
+
xr_dataset.nesz_cross_flattened,
|
|
1053
|
+
)
|
|
1054
|
+
|
|
1055
|
+
xr_dataset.dsig_cross.attrs["formula_used"] = config[
|
|
1056
|
+
"dsig_" + crosspol_gmf + "_NAME"
|
|
1057
|
+
]
|
|
1058
|
+
|
|
838
1059
|
else:
|
|
839
1060
|
# dsig
|
|
840
|
-
xr_dataset["dsig_cross"] = windspeed.get_dsig(
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
1061
|
+
xr_dataset["dsig_cross"] = windspeed.get_dsig(
|
|
1062
|
+
config["dsig_" + crosspol_gmf + "_NAME"],
|
|
1063
|
+
xr_dataset.incidence,
|
|
1064
|
+
xr_dataset["sigma0_ocean"].sel(pol=crosspol),
|
|
1065
|
+
xr_dataset.nesz.sel(pol=crosspol),
|
|
1066
|
+
)
|
|
1067
|
+
|
|
1068
|
+
xr_dataset.dsig_cross.attrs["comment"] = (
|
|
1069
|
+
"variable used to ponderate copol and crosspol"
|
|
1070
|
+
)
|
|
1071
|
+
|
|
1072
|
+
xr_dataset.dsig_cross.attrs["apply_flattening"] = str(
|
|
1073
|
+
config["apply_flattening"]
|
|
1074
|
+
)
|
|
1075
|
+
|
|
1076
|
+
if (recalibration) & ("SENTINEL" in sensor_longname):
|
|
1077
|
+
xr_dataset.attrs["path_aux_pp1_new"] = os.path.basename(
|
|
1078
|
+
os.path.dirname(
|
|
1079
|
+
os.path.dirname(
|
|
1080
|
+
xsar_dataset.datatree["recalibration"].attrs["path_aux_pp1_new"]
|
|
1081
|
+
)
|
|
1082
|
+
)
|
|
1083
|
+
)
|
|
1084
|
+
xr_dataset.attrs["path_aux_cal_new"] = os.path.basename(
|
|
1085
|
+
os.path.dirname(
|
|
1086
|
+
os.path.dirname(
|
|
1087
|
+
xsar_dataset.datatree["recalibration"].attrs["path_aux_cal_new"]
|
|
1088
|
+
)
|
|
1089
|
+
)
|
|
1090
|
+
)
|
|
1091
|
+
|
|
1092
|
+
xr_dataset.attrs["path_aux_pp1_old"] = os.path.basename(
|
|
1093
|
+
os.path.dirname(
|
|
1094
|
+
os.path.dirname(
|
|
1095
|
+
xsar_dataset.datatree["recalibration"].attrs["path_aux_pp1_old"]
|
|
1096
|
+
)
|
|
1097
|
+
)
|
|
1098
|
+
)
|
|
1099
|
+
xr_dataset.attrs["path_aux_cal_old"] = os.path.basename(
|
|
1100
|
+
os.path.dirname(
|
|
1101
|
+
os.path.dirname(
|
|
1102
|
+
xsar_dataset.datatree["recalibration"].attrs["path_aux_cal_old"]
|
|
1103
|
+
)
|
|
1104
|
+
)
|
|
1105
|
+
)
|
|
859
1106
|
|
|
860
1107
|
if add_nrcs_model:
|
|
861
1108
|
# add timing
|
|
862
1109
|
phi = np.abs(
|
|
863
|
-
np.rad2deg(
|
|
864
|
-
|
|
1110
|
+
np.rad2deg(
|
|
1111
|
+
xsarsea.dir_meteo_to_sample(
|
|
1112
|
+
xr_dataset["ancillary_wind_direction"], xr_dataset["ground_heading"]
|
|
1113
|
+
)
|
|
1114
|
+
)
|
|
865
1115
|
)
|
|
866
1116
|
|
|
867
1117
|
varnames = ["ancillary_nrcs"]
|
|
@@ -883,9 +1133,7 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_gradientsfeat
|
|
|
883
1133
|
incidence=incidence, wspd=wspd, phi=phi, method="nearest"
|
|
884
1134
|
)
|
|
885
1135
|
else:
|
|
886
|
-
return lut.sel(
|
|
887
|
-
incidence=incidence, wspd=wspd, method="nearest"
|
|
888
|
-
)
|
|
1136
|
+
return lut.sel(incidence=incidence, wspd=wspd, method="nearest")
|
|
889
1137
|
|
|
890
1138
|
xr_dataset[varnames[idx]] = xr.apply_ufunc(
|
|
891
1139
|
lut_selection,
|
|
@@ -937,38 +1185,46 @@ def process_gradients(xr_dataset, config):
|
|
|
937
1185
|
dual_pol = config["l2_params"]["dual_pol"]
|
|
938
1186
|
|
|
939
1187
|
# Load the 100m dataset
|
|
940
|
-
xsar_dataset_100 = fct_dataset(
|
|
941
|
-
meta, resolution='100m')
|
|
1188
|
+
xsar_dataset_100 = fct_dataset(meta, resolution="100m")
|
|
942
1189
|
|
|
943
|
-
xr_dataset_100 = xsar_dataset_100.datatree[
|
|
1190
|
+
xr_dataset_100 = xsar_dataset_100.datatree["measurement"].to_dataset()
|
|
944
1191
|
xr_dataset_100 = xr_dataset_100.rename(map_model)
|
|
945
1192
|
# load dataset
|
|
946
1193
|
xr_dataset_100 = xr_dataset_100.load()
|
|
947
1194
|
|
|
948
1195
|
# adding sigma0 detrend
|
|
949
|
-
xr_dataset_100[
|
|
950
|
-
xr_dataset_100.sigma0.sel(pol=copol), xr_dataset_100.incidence, model=model_co
|
|
1196
|
+
xr_dataset_100["sigma0_detrend"] = xsarsea.sigma0_detrend(
|
|
1197
|
+
xr_dataset_100.sigma0.sel(pol=copol), xr_dataset_100.incidence, model=model_co
|
|
1198
|
+
)
|
|
951
1199
|
|
|
952
1200
|
if dual_pol:
|
|
953
|
-
xr_dataset_100[
|
|
954
|
-
xr_dataset_100.sigma0.sel(pol=crosspol),
|
|
1201
|
+
xr_dataset_100["sigma0_detrend_cross"] = xsarsea.sigma0_detrend(
|
|
1202
|
+
xr_dataset_100.sigma0.sel(pol=crosspol),
|
|
1203
|
+
xr_dataset_100.incidence,
|
|
1204
|
+
model=model_cross,
|
|
1205
|
+
)
|
|
955
1206
|
|
|
956
1207
|
sigma0_detrend_combined = xr.concat(
|
|
957
|
-
[xr_dataset_100[
|
|
958
|
-
xr_dataset_100[
|
|
959
|
-
dim=
|
|
1208
|
+
[xr_dataset_100["sigma0_detrend"],
|
|
1209
|
+
xr_dataset_100["sigma0_detrend_cross"]],
|
|
1210
|
+
dim="pol",
|
|
960
1211
|
)
|
|
961
|
-
sigma0_detrend_combined[
|
|
1212
|
+
sigma0_detrend_combined["pol"] = [copol, crosspol]
|
|
962
1213
|
|
|
963
|
-
xr_dataset_100[
|
|
1214
|
+
xr_dataset_100["sigma0_detrend"] = sigma0_detrend_combined
|
|
964
1215
|
|
|
965
|
-
xr_dataset_100.land_mask.values = binary_dilation(
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
1216
|
+
xr_dataset_100.land_mask.values = binary_dilation(
|
|
1217
|
+
xr_dataset_100["land_mask"].values.astype("uint8"),
|
|
1218
|
+
structure=np.ones((3, 3), np.uint8),
|
|
1219
|
+
iterations=3,
|
|
1220
|
+
)
|
|
1221
|
+
xr_dataset_100["sigma0_detrend"] = xr.where(
|
|
1222
|
+
xr_dataset_100["land_mask"], np.nan, xr_dataset_100["sigma0"]
|
|
1223
|
+
).transpose(*xr_dataset_100["sigma0"].dims)
|
|
969
1224
|
|
|
970
|
-
xr_dataset_100[
|
|
971
|
-
xr_dataset_100.model_U10 + 1j * xr_dataset_100.model_V10
|
|
1225
|
+
xr_dataset_100["ancillary_wind"] = (
|
|
1226
|
+
xr_dataset_100.model_U10 + 1j * xr_dataset_100.model_V10
|
|
1227
|
+
) * np.exp(1j * np.deg2rad(xr_dataset_100.ground_heading))
|
|
972
1228
|
|
|
973
1229
|
downscales_factors = [1, 2, 4, 8]
|
|
974
1230
|
# 4 and 8 must be in downscales_factors
|
|
@@ -979,7 +1235,7 @@ def process_gradients(xr_dataset, config):
|
|
|
979
1235
|
xr_dataset_100=xr_dataset_100,
|
|
980
1236
|
windows_sizes=[1600, 3200],
|
|
981
1237
|
downscales_factors=downscales_factors,
|
|
982
|
-
window_step=1
|
|
1238
|
+
window_step=1,
|
|
983
1239
|
)
|
|
984
1240
|
|
|
985
1241
|
# Compute heterogeneity mask and variables
|
|
@@ -988,24 +1244,29 @@ def process_gradients(xr_dataset, config):
|
|
|
988
1244
|
|
|
989
1245
|
# Add streaks dataset
|
|
990
1246
|
streaks_indiv = gradientFeatures.streaks_individual()
|
|
991
|
-
if
|
|
992
|
-
xr_dataset_streaks = xr.Dataset(
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1247
|
+
if "longitude" in streaks_indiv:
|
|
1248
|
+
xr_dataset_streaks = xr.Dataset(
|
|
1249
|
+
{
|
|
1250
|
+
"longitude": streaks_indiv.longitude,
|
|
1251
|
+
"latitude": streaks_indiv.latitude,
|
|
1252
|
+
"dir_smooth": streaks_indiv.angle,
|
|
1253
|
+
"dir_mean_smooth": gradientFeatures.streaks_mean_smooth().angle,
|
|
1254
|
+
"dir_smooth_mean": gradientFeatures.streaks_smooth_mean().angle,
|
|
1255
|
+
}
|
|
1256
|
+
)
|
|
999
1257
|
else:
|
|
1000
1258
|
logger.warn(
|
|
1001
|
-
"'longitude' not found in streaks_indiv : there is probably an error"
|
|
1259
|
+
"'longitude' not found in streaks_indiv : there is probably an error"
|
|
1260
|
+
)
|
|
1002
1261
|
xr_dataset_streaks = None
|
|
1003
1262
|
|
|
1004
1263
|
return xr_dataset, xr_dataset_streaks
|
|
1005
1264
|
|
|
1006
1265
|
|
|
1007
1266
|
@timing(logger=logger.info)
|
|
1008
|
-
def makeL2(
|
|
1267
|
+
def makeL2(
|
|
1268
|
+
filename, outdir, config_path, overwrite=False, generateCSV=True, resolution="1000m"
|
|
1269
|
+
):
|
|
1009
1270
|
"""
|
|
1010
1271
|
Main function to generate L2 product.
|
|
1011
1272
|
|
|
@@ -1033,11 +1294,11 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, res
|
|
|
1033
1294
|
"""
|
|
1034
1295
|
|
|
1035
1296
|
xr_dataset, out_file, config = preprocess(
|
|
1036
|
-
filename, outdir, config_path, overwrite, resolution
|
|
1297
|
+
filename, outdir, config_path, overwrite, resolution
|
|
1298
|
+
)
|
|
1037
1299
|
|
|
1038
1300
|
if config["add_gradientsfeatures"]:
|
|
1039
|
-
xr_dataset, xr_dataset_streaks = process_gradients(
|
|
1040
|
-
xr_dataset, config)
|
|
1301
|
+
xr_dataset, xr_dataset_streaks = process_gradients(xr_dataset, config)
|
|
1041
1302
|
else:
|
|
1042
1303
|
xr_dataset_streaks = None
|
|
1043
1304
|
|
|
@@ -1052,8 +1313,8 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, res
|
|
|
1052
1313
|
sensor_longname = config["sensor_longname"]
|
|
1053
1314
|
|
|
1054
1315
|
if dual_pol:
|
|
1055
|
-
sigma0_ocean_cross = xr_dataset[
|
|
1056
|
-
dsig_cross = xr_dataset[
|
|
1316
|
+
sigma0_ocean_cross = xr_dataset["sigma0_ocean"].sel(pol=crosspol)
|
|
1317
|
+
dsig_cross = xr_dataset["dsig_cross"]
|
|
1057
1318
|
else:
|
|
1058
1319
|
sigma0_ocean_cross = None
|
|
1059
1320
|
dsig_cross = 0.1 # default value set in xsarsea
|
|
@@ -1071,97 +1332,119 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, res
|
|
|
1071
1332
|
logging.info("Checking incidence range within LUTS incidence range")
|
|
1072
1333
|
# warning if incidence is out of lut incidence range
|
|
1073
1334
|
inc_check_co, inc_check_cross = check_incidence_range(
|
|
1074
|
-
xr_dataset[
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1335
|
+
xr_dataset["incidence"], [model_co, model_cross], **kwargs
|
|
1336
|
+
)
|
|
1337
|
+
|
|
1338
|
+
wind_co, wind_dual, windspeed_cr = inverse(
|
|
1339
|
+
dual_pol,
|
|
1340
|
+
inc=xr_dataset["incidence"],
|
|
1341
|
+
sigma0=xr_dataset["sigma0_ocean"].sel(pol=copol),
|
|
1342
|
+
sigma0_dual=sigma0_ocean_cross,
|
|
1343
|
+
ancillary_wind=xr_dataset["ancillary_wind"],
|
|
1344
|
+
dsig_cr=dsig_cross,
|
|
1345
|
+
model_co=model_co,
|
|
1346
|
+
model_cross=model_cross,
|
|
1347
|
+
**kwargs,
|
|
1348
|
+
)
|
|
1086
1349
|
# windspeed_co
|
|
1087
|
-
xr_dataset[
|
|
1350
|
+
xr_dataset["windspeed_co"] = np.abs(wind_co)
|
|
1088
1351
|
xr_dataset["windspeed_co"].attrs["units"] = "m.s⁻1"
|
|
1089
|
-
xr_dataset["windspeed_co"].attrs["long_name"] =
|
|
1090
|
-
model_co, copol)
|
|
1352
|
+
xr_dataset["windspeed_co"].attrs["long_name"] = (
|
|
1353
|
+
"Wind speed inverted from model %s (%s)" % (model_co, copol)
|
|
1354
|
+
)
|
|
1091
1355
|
xr_dataset["windspeed_co"].attrs["standart_name"] = "wind_speed"
|
|
1092
1356
|
xr_dataset["windspeed_co"].attrs["model"] = wind_co.attrs["model"]
|
|
1093
|
-
del xr_dataset["windspeed_co"].attrs[
|
|
1357
|
+
del xr_dataset["windspeed_co"].attrs["comment"]
|
|
1094
1358
|
|
|
1095
1359
|
# winddir_co
|
|
1096
|
-
xr_dataset[
|
|
1097
|
-
wind_co,
|
|
1098
|
-
|
|
1360
|
+
xr_dataset["winddir_co"] = transform_winddir(
|
|
1361
|
+
wind_co,
|
|
1362
|
+
xr_dataset.ground_heading,
|
|
1363
|
+
winddir_convention=config["winddir_convention"],
|
|
1364
|
+
)
|
|
1365
|
+
xr_dataset["winddir_co"].attrs["model"] = "%s (%s)" % (model_co, copol)
|
|
1099
1366
|
|
|
1100
1367
|
# windspeed_dual / windspeed_cr / /winddir_dual / winddir_cr
|
|
1101
1368
|
if dual_pol and wind_dual is not None:
|
|
1102
|
-
xr_dataset[
|
|
1369
|
+
xr_dataset["windspeed_dual"] = np.abs(wind_dual)
|
|
1103
1370
|
xr_dataset["windspeed_dual"].attrs["units"] = "m.s⁻1"
|
|
1104
|
-
xr_dataset["windspeed_dual"].attrs["long_name"] =
|
|
1105
|
-
|
|
1371
|
+
xr_dataset["windspeed_dual"].attrs["long_name"] = (
|
|
1372
|
+
"Wind speed inverted from model %s (%s) & %s (%s)"
|
|
1373
|
+
% (model_co, copol, model_cross, crosspol)
|
|
1374
|
+
)
|
|
1106
1375
|
xr_dataset["windspeed_dual"].attrs["standart_name"] = "wind_speed"
|
|
1107
1376
|
xr_dataset["windspeed_dual"].attrs["model"] = wind_dual.attrs["model"]
|
|
1108
|
-
del xr_dataset["windspeed_dual"].attrs[
|
|
1377
|
+
del xr_dataset["windspeed_dual"].attrs["comment"]
|
|
1109
1378
|
|
|
1110
|
-
xr_dataset[
|
|
1111
|
-
wind_dual,
|
|
1112
|
-
|
|
1379
|
+
xr_dataset["winddir_dual"] = transform_winddir(
|
|
1380
|
+
wind_dual,
|
|
1381
|
+
xr_dataset.ground_heading,
|
|
1382
|
+
winddir_convention=config["winddir_convention"],
|
|
1383
|
+
)
|
|
1384
|
+
xr_dataset["winddir_dual"].attrs[
|
|
1385
|
+
"model"
|
|
1386
|
+
] = "winddir_dual is a copy of copol wind direction"
|
|
1113
1387
|
|
|
1114
1388
|
xr_dataset = xr_dataset.assign(
|
|
1115
|
-
windspeed_cross=([
|
|
1389
|
+
windspeed_cross=(["line", "sample"], windspeed_cr.data)
|
|
1390
|
+
)
|
|
1116
1391
|
xr_dataset["windspeed_cross"].attrs["units"] = "m.s⁻1"
|
|
1117
|
-
xr_dataset["windspeed_cross"].attrs["long_name"] =
|
|
1118
|
-
model_cross, crosspol)
|
|
1392
|
+
xr_dataset["windspeed_cross"].attrs["long_name"] = (
|
|
1393
|
+
"Wind Speed inverted from model %s (%s)" % (model_cross, crosspol)
|
|
1394
|
+
)
|
|
1119
1395
|
xr_dataset["windspeed_cross"].attrs["standart_name"] = "wind_speed"
|
|
1120
1396
|
xr_dataset["windspeed_cross"].attrs["model"] = "%s" % (model_cross)
|
|
1121
1397
|
|
|
1122
|
-
xr_dataset[
|
|
1123
|
-
xr_dataset[
|
|
1124
|
-
xr_dataset["winddir_cross"].attrs[
|
|
1398
|
+
xr_dataset["winddir_cross"] = xr_dataset["winddir_dual"].copy()
|
|
1399
|
+
xr_dataset["winddir_cross"].attrs = xr_dataset["winddir_dual"].attrs
|
|
1400
|
+
xr_dataset["winddir_cross"].attrs[
|
|
1401
|
+
"model"
|
|
1402
|
+
] = "winddir_cross is a copy of copol wind direction"
|
|
1125
1403
|
|
|
1126
1404
|
if config["winddir_convention"] == "oceanographic":
|
|
1127
|
-
attrs = xr_dataset[
|
|
1128
|
-
xr_dataset[
|
|
1129
|
-
xr_dataset[
|
|
1130
|
-
|
|
1131
|
-
xr_dataset[
|
|
1132
|
-
|
|
1405
|
+
attrs = xr_dataset["ancillary_wind_direction"].attrs
|
|
1406
|
+
xr_dataset["ancillary_wind_direction"] = xsarsea.dir_meteo_to_oceano(
|
|
1407
|
+
xr_dataset["ancillary_wind_direction"]
|
|
1408
|
+
)
|
|
1409
|
+
xr_dataset["ancillary_wind_direction"].attrs = attrs
|
|
1410
|
+
xr_dataset["ancillary_wind_direction"].attrs[
|
|
1411
|
+
"long_name"
|
|
1412
|
+
] = f"{ancillary_name} wind direction in oceanographic convention (clockwise, to), ex: 0°=to north, 90°=to east"
|
|
1133
1413
|
|
|
1134
|
-
xr_dataset, encoding = makeL2asOwi(
|
|
1135
|
-
xr_dataset, config)
|
|
1414
|
+
xr_dataset, encoding = makeL2asOwi(xr_dataset, config)
|
|
1136
1415
|
|
|
1137
1416
|
xr_dataset = xr_dataset.compute()
|
|
1138
1417
|
# add attributes
|
|
1139
1418
|
firstMeasurementTime = None
|
|
1140
1419
|
lastMeasurementTime = None
|
|
1141
1420
|
try:
|
|
1142
|
-
firstMeasurementTime = datetime.datetime.strptime(
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
lastMeasurementTime = datetime.datetime.strptime(
|
|
1146
|
-
|
|
1147
|
-
|
|
1421
|
+
firstMeasurementTime = datetime.datetime.strptime(
|
|
1422
|
+
xr_dataset.attrs["start_date"], "%Y-%m-%d %H:%M:%S.%f"
|
|
1423
|
+
).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
1424
|
+
lastMeasurementTime = datetime.datetime.strptime(
|
|
1425
|
+
xr_dataset.attrs["stop_date"], "%Y-%m-%d %H:%M:%S.%f"
|
|
1426
|
+
).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
1148
1427
|
except:
|
|
1149
|
-
firstMeasurementTime = datetime.datetime.strptime(
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
lastMeasurementTime = datetime.datetime.strptime(
|
|
1153
|
-
|
|
1154
|
-
|
|
1428
|
+
firstMeasurementTime = datetime.datetime.strptime(
|
|
1429
|
+
xr_dataset.attrs["start_date"], "%Y-%m-%d %H:%M:%S"
|
|
1430
|
+
).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
1431
|
+
lastMeasurementTime = datetime.datetime.strptime(
|
|
1432
|
+
xr_dataset.attrs["stop_date"], "%Y-%m-%d %H:%M:%S"
|
|
1433
|
+
).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
1155
1434
|
|
|
1156
1435
|
attrs = {
|
|
1157
1436
|
"TITLE": "Sentinel-1 OWI Component",
|
|
1158
1437
|
"productOwner": "IFREMER",
|
|
1159
|
-
"sourceProduct": (
|
|
1160
|
-
|
|
1438
|
+
"sourceProduct": (
|
|
1439
|
+
xr_dataset.attrs["safe"]
|
|
1440
|
+
if "safe" in xr_dataset.attrs
|
|
1441
|
+
else os.path.basename(xr_dataset.attrs["product_path"])
|
|
1442
|
+
),
|
|
1443
|
+
"sourceProduct_fullpath": xr_dataset.attrs.pop("name"),
|
|
1161
1444
|
"missionName": sensor_longname,
|
|
1162
|
-
"missionPhase":
|
|
1163
|
-
"polarisation": xr_dataset.attrs[
|
|
1164
|
-
"acquisitionStation":
|
|
1445
|
+
"missionPhase": "Operational",
|
|
1446
|
+
"polarisation": xr_dataset.attrs["pols"],
|
|
1447
|
+
"acquisitionStation": "",
|
|
1165
1448
|
"xsar_version": xsar.__version__,
|
|
1166
1449
|
"xsarsea_version": xsarsea.__version__,
|
|
1167
1450
|
"pythonVersion": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
|
|
@@ -1174,25 +1457,32 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, res
|
|
|
1174
1457
|
"bathySource": "/",
|
|
1175
1458
|
"oswAlgorithmName": "grdwindinversion",
|
|
1176
1459
|
"owiAlgorithmVersion": grdwindinversion.__version__,
|
|
1177
|
-
"gmf": config[
|
|
1460
|
+
"gmf": config["GMF_" + copol_gmf + "_NAME"]
|
|
1461
|
+
+ ", "
|
|
1462
|
+
+ config["GMF_" + crosspol_gmf + "_NAME"],
|
|
1178
1463
|
"iceSource": "/",
|
|
1179
1464
|
"owiNoiseCorrection": "True",
|
|
1180
|
-
"inversionTabGMF": config[
|
|
1181
|
-
|
|
1465
|
+
"inversionTabGMF": config["GMF_" + copol_gmf + "_NAME"]
|
|
1466
|
+
+ ", "
|
|
1467
|
+
+ config["GMF_" + crosspol_gmf + "_NAME"],
|
|
1182
1468
|
"wnf_3km_average": "False",
|
|
1183
1469
|
"owiWindSpeedSrc": "owiWindSpeed",
|
|
1184
1470
|
"owiWindDirectionSrc": "/",
|
|
1185
|
-
"ancillary_source": xr_dataset.attrs[
|
|
1471
|
+
"ancillary_source": xr_dataset.attrs["ancillary_source"],
|
|
1186
1472
|
"winddir_convention": config["winddir_convention"],
|
|
1187
1473
|
"incidence_within_lut_copol_incidence_range": str(inc_check_co),
|
|
1188
1474
|
"incidence_within_lut_crosspol_incidence_range": str(inc_check_cross),
|
|
1189
|
-
"swath": xr_dataset.attrs[
|
|
1190
|
-
"footprint": xr_dataset.attrs[
|
|
1191
|
-
"coverage": xr_dataset.attrs[
|
|
1192
|
-
|
|
1475
|
+
"swath": xr_dataset.attrs["swath"],
|
|
1476
|
+
"footprint": xr_dataset.attrs["footprint"],
|
|
1477
|
+
"coverage": xr_dataset.attrs["coverage"],
|
|
1193
1478
|
}
|
|
1194
1479
|
|
|
1195
|
-
for recalib_attrs in [
|
|
1480
|
+
for recalib_attrs in [
|
|
1481
|
+
"path_aux_pp1_new",
|
|
1482
|
+
"path_aux_pp1_old",
|
|
1483
|
+
"path_aux_cal_new",
|
|
1484
|
+
"path_aux_cal_old",
|
|
1485
|
+
]:
|
|
1196
1486
|
if recalib_attrs in xr_dataset.attrs:
|
|
1197
1487
|
attrs[recalib_attrs] = xr_dataset.attrs[recalib_attrs]
|
|
1198
1488
|
|
|
@@ -1207,11 +1497,11 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, res
|
|
|
1207
1497
|
if sup_attr in xr_dataset.attrs:
|
|
1208
1498
|
attrs[sup_attr] = xr_dataset.attrs[sup_attr]
|
|
1209
1499
|
|
|
1210
|
-
attrs[
|
|
1500
|
+
attrs["footprint"] = str(attrs["footprint"])
|
|
1211
1501
|
|
|
1212
1502
|
# add in kwargs in attrs
|
|
1213
1503
|
for key in kwargs:
|
|
1214
|
-
attrs["lut_params_"+key] = "/" if kwargs[key] is None else kwargs[key]
|
|
1504
|
+
attrs["lut_params_" + key] = "/" if kwargs[key] is None else kwargs[key]
|
|
1215
1505
|
|
|
1216
1506
|
xr_dataset.attrs = attrs
|
|
1217
1507
|
|
|
@@ -1250,7 +1540,7 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, res
|
|
|
1250
1540
|
return out_file, xr_dataset
|
|
1251
1541
|
|
|
1252
1542
|
|
|
1253
|
-
def transform_winddir(wind_cpx, ground_heading, winddir_convention=
|
|
1543
|
+
def transform_winddir(wind_cpx, ground_heading, winddir_convention="meteorological"):
|
|
1254
1544
|
"""
|
|
1255
1545
|
|
|
1256
1546
|
Parameters
|
|
@@ -1271,7 +1561,8 @@ def transform_winddir(wind_cpx, ground_heading, winddir_convention='meteorologic
|
|
|
1271
1561
|
"""
|
|
1272
1562
|
# to meteo winddir_convention
|
|
1273
1563
|
dataArray = xsarsea.dir_sample_to_meteo(
|
|
1274
|
-
np.angle(wind_cpx, deg=True), ground_heading
|
|
1564
|
+
np.angle(wind_cpx, deg=True), ground_heading
|
|
1565
|
+
)
|
|
1275
1566
|
long_name = "Wind direction in meteorological convention (clockwise, from), ex: 0°=from north, 90°=from east"
|
|
1276
1567
|
|
|
1277
1568
|
if winddir_convention == "meteorological":
|
|
@@ -1284,7 +1575,8 @@ def transform_winddir(wind_cpx, ground_heading, winddir_convention='meteorologic
|
|
|
1284
1575
|
else:
|
|
1285
1576
|
# warning
|
|
1286
1577
|
logging.warning(
|
|
1287
|
-
f"wind direction convention {winddir_convention} is not supported, using meteorological",
|
|
1578
|
+
f"wind direction convention {winddir_convention} is not supported, using meteorological",
|
|
1579
|
+
)
|
|
1288
1580
|
long_name = "Wind direction in meteorological convention (clockwise, from), ex: 0°=from north, 90°=from east"
|
|
1289
1581
|
|
|
1290
1582
|
dataArray = xsarsea.dir_to_360(dataArray)
|