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.
@@ -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 ("S1A" in filename):
53
+ if "S1A" in filename:
42
54
  return "S1A", "SENTINEL-1 A", xsar.Sentinel1Meta, xsar.Sentinel1Dataset
43
- elif ("S1B" in filename):
55
+ elif "S1B" in filename:
44
56
  return "S1B", "SENTINEL-1 B", xsar.Sentinel1Meta, xsar.Sentinel1Dataset
45
- elif ("RS2" in filename):
57
+ elif "RS2" in filename:
46
58
  return "RS2", "RADARSAT-2", xsar.RadarSat2Meta, xsar.RadarSat2Dataset
47
- elif ("RCM1" in filename):
59
+ elif "RCM1" in filename:
48
60
  return "RCM", "RADARSAT Constellation 1", xsar.RcmMeta, xsar.RcmDataset
49
- elif ("RCM2" in filename):
61
+ elif "RCM2" in filename:
50
62
  return "RCM", "RADARSAT Constellation 2", xsar.RcmMeta, xsar.RcmDataset
51
- elif ("RCM3" in filename):
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(input_file, outdir, sensor, meta_start_date, meta_stop_date, subdir=True):
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 == 'S1A' or sensor == 'S1B':
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
- MISSIONID, BEAM, PRODUCT, RESOLUTION, LEVEL, CLASS, POL, STARTDATE, STOPDATE, ORBIT, TAKEID, PRODID = match.groups()
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 == 'RS2':
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 = match.groups()
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 == 'RCM':
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 = match.groups()
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='ecmwf'):
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 == 'ecmwf':
186
+ if ancillary_name == "ecmwf":
147
187
 
148
- logging.debug('conf: %s', getConf())
149
- ec01 = getConf()['ecmwf_0100_1h']
150
- ec0125 = getConf()['ecmwf_0125_1h']
151
- logging.debug('ec01 : %s', ec01)
152
- meta.set_raster('ecmwf_0100_1h', ec01)
153
- meta.set_raster('ecmwf_0125_1h', ec0125)
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 ['ecmwf_0125_1h', 'ecmwf_0100_1h']:
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['get_function'](ecmwf_infos['resource'],
161
- date=datetime.datetime.strptime(meta.start_date,
162
- '%Y-%m-%d %H:%M:%S.%f'))[1]
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['get_function'](ecmwf_infos['resource'],
166
- date=datetime.datetime.strptime(meta.start_date,
167
- '%Y-%m-%d %H:%M:%S'))[1]
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 = {'%s_%s' % (ecmwf_name, uv): 'model_%s' %
195
- uv for uv in ['U10', 'V10']}
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 == 'era5':
246
+ elif ancillary_name == "era5":
200
247
  era5_name = "era5_0250_1h"
201
- logging.debug('conf: %s', getConf())
248
+ logging.debug("conf: %s", getConf())
202
249
  era0250 = getConf()[era5_name]
203
- logging.debug('%s : %s', (era5_name, era0250))
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['get_function'](era5_infos['resource'],
209
- date=datetime.datetime.strptime(meta.start_date,
210
- '%Y-%m-%d %H:%M:%S.%f'))[1]
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['get_function'](era5_infos['resource'],
213
- date=datetime.datetime.strptime(meta.start_date,
214
- '%Y-%m-%d %H:%M:%S'))[1]
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 = {'%s_%s' % (era5_name, uv): 'model_%s' %
219
- uv for uv in ['U10', 'V10']}
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("ancillary_name must be ecmwf/era5, got %s" %
224
- ancillary_name)
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(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_co, model_cross, **kwargs):
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 = windspeed.available_models().index.tolist(
267
- ) + windspeed.available_models().alias.tolist() + [None]
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
- 'longitude': 'owiLon',
326
- 'latitude': 'owiLat',
327
- 'incidence': 'owiIncidenceAngle',
328
- 'elevation': 'owiElevationAngle',
329
- 'ground_heading': 'owiHeading',
330
- 'land_mask': 'owiLandFlag',
331
- 'mask': 'owiMask',
332
- 'windspeed_co': 'owiWindSpeed_co',
333
- 'winddir_co': 'owiWindDirection_co',
334
- 'ancillary_wind_speed': 'owiAncillaryWindSpeed',
335
- 'ancillary_wind_direction': 'owiAncillaryWindDirection',
336
- 'sigma0_detrend': 'owiNrcs_detrend',
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
- "long_name"] = f"Ancillary Normalized Radar Cross Section - simulated from {config['l2_params']['copol_gmf']} & ancillary wind"
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
- "long_name"] = f"Ancillary Normalized Radar Cross Section - simulated from {config['l2_params']['crosspol_gmf']} & ancillary wind"
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"] = "Incidence angle at wind cell center"
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"] = "Elevation angle at wind cell center"
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['owiNrcs'] = xr_dataset['sigma0_ocean'].sel(
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['units'] = 'm^2 / m^2'
377
- xr_dataset.owiNrcs.attrs['long_name'] = 'Normalized Radar Cross Section'
378
- xr_dataset.owiNrcs.attrs['definition'] = 'owiNrcs_no_noise_correction - owiNesz'
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['owiMask_Nrcs'] = xr_dataset['sigma0_mask'].sel(
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=(['line', 'sample'], xr_dataset.nesz.sel(pol=config["l2_params"]["copol"]).values))
387
- xr_dataset.owiNesz.attrs['units'] = 'm^2 / m^2'
388
- xr_dataset.owiNesz.attrs['long_name'] = 'Noise Equivalent SigmaNaught'
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['owiNrcs_no_noise_correction'] = xr_dataset['sigma0_ocean_raw'].sel(
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['units'] = 'm^2 / m^2'
394
- xr_dataset.owiNrcs_no_noise_correction.attrs[
395
- 'long_name'] = 'Normalized Radar Cross Section ; no noise correction applied'
396
- xr_dataset.owiNrcs_no_noise_correction.attrs[
397
- 'comment'] = 'owiNrcs_no_noise_correction ; no recalibration'
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 'swath_number' in xr_dataset:
400
- xr_dataset = xr_dataset.rename({
401
- 'swath_number': 'owiSwathNumber',
402
- 'swath_number_flag': 'owiSwathNumberFlag'
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['owiNrcs_no_noise_correction_recalibrated'] = xr_dataset['sigma0_raw__corrected'].sel(
410
- pol=config["l2_params"]["copol"])
411
- xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs = xr_dataset.sigma0_raw__corrected.attrs
412
- xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs['units'] = 'm^2 / m^2'
413
- xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs[
414
- 'long_name'] = 'Normalized Radar Cross Section, no noise correction applied'
415
- xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs[
416
- 'comment'] = 'owiNrcs_no_noise_correction ; recalibrated with kersten method'
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['definition'] = 'owiNrcs_no_noise_correction_recalibrated - owiNesz'
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['owiNrcs_cross'] = xr_dataset['sigma0_ocean'].sel(
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['units'] = 'm^2 / m^2'
441
- xr_dataset.owiNrcs_cross.attrs['long_name'] = 'Normalized Radar Cross Section'
442
- xr_dataset.owiNrcs_cross.attrs['definition'] = 'owiNrcs_cross_no_noise_correction - owiNesz_cross'
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['owiMask_Nrcs_cross'] = xr_dataset['sigma0_mask'].sel(
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(owiNesz_cross=(
450
- ['line', 'sample'], xr_dataset.nesz.sel(pol=config["l2_params"]["crosspol"]).values)) # no flattening
451
- xr_dataset.owiNesz_cross.attrs['units'] = 'm^2 / m^2'
452
- xr_dataset.owiNesz_cross.attrs['long_name'] = 'Noise Equivalent SigmaNaught'
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['owiNrcs_cross_no_noise_correction'] = xr_dataset['sigma0_ocean_raw'].sel(
455
- pol=config["l2_params"]["crosspol"])
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.owiNrcs_cross_no_noise_correction.attrs['units'] = 'm^2 / m^2'
458
- xr_dataset.owiNrcs_cross_no_noise_correction.attrs[
459
- 'long_name'] = 'Normalized Radar Cross Section, no noise correction applied'
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['owiNrcs_cross_no_noise_correction_recalibrated'] = xr_dataset['sigma0_raw__corrected'].sel(
464
- pol=config["l2_params"]["crosspol"])
465
- xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs = xr_dataset.sigma0_raw__corrected.attrs
466
- xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs['units'] = 'm^2 / m^2'
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
- 'long_name'] = 'Normalized Radar Cross Section ; no noise correction applied'
578
+ "long_name"
579
+ ] = "Normalized Radar Cross Section ; no noise correction applied"
469
580
  xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs[
470
- 'comment'] = 'owiNrcs_cross_no_noise_correction ; recalibrated with kersten method'
581
+ "comment"
582
+ ] = "owiNrcs_cross_no_noise_correction ; recalibrated with kersten method"
471
583
 
472
- xr_dataset.owiNrcs_cross.attrs['definition'] = 'owiNrcs_cross_no_noise_correction_recalibrated - owiNesz_cross'
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['owiWindFilter'] = xr.full_like(xr_dataset.owiNrcs, 0)
480
- xr_dataset['owiWindFilter'].attrs['long_name'] = "Quality flag taking into account the local heterogeneity"
481
- xr_dataset['owiWindFilter'].attrs['valid_range'] = np.array([0, 3])
482
- xr_dataset['owiWindFilter'].attrs['flag_values'] = np.array([
483
- 0, 1, 2, 3])
484
- xr_dataset['owiWindFilter'].attrs[
485
- 'flag_meanings'] = "homogeneous_NRCS, heterogeneous_from_co-polarization_NRCS, heterogeneous_from_cross-polarization_NRCS, heterogeneous_from_dual-polarization_NRCS"
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['owiWindQuality'] = xr.full_like(xr_dataset.owiNrcs, 0)
490
- xr_dataset['owiWindQuality'].attrs[
491
- 'long_name'] = "Quality flag taking into account the consistency_between_wind_inverted_and_NRCS_and_Doppler_measured"
492
- xr_dataset['owiWindQuality'].attrs['valid_range'] = np.array([0, 3])
493
- xr_dataset['owiWindQuality'].attrs['flag_values'] = np.array([
494
- 0, 1, 2, 3])
495
- xr_dataset['owiWindQuality'].attrs['flag_meanings'] = "good medium low poor"
496
- xr_dataset['owiWindQuality'].attrs['comment'] = 'NOT COMPUTED YET'
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
- ['sigma0_ocean', 'sigma0', 'sigma0_ocean_raw', 'sigma0_raw', 'ancillary_wind', 'nesz', 'spatial_ref'])
503
- if 'sigma0_raw__corrected' in xr_dataset:
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(['pol'])
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({'_FillValue': table_fillValue[var]})
648
+ encoding[var].update({"_FillValue": table_fillValue[var]})
525
649
  except:
526
- if (var in ["owiWindSpeed_co", "owiWindSpeed_cross", "owiWindSpeed"]):
527
- encoding[var].update({'_FillValue': -9999.0})
650
+ if var in ["owiWindSpeed_co", "owiWindSpeed_cross", "owiWindSpeed"]:
651
+ encoding[var].update({"_FillValue": -9999.0})
528
652
  else:
529
- encoding[var].update({'_FillValue': None})
653
+ encoding[var].update({"_FillValue": None})
530
654
 
531
655
  return xr_dataset, encoding
532
656
 
533
657
 
534
- def preprocess(filename, outdir, config_path, overwrite=False, add_gradientsfeatures=False, resolution='1000m'):
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, 'r') as file:
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
- 'config_path do not exists, got %s ' % config_path)
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'Force this variable to be false, before fixing the issue'
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 = meta.start_date.split(".")[0].replace(
617
- "-", "").replace(":", "").replace(" ", "t").replace("Z", "")
618
- meta_stop_date = meta.stop_date.split(".")[0].replace(
619
- "-", "").replace(":", "").replace(" ", "t").replace("Z", "")
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(filename, outdir, sensor,
622
- meta_start_date, meta_stop_date, subdir=not no_subdir_cfg)
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 ((recalibration) & ("SENTINEL" in sensor_longname)):
782
+ if (recalibration) & ("SENTINEL" in sensor_longname):
635
783
  logging.info(
636
- f'recalibration is {recalibration} : Kersten formula is applied')
784
+ f"recalibration is {recalibration} : Kersten formula is applied"
785
+ )
637
786
  xsar_dataset = fct_dataset(
638
- meta, resolution=resolution, recalibration=recalibration)
639
- xr_dataset = xsar_dataset.datatree['measurement'].to_dataset()
640
- xr_dataset = xr_dataset.merge(xsar_dataset.datatree["recalibration"].to_dataset()[
641
- ['swath_number', 'swath_number_flag', 'sigma0_raw__corrected']])
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'recalibration is {recalibration} : Kersten formula is not applied')
646
- if ("SENTINEL" in sensor_longname):
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
- xr_dataset = xsar_dataset.datatree['measurement'].to_dataset()
650
- xr_dataset = xr_dataset.merge(xsar_dataset.datatree["recalibration"].to_dataset()[
651
- ['swath_number', 'swath_number_flag']])
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['measurement'].to_dataset()
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('%s', traceback.format_exc())
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 'VV' in xr_dataset.pol.values:
680
- copol = 'VV'
681
- crosspol = 'VH'
682
- copol_gmf = 'VV'
683
- crosspol_gmf = 'VH'
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('for now this processor does not support entirely HH+HV acquisitions\n '
686
- 'it wont crash but it will use HH+VH GMF for wind inversion -> wrong hypothesis\n '
687
- '!! dual WIND SPEED IS NOT USABLE !! But co WIND SPEED IS USABLE !!')
688
- copol = 'HH'
689
- crosspol = 'HV'
690
- copol_gmf = 'HH'
691
- crosspol_gmf = 'VH'
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 (model_co == "gmf_cmod7"):
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 = ['digital_number', 'gamma0_raw', 'negz',
719
- 'azimuth_time', 'slant_range_time', 'velocity', 'range_ground_spacing',
720
- 'gamma0', 'time', 'nd_co', 'nd_cr', 'gamma0_lut', 'sigma0_lut', "noise_lut_range", "lineSpacing",
721
- "sampleSpacing", "noise_lut", "noise_lut_azi",
722
- 'nebz', 'beta0_raw', 'lines_flipped', 'samples_flipped', "altitude", "beta0"]
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"] = "Offboresight angle at wind cell center"
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(xr_dataset['land_mask'].values.astype('uint8'),
754
- structure=np.ones((3, 3), np.uint8), iterations=3)
755
- xr_dataset.land_mask.attrs['long_name'] = 'Mask of data'
756
- xr_dataset.land_mask.attrs['valid_range'] = np.array([0, 1])
757
- xr_dataset.land_mask.attrs['flag_values'] = np.array([0, 1])
758
- xr_dataset.land_mask.attrs['flag_meanings'] = 'valid no_valid'
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['mask'] = xr.DataArray(xr_dataset.land_mask)
948
+ xr_dataset["mask"] = xr.DataArray(xr_dataset.land_mask)
763
949
  xr_dataset.mask.attrs = {}
764
- xr_dataset.mask.attrs['long_name'] = 'Mask of data'
765
- xr_dataset.mask.attrs['valid_range'] = np.array([0, 3])
766
- xr_dataset.mask.attrs['flag_values'] = np.array([0, 1, 2, 3])
767
- xr_dataset.mask.attrs['flag_meanings'] = 'valid land ice no_valid'
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['ancillary_wind_direction'] = (
771
- 90. - np.rad2deg(np.arctan2(xr_dataset.model_V10, xr_dataset.model_U10)) + 180) % 360
772
-
773
- xr_dataset['ancillary_wind_direction'] = xr.where(xr_dataset['mask'], np.nan,
774
- xr_dataset['ancillary_wind_direction']).transpose(
775
- *xr_dataset['ancillary_wind_direction'].dims)
776
- xr_dataset['ancillary_wind_direction'].attrs = {}
777
- xr_dataset['ancillary_wind_direction'].attrs['units'] = 'degrees_north'
778
- xr_dataset['ancillary_wind_direction'].attrs[
779
- 'long_name'] = f'{ancillary_name} wind direction in meteorological convention (clockwise, from), ex: 0°=from north, 90°=from east'
780
- xr_dataset['ancillary_wind_direction'].attrs['standart_name'] = 'wind_direction'
781
-
782
- xr_dataset['ancillary_wind_speed'] = np.sqrt(
783
- xr_dataset['model_U10']**2+xr_dataset['model_V10']**2)
784
- xr_dataset['ancillary_wind_speed'] = xr.where(xr_dataset['mask'], np.nan,
785
- xr_dataset['ancillary_wind_speed']).transpose(
786
- *xr_dataset['ancillary_wind_speed'].dims)
787
- xr_dataset['ancillary_wind_speed'].attrs = {}
788
- xr_dataset['ancillary_wind_speed'].attrs['units'] = 'm s^-1'
789
- xr_dataset['ancillary_wind_speed'].attrs[
790
- 'long_name'] = f'{ancillary_name} wind speed'
791
- xr_dataset['ancillary_wind_speed'].attrs['standart_name'] = 'wind_speed'
792
-
793
- xr_dataset['ancillary_wind'] = xr.where(xr_dataset['mask'], np.nan,
794
- (xr_dataset.ancillary_wind_speed * np.exp(1j * xsarsea.dir_meteo_to_sample(xr_dataset.ancillary_wind_direction, xr_dataset.ground_heading)))).transpose(
795
- *xr_dataset['ancillary_wind_speed'].dims)
796
-
797
- xr_dataset.attrs['ancillary_source'] = xr_dataset['model_U10'].attrs['history'].split('decoded: ')[
798
- 1].strip()
799
- xr_dataset = xr_dataset.drop_vars(['model_U10', 'model_V10'])
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['sigma0_ocean'] = xr.where(xr_dataset['mask'], np.nan,
803
- xr_dataset['sigma0']).transpose(*xr_dataset['sigma0'].dims)
804
- xr_dataset['sigma0_ocean'].attrs = xr_dataset['sigma0'].attrs
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['sigma0_ocean'].attrs['comment'] = "clipped, no values <=0 ; 1e-15 instread"
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['sigma0_mask'] = xr.where(
810
- xr_dataset['sigma0_ocean'] <= 0, 1, 0).transpose(*xr_dataset['sigma0'].dims)
811
- xr_dataset.sigma0_mask.attrs['valid_range'] = np.array([0, 1])
812
- xr_dataset.sigma0_mask.attrs['flag_values'] = np.array([0, 1])
813
- xr_dataset.sigma0_mask.attrs['flag_meanings'] = 'valid no_valid'
814
- xr_dataset['sigma0_ocean'] = xr.where(
815
- xr_dataset['sigma0_ocean'] <= 0, 1e-15, xr_dataset['sigma0_ocean'])
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['sigma0_ocean_raw'] = xr.where(xr_dataset['mask'], np.nan,
818
- xr_dataset['sigma0_raw']).transpose(*xr_dataset['sigma0_raw'].dims)
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['sigma0_ocean_raw'].attrs = xr_dataset['sigma0_raw'].attrs
1028
+ xr_dataset["sigma0_ocean_raw"].attrs = xr_dataset["sigma0_raw"].attrs
821
1029
 
822
- xr_dataset['sigma0_detrend'] = xsarsea.sigma0_detrend(
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(config["dsig_"+crosspol_gmf+"_NAME"], xr_dataset.incidence,
837
- xr_dataset['sigma0_ocean'].sel(pol=crosspol), xr_dataset.nesz_cross_flattened)
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(config["dsig_"+crosspol_gmf+"_NAME"], xr_dataset.incidence,
841
- xr_dataset['sigma0_ocean'].sel(pol=crosspol), xr_dataset.nesz.sel(pol=crosspol))
842
-
843
- xr_dataset.dsig_cross.attrs['comment'] = 'variable used to ponderate copol and crosspol'
844
- xr_dataset.dsig_cross.attrs['formula_used'] = config["dsig_" +
845
- crosspol_gmf+"_NAME"]
846
- xr_dataset.dsig_cross.attrs['apply_flattening'] = str(
847
- config["apply_flattening"])
848
-
849
- if ((recalibration) & ("SENTINEL" in sensor_longname)):
850
- xr_dataset.attrs["path_aux_pp1_new"] = os.path.basename(os.path.dirname(
851
- os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_pp1_new'])))
852
- xr_dataset.attrs["path_aux_cal_new"] = os.path.basename(os.path.dirname(
853
- os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_cal_new'])))
854
-
855
- xr_dataset.attrs["path_aux_pp1_old"] = os.path.basename(os.path.dirname(
856
- os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_pp1_old'])))
857
- xr_dataset.attrs["path_aux_cal_old"] = os.path.basename(os.path.dirname(
858
- os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_cal_old'])))
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(xsarsea.dir_meteo_to_sample(
864
- xr_dataset["ancillary_wind_direction"], xr_dataset["ground_heading"]))
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['measurement'].to_dataset()
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['sigma0_detrend'] = xsarsea.sigma0_detrend(
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['sigma0_detrend_cross'] = xsarsea.sigma0_detrend(
954
- xr_dataset_100.sigma0.sel(pol=crosspol), xr_dataset_100.incidence, model=model_cross)
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['sigma0_detrend'],
958
- xr_dataset_100['sigma0_detrend_cross']],
959
- dim='pol'
1208
+ [xr_dataset_100["sigma0_detrend"],
1209
+ xr_dataset_100["sigma0_detrend_cross"]],
1210
+ dim="pol",
960
1211
  )
961
- sigma0_detrend_combined['pol'] = [copol, crosspol]
1212
+ sigma0_detrend_combined["pol"] = [copol, crosspol]
962
1213
 
963
- xr_dataset_100['sigma0_detrend'] = sigma0_detrend_combined
1214
+ xr_dataset_100["sigma0_detrend"] = sigma0_detrend_combined
964
1215
 
965
- xr_dataset_100.land_mask.values = binary_dilation(xr_dataset_100['land_mask'].values.astype('uint8'),
966
- structure=np.ones((3, 3), np.uint8), iterations=3)
967
- xr_dataset_100['sigma0_detrend'] = xr.where(
968
- xr_dataset_100['land_mask'], np.nan, xr_dataset_100['sigma0']).transpose(*xr_dataset_100['sigma0'].dims)
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['ancillary_wind'] = (
971
- xr_dataset_100.model_U10 + 1j * xr_dataset_100.model_V10) * np.exp(1j * np.deg2rad(xr_dataset_100.ground_heading))
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 'longitude' in streaks_indiv:
992
- xr_dataset_streaks = xr.Dataset({
993
- 'longitude': streaks_indiv.longitude,
994
- 'latitude': streaks_indiv.latitude,
995
- 'dir_smooth': streaks_indiv.angle,
996
- 'dir_mean_smooth': gradientFeatures.streaks_mean_smooth().angle,
997
- 'dir_smooth_mean': gradientFeatures.streaks_smooth_mean().angle,
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(filename, outdir, config_path, overwrite=False, generateCSV=True, resolution='1000m'):
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['sigma0_ocean'].sel(pol=crosspol)
1056
- dsig_cross = xr_dataset['dsig_cross']
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['incidence'], [model_co, model_cross], **kwargs)
1075
-
1076
- wind_co, wind_dual, windspeed_cr = inverse(dual_pol,
1077
- inc=xr_dataset['incidence'],
1078
- sigma0=xr_dataset['sigma0_ocean'].sel(
1079
- pol=copol),
1080
- sigma0_dual=sigma0_ocean_cross,
1081
- ancillary_wind=xr_dataset['ancillary_wind'],
1082
- dsig_cr=dsig_cross,
1083
- model_co=model_co,
1084
- model_cross=model_cross,
1085
- ** kwargs)
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['windspeed_co'] = np.abs(wind_co)
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"] = "Wind speed inverted from model %s (%s)" % (
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['comment']
1357
+ del xr_dataset["windspeed_co"].attrs["comment"]
1094
1358
 
1095
1359
  # winddir_co
1096
- xr_dataset['winddir_co'] = transform_winddir(
1097
- wind_co, xr_dataset.ground_heading, winddir_convention=config["winddir_convention"])
1098
- xr_dataset['winddir_co'].attrs["model"] = "%s (%s)" % (model_co, copol)
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['windspeed_dual'] = np.abs(wind_dual)
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"] = "Wind speed inverted from model %s (%s) & %s (%s)" % (
1105
- model_co, copol, model_cross, crosspol)
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['comment']
1377
+ del xr_dataset["windspeed_dual"].attrs["comment"]
1109
1378
 
1110
- xr_dataset['winddir_dual'] = transform_winddir(
1111
- wind_dual, xr_dataset.ground_heading, winddir_convention=config["winddir_convention"])
1112
- xr_dataset["winddir_dual"].attrs["model"] = "winddir_dual is a copy of copol wind direction"
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=(['line', 'sample'], windspeed_cr.data))
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"] = "Wind Speed inverted from model %s (%s)" % (
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['winddir_cross'] = xr_dataset['winddir_dual'].copy()
1123
- xr_dataset['winddir_cross'].attrs = xr_dataset['winddir_dual'].attrs
1124
- xr_dataset["winddir_cross"].attrs["model"] = "winddir_cross is a copy of copol wind direction"
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['ancillary_wind_direction'].attrs
1128
- xr_dataset['ancillary_wind_direction'] = xsarsea.dir_meteo_to_oceano(
1129
- xr_dataset['ancillary_wind_direction'])
1130
- xr_dataset['ancillary_wind_direction'].attrs = attrs
1131
- xr_dataset['ancillary_wind_direction'].attrs[
1132
- "long_name"] = f"{ancillary_name} wind direction in oceanographic convention (clockwise, to), ex: 0°=to north, 90°=to east"
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(xr_dataset.attrs['start_date'],
1143
- "%Y-%m-%d %H:%M:%S.%f").strftime(
1144
- "%Y-%m-%dT%H:%M:%SZ")
1145
- lastMeasurementTime = datetime.datetime.strptime(xr_dataset.attrs['stop_date'],
1146
- "%Y-%m-%d %H:%M:%S.%f").strftime(
1147
- "%Y-%m-%dT%H:%M:%SZ")
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(xr_dataset.attrs['start_date'],
1150
- "%Y-%m-%d %H:%M:%S").strftime(
1151
- "%Y-%m-%dT%H:%M:%SZ")
1152
- lastMeasurementTime = datetime.datetime.strptime(xr_dataset.attrs['stop_date'],
1153
- "%Y-%m-%d %H:%M:%S").strftime(
1154
- "%Y-%m-%dT%H:%M:%SZ")
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": (xr_dataset.attrs["safe"] if "safe" in xr_dataset.attrs else os.path.basename(xr_dataset.attrs["product_path"])),
1160
- "sourceProduct_fullpath": xr_dataset.attrs.pop('name'),
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": "Operational",
1163
- "polarisation": xr_dataset.attrs['pols'],
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['GMF_'+copol_gmf+'_NAME'] + ", " + config["GMF_"+crosspol_gmf+"_NAME"],
1460
+ "gmf": config["GMF_" + copol_gmf + "_NAME"]
1461
+ + ", "
1462
+ + config["GMF_" + crosspol_gmf + "_NAME"],
1178
1463
  "iceSource": "/",
1179
1464
  "owiNoiseCorrection": "True",
1180
- "inversionTabGMF": config['GMF_'+copol_gmf +
1181
- '_NAME'] + ", " + config["GMF_"+crosspol_gmf+"_NAME"],
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['ancillary_source'],
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['swath'],
1190
- "footprint": xr_dataset.attrs['footprint'],
1191
- "coverage": xr_dataset.attrs['coverage'],
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 ["path_aux_pp1_new", 'path_aux_pp1_old', "path_aux_cal_new", "path_aux_cal_old"]:
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['footprint'] = str(attrs['footprint'])
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='meteorological'):
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)