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