grdwindinversion 0.3.2__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 getOutputName2(input_file, outdir, sensor, meta, 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
 
@@ -68,8 +83,10 @@ def getOutputName2(input_file, outdir, sensor, meta, subdir=True):
68
83
  output folder
69
84
  sensor : str
70
85
  sensor name
71
- meta : obj `xsar.BaseMeta` (one of the supported SAR mission)
72
- meta object
86
+ start_date : str
87
+ start date
88
+ stop_date : str
89
+ stop date
73
90
 
74
91
  Returns
75
92
  -------
@@ -78,33 +95,68 @@ def getOutputName2(input_file, outdir, sensor, meta, subdir=True):
78
95
  """
79
96
  basename = os.path.basename(input_file)
80
97
  basename_match = basename
81
- meta_start_date = meta.start_date.split(".")[0].replace(
82
- "-", "").replace(":", "").replace(" ", "t").replace("Z", "")
83
- meta_stop_date = meta.stop_date.split(".")[0].replace(
84
- "-", "").replace(":", "").replace(" ", "t").replace("Z", "")
85
98
 
86
- if sensor == 'S1A' or sensor == 'S1B':
99
+ if sensor == "S1A" or sensor == "S1B":
87
100
  regex = re.compile(
88
- "(...)_(..)_(...)(.)_(.)(.)(..)_(........T......)_(........T......)_(......)_(......)_(....).SAFE")
101
+ "(...)_(..)_(...)(.)_(.)(.)(..)_(........T......)_(........T......)_(......)_(......)_(....).SAFE"
102
+ )
89
103
  template = string.Template(
90
- "${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
+ )
91
106
  match = regex.match(basename_match)
92
- MISSIONID, BEAM, PRODUCT, RESOLUTION, LEVEL, CLASS, POL, STARTDATE, STOPDATE, ORBIT, TAKEID, PRODID = match.groups()
107
+ if not match:
108
+ raise AttributeError(
109
+ f"S1 file {basename_match} does not match the expected pattern"
110
+ )
111
+
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()
93
126
  new_format = f"{MISSIONID.lower()}-{BEAM.lower()}-owi-xx-{STARTDATE.lower()}-{STOPDATE.lower()}-{ORBIT}-{TAKEID}.nc"
94
- elif sensor == 'RS2':
127
+ elif sensor == "RS2":
95
128
  regex = re.compile(
96
- "(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
+ )
97
131
  template = string.Template(
98
- "${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
+ )
99
134
  match = regex.match(basename_match)
100
- MISSIONID, DATA1, DATA2, DATA3, DATA4, DATE, TIME, POLARIZATION, LAST = match.groups()
135
+ if not match:
136
+ raise AttributeError(
137
+ f"RC2 file {basename_match} does not match the expected pattern"
138
+ )
139
+
140
+ MISSIONID, DATA1, DATA2, DATA3, DATA4, DATE, TIME, POLARIZATION, LAST = (
141
+ match.groups()
142
+ )
101
143
  new_format = f"{MISSIONID.lower()}--owi-xx-{meta_start_date.lower()}-{meta_stop_date.lower()}-_____-_____.nc"
102
- elif sensor == 'RCM':
144
+ elif sensor == "RCM":
145
+
103
146
  regex = re.compile(
104
- r"(RCM[0-9])_OK([0-9]+)_PK([0-9]+)_([0-9]+)_([A-Z]+)_(\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
+ )
105
149
  match = regex.match(basename_match)
106
- MISSIONID, DATA1, DATA2, DATA3, BEAM, DATE, TIME, POLARIZATION, PRODUCT = match.groups()
150
+ if not match:
151
+ raise AttributeError(
152
+ f"RCM file {basename_match} does not match the expected pattern"
153
+ )
154
+
155
+ MISSIONID, DATA1, DATA2, DATA3, BEAM, DATE, TIME, POLARIZATION, PRODUCT = (
156
+ match.groups()
157
+ )
107
158
  new_format = f"{MISSIONID.lower()}-{BEAM.lower()}-owi-xx-{meta_start_date.lower()}-{meta_stop_date.lower()}-_____-_____.nc"
159
+
108
160
  else:
109
161
  raise ValueError(
110
162
  "sensor must be S1A|S1B|RS2|RCM, got sensor %s" % sensor)
@@ -116,7 +168,7 @@ def getOutputName2(input_file, outdir, sensor, meta, subdir=True):
116
168
  return out_file
117
169
 
118
170
 
119
- def getAncillary(meta, ancillary_name='ecmwf'):
171
+ def getAncillary(meta, ancillary_name="ecmwf"):
120
172
  """
121
173
  Map ancillary wind from ECMWF or ERA5.
122
174
  This function is used to check if the model files are available and to map the model to the SAR data.
@@ -131,28 +183,34 @@ def getAncillary(meta, ancillary_name='ecmwf'):
131
183
  map model to SAR data
132
184
  """
133
185
 
134
- if ancillary_name == 'ecmwf':
186
+ if ancillary_name == "ecmwf":
135
187
 
136
- logging.debug('conf: %s', getConf())
137
- ec01 = getConf()['ecmwf_0100_1h']
138
- ec0125 = getConf()['ecmwf_0125_1h']
139
- logging.debug('ec01 : %s', ec01)
140
- meta.set_raster('ecmwf_0100_1h', ec01)
141
- 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)
142
194
 
143
195
  map_model = None
144
196
  # only keep best ecmwf (FIXME: it's hacky, and xsar should provide a better method to handle this)
145
- for ecmwf_name in ['ecmwf_0125_1h', 'ecmwf_0100_1h']:
197
+ for ecmwf_name in ["ecmwf_0125_1h", "ecmwf_0100_1h"]:
146
198
  ecmwf_infos = meta.rasters.loc[ecmwf_name]
147
199
  try:
148
- ecmwf_file = ecmwf_infos['get_function'](ecmwf_infos['resource'],
149
- date=datetime.datetime.strptime(meta.start_date,
150
- '%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]
151
206
  # temporary for RCM issue https://github.com/umr-lops/xarray-safe-rcm/issues/34
152
207
  except Exception as e:
153
- ecmwf_file = ecmwf_infos['get_function'](ecmwf_infos['resource'],
154
- date=datetime.datetime.strptime(meta.start_date,
155
- '%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]
156
214
  if not os.path.isfile(ecmwf_file):
157
215
  # temporary
158
216
  # if repro does not exist we look at not repro folder (only one will exist after)
@@ -179,41 +237,58 @@ def getAncillary(meta, ancillary_name='ecmwf'):
179
237
  """
180
238
  meta.rasters = meta.rasters.drop([ecmwf_name])
181
239
  else:
182
- map_model = {'%s_%s' % (ecmwf_name, uv): 'model_%s' %
183
- uv for uv in ['U10', 'V10']}
240
+ map_model = {
241
+ "%s_%s" % (ecmwf_name, uv): "model_%s" % uv for uv in ["U10", "V10"]
242
+ }
184
243
 
185
244
  return map_model
186
245
 
187
- elif ancillary_name == 'era5':
246
+ elif ancillary_name == "era5":
188
247
  era5_name = "era5_0250_1h"
189
- logging.debug('conf: %s', getConf())
248
+ logging.debug("conf: %s", getConf())
190
249
  era0250 = getConf()[era5_name]
191
- logging.debug('%s : %s', (era5_name, era0250))
250
+ logging.debug("%s : %s", (era5_name, era0250))
192
251
  meta.set_raster(era5_name, era0250)
193
252
 
194
253
  era5_infos = meta.rasters.loc[era5_name]
195
254
  try:
196
- era5_file = era5_infos['get_function'](era5_infos['resource'],
197
- date=datetime.datetime.strptime(meta.start_date,
198
- '%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]
199
261
  except Exception as e:
200
- era5_file = era5_infos['get_function'](era5_infos['resource'],
201
- date=datetime.datetime.strptime(meta.start_date,
202
- '%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]
203
267
  if not os.path.isfile(era5_file):
204
268
  raise ValueError(f"era5 file {era5_file} not found")
205
269
 
206
- map_model = {'%s_%s' % (era5_name, uv): 'model_%s' %
207
- uv for uv in ['U10', 'V10']}
270
+ map_model = {
271
+ "%s_%s" % (era5_name, uv): "model_%s" % uv for uv in ["U10", "V10"]
272
+ }
208
273
  return map_model
209
274
 
210
275
  else:
211
- raise ValueError("ancillary_name must be ecmwf/era5, got %s" %
212
- ancillary_name)
276
+ raise ValueError(
277
+ "ancillary_name must be ecmwf/era5, got %s" % ancillary_name)
213
278
 
214
279
 
215
280
  @timing(logger=logger.debug)
216
- 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
+ ):
217
292
  """
218
293
  Invert sigma0 to retrieve wind using model (lut or gmf).
219
294
 
@@ -251,14 +326,19 @@ def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_c
251
326
  """
252
327
  logging.debug("inversion")
253
328
 
254
- list_mods = windspeed.available_models().index.tolist(
255
- ) + windspeed.available_models().alias.tolist() + [None]
329
+ list_mods = (
330
+ windspeed.available_models().index.tolist()
331
+ + windspeed.available_models().alias.tolist()
332
+ + [None]
333
+ )
256
334
  if model_co not in list_mods:
257
335
  raise ValueError(
258
- 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
+ )
259
338
  if model_cross not in list_mods:
260
339
  raise ValueError(
261
- 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
+ )
262
342
 
263
343
  winds = windspeed.invert_from_model(
264
344
  inc,
@@ -267,7 +347,8 @@ def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_c
267
347
  ancillary_wind=ancillary_wind,
268
348
  dsig_cr=dsig_cr,
269
349
  model=(model_co, model_cross),
270
- **kwargs)
350
+ **kwargs,
351
+ )
271
352
 
272
353
  if dual_pol:
273
354
  wind_co, wind_dual = winds
@@ -277,7 +358,8 @@ def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_c
277
358
  sigma0_dual.values,
278
359
  dsig_cr=dsig_cr.values,
279
360
  model=model_cross,
280
- **kwargs)
361
+ **kwargs,
362
+ )
281
363
 
282
364
  return wind_co, wind_dual, wind_cross
283
365
  else:
@@ -309,38 +391,42 @@ def makeL2asOwi(xr_dataset, config):
309
391
  --------
310
392
  """
311
393
 
312
- xr_dataset = xr_dataset.rename({
313
- 'longitude': 'owiLon',
314
- 'latitude': 'owiLat',
315
- 'incidence': 'owiIncidenceAngle',
316
- 'elevation': 'owiElevationAngle',
317
- 'ground_heading': 'owiHeading',
318
- 'land_mask': 'owiLandFlag',
319
- 'mask': 'owiMask',
320
- 'windspeed_co': 'owiWindSpeed_co',
321
- 'winddir_co': 'owiWindDirection_co',
322
- 'ancillary_wind_speed': 'owiAncillaryWindSpeed',
323
- 'ancillary_wind_direction': 'owiAncillaryWindDirection',
324
- 'sigma0_detrend': 'owiNrcs_detrend',
325
- })
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
+ )
326
410
 
327
411
  if "offboresight" in xr_dataset:
328
412
  xr_dataset = xr_dataset.rename(
329
413
  {"offboresight": "owiOffboresightAngle"})
330
414
 
331
415
  if config["add_nrcs_model"]:
332
- xr_dataset = xr_dataset.rename(
333
- {"ancillary_nrcs": "owiAncillaryNrcs"})
416
+ xr_dataset = xr_dataset.rename({"ancillary_nrcs": "owiAncillaryNrcs"})
334
417
  xr_dataset.owiAncillaryNrcs.attrs["units"] = "m^2 / m^2"
335
- xr_dataset.owiAncillaryNrcs.attrs[
336
- "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
+ )
337
421
 
338
422
  if config["l2_params"]["dual_pol"]:
339
423
  xr_dataset = xr_dataset.rename(
340
- {"ancillary_nrcs_cross": "owiAncillaryNrcs_cross"})
424
+ {"ancillary_nrcs_cross": "owiAncillaryNrcs_cross"}
425
+ )
341
426
  xr_dataset.owiAncillaryNrcs_cross.attrs["units"] = "m^2 / m^2"
342
- xr_dataset.owiAncillaryNrcs_cross.attrs[
343
- "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
+ )
344
430
 
345
431
  xr_dataset.owiLon.attrs["units"] = "degrees_east"
346
432
  xr_dataset.owiLon.attrs["long_name"] = "Longitude at wind cell center"
@@ -351,146 +437,196 @@ def makeL2asOwi(xr_dataset, config):
351
437
  xr_dataset.owiLat.attrs["standard_name"] = "latitude"
352
438
 
353
439
  xr_dataset.owiIncidenceAngle.attrs["units"] = "degrees"
354
- 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
+ )
355
443
  xr_dataset.owiIncidenceAngle.attrs["standard_name"] = "incidence"
356
444
 
357
445
  xr_dataset.owiElevationAngle.attrs["units"] = "degrees"
358
- 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
+ )
359
449
  xr_dataset.owiElevationAngle.attrs["standard_name"] = "elevation"
360
450
 
361
- xr_dataset['owiNrcs'] = xr_dataset['sigma0_ocean'].sel(
362
- pol=config["l2_params"]["copol"])
451
+ xr_dataset["owiNrcs"] = xr_dataset["sigma0_ocean"].sel(
452
+ pol=config["l2_params"]["copol"]
453
+ )
363
454
  xr_dataset.owiNrcs.attrs = xr_dataset.sigma0_ocean.attrs
364
- xr_dataset.owiNrcs.attrs['units'] = 'm^2 / m^2'
365
- xr_dataset.owiNrcs.attrs['long_name'] = 'Normalized Radar Cross Section'
366
- 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"
367
458
 
368
- xr_dataset['owiMask_Nrcs'] = xr_dataset['sigma0_mask'].sel(
369
- pol=config["l2_params"]["copol"])
459
+ xr_dataset["owiMask_Nrcs"] = xr_dataset["sigma0_mask"].sel(
460
+ pol=config["l2_params"]["copol"]
461
+ )
370
462
  xr_dataset.owiMask_Nrcs.attrs = xr_dataset.sigma0_mask.attrs
371
463
 
372
464
  # NESZ & DSIG
373
465
  xr_dataset = xr_dataset.assign(
374
- owiNesz=(['line', 'sample'], xr_dataset.nesz.sel(pol=config["l2_params"]["copol"]).values))
375
- xr_dataset.owiNesz.attrs['units'] = 'm^2 / m^2'
376
- 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"
377
473
 
378
- xr_dataset['owiNrcs_no_noise_correction'] = xr_dataset['sigma0_ocean_raw'].sel(
379
- 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
+ )
380
477
  xr_dataset.owiNrcs_no_noise_correction.attrs = xr_dataset.sigma0_ocean_raw.attrs
381
- xr_dataset.owiNrcs_no_noise_correction.attrs['units'] = 'm^2 / m^2'
382
- xr_dataset.owiNrcs_no_noise_correction.attrs[
383
- 'long_name'] = 'Normalized Radar Cross Section ; no noise correction applied'
384
- xr_dataset.owiNrcs_no_noise_correction.attrs[
385
- '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
+ )
386
485
 
387
- if 'swath_number' in xr_dataset:
388
- xr_dataset = xr_dataset.rename({
389
- 'swath_number': 'owiSwathNumber',
390
- 'swath_number_flag': 'owiSwathNumberFlag'
391
- })
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
+ )
392
493
 
393
494
  xr_dataset["owiSwathNumber"].attrs["standart_name"] = "swath number"
394
495
 
395
496
  # sigma0_raw__corrected cross
396
497
  if "sigma0_raw__corrected" in xr_dataset:
397
- xr_dataset['owiNrcs_no_noise_correction_recalibrated'] = xr_dataset['sigma0_raw__corrected'].sel(
398
- pol=config["l2_params"]["copol"])
399
- xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs = xr_dataset.sigma0_raw__corrected.attrs
400
- xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs['units'] = 'm^2 / m^2'
401
- xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs[
402
- 'long_name'] = 'Normalized Radar Cross Section, no noise correction applied'
403
- xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs[
404
- '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
+ )
405
511
 
406
- 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
+ )
407
515
 
408
516
  if config["l2_params"]["dual_pol"]:
409
-
410
517
  xr_dataset = xr_dataset.rename({
411
518
  'dsig_cross': 'owiDsig_cross',
412
519
  'winddir_cross': 'owiWindDirection_cross',
413
520
  'winddir_dual': 'owiWindDirection',
414
521
  'windspeed_cross': 'owiWindSpeed_cross',
415
522
  'windspeed_dual': 'owiWindSpeed',
416
- 'sigma0_detrend_cross': 'owiNrcs_detrend_cross'
523
+ 'sigma0_detrend_cross': 'owiNrcs_detrend_cross',
524
+ 'nesz_cross_flattened': 'owiNesz_cross_flattened'
417
525
  })
418
526
 
419
- if config["apply_flattening"]:
420
- xr_dataset = xr_dataset.rename({
421
- 'nesz_cross_flattened': 'owiNesz_cross_flattened',
422
- })
423
-
424
527
  # nrcs cross
425
- xr_dataset['owiNrcs_cross'] = xr_dataset['sigma0_ocean'].sel(
426
- pol=config["l2_params"]["crosspol"])
528
+ xr_dataset["owiNrcs_cross"] = xr_dataset["sigma0_ocean"].sel(
529
+ pol=config["l2_params"]["crosspol"]
530
+ )
427
531
 
428
- xr_dataset.owiNrcs_cross.attrs['units'] = 'm^2 / m^2'
429
- xr_dataset.owiNrcs_cross.attrs['long_name'] = 'Normalized Radar Cross Section'
430
- 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
+ )
431
537
 
432
- xr_dataset['owiMask_Nrcs_cross'] = xr_dataset['sigma0_mask'].sel(
433
- pol=config["l2_params"]["crosspol"])
538
+ xr_dataset["owiMask_Nrcs_cross"] = xr_dataset["sigma0_mask"].sel(
539
+ pol=config["l2_params"]["crosspol"]
540
+ )
434
541
  xr_dataset.owiMask_Nrcs_cross.attrs = xr_dataset.sigma0_mask.attrs
435
542
 
436
543
  # nesz cross
437
- xr_dataset = xr_dataset.assign(owiNesz_cross=(
438
- ['line', 'sample'], xr_dataset.nesz.sel(pol=config["l2_params"]["crosspol"]).values)) # no flattening
439
- xr_dataset.owiNesz_cross.attrs['units'] = 'm^2 / m^2'
440
- 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"
553
+
554
+ xr_dataset.owiNesz_cross_flattened.attrs["units"] = "m^2 / m^2"
555
+ xr_dataset.owiNesz_cross_flattened.attrs["long_name"] = "Noise Equivalent SigmaNaught"
441
556
 
442
- xr_dataset['owiNrcs_cross_no_noise_correction'] = xr_dataset['sigma0_ocean_raw'].sel(
443
- pol=config["l2_params"]["crosspol"])
557
+ xr_dataset["owiNrcs_cross_no_noise_correction"] = xr_dataset[
558
+ "sigma0_ocean_raw"
559
+ ].sel(pol=config["l2_params"]["crosspol"])
444
560
 
445
- xr_dataset.owiNrcs_cross_no_noise_correction.attrs['units'] = 'm^2 / m^2'
446
- xr_dataset.owiNrcs_cross_no_noise_correction.attrs[
447
- 'long_name'] = 'Normalized Radar Cross Section, no noise correction applied'
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
+ )
448
565
 
449
566
  #  sigma0_raw__corrected cross
450
567
  if "sigma0_raw__corrected" in xr_dataset:
451
- xr_dataset['owiNrcs_cross_no_noise_correction_recalibrated'] = xr_dataset['sigma0_raw__corrected'].sel(
452
- pol=config["l2_params"]["crosspol"])
453
- xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs = xr_dataset.sigma0_raw__corrected.attrs
454
- 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
+ )
455
577
  xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs[
456
- 'long_name'] = 'Normalized Radar Cross Section ; no noise correction applied'
578
+ "long_name"
579
+ ] = "Normalized Radar Cross Section ; no noise correction applied"
457
580
  xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs[
458
- 'comment'] = 'owiNrcs_cross_no_noise_correction ; recalibrated with kersten method'
581
+ "comment"
582
+ ] = "owiNrcs_cross_no_noise_correction ; recalibrated with kersten method"
459
583
 
460
- 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
+ )
461
587
 
462
588
  if config["add_gradientsfeatures"]:
463
- xr_dataset = xr_dataset.rename({
464
- 'heterogeneity_mask': 'owiWindFilter'
465
- })
589
+ xr_dataset = xr_dataset.rename({"heterogeneity_mask": "owiWindFilter"})
466
590
  else:
467
- xr_dataset['owiWindFilter'] = xr.full_like(xr_dataset.owiNrcs, 0)
468
- xr_dataset['owiWindFilter'].attrs['long_name'] = "Quality flag taking into account the local heterogeneity"
469
- xr_dataset['owiWindFilter'].attrs['valid_range'] = np.array([0, 3])
470
- xr_dataset['owiWindFilter'].attrs['flag_values'] = np.array([
471
- 0, 1, 2, 3])
472
- xr_dataset['owiWindFilter'].attrs[
473
- '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"
474
601
 
475
602
  #  other variables
476
603
 
477
- xr_dataset['owiWindQuality'] = xr.full_like(xr_dataset.owiNrcs, 0)
478
- xr_dataset['owiWindQuality'].attrs[
479
- 'long_name'] = "Quality flag taking into account the consistency_between_wind_inverted_and_NRCS_and_Doppler_measured"
480
- xr_dataset['owiWindQuality'].attrs['valid_range'] = np.array([0, 3])
481
- xr_dataset['owiWindQuality'].attrs['flag_values'] = np.array([
482
- 0, 1, 2, 3])
483
- xr_dataset['owiWindQuality'].attrs['flag_meanings'] = "good medium low poor"
484
- 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"
485
612
 
486
613
  xr_dataset = xr_dataset.rename(
487
614
  {"line": "owiAzSize", "sample": "owiRaSize"})
488
615
 
489
616
  xr_dataset = xr_dataset.drop_vars(
490
- ['sigma0_ocean', 'sigma0', 'sigma0_ocean_raw', 'sigma0_raw', 'ancillary_wind', 'nesz', 'spatial_ref'])
491
- 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:
492
628
  xr_dataset = xr_dataset.drop_vars(["sigma0_raw__corrected"])
493
- xr_dataset = xr_dataset.drop_dims(['pol'])
629
+ xr_dataset = xr_dataset.drop_dims(["pol"])
494
630
 
495
631
  table_fillValue = {
496
632
  "owiWindQuality": -1,
@@ -509,17 +645,24 @@ def makeL2asOwi(xr_dataset, config):
509
645
  for var in list(set(xr_dataset.coords.keys()) | set(xr_dataset.keys())):
510
646
  encoding[var] = {}
511
647
  try:
512
- encoding[var].update({'_FillValue': table_fillValue[var]})
648
+ encoding[var].update({"_FillValue": table_fillValue[var]})
513
649
  except:
514
- if (var in ["owiWindSpeed_co", "owiWindSpeed_cross", "owiWindSpeed"]):
515
- encoding[var].update({'_FillValue': -9999.0})
650
+ if var in ["owiWindSpeed_co", "owiWindSpeed_cross", "owiWindSpeed"]:
651
+ encoding[var].update({"_FillValue": -9999.0})
516
652
  else:
517
- encoding[var].update({'_FillValue': None})
653
+ encoding[var].update({"_FillValue": None})
518
654
 
519
655
  return xr_dataset, encoding
520
656
 
521
657
 
522
- 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
+ ):
523
666
  """
524
667
  Main function to generate L2 product.
525
668
 
@@ -546,11 +689,8 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_gradientsfeat
546
689
  filename)
547
690
 
548
691
  if os.path.exists(config_path):
549
- with open(config_path, 'r') as file:
550
- config_base = yaml.load(
551
- file,
552
- Loader=yaml.FullLoader
553
- )
692
+ with open(config_path, "r") as file:
693
+ config_base = yaml.load(file, Loader=yaml.FullLoader)
554
694
  try:
555
695
  # check if sensor is in the config
556
696
  config = config_base[sensor]
@@ -558,15 +698,20 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_gradientsfeat
558
698
  raise KeyError("sensor %s not in this config" % sensor)
559
699
  else:
560
700
  raise FileNotFoundError(
561
- 'config_path do not exists, got %s ' % config_path)
701
+ "config_path do not exists, got %s " % config_path)
562
702
 
563
703
  recalibration = config["recalibration"]
564
704
  meta = fct_meta(filename)
565
705
 
566
706
  # si une des deux n'est pas VV VH HH HV on ne fait rien
567
- 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(" ")]):
568
708
  raise ValueError(f"Polarisation non gérée : meta.pols = {meta.pols}")
569
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
+
570
715
  no_subdir_cfg = config_base.get("no_subdir", False)
571
716
  config["no_subdir"] = no_subdir_cfg
572
717
 
@@ -575,34 +720,53 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_gradientsfeat
575
720
  else:
576
721
  winddir_convention = "meteorological"
577
722
  logging.warning(
578
- 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
+ )
579
725
  config["winddir_convention"] = winddir_convention
580
726
 
581
727
  if "add_gradientsfeatures" in config_base:
582
728
  add_gradientsfeatures = config_base["add_gradientsfeatures"]
583
729
  else:
584
730
  add_gradientsfeatures = False
585
- logging.warning(
586
- f'Not computing gradients by default')
731
+ logging.warning(f"Not computing gradients by default")
587
732
  config["add_gradientsfeatures"] = add_gradientsfeatures
588
733
 
589
734
  if "add_nrcs_model" in config_base:
590
735
  add_nrcs_model = config_base["add_nrcs_model"]
591
736
  add_nrcs_model = False
592
737
  logging.warning(
593
- f'Force this variable to be false, before fixing the issue'
594
- )
738
+ f"Force add_nrcs_model to be false, before fixing an issue")
595
739
  else:
596
740
  add_nrcs_model = False
597
- logging.warning(
598
- f'Not computing nrcs from model by default')
741
+ logging.warning(f"Not computing nrcs from model by default")
599
742
  config["add_nrcs_model"] = add_nrcs_model
600
743
 
601
744
  # creating a dictionnary of parameters
602
745
  config["l2_params"] = {}
603
746
 
604
- out_file = getOutputName2(filename, outdir, sensor,
605
- meta, subdir=not no_subdir_cfg)
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
+ )
761
+
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
+ )
606
770
 
607
771
  if os.path.exists(out_file) and overwrite is False:
608
772
  raise FileExistsError("outfile %s already exists" % out_file)
@@ -611,37 +775,48 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_gradientsfeat
611
775
  map_model = getAncillary(meta, ancillary_name)
612
776
  if map_model is None:
613
777
  raise Exception(
614
- 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
+ )
615
780
 
616
781
  try:
617
- if ((recalibration) & ("SENTINEL" in sensor_longname)):
782
+ if (recalibration) & ("SENTINEL" in sensor_longname):
618
783
  logging.info(
619
- f'recalibration is {recalibration} : Kersten formula is applied')
784
+ f"recalibration is {recalibration} : Kersten formula is applied"
785
+ )
620
786
  xsar_dataset = fct_dataset(
621
- meta, resolution=resolution, recalibration=recalibration)
622
- xr_dataset = xsar_dataset.datatree['measurement'].to_dataset()
623
- xr_dataset = xr_dataset.merge(xsar_dataset.datatree["recalibration"].to_dataset()[
624
- ['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
+ )
625
795
 
626
796
  else:
627
797
  logging.info(
628
- f'recalibration is {recalibration} : Kersten formula is not applied')
629
- if ("SENTINEL" in sensor_longname):
798
+ f"recalibration is {recalibration} : Kersten formula is not applied"
799
+ )
800
+ if "SENTINEL" in sensor_longname:
630
801
  xsar_dataset = fct_dataset(
631
- meta, resolution=resolution, recalibration=recalibration)
632
- xr_dataset = xsar_dataset.datatree['measurement'].to_dataset()
633
- xr_dataset = xr_dataset.merge(xsar_dataset.datatree["recalibration"].to_dataset()[
634
- ['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
+ )
635
810
 
636
811
  else:
637
812
  xsar_dataset = fct_dataset(meta, resolution=resolution)
638
- xr_dataset = xsar_dataset.datatree['measurement'].to_dataset()
813
+ xr_dataset = xsar_dataset.datatree["measurement"].to_dataset()
639
814
 
640
815
  xr_dataset = xr_dataset.rename(map_model)
641
816
  xr_dataset.attrs = xsar_dataset.dataset.attrs
642
817
 
643
818
  except Exception as e:
644
- logging.info('%s', traceback.format_exc())
819
+ logging.info("%s", traceback.format_exc())
645
820
  logging.error(e)
646
821
  sys.exit(-1)
647
822
 
@@ -659,22 +834,24 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_gradientsfeat
659
834
  else:
660
835
  dual_pol = False
661
836
 
662
- if 'VV' in xr_dataset.pol.values:
663
- copol = 'VV'
664
- crosspol = 'VH'
665
- copol_gmf = 'VV'
666
- 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"
667
842
  else:
668
- logging.warning('for now this processor does not support entirely HH+HV acquisitions\n '
669
- 'it wont crash but it will use HH+VH GMF for wind inversion -> wrong hypothesis\n '
670
- '!! dual WIND SPEED IS NOT USABLE !! But co WIND SPEED IS USABLE !!')
671
- copol = 'HH'
672
- crosspol = 'HV'
673
- copol_gmf = 'HH'
674
- 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"
675
852
 
676
- model_co = config["GMF_"+copol_gmf+"_NAME"]
677
- model_cross = config["GMF_"+crosspol_gmf+"_NAME"]
853
+ model_co = config["GMF_" + copol_gmf + "_NAME"]
854
+ model_cross = config["GMF_" + crosspol_gmf + "_NAME"]
678
855
 
679
856
  # register paramaters in config
680
857
  config["l2_params"]["dual_pol"] = dual_pol
@@ -693,16 +870,37 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_gradientsfeat
693
870
  if len(nc_luts) > 0:
694
871
  windspeed.register_nc_luts(getConf()["nc_luts_path"])
695
872
 
696
- if (model_co == "gmf_cmod7"):
873
+ if model_co == "gmf_cmod7":
697
874
  windspeed.register_cmod7(getConf()["lut_cmod7_path"])
698
875
  #  Step 2 - clean and prepare dataset
699
876
 
700
877
  # variables to not keep in the L2
701
- black_list = ['digital_number', 'gamma0_raw', 'negz',
702
- 'azimuth_time', 'slant_range_time', 'velocity', 'range_ground_spacing',
703
- 'gamma0', 'time', 'nd_co', 'nd_cr', 'gamma0_lut', 'sigma0_lut', "noise_lut_range", "lineSpacing",
704
- "sampleSpacing", "noise_lut", "noise_lut_azi",
705
- '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
+ ]
706
904
  variables = list(set(xr_dataset) - set(black_list))
707
905
  xr_dataset = xr_dataset[variables]
708
906
 
@@ -729,122 +927,191 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_gradientsfeat
729
927
  # TOREMOVE
730
928
  if "offboresight" in xr_dataset:
731
929
  xr_dataset.offboresight.attrs["units"] = "degrees"
732
- 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
+ )
733
933
  xr_dataset.elevation.attrs["standard_name"] = "offboresight"
734
934
 
735
935
  # masks (no ice / no_valid)
736
- xr_dataset.land_mask.values = binary_dilation(xr_dataset['land_mask'].values.astype('uint8'),
737
- structure=np.ones((3, 3), np.uint8), iterations=3)
738
- xr_dataset.land_mask.attrs['long_name'] = 'Mask of data'
739
- xr_dataset.land_mask.attrs['valid_range'] = np.array([0, 1])
740
- xr_dataset.land_mask.attrs['flag_values'] = np.array([0, 1])
741
- 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"
742
945
 
743
946
  logging.debug("mask is a copy of land_mask")
744
947
 
745
- xr_dataset['mask'] = xr.DataArray(xr_dataset.land_mask)
948
+ xr_dataset["mask"] = xr.DataArray(xr_dataset.land_mask)
746
949
  xr_dataset.mask.attrs = {}
747
- xr_dataset.mask.attrs['long_name'] = 'Mask of data'
748
- xr_dataset.mask.attrs['valid_range'] = np.array([0, 3])
749
- xr_dataset.mask.attrs['flag_values'] = np.array([0, 1, 2, 3])
750
- 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"
751
954
 
752
955
  # ancillary
753
- xr_dataset['ancillary_wind_direction'] = (
754
- 90. - np.rad2deg(np.arctan2(xr_dataset.model_V10, xr_dataset.model_U10)) + 180) % 360
755
-
756
- xr_dataset['ancillary_wind_direction'] = xr.where(xr_dataset['mask'], np.nan,
757
- xr_dataset['ancillary_wind_direction']).transpose(
758
- *xr_dataset['ancillary_wind_direction'].dims)
759
- xr_dataset['ancillary_wind_direction'].attrs = {}
760
- xr_dataset['ancillary_wind_direction'].attrs['units'] = 'degrees_north'
761
- xr_dataset['ancillary_wind_direction'].attrs[
762
- 'long_name'] = f'{ancillary_name} wind direction in meteorological convention (clockwise, from), ex: 0°=from north, 90°=from east'
763
- xr_dataset['ancillary_wind_direction'].attrs['standart_name'] = 'wind_direction'
764
-
765
- xr_dataset['ancillary_wind_speed'] = np.sqrt(
766
- xr_dataset['model_U10']**2+xr_dataset['model_V10']**2)
767
- xr_dataset['ancillary_wind_speed'] = xr.where(xr_dataset['mask'], np.nan,
768
- xr_dataset['ancillary_wind_speed']).transpose(
769
- *xr_dataset['ancillary_wind_speed'].dims)
770
- xr_dataset['ancillary_wind_speed'].attrs = {}
771
- xr_dataset['ancillary_wind_speed'].attrs['units'] = 'm s^-1'
772
- xr_dataset['ancillary_wind_speed'].attrs[
773
- 'long_name'] = f'{ancillary_name} wind speed'
774
- xr_dataset['ancillary_wind_speed'].attrs['standart_name'] = 'wind_speed'
775
-
776
- xr_dataset['ancillary_wind'] = xr.where(xr_dataset['mask'], np.nan,
777
- (xr_dataset.ancillary_wind_speed * np.exp(1j * xsarsea.dir_meteo_to_sample(xr_dataset.ancillary_wind_direction, xr_dataset.ground_heading)))).transpose(
778
- *xr_dataset['ancillary_wind_speed'].dims)
779
-
780
- xr_dataset.attrs['ancillary_source'] = xr_dataset['model_U10'].attrs['history'].split('decoded: ')[
781
- 1].strip()
782
- 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"])
783
1002
 
784
1003
  # nrcs processing
785
- xr_dataset['sigma0_ocean'] = xr.where(xr_dataset['mask'], np.nan,
786
- xr_dataset['sigma0']).transpose(*xr_dataset['sigma0'].dims)
787
- 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
788
1008
  #  we forced it to 1e-15
789
- 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"
790
1012
 
791
1013
  # rajout d'un mask pour les valeurs <=0:
792
- xr_dataset['sigma0_mask'] = xr.where(
793
- xr_dataset['sigma0_ocean'] <= 0, 1, 0).transpose(*xr_dataset['sigma0'].dims)
794
- xr_dataset.sigma0_mask.attrs['valid_range'] = np.array([0, 1])
795
- xr_dataset.sigma0_mask.attrs['flag_values'] = np.array([0, 1])
796
- xr_dataset.sigma0_mask.attrs['flag_meanings'] = 'valid no_valid'
797
- xr_dataset['sigma0_ocean'] = xr.where(
798
- 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
+ )
799
1023
 
800
- xr_dataset['sigma0_ocean_raw'] = xr.where(xr_dataset['mask'], np.nan,
801
- 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)
802
1027
 
803
- xr_dataset['sigma0_ocean_raw'].attrs = xr_dataset['sigma0_raw'].attrs
1028
+ xr_dataset["sigma0_ocean_raw"].attrs = xr_dataset["sigma0_raw"].attrs
804
1029
 
805
- xr_dataset['sigma0_detrend'] = xsarsea.sigma0_detrend(
806
- 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
+ )
807
1033
 
808
1034
  # processing
809
1035
  if dual_pol:
810
1036
 
811
1037
  xr_dataset['sigma0_detrend_cross'] = xsarsea.sigma0_detrend(
812
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
+
813
1046
  if config["apply_flattening"]:
814
- xr_dataset = xr_dataset.assign(nesz_cross_flattened=(
815
- ['line', 'sample'], windspeed.nesz_flattening(xr_dataset.nesz.sel(pol=crosspol), xr_dataset.incidence).data))
816
- xr_dataset['nesz_cross_flattened'].attrs[
817
- "comment"] = 'nesz has been flattened using windspeed.nesz_flattening'
818
1047
  # dsig
819
- xr_dataset["dsig_cross"] = windspeed.get_dsig(config["dsig_"+crosspol_gmf+"_NAME"], xr_dataset.incidence,
820
- 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
+
821
1059
  else:
822
1060
  # dsig
823
- xr_dataset["dsig_cross"] = windspeed.get_dsig(config["dsig_"+crosspol_gmf+"_NAME"], xr_dataset.incidence,
824
- xr_dataset['sigma0_ocean'].sel(pol=crosspol), xr_dataset.nesz.sel(pol=crosspol))
825
-
826
- xr_dataset.dsig_cross.attrs['comment'] = 'variable used to ponderate copol and crosspol'
827
- xr_dataset.dsig_cross.attrs['formula_used'] = config["dsig_" +
828
- crosspol_gmf+"_NAME"]
829
- xr_dataset.dsig_cross.attrs['apply_flattening'] = str(
830
- config["apply_flattening"])
831
-
832
- if ((recalibration) & ("SENTINEL" in sensor_longname)):
833
- xr_dataset.attrs["path_aux_pp1_new"] = os.path.basename(os.path.dirname(
834
- os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_pp1_new'])))
835
- xr_dataset.attrs["path_aux_cal_new"] = os.path.basename(os.path.dirname(
836
- os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_cal_new'])))
837
-
838
- xr_dataset.attrs["path_aux_pp1_old"] = os.path.basename(os.path.dirname(
839
- os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_pp1_old'])))
840
- xr_dataset.attrs["path_aux_cal_old"] = os.path.basename(os.path.dirname(
841
- 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
+ )
842
1106
 
843
1107
  if add_nrcs_model:
844
1108
  # add timing
845
1109
  phi = np.abs(
846
- np.rad2deg(xsarsea.dir_meteo_to_sample(
847
- 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
+ )
848
1115
  )
849
1116
 
850
1117
  varnames = ["ancillary_nrcs"]
@@ -866,9 +1133,7 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_gradientsfeat
866
1133
  incidence=incidence, wspd=wspd, phi=phi, method="nearest"
867
1134
  )
868
1135
  else:
869
- return lut.sel(
870
- incidence=incidence, wspd=wspd, method="nearest"
871
- )
1136
+ return lut.sel(incidence=incidence, wspd=wspd, method="nearest")
872
1137
 
873
1138
  xr_dataset[varnames[idx]] = xr.apply_ufunc(
874
1139
  lut_selection,
@@ -920,38 +1185,46 @@ def process_gradients(xr_dataset, config):
920
1185
  dual_pol = config["l2_params"]["dual_pol"]
921
1186
 
922
1187
  # Load the 100m dataset
923
- xsar_dataset_100 = fct_dataset(
924
- meta, resolution='100m')
1188
+ xsar_dataset_100 = fct_dataset(meta, resolution="100m")
925
1189
 
926
- xr_dataset_100 = xsar_dataset_100.datatree['measurement'].to_dataset()
1190
+ xr_dataset_100 = xsar_dataset_100.datatree["measurement"].to_dataset()
927
1191
  xr_dataset_100 = xr_dataset_100.rename(map_model)
928
1192
  # load dataset
929
1193
  xr_dataset_100 = xr_dataset_100.load()
930
1194
 
931
1195
  # adding sigma0 detrend
932
- xr_dataset_100['sigma0_detrend'] = xsarsea.sigma0_detrend(
933
- 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
+ )
934
1199
 
935
1200
  if dual_pol:
936
- xr_dataset_100['sigma0_detrend_cross'] = xsarsea.sigma0_detrend(
937
- 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
+ )
938
1206
 
939
1207
  sigma0_detrend_combined = xr.concat(
940
- [xr_dataset_100['sigma0_detrend'],
941
- xr_dataset_100['sigma0_detrend_cross']],
942
- dim='pol'
1208
+ [xr_dataset_100["sigma0_detrend"],
1209
+ xr_dataset_100["sigma0_detrend_cross"]],
1210
+ dim="pol",
943
1211
  )
944
- sigma0_detrend_combined['pol'] = [copol, crosspol]
1212
+ sigma0_detrend_combined["pol"] = [copol, crosspol]
945
1213
 
946
- xr_dataset_100['sigma0_detrend'] = sigma0_detrend_combined
1214
+ xr_dataset_100["sigma0_detrend"] = sigma0_detrend_combined
947
1215
 
948
- xr_dataset_100.land_mask.values = binary_dilation(xr_dataset_100['land_mask'].values.astype('uint8'),
949
- structure=np.ones((3, 3), np.uint8), iterations=3)
950
- xr_dataset_100['sigma0_detrend'] = xr.where(
951
- 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)
952
1224
 
953
- xr_dataset_100['ancillary_wind'] = (
954
- 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))
955
1228
 
956
1229
  downscales_factors = [1, 2, 4, 8]
957
1230
  # 4 and 8 must be in downscales_factors
@@ -962,7 +1235,7 @@ def process_gradients(xr_dataset, config):
962
1235
  xr_dataset_100=xr_dataset_100,
963
1236
  windows_sizes=[1600, 3200],
964
1237
  downscales_factors=downscales_factors,
965
- window_step=1
1238
+ window_step=1,
966
1239
  )
967
1240
 
968
1241
  # Compute heterogeneity mask and variables
@@ -971,24 +1244,29 @@ def process_gradients(xr_dataset, config):
971
1244
 
972
1245
  # Add streaks dataset
973
1246
  streaks_indiv = gradientFeatures.streaks_individual()
974
- if 'longitude' in streaks_indiv:
975
- xr_dataset_streaks = xr.Dataset({
976
- 'longitude': streaks_indiv.longitude,
977
- 'latitude': streaks_indiv.latitude,
978
- 'dir_smooth': streaks_indiv.angle,
979
- 'dir_mean_smooth': gradientFeatures.streaks_mean_smooth().angle,
980
- 'dir_smooth_mean': gradientFeatures.streaks_smooth_mean().angle,
981
- })
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
+ )
982
1257
  else:
983
1258
  logger.warn(
984
- "'longitude' not found in streaks_indiv : there is probably an error")
1259
+ "'longitude' not found in streaks_indiv : there is probably an error"
1260
+ )
985
1261
  xr_dataset_streaks = None
986
1262
 
987
1263
  return xr_dataset, xr_dataset_streaks
988
1264
 
989
1265
 
990
1266
  @timing(logger=logger.info)
991
- 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
+ ):
992
1270
  """
993
1271
  Main function to generate L2 product.
994
1272
 
@@ -1016,11 +1294,11 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, res
1016
1294
  """
1017
1295
 
1018
1296
  xr_dataset, out_file, config = preprocess(
1019
- filename, outdir, config_path, overwrite, resolution)
1297
+ filename, outdir, config_path, overwrite, resolution
1298
+ )
1020
1299
 
1021
1300
  if config["add_gradientsfeatures"]:
1022
- xr_dataset, xr_dataset_streaks = process_gradients(
1023
- xr_dataset, config)
1301
+ xr_dataset, xr_dataset_streaks = process_gradients(xr_dataset, config)
1024
1302
  else:
1025
1303
  xr_dataset_streaks = None
1026
1304
 
@@ -1035,8 +1313,8 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, res
1035
1313
  sensor_longname = config["sensor_longname"]
1036
1314
 
1037
1315
  if dual_pol:
1038
- sigma0_ocean_cross = xr_dataset['sigma0_ocean'].sel(pol=crosspol)
1039
- dsig_cross = xr_dataset['dsig_cross']
1316
+ sigma0_ocean_cross = xr_dataset["sigma0_ocean"].sel(pol=crosspol)
1317
+ dsig_cross = xr_dataset["dsig_cross"]
1040
1318
  else:
1041
1319
  sigma0_ocean_cross = None
1042
1320
  dsig_cross = 0.1 # default value set in xsarsea
@@ -1054,97 +1332,119 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, res
1054
1332
  logging.info("Checking incidence range within LUTS incidence range")
1055
1333
  #  warning if incidence is out of lut incidence range
1056
1334
  inc_check_co, inc_check_cross = check_incidence_range(
1057
- xr_dataset['incidence'], [model_co, model_cross], **kwargs)
1058
-
1059
- wind_co, wind_dual, windspeed_cr = inverse(dual_pol,
1060
- inc=xr_dataset['incidence'],
1061
- sigma0=xr_dataset['sigma0_ocean'].sel(
1062
- pol=copol),
1063
- sigma0_dual=sigma0_ocean_cross,
1064
- ancillary_wind=xr_dataset['ancillary_wind'],
1065
- dsig_cr=dsig_cross,
1066
- model_co=model_co,
1067
- model_cross=model_cross,
1068
- ** 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
+ )
1069
1349
  # windspeed_co
1070
- xr_dataset['windspeed_co'] = np.abs(wind_co)
1350
+ xr_dataset["windspeed_co"] = np.abs(wind_co)
1071
1351
  xr_dataset["windspeed_co"].attrs["units"] = "m.s⁻1"
1072
- xr_dataset["windspeed_co"].attrs["long_name"] = "Wind speed inverted from model %s (%s)" % (
1073
- model_co, copol)
1352
+ xr_dataset["windspeed_co"].attrs["long_name"] = (
1353
+ "Wind speed inverted from model %s (%s)" % (model_co, copol)
1354
+ )
1074
1355
  xr_dataset["windspeed_co"].attrs["standart_name"] = "wind_speed"
1075
1356
  xr_dataset["windspeed_co"].attrs["model"] = wind_co.attrs["model"]
1076
- del xr_dataset["windspeed_co"].attrs['comment']
1357
+ del xr_dataset["windspeed_co"].attrs["comment"]
1077
1358
 
1078
1359
  # winddir_co
1079
- xr_dataset['winddir_co'] = transform_winddir(
1080
- wind_co, xr_dataset.ground_heading, winddir_convention=config["winddir_convention"])
1081
- 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)
1082
1366
 
1083
1367
  # windspeed_dual / windspeed_cr / /winddir_dual / winddir_cr
1084
1368
  if dual_pol and wind_dual is not None:
1085
- xr_dataset['windspeed_dual'] = np.abs(wind_dual)
1369
+ xr_dataset["windspeed_dual"] = np.abs(wind_dual)
1086
1370
  xr_dataset["windspeed_dual"].attrs["units"] = "m.s⁻1"
1087
- xr_dataset["windspeed_dual"].attrs["long_name"] = "Wind speed inverted from model %s (%s) & %s (%s)" % (
1088
- 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
+ )
1089
1375
  xr_dataset["windspeed_dual"].attrs["standart_name"] = "wind_speed"
1090
1376
  xr_dataset["windspeed_dual"].attrs["model"] = wind_dual.attrs["model"]
1091
- del xr_dataset["windspeed_dual"].attrs['comment']
1377
+ del xr_dataset["windspeed_dual"].attrs["comment"]
1092
1378
 
1093
- xr_dataset['winddir_dual'] = transform_winddir(
1094
- wind_dual, xr_dataset.ground_heading, winddir_convention=config["winddir_convention"])
1095
- 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"
1096
1387
 
1097
1388
  xr_dataset = xr_dataset.assign(
1098
- windspeed_cross=(['line', 'sample'], windspeed_cr.data))
1389
+ windspeed_cross=(["line", "sample"], windspeed_cr.data)
1390
+ )
1099
1391
  xr_dataset["windspeed_cross"].attrs["units"] = "m.s⁻1"
1100
- xr_dataset["windspeed_cross"].attrs["long_name"] = "Wind Speed inverted from model %s (%s)" % (
1101
- model_cross, crosspol)
1392
+ xr_dataset["windspeed_cross"].attrs["long_name"] = (
1393
+ "Wind Speed inverted from model %s (%s)" % (model_cross, crosspol)
1394
+ )
1102
1395
  xr_dataset["windspeed_cross"].attrs["standart_name"] = "wind_speed"
1103
1396
  xr_dataset["windspeed_cross"].attrs["model"] = "%s" % (model_cross)
1104
1397
 
1105
- xr_dataset['winddir_cross'] = xr_dataset['winddir_dual'].copy()
1106
- xr_dataset['winddir_cross'].attrs = xr_dataset['winddir_dual'].attrs
1107
- 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"
1108
1403
 
1109
1404
  if config["winddir_convention"] == "oceanographic":
1110
- attrs = xr_dataset['ancillary_wind_direction'].attrs
1111
- xr_dataset['ancillary_wind_direction'] = xsarsea.dir_meteo_to_oceano(
1112
- xr_dataset['ancillary_wind_direction'])
1113
- xr_dataset['ancillary_wind_direction'].attrs = attrs
1114
- xr_dataset['ancillary_wind_direction'].attrs[
1115
- "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"
1116
1413
 
1117
- xr_dataset, encoding = makeL2asOwi(
1118
- xr_dataset, config)
1414
+ xr_dataset, encoding = makeL2asOwi(xr_dataset, config)
1119
1415
 
1120
1416
  xr_dataset = xr_dataset.compute()
1121
1417
  #  add attributes
1122
1418
  firstMeasurementTime = None
1123
1419
  lastMeasurementTime = None
1124
1420
  try:
1125
- firstMeasurementTime = datetime.datetime.strptime(xr_dataset.attrs['start_date'],
1126
- "%Y-%m-%d %H:%M:%S.%f").strftime(
1127
- "%Y-%m-%dT%H:%M:%SZ")
1128
- lastMeasurementTime = datetime.datetime.strptime(xr_dataset.attrs['stop_date'],
1129
- "%Y-%m-%d %H:%M:%S.%f").strftime(
1130
- "%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")
1131
1427
  except:
1132
- firstMeasurementTime = datetime.datetime.strptime(xr_dataset.attrs['start_date'],
1133
- "%Y-%m-%d %H:%M:%S").strftime(
1134
- "%Y-%m-%dT%H:%M:%SZ")
1135
- lastMeasurementTime = datetime.datetime.strptime(xr_dataset.attrs['stop_date'],
1136
- "%Y-%m-%d %H:%M:%S").strftime(
1137
- "%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")
1138
1434
 
1139
1435
  attrs = {
1140
1436
  "TITLE": "Sentinel-1 OWI Component",
1141
1437
  "productOwner": "IFREMER",
1142
- "sourceProduct": (xr_dataset.attrs["safe"] if "safe" in xr_dataset.attrs else os.path.basename(xr_dataset.attrs["product_path"])),
1143
- "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"),
1144
1444
  "missionName": sensor_longname,
1145
- "missionPhase": "Operational",
1146
- "polarisation": xr_dataset.attrs['pols'],
1147
- "acquisitionStation": '',
1445
+ "missionPhase": "Operational",
1446
+ "polarisation": xr_dataset.attrs["pols"],
1447
+ "acquisitionStation": "",
1148
1448
  "xsar_version": xsar.__version__,
1149
1449
  "xsarsea_version": xsarsea.__version__,
1150
1450
  "pythonVersion": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
@@ -1157,25 +1457,32 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, res
1157
1457
  "bathySource": "/",
1158
1458
  "oswAlgorithmName": "grdwindinversion",
1159
1459
  "owiAlgorithmVersion": grdwindinversion.__version__,
1160
- "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"],
1161
1463
  "iceSource": "/",
1162
1464
  "owiNoiseCorrection": "True",
1163
- "inversionTabGMF": config['GMF_'+copol_gmf +
1164
- '_NAME'] + ", " + config["GMF_"+crosspol_gmf+"_NAME"],
1465
+ "inversionTabGMF": config["GMF_" + copol_gmf + "_NAME"]
1466
+ + ", "
1467
+ + config["GMF_" + crosspol_gmf + "_NAME"],
1165
1468
  "wnf_3km_average": "False",
1166
1469
  "owiWindSpeedSrc": "owiWindSpeed",
1167
1470
  "owiWindDirectionSrc": "/",
1168
- "ancillary_source": xr_dataset.attrs['ancillary_source'],
1471
+ "ancillary_source": xr_dataset.attrs["ancillary_source"],
1169
1472
  "winddir_convention": config["winddir_convention"],
1170
1473
  "incidence_within_lut_copol_incidence_range": str(inc_check_co),
1171
1474
  "incidence_within_lut_crosspol_incidence_range": str(inc_check_cross),
1172
- "swath": xr_dataset.attrs['swath'],
1173
- "footprint": xr_dataset.attrs['footprint'],
1174
- "coverage": xr_dataset.attrs['coverage'],
1175
-
1475
+ "swath": xr_dataset.attrs["swath"],
1476
+ "footprint": xr_dataset.attrs["footprint"],
1477
+ "coverage": xr_dataset.attrs["coverage"],
1176
1478
  }
1177
1479
 
1178
- 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
+ ]:
1179
1486
  if recalib_attrs in xr_dataset.attrs:
1180
1487
  attrs[recalib_attrs] = xr_dataset.attrs[recalib_attrs]
1181
1488
 
@@ -1190,11 +1497,11 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, res
1190
1497
  if sup_attr in xr_dataset.attrs:
1191
1498
  attrs[sup_attr] = xr_dataset.attrs[sup_attr]
1192
1499
 
1193
- attrs['footprint'] = str(attrs['footprint'])
1500
+ attrs["footprint"] = str(attrs["footprint"])
1194
1501
 
1195
1502
  # add in kwargs in attrs
1196
1503
  for key in kwargs:
1197
- 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]
1198
1505
 
1199
1506
  xr_dataset.attrs = attrs
1200
1507
 
@@ -1233,7 +1540,7 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, res
1233
1540
  return out_file, xr_dataset
1234
1541
 
1235
1542
 
1236
- def transform_winddir(wind_cpx, ground_heading, winddir_convention='meteorological'):
1543
+ def transform_winddir(wind_cpx, ground_heading, winddir_convention="meteorological"):
1237
1544
  """
1238
1545
 
1239
1546
  Parameters
@@ -1254,7 +1561,8 @@ def transform_winddir(wind_cpx, ground_heading, winddir_convention='meteorologic
1254
1561
  """
1255
1562
  # to meteo winddir_convention
1256
1563
  dataArray = xsarsea.dir_sample_to_meteo(
1257
- np.angle(wind_cpx, deg=True), ground_heading)
1564
+ np.angle(wind_cpx, deg=True), ground_heading
1565
+ )
1258
1566
  long_name = "Wind direction in meteorological convention (clockwise, from), ex: 0°=from north, 90°=from east"
1259
1567
 
1260
1568
  if winddir_convention == "meteorological":
@@ -1267,7 +1575,8 @@ def transform_winddir(wind_cpx, ground_heading, winddir_convention='meteorologic
1267
1575
  else:
1268
1576
  #  warning
1269
1577
  logging.warning(
1270
- f"wind direction convention {winddir_convention} is not supported, using meteorological",)
1578
+ f"wind direction convention {winddir_convention} is not supported, using meteorological",
1579
+ )
1271
1580
  long_name = "Wind direction in meteorological convention (clockwise, from), ex: 0°=from north, 90°=from east"
1272
1581
 
1273
1582
  dataArray = xsarsea.dir_to_360(dataArray)