grdwindinversion 0.2.3.post7__tar.gz → 0.2.3.post9__tar.gz

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.
Files changed (58) hide show
  1. {grdwindinversion-0.2.3.post7/grdwindinversion.egg-info → grdwindinversion-0.2.3.post9}/PKG-INFO +1 -1
  2. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/grdwindinversion/__init__.py +2 -0
  3. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/grdwindinversion/config_prod.yaml +4 -4
  4. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/grdwindinversion/config_prod_recal.yaml +4 -8
  5. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/grdwindinversion/inversion.py +377 -213
  6. grdwindinversion-0.2.3.post9/grdwindinversion/load_config.py +24 -0
  7. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/grdwindinversion/main.py +3 -16
  8. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9/grdwindinversion.egg-info}/PKG-INFO +1 -1
  9. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/grdwindinversion.egg-info/SOURCES.txt +0 -4
  10. grdwindinversion-0.2.3.post7/grdwindinversion/config_RCM.yaml +0 -6
  11. grdwindinversion-0.2.3.post7/grdwindinversion/config_RS2.yaml +0 -6
  12. grdwindinversion-0.2.3.post7/grdwindinversion/config_S1.yaml +0 -12
  13. grdwindinversion-0.2.3.post7/grdwindinversion/config_hy2b.yaml +0 -24
  14. grdwindinversion-0.2.3.post7/grdwindinversion/load_config.py +0 -22
  15. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/.editorconfig +0 -0
  16. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/.github/dependabot.yml +0 -0
  17. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/.github/workflows/publish.yml +0 -0
  18. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/.gitignore +0 -0
  19. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/.pre-commit-config.yaml +0 -0
  20. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/AUTHORS.rst +0 -0
  21. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/CONTRIBUTING.rst +0 -0
  22. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/HISTORY.rst +0 -0
  23. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/LICENSE +0 -0
  24. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/MANIFEST.in +0 -0
  25. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/Makefile +0 -0
  26. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/README.md +0 -0
  27. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/ci/requirements/docs.yaml +0 -0
  28. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/ci/requirements/environment.yaml +0 -0
  29. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/docs/Makefile +0 -0
  30. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/docs/_static/css/grdwindinversion.css +0 -0
  31. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/docs/algorithm.rst +0 -0
  32. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/docs/authors.rst +0 -0
  33. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/docs/conf.py +0 -0
  34. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/docs/contributing.rst +0 -0
  35. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/docs/examples/wind-inversion-from-grd.ipynb +0 -0
  36. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/docs/history.rst +0 -0
  37. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/docs/index.rst +0 -0
  38. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/docs/installation.rst +0 -0
  39. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/docs/make.bat +0 -0
  40. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/docs/modules.rst +0 -0
  41. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/docs/readme.rst +0 -0
  42. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/docs/usage.rst +0 -0
  43. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/grdwindinversion/.github/ISSUE_TEMPLATE.md +0 -0
  44. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/grdwindinversion/.gitignore +0 -0
  45. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/grdwindinversion/.travis.yml +0 -0
  46. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/grdwindinversion/data_config.yaml +0 -0
  47. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/grdwindinversion/utils.py +0 -0
  48. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/grdwindinversion.egg-info/dependency_links.txt +0 -0
  49. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/grdwindinversion.egg-info/entry_points.txt +0 -0
  50. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/grdwindinversion.egg-info/requires.txt +0 -0
  51. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/grdwindinversion.egg-info/top_level.txt +0 -0
  52. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/pyproject.toml +0 -0
  53. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/requirements_dev.txt +0 -0
  54. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/requirements_doc.txt +0 -0
  55. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/setup.cfg +0 -0
  56. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/tests/__init__.py +0 -0
  57. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/tests/test_grdwindinversion.py +0 -0
  58. {grdwindinversion-0.2.3.post7 → grdwindinversion-0.2.3.post9}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: grdwindinversion
3
- Version: 0.2.3.post7
3
+ Version: 0.2.3.post9
4
4
  Summary: Package to perform Wind inversion from GRD Level-1 SAR images
5
5
  License: MIT
6
6
  Classifier: Development Status :: 2 - Pre-Alpha
@@ -6,6 +6,8 @@ __all__ = ['inversion']
6
6
  # __version__ = metadata.version('grdwindinversion')
7
7
  from grdwindinversion import *
8
8
  from importlib.metadata import version
9
+ from grdwindinversion.inversion import inverse
10
+
9
11
  try:
10
12
  __version__ = version("grdwindinversion")
11
13
  except Exception:
@@ -1,23 +1,23 @@
1
1
  S1A:
2
- GMF_VV_NAME: "cmod5n"
2
+ GMF_VV_NAME: "gmf_cmod5n"
3
3
  GMF_VH_NAME: "gmf_s1_v2"
4
4
  dsig_VH_NAME: "gmf_s1_v2"
5
5
  apply_flattening: True
6
6
  recalibration: False
7
7
  S1B:
8
- GMF_VV_NAME: "cmod5n"
8
+ GMF_VV_NAME: "gmf_cmod5n"
9
9
  GMF_VH_NAME: "gmf_s1_v2"
10
10
  dsig_VH_NAME: "gmf_s1_v2"
11
11
  apply_flattening: True
12
12
  recalibration: False
13
13
  RS2:
14
- GMF_VV_NAME: "cmod5n"
14
+ GMF_VV_NAME: "gmf_cmod5n"
15
15
  GMF_VH_NAME: "gmf_rs2_v2"
16
16
  dsig_VH_NAME: "gmf_rs2_v2"
17
17
  apply_flattening: False
18
18
  recalibration: False
19
19
  RCM:
20
- GMF_VV_NAME: "cmod5n"
20
+ GMF_VV_NAME: "gmf_cmod5n"
21
21
  GMF_VH_NAME: "gmf_rcm_noaa"
22
22
  dsig_VH_NAME: "gmf_s1_v2"
23
23
  apply_flattening: True
@@ -1,28 +1,24 @@
1
1
  S1A:
2
- GMF_VV_NAME: "cmod5n"
2
+ GMF_VV_NAME: "gmf_cmod5n"
3
3
  GMF_VH_NAME: "gmf_s1_v2"
4
4
  dsig_VH_NAME: "gmf_s1_v2"
5
5
  apply_flattening: True
6
6
  recalibration: True
7
- aux_config_name: "v_IPF_36"
8
7
  S1B:
9
- GMF_VV_NAME: "cmod5n"
8
+ GMF_VV_NAME: "gmf_cmod5n"
10
9
  GMF_VH_NAME: "gmf_s1_v2"
11
10
  dsig_VH_NAME: "gmf_s1_v2"
12
11
  apply_flattening: True
13
12
  recalibration: True
14
- aux_config_name: "v_IPF_36"
15
13
  RS2:
16
- GMF_VV_NAME: "cmod5n"
14
+ GMF_VV_NAME: "gmf_cmod5n"
17
15
  GMF_VH_NAME: "gmf_rs2_v2"
18
16
  dsig_VH_NAME: "gmf_rs2_v2"
19
17
  apply_flattening: False
20
18
  recalibration: True
21
- aux_config_name: "v_IPF_36"
22
19
  RCM:
23
- GMF_VV_NAME: "cmod5n"
20
+ GMF_VV_NAME: "gmf_cmod5n"
24
21
  GMF_VH_NAME: "gmf_rcm_noaa"
25
22
  dsig_VH_NAME: "gmf_s1_v2"
26
23
  apply_flattening: True
27
24
  recalibration: True
28
- aux_config_name: "v_IPF_36"
@@ -1,5 +1,3 @@
1
- import json
2
- import pdb
3
1
  import traceback
4
2
 
5
3
  import xsar
@@ -21,24 +19,24 @@ import os
21
19
  from grdwindinversion.load_config import getConf
22
20
  # optional debug messages
23
21
  import logging
24
-
25
22
  logging.basicConfig()
26
23
  logging.getLogger('xsarsea.windspeed').setLevel(
27
24
  logging.INFO) # or .setLevel(logging.INFO)
28
- # encode gcps as json string
29
-
30
-
31
- class JSONEncoder(json.JSONEncoder):
32
- def default(self, obj):
33
- if isinstance(obj, np.integer):
34
- return int(obj)
35
25
 
36
26
 
37
27
  def getSensorMetaDataset(filename):
38
28
  """
29
+ Find the sensor name and the corresponding meta and dataset functions
39
30
 
40
- :param filename: str SAR SAFE or equivalent
41
- :return:
31
+ Parameters
32
+ ----------
33
+ filename : str
34
+ input filename
35
+
36
+ Returns
37
+ -------
38
+ tuple
39
+ sensor name, sensor long name, meta function, dataset function
42
40
  """
43
41
  if ("S1A" in filename):
44
42
  return "S1A", "SENTINEL-1 A", xsar.Sentinel1Meta, xsar.Sentinel1Dataset
@@ -54,12 +52,23 @@ def getSensorMetaDataset(filename):
54
52
 
55
53
  def getOutputName2(input_file, out_folder, sensor, meta):
56
54
  """
57
-
58
- :param input_file: str
59
- :param out_folder: str
60
- :param sensor: str S1A or S1B
61
- :param meta: obj `xsar.Sentinel1Meta` (or any other supported SAR mission)
62
- :return:
55
+ Create output filename for L2-GRD product
56
+
57
+ Parameters
58
+ ----------
59
+ input_file : str
60
+ input filename
61
+ out_folder : str
62
+ output folder
63
+ sensor : str
64
+ sensor name
65
+ meta : obj `xsar.BaseMeta` (one of the supported SAR mission)
66
+ meta object
67
+
68
+ Returns
69
+ -------
70
+ outfile : str
71
+ output filename
63
72
  """
64
73
  basename = os.path.basename(input_file)
65
74
  basename_match = basename
@@ -107,91 +116,203 @@ def getOutputName2(input_file, out_folder, sensor, meta):
107
116
  "sensor must be S1A|S1B|RS2|RCM, got sensor %s" % sensor)
108
117
 
109
118
 
110
- def getAncillary(meta):
119
+ def getAncillary(meta, ancillary_name='ecmwf'):
120
+ """
121
+ Map ancillary wind from ECMWF or ERA5.
122
+ This function is used to check if the model files are available and to map the model to the SAR data.
123
+
124
+ Parameters
125
+ ----------
126
+ meta: obj `xsar.BaseMeta` (one of the supported SAR mission)
111
127
 
112
- logging.debug('conf: %s', getConf())
113
- ec01 = getConf()['ecmwf_0100_1h']
114
- ec0125 = getConf()['ecmwf_0125_1h']
115
- logging.debug('ec01 : %s', ec01)
116
- meta.set_raster('ecmwf_0100_1h', ec01)
117
- meta.set_raster('ecmwf_0125_1h', ec0125)
128
+ Returns
129
+ -------
130
+ dict
131
+ map model to SAR data
132
+ """
118
133
 
119
- map_model = None
120
- # only keep best ecmwf (FIXME: it's hacky, and xsar should provide a better method to handle this)
121
- for ecmwf_name in ['ecmwf_0125_1h', 'ecmwf_0100_1h']:
122
- ecmwf_infos = meta.rasters.loc[ecmwf_name]
134
+ if ancillary_name == 'ecmwf':
135
+
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)
142
+
143
+ map_model = None
144
+ # 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']:
146
+ ecmwf_infos = meta.rasters.loc[ecmwf_name]
147
+ 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]
151
+ # temporary for RCM issue https://github.com/umr-lops/xarray-safe-rcm/issues/34
152
+ 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]
156
+ if not os.path.isfile(ecmwf_file):
157
+ # temporary
158
+ # if repro does not exist we look at not repro folder (only one will exist after)
159
+ """
160
+ if ecmwf_name == "ecmwf_0100_1h":
161
+ ecmwf_infos['resource'] = ecmwf_infos['resource'].replace(
162
+ "netcdf_light_REPRO_tree", "netcdf_light")
163
+ try:
164
+ ecmwf_file = ecmwf_infos['get_function'](ecmwf_infos['resource'],
165
+ date=datetime.datetime.strptime(meta.start_date,
166
+ '%Y-%m-%d %H:%M:%S.%f'))[1]
167
+ except Exception as e:
168
+ ecmwf_file = ecmwf_infos['get_function'](ecmwf_infos['resource'],
169
+ date=datetime.datetime.strptime(meta.start_date,
170
+ '%Y-%m-%d %H:%M:%S'))[1]
171
+
172
+ if not os.path.isfile(ecmwf_file):
173
+ meta.rasters = meta.rasters.drop([ecmwf_name])
174
+ else:
175
+ map_model = {'%s_%s' % (ecmwf_name, uv): 'model_%s' % uv for uv in [
176
+ 'U10', 'V10']}
177
+
178
+ else:
179
+ """
180
+ meta.rasters = meta.rasters.drop([ecmwf_name])
181
+ else:
182
+ map_model = {'%s_%s' % (ecmwf_name, uv): 'model_%s' %
183
+ uv for uv in ['U10', 'V10']}
184
+
185
+ return map_model
186
+
187
+ elif ancillary_name == 'era5':
188
+ era5_name = "era5_0250_1h"
189
+ logging.debug('conf: %s', getConf())
190
+ era0250 = getConf()[era5_name]
191
+ logging.debug('%s : %s', (era5_name, era0250))
192
+ meta.set_raster(era5_name, era0250)
193
+
194
+ era5_infos = meta.rasters.loc[era5_name]
123
195
  try:
124
- ecmwf_file = ecmwf_infos['get_function'](ecmwf_infos['resource'],
125
- date=datetime.datetime.strptime(meta.start_date,
126
- '%Y-%m-%d %H:%M:%S.%f'))[1]
127
- # temporary for RCM issue https://github.com/umr-lops/xarray-safe-rcm/issues/34
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]
128
199
  except Exception as e:
129
- ecmwf_file = ecmwf_infos['get_function'](ecmwf_infos['resource'],
130
- date=datetime.datetime.strptime(meta.start_date,
131
- '%Y-%m-%d %H:%M:%S'))[1]
132
-
133
- if not os.path.isfile(ecmwf_file):
134
- # temporary
135
- # if repro does not exist we look at not repro folder (only one will exist after)
136
- if ecmwf_name == "ecmwf_0100_1h":
137
- ecmwf_infos['resource'] = ecmwf_infos['resource'].replace(
138
- "netcdf_light_REPRO_tree", "netcdf_light")
139
- try:
140
- ecmwf_file = ecmwf_infos['get_function'](ecmwf_infos['resource'],
141
- date=datetime.datetime.strptime(meta.start_date,
142
- '%Y-%m-%d %H:%M:%S.%f'))[1]
143
- except Exception as e:
144
- ecmwf_file = ecmwf_infos['get_function'](ecmwf_infos['resource'],
145
- date=datetime.datetime.strptime(meta.start_date,
146
- '%Y-%m-%d %H:%M:%S'))[1]
147
-
148
- if not os.path.isfile(ecmwf_file):
149
- meta.rasters = meta.rasters.drop([ecmwf_name])
150
- else:
151
- map_model = {'%s_%s' % (ecmwf_name, uv): 'model_%s' % uv for uv in [
152
- 'U10', 'V10']}
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]
203
+ if not os.path.isfile(era5_file):
204
+ raise ValueError(f"era5 file {era5_file} not found")
153
205
 
154
- else:
155
- meta.rasters = meta.rasters.drop([ecmwf_name])
156
- else:
157
- map_model = {'%s_%s' % (ecmwf_name, uv): 'model_%s' %
158
- uv for uv in ['U10', 'V10']}
206
+ map_model = {'%s_%s' % (era5_name, uv): 'model_%s' %
207
+ uv for uv in ['U10', 'V10']}
208
+ return map_model
159
209
 
160
- return map_model
210
+ else:
211
+ raise ValueError("ancillary_name must be ecmwf/era5, got %s" %
212
+ ancillary_name)
161
213
 
162
214
 
163
215
  def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_vv, model_vh):
216
+ """
217
+ Invert sigma0 to retrieve wind using model (lut or gmf).
218
+
219
+ Parameters
220
+ ----------
221
+ dual_pol: bool
222
+ True if dualpol, False if singlepol
223
+ inc: xarray.DataArray
224
+ incidence angle
225
+ sigma0: xarray.DataArray
226
+ sigma0 to be inverted
227
+ sigma0_dual: xarray.DataArray
228
+ sigma0 to be inverted for dualpol
229
+ ancillary_wind=: xarray.DataArray (numpy.complex28)
230
+ ancillary wind
231
+ | (for example ecmwf winds), in **model convention**
232
+ dsig_cr=: float or xarray.DataArray
233
+ parameters used for
234
+
235
+ | `Jsig_cr=((sigma0_gmf - sigma0) / dsig_cr) ** 2`
236
+ model_vv=: str
237
+ model to use for VV or HH polarization.
238
+ model_vh=: str
239
+ model to use for VH or HV polarization.
240
+
241
+ Returns
242
+ -------
243
+ xarray.DataArray or tuple
244
+ inverted wind in **gmf convention** .
245
+
246
+ See Also
247
+ --------
248
+ xsarsea documentation
249
+ https://cyclobs.ifremer.fr/static/sarwing_datarmor/xsarsea/examples/windspeed_inversion.html
250
+ """
164
251
  logging.debug("inversion")
165
- # 4 - Inversion
166
- windspeeds = windspeed.invert_from_model(
252
+
253
+ # add potential missing gmfs (only cmod7 & ms1ahw)
254
+
255
+ if (model_vv == "gmf_cmod7"):
256
+ windspeed.register_cmod7(getConf()["lut_cmod7_path"])
257
+
258
+ if (model_vh == "sarwing_lut_cmodms1ahw"):
259
+ windspeed.register_one_sarwing_lut(getConf()["lut_ms1ahw_path"])
260
+
261
+ winds = windspeed.invert_from_model(
167
262
  inc,
168
263
  sigma0,
169
264
  sigma0_dual,
170
- # ancillary_wind=-np.conj(xsar_dataset.dataset['ancillary_wind']),
171
- ancillary_wind=-ancillary_wind,
265
+ ancillary_wind=-np.conj(ancillary_wind),
172
266
  dsig_cr=dsig_cr,
173
267
  model=(model_vv, model_vh))
268
+
174
269
  if dual_pol:
175
- windspeed_co, windspeed_dual = windspeeds
176
-
177
- windspeed_cr = windspeed.invert_from_model(
270
+ wind_co, wind_dual = winds
271
+
272
+ wind_cross = windspeed.invert_from_model(
178
273
  inc.values,
179
274
  sigma0_dual.values,
180
- # ancillary_wind=-np.conj(xsar_dataset.dataset['ancillary_wind']),
181
275
  dsig_cr=dsig_cr.values,
182
276
  model=model_vh)
183
277
 
184
- return np.abs(windspeed_co), np.abs(windspeed_dual), np.abs(windspeed_cr)
278
+ return wind_co, wind_dual, wind_cross
185
279
  else:
186
- windspeed_co = windspeeds
187
-
188
- return np.abs(windspeed_co), None, None
189
-
280
+ wind_co = winds
190
281
 
282
+ return wind_co, None, None
191
283
 
192
284
 
193
285
  def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf, config):
194
- # rename to match sarwing naming
286
+ """
287
+ Rename xr_dataset variables and attributes to match naming convention.
288
+
289
+ Parameters
290
+ ----------
291
+ xr_dataset: xarray.Dataset
292
+ dataset to rename
293
+ dual_pol: bool
294
+ True if dualpol, False if singlepol
295
+ copol: str
296
+ copolarization name
297
+ crosspol: str
298
+ crosspolarization name
299
+ copol_gmf: str
300
+ copolarization GMF name
301
+ crosspol_gmf: str
302
+ crosspolarization GMF name
303
+ config: dict
304
+ configuration file
305
+
306
+ Returns
307
+ -------
308
+ xarray.Dataset
309
+ final dataset
310
+ dict
311
+ encoding dict
312
+
313
+ See Also
314
+ --------
315
+ """
195
316
 
196
317
  xr_dataset = xr_dataset.rename({
197
318
  'longitude': 'owiLon',
@@ -200,12 +321,17 @@ def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf,
200
321
  'elevation': 'owiElevationAngle',
201
322
  'ground_heading': 'owiHeading',
202
323
  'land_mask': 'owiLandFlag',
203
- 'mask' : 'owiMask',
324
+ 'offboresight': 'owiOffBoresightAngle',
325
+ 'mask': 'owiMask',
204
326
  'windspeed_co': 'owiWindSpeed_co',
205
327
  'windspeed_cross': 'owiWindSpeed_cross',
206
- 'windspeed_dual': 'owiWindSpeed',
328
+ 'windspeed_dual': 'owiWindSpeed',
329
+ 'winddir_co': 'owiWindDirection_co',
330
+ 'winddir_cross': 'owiWindDirection_cross',
331
+ 'winddir_dual': 'owiWindDirection',
332
+ 'ancillary_wind_speed': 'owiAncillaryWindSpeed',
333
+ 'ancillary_wind_direction': 'owiAncillaryWindDirection',
207
334
  })
208
-
209
335
  xr_dataset['owiNrcs'] = xr_dataset['sigma0_ocean'].sel(pol=copol)
210
336
  xr_dataset.owiNrcs.attrs = xr_dataset.sigma0_ocean.attrs
211
337
  xr_dataset.owiNrcs.attrs['units'] = 'm^2 / m^2'
@@ -224,36 +350,33 @@ def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf,
224
350
  xr_dataset.owiNrcs_no_noise_correction.attrs[
225
351
  'long_name'] = 'Normalized Radar Cross Section ; no noise correction applied'
226
352
  xr_dataset.owiNrcs_no_noise_correction.attrs[
227
- 'comment'] = 'owiNrcs_no_noise_correction ; no recalibration'
228
-
353
+ 'comment'] = 'owiNrcs_no_noise_correction ; no recalibration'
354
+
229
355
  if 'swath_number' in xr_dataset:
230
356
  xr_dataset = xr_dataset.rename({
231
- 'swath_number' : 'owiSwathNumber',
232
- 'swath_number_flag' : 'owiSwathNumberFlag'
233
- })
234
-
357
+ 'swath_number': 'owiSwathNumber',
358
+ 'swath_number_flag': 'owiSwathNumberFlag'
359
+ })
360
+
235
361
  if "sigma0_raw__corrected" in xr_dataset:
236
- xr_dataset['owiNrcs_no_noise_correction_recalibrated'] = xr_dataset['sigma0_raw__corrected'].sel(pol=copol)
362
+ xr_dataset['owiNrcs_no_noise_correction_recalibrated'] = xr_dataset['sigma0_raw__corrected'].sel(
363
+ pol=copol)
237
364
  xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs = xr_dataset.sigma0_raw__corrected.attrs
238
365
  xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs['units'] = 'm^2 / m^2'
239
366
  xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs[
240
367
  'long_name'] = 'Normalized Radar Cross Section, no noise correction applied'
241
368
  xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs[
242
- 'comment'] = 'owiNrcs_no_noise_correction ; recalibrated with kersten method'
243
-
244
- xr_dataset.owiNrcs.attrs['definition'] = 'owiNrcs_no_noise_correction_recalibrated - owiNesz'
245
-
246
-
369
+ 'comment'] = 'owiNrcs_no_noise_correction ; recalibrated with kersten method'
247
370
 
371
+ xr_dataset.owiNrcs.attrs['definition'] = 'owiNrcs_no_noise_correction_recalibrated - owiNesz'
248
372
 
249
-
250
373
  if dual_pol:
251
-
374
+
252
375
  xr_dataset = xr_dataset.rename({
253
376
  'dsig_cross': 'owiDsig_cross',
254
- 'nesz_cross_final' : 'owiNesz_cross_final'
255
- })
256
-
377
+ 'nesz_cross_final': 'owiNesz_cross_final'
378
+ })
379
+
257
380
  xr_dataset['owiNrcs_cross'] = xr_dataset['sigma0_ocean'].sel(
258
381
  pol=crosspol)
259
382
  xr_dataset.owiNrcs_cross.attrs['units'] = 'm^2 / m^2'
@@ -272,37 +395,35 @@ def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf,
272
395
  'long_name'] = 'Normalized Radar Cross Section, no noise correction applied'
273
396
 
274
397
  if "sigma0_raw__corrected" in xr_dataset:
275
- xr_dataset['owiNrcs_cross_no_noise_correction_recalibrated'] = xr_dataset['sigma0_raw__corrected'].sel(pol=crosspol)
398
+ xr_dataset['owiNrcs_cross_no_noise_correction_recalibrated'] = xr_dataset['sigma0_raw__corrected'].sel(
399
+ pol=crosspol)
276
400
  xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs = xr_dataset.sigma0_raw__corrected.attrs
277
401
  xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs['units'] = 'm^2 / m^2'
278
402
  xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs[
279
403
  'long_name'] = 'Normalized Radar Cross Section ; no noise correction applied'
280
404
  xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs[
281
- 'comment'] = 'owiNrcs_cross_no_noise_correction ; recalibrated with kersten method'
282
-
405
+ 'comment'] = 'owiNrcs_cross_no_noise_correction ; recalibrated with kersten method'
406
+
283
407
  xr_dataset.owiNrcs_cross.attrs['definition'] = 'owiNrcs_cross_no_noise_correction_recalibrated - owiNesz_cross'
284
408
 
285
-
286
-
287
409
  xr_dataset["owiWindSpeed_co"].attrs["comment"] = xr_dataset["owiWindSpeed_co"].attrs["comment"].replace(
288
410
  "wind speed and direction", "wind speed")
289
411
 
412
+ xr_dataset["owiWindDirection_co"].attrs["comment"] = "wind direction in meteorological convention, 0=North, 90=East"
413
+
290
414
  if dual_pol:
291
415
  xr_dataset["owiWindSpeed"].attrs["comment"] = xr_dataset["owiWindSpeed"].attrs["comment"].replace(
292
416
  "wind speed and direction", "wind speed")
417
+ xr_dataset["owiWindDirection"].attrs["comment"] = "wind direction in meteorological convention, 0=North, 90=East"
293
418
 
294
419
  xr_dataset["owiWindSpeed_cross"].attrs['comment'] = "wind speed inverted from model %s (%s)" % (
295
420
  crosspol_gmf, crosspol)
296
421
 
422
+ xr_dataset["owiWindDirection_cross"].attrs["comment"] = "wind direction in meteorological convention, 0=North, 90=East, copied from dualpol"
423
+
297
424
  xr_dataset.owiWindSpeed_cross.attrs['model'] = crosspol_gmf
298
425
  xr_dataset.owiWindSpeed_cross.attrs['units'] = 'm/s'
299
426
 
300
- xr_dataset = xr_dataset.assign(
301
- owiEcmwfWindSpeed=(['line', 'sample'], np.abs(xr_dataset['ancillary_wind'].data)))
302
- xr_dataset = xr_dataset.assign(
303
- owiEcmwfWindDirection=(['line', 'sample'], np.angle(xr_dataset['ancillary_wind'])))
304
- xr_dataset['owiEcmwfWindDirection'].attrs['comment'] = 'angle in radians, anticlockwise, 0=sample'
305
-
306
427
  xr_dataset['owiWindQuality'] = xr.full_like(xr_dataset.owiNrcs, 0)
307
428
  xr_dataset['owiWindQuality'].attrs[
308
429
  'long_name'] = "Quality flag taking into account the consistency_between_wind_inverted_and_NRCS_and_Doppler_measured"
@@ -323,14 +444,14 @@ def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf,
323
444
 
324
445
  xr_dataset = xr_dataset.rename(
325
446
  {"line": "owiAzSize", "sample": "owiRaSize"})
326
-
327
-
328
- xr_dataset = xr_dataset.drop_vars(['sigma0_ocean', 'sigma0', 'sigma0_ocean_raw','sigma0_raw', 'ancillary_wind','nesz','spatial_ref'])
447
+
448
+ xr_dataset = xr_dataset.drop_vars(
449
+ ['sigma0_ocean', 'sigma0', 'sigma0_ocean_raw', 'sigma0_raw', 'ancillary_wind', 'nesz', 'spatial_ref'])
329
450
  if 'sigma0_raw__corrected' in xr_dataset:
330
451
  xr_dataset = xr_dataset.drop_vars(["sigma0_raw__corrected"])
331
452
  xr_dataset = xr_dataset.drop_dims(['pol'])
332
-
333
- #attrs
453
+
454
+ # attrs
334
455
 
335
456
  xr_dataset.compute()
336
457
 
@@ -340,50 +461,44 @@ def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf,
340
461
  if "approx_transform" in xr_dataset.attrs:
341
462
  del xr_dataset.attrs["approx_transform"]
342
463
 
343
- xr_dataset.attrs["TITLE"] = "Sentinel-1 OWI Component"
344
- xr_dataset.attrs["missionPhase"] = "Test"
345
- xr_dataset.attrs["polarisation"] = xr_dataset.pols
346
- xr_dataset.attrs["acquisitionStation"] = "/"
347
- xr_dataset.attrs["softwareVersion"] = "/"
348
- xr_dataset.attrs["pythonVersion"] = str(
349
- sys.version_info.major)+'.'+str(sys.version_info.minor)
350
- xr_dataset.attrs["polarisationRatio"] = "/"
351
- xr_dataset.attrs["l2ProcessingUtcTime"] = datetime.datetime.now().strftime(
464
+ xr_dataset.attrs["TITLE"] = "Sentinel-1 OWI Component"
465
+ xr_dataset.attrs["missionPhase"] = "Test"
466
+ xr_dataset.attrs["acquisitionStation"] = "/"
467
+ xr_dataset.attrs["softwareVersion"] = "/"
468
+ xr_dataset.attrs["pythonVersion"] = str(
469
+ sys.version_info.major)+'.'+str(sys.version_info.minor)
470
+ xr_dataset.attrs["polarisationRatio"] = "/"
471
+ xr_dataset.attrs["l2ProcessingUtcTime"] = datetime.datetime.now().strftime(
472
+ "%Y-%m-%dT%H:%M:%SZ")
473
+ xr_dataset.attrs["processingCenter"] = "/"
474
+ try:
475
+ xr_dataset.attrs["firstMeasurementTime"] = datetime.datetime.strptime(xr_dataset.attrs['start_date'],
476
+ "%Y-%m-%d %H:%M:%S.%f").strftime(
352
477
  "%Y-%m-%dT%H:%M:%SZ")
353
- xr_dataset.attrs["processingCenter"] = "/"
354
- try:
355
- xr_dataset.attrs["firstMeasurementTime"] = datetime.datetime.strptime(xr_dataset.attrs['start_date'],
356
- "%Y-%m-%d %H:%M:%S.%f").strftime(
357
- "%Y-%m-%dT%H:%M:%SZ")
358
- xr_dataset.attrs["lastMeasurementTime"] = datetime.datetime.strptime(xr_dataset.attrs['stop_date'],
359
- "%Y-%m-%d %H:%M:%S.%f").strftime(
360
- "%Y-%m-%dT%H:%M:%SZ")
361
- except:
362
- xr_dataset.attrs["firstMeasurementTime"] = datetime.datetime.strptime(xr_dataset.attrs['start_date'],
363
- "%Y-%m-%d %H:%M:%S").strftime(
364
- "%Y-%m-%dT%H:%M:%SZ")
365
- xr_dataset.attrs["lastMeasurementTime"] = datetime.datetime.strptime(xr_dataset.attrs['stop_date'],
366
- "%Y-%m-%d %H:%M:%S").strftime(
367
- "%Y-%m-%dT%H:%M:%SZ")
368
- xr_dataset.attrs["clmSource"] = "/"
369
- xr_dataset.attrs["bathySource"] = "/"
370
- xr_dataset.attrs['oswAlgorithmName'] = 'grdwindinversion'
371
- xr_dataset.attrs["owiAlgorithmVersion"] = grdwindinversion.__version__
372
- xr_dataset.attrs["gmf"] = config['GMF_'+copol_gmf+'_NAME'] + \
373
- ", " + config["GMF_"+crosspol_gmf+"_NAME"]
374
- xr_dataset.attrs["iceSource"] = "/"
375
- xr_dataset.attrs["owiNoiseCorrection"] = "False"
376
- xr_dataset.attrs["inversionTabGMF"] = config['GMF_'+copol_gmf +
377
- '_NAME'] + ", " + config["GMF_"+crosspol_gmf+"_NAME"]
378
- xr_dataset.attrs["wnf_3km_average"] = "/"
379
- xr_dataset.attrs["owiWindSpeedSrc"] = "owiWindSpeed"
380
- xr_dataset.attrs["owiWindDirectionSrc"] = "/"
381
-
382
- for var in xr_dataset.variables:
383
- if "history" in xr_dataset[var].attrs:
384
- del xr_dataset[var].attrs["history"]
385
-
386
-
478
+ xr_dataset.attrs["lastMeasurementTime"] = datetime.datetime.strptime(xr_dataset.attrs['stop_date'],
479
+ "%Y-%m-%d %H:%M:%S.%f").strftime(
480
+ "%Y-%m-%dT%H:%M:%SZ")
481
+ except:
482
+ xr_dataset.attrs["firstMeasurementTime"] = datetime.datetime.strptime(xr_dataset.attrs['start_date'],
483
+ "%Y-%m-%d %H:%M:%S").strftime(
484
+ "%Y-%m-%dT%H:%M:%SZ")
485
+ xr_dataset.attrs["lastMeasurementTime"] = datetime.datetime.strptime(xr_dataset.attrs['stop_date'],
486
+ "%Y-%m-%d %H:%M:%S").strftime(
487
+ "%Y-%m-%dT%H:%M:%SZ")
488
+ xr_dataset.attrs["clmSource"] = "/"
489
+ xr_dataset.attrs["bathySource"] = "/"
490
+ xr_dataset.attrs['oswAlgorithmName'] = 'grdwindinversion'
491
+ xr_dataset.attrs["owiAlgorithmVersion"] = grdwindinversion.__version__
492
+ xr_dataset.attrs["gmf"] = config['GMF_'+copol_gmf+'_NAME'] + \
493
+ ", " + config["GMF_"+crosspol_gmf+"_NAME"]
494
+ xr_dataset.attrs["iceSource"] = "/"
495
+ xr_dataset.attrs["owiNoiseCorrection"] = "False"
496
+ xr_dataset.attrs["inversionTabGMF"] = config['GMF_'+copol_gmf +
497
+ '_NAME'] + ", " + config["GMF_"+crosspol_gmf+"_NAME"]
498
+ xr_dataset.attrs["wnf_3km_average"] = "/"
499
+ xr_dataset.attrs["owiWindSpeedSrc"] = "owiWindSpeed"
500
+ xr_dataset.attrs["owiWindDirectionSrc"] = "/"
501
+
387
502
  table_fillValue = {
388
503
  "owiWindQuality": -1,
389
504
  "owiHeading": 9999.99,
@@ -396,43 +511,51 @@ def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf,
396
511
  "owiWindSpeed_co": -9999.0,
397
512
  "owiWindSpeed_cross": -9999.0,
398
513
  }
399
-
514
+
400
515
  encoding = {}
401
516
  for var in list(set(xr_dataset.coords.keys()) | set(xr_dataset.keys())):
402
517
  encoding[var] = {}
403
518
  try:
404
- # sarwing_ds[var].attrs["_FillValue"] = table_fillValue[var]
405
519
  encoding[var].update({'_FillValue': table_fillValue[var]})
406
520
  except:
407
- # Nouvelles variables..
408
521
  if (var in ["owiWindSpeed_co", "owiWindSpeed_cross", "owiWindSpeed"]):
409
- # sarwing_ds[var].attrs["_FillValue"] = -9999.0
410
522
  encoding[var].update({'_FillValue': -9999.0})
411
523
  else:
412
524
  encoding[var].update({'_FillValue': None})
413
525
 
414
526
  xr_dataset.attrs["xsar_version"] = xsar.__version__
415
527
  xr_dataset.attrs["xsarsea_version"] = xsarsea.__version__
416
-
528
+
417
529
  return xr_dataset, encoding
418
530
 
419
531
 
420
532
  def makeL2(filename, out_folder, config_path, overwrite=False, generateCSV=True, resolution='1000m'):
421
533
  """
422
-
423
- :param filename: str
424
- :param out_folder: str
425
- :param config_path: str
426
- :param overwrite: bool True -> existing files will be overwritten
427
- :return:
428
- out_file: str
429
- xr_dataset: xarray.Dataset final dataset with wind speed variables
534
+ Main function to generate L2 product.
535
+
536
+ Parameters
537
+ ----------
538
+ filename : str
539
+ input filename
540
+ out_folder : str
541
+ output folder
542
+ config_path : str
543
+ configuration file path
544
+ overwrite : bool, optional
545
+ overwrite existing file
546
+ generateCSV : bool, optional
547
+ generate CSV file
548
+ resolution : str, optional
549
+ working resolution
550
+
551
+ Returns
552
+ -------
553
+ str
554
+ output filename
555
+ xarray.Dataset
556
+ final dataset
430
557
  """
431
558
 
432
- # final xr.Dataset
433
-
434
- #  Step 1 - load L1 product
435
-
436
559
  sensor, sensor_longname, fct_meta, fct_dataset = getSensorMetaDataset(
437
560
  filename)
438
561
 
@@ -448,58 +571,66 @@ def makeL2(filename, out_folder, config_path, overwrite=False, generateCSV=True,
448
571
  else:
449
572
  raise FileNotFoundError(
450
573
  'config_path do not exists, got %s ' % config_path)
451
-
574
+
452
575
  recalibration = config["recalibration"]
453
- if recalibration:
454
- aux_config_name=config["aux_config_name"]
455
-
456
576
  meta = fct_meta(filename)
457
577
  out_file = getOutputName2(filename, out_folder, sensor, meta)
458
578
 
459
-
460
579
  if os.path.exists(out_file) and overwrite is False:
461
- logging.info("out_file %s exists" % out_file)
580
+ logging.info("out_file %s exists ; returning empty Dataset" % out_file)
462
581
  return out_file, xr.Dataset()
463
582
 
464
- # get ancillary wind from ECMWF
465
- map_model = getAncillary(meta)
583
+ ancillary_name = config["ancillary"]
584
+ map_model = getAncillary(meta, ancillary_name)
466
585
  if map_model is None:
467
586
  raise Exception(
468
- 'the weather model is not set `map_model` is None -> you probably don"t have access to ECMWF archive')
587
+ f'the weather model is not set `map_model` is None -> you probably don"t have access to f{ancillary_name} archive')
469
588
 
470
589
  try:
471
590
  if ((recalibration) & ("SENTINEL" in sensor_longname)):
472
- logging.info('recalibration is True : Kersten formula is applied')
591
+ logging.info(
592
+ f'recalibration is {recalibration} : Kersten formula is applied')
473
593
  xsar_dataset = fct_dataset(
474
- meta, resolution=resolution, recalibration=recalibration, aux_config_name = aux_config_name)
594
+ meta, resolution=resolution, recalibration=recalibration)
475
595
  xr_dataset = xsar_dataset.datatree['measurement'].to_dataset()
476
- xr_dataset = xr_dataset.merge(xsar_dataset.datatree["recalibration"].to_dataset()[['swath_number','swath_number_flag','sigma0_raw__corrected']])
477
-
596
+ xr_dataset = xr_dataset.merge(xsar_dataset.datatree["recalibration"].to_dataset()[
597
+ ['swath_number', 'swath_number_flag', 'sigma0_raw__corrected']])
598
+
478
599
  else:
479
600
  logging.info(
480
- 'recalibration is True : Kersten formula is not applied')
601
+ f'recalibration is {recalibration} : Kersten formula is not applied')
481
602
  if ("SENTINEL" in sensor_longname):
482
- xsar_dataset = fct_dataset(meta, resolution=resolution,recalibration=recalibration)
603
+ xsar_dataset = fct_dataset(
604
+ meta, resolution=resolution, recalibration=recalibration)
483
605
  xr_dataset = xsar_dataset.datatree['measurement'].to_dataset()
484
- xr_dataset = xr_dataset.merge(xsar_dataset.datatree["recalibration"].to_dataset()[['swath_number','swath_number_flag']])
606
+ xr_dataset = xr_dataset.merge(xsar_dataset.datatree["recalibration"].to_dataset()[
607
+ ['swath_number', 'swath_number_flag']])
485
608
 
486
- else:
609
+ else:
487
610
  xsar_dataset = fct_dataset(meta, resolution=resolution)
488
611
  xr_dataset = xsar_dataset.datatree['measurement'].to_dataset()
489
612
 
490
-
491
613
  xr_dataset = xr_dataset.rename(map_model)
492
614
  # add attributes
493
615
  xr_dataset.attrs = xsar_dataset.dataset.attrs
494
616
  xr_dataset.attrs['L1_path'] = xr_dataset.attrs.pop('name')
495
617
  xr_dataset.attrs["sourceProduct"] = sensor
496
618
  xr_dataset.attrs["missionName"] = sensor_longname
497
-
619
+ if ((recalibration) & ("SENTINEL" in sensor_longname)):
620
+ xr_dataset.attrs["path_aux_pp1_new"] = os.path.basename(os.path.dirname(
621
+ os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_pp1_new'])))
622
+ xr_dataset.attrs["path_aux_cal_new"] = os.path.basename(os.path.dirname(
623
+ os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_cal_new'])))
624
+
625
+ xr_dataset.attrs["path_aux_pp1_old"] = os.path.basename(os.path.dirname(
626
+ os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_pp1_old'])))
627
+ xr_dataset.attrs["path_aux_cal_old"] = os.path.basename(os.path.dirname(
628
+ os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_cal_old'])))
629
+
498
630
  except Exception as e:
499
631
  logging.info('%s', traceback.format_exc())
500
632
  logging.error(e)
501
633
  sys.exit(-1)
502
-
503
634
 
504
635
  # defining dual_pol, and gmfs by channel
505
636
  if len(xr_dataset.pol.values) == 2:
@@ -553,11 +684,33 @@ def makeL2(filename, out_folder, config_path, overwrite=False, generateCSV=True,
553
684
  xr_dataset.mask.attrs['flag_meanings'] = 'valid land ice no_valid'
554
685
 
555
686
  # ANCILLARY
556
- xr_dataset['ancillary_wind'] = (xr_dataset.model_U10 + 1j * xr_dataset.model_V10) * np.exp(
557
- 1j * np.deg2rad(xr_dataset.ground_heading))
687
+ xr_dataset['ancillary_wind_direction'] = (
688
+ 90. - np.rad2deg(np.arctan2(xr_dataset.model_V10, xr_dataset.model_U10)) + 180) % 360
689
+
690
+ xr_dataset['ancillary_wind_direction'] = xr.where(xr_dataset['mask'], np.nan,
691
+ xr_dataset['ancillary_wind_direction'].compute()).transpose(
692
+ *xr_dataset['ancillary_wind_direction'].dims)
693
+ xr_dataset['ancillary_wind_direction'].attrs = {}
694
+ xr_dataset['ancillary_wind_direction'].attrs['units'] = 'degrees_north'
695
+ xr_dataset['ancillary_wind_direction'].attrs[
696
+ 'long_name'] = f'{ancillary_name} Wind direction (meteorological convention)'
697
+ xr_dataset['ancillary_wind_direction'].attrs['standart_name'] = 'wind_direction'
698
+
699
+ xr_dataset['ancillary_wind_speed'] = np.sqrt(
700
+ xr_dataset['model_U10']**2+xr_dataset['model_V10']**2)
701
+ xr_dataset['ancillary_wind_speed'] = xr.where(xr_dataset['mask'], np.nan,
702
+ xr_dataset['ancillary_wind_speed'].compute()).transpose(
703
+ *xr_dataset['ancillary_wind_speed'].dims)
704
+ xr_dataset['ancillary_wind_speed'].attrs = {}
705
+ xr_dataset['ancillary_wind_speed'].attrs['units'] = 'm s^-1'
706
+ xr_dataset['ancillary_wind_speed'].attrs[
707
+ 'long_name'] = f'{ancillary_name} Wind speed'
708
+ xr_dataset['ancillary_wind_speed'].attrs['standart_name'] = 'wind_speed'
709
+
558
710
  xr_dataset['ancillary_wind'] = xr.where(xr_dataset['mask'], np.nan,
559
- xr_dataset['ancillary_wind'].compute()).transpose(
560
- *xr_dataset['ancillary_wind'].dims)
711
+ (xr_dataset.ancillary_wind_speed * np.exp(1j * xsarsea.dir_geo_to_sample(xr_dataset.ancillary_wind_direction, xr_dataset.ground_heading))).compute()).transpose(
712
+ *xr_dataset['ancillary_wind_speed'].dims)
713
+
561
714
  xr_dataset.attrs['ancillary_source'] = xr_dataset['model_U10'].attrs['history'].split('decoded: ')[
562
715
  1].strip()
563
716
  xr_dataset = xr_dataset.drop_vars(['model_U10', 'model_V10'])
@@ -567,7 +720,7 @@ def makeL2(filename, out_folder, config_path, overwrite=False, generateCSV=True,
567
720
  xr_dataset['sigma0'].compute()).transpose(*xr_dataset['sigma0'].dims)
568
721
  xr_dataset['sigma0_ocean'] = xr.where(
569
722
  xr_dataset['sigma0_ocean'] <= 0, np.nan, xr_dataset['sigma0_ocean'])
570
-
723
+
571
724
  xr_dataset['sigma0_ocean'].attrs = xr_dataset['sigma0'].attrs
572
725
 
573
726
  xr_dataset['sigma0_ocean_raw'] = xr.where(xr_dataset['mask'], np.nan,
@@ -600,26 +753,37 @@ def makeL2(filename, out_folder, config_path, overwrite=False, generateCSV=True,
600
753
  sigma0_ocean_cross = None
601
754
  dsig_cross = 0.1 # default value set in xsarsea
602
755
 
603
- windspeed_co, windspeed_dual, windspeed_cr = inverse(dual_pol,
604
- inc=xr_dataset.incidence,
605
- sigma0=xr_dataset['sigma0_ocean'].sel(
606
- pol=copol),
607
- sigma0_dual=sigma0_ocean_cross,
608
- ancillary_wind=xr_dataset['ancillary_wind'],
609
- dsig_cr=dsig_cross,
610
- model_vv=config["GMF_" +
611
- copol_gmf+"_NAME"],
612
- model_vh=config["GMF_"+crosspol_gmf+"_NAME"])
613
-
614
- xr_dataset['windspeed_co'] = windspeed_co
615
- xr_dataset['windspeed_dual'] = windspeed_dual
756
+ wind_co, wind_dual, windspeed_cr = inverse(dual_pol,
757
+ inc=xr_dataset.incidence,
758
+ sigma0=xr_dataset['sigma0_ocean'].sel(
759
+ pol=copol),
760
+ sigma0_dual=sigma0_ocean_cross,
761
+ ancillary_wind=xr_dataset['ancillary_wind'],
762
+ dsig_cr=dsig_cross,
763
+ model_vv=config["GMF_" +
764
+ copol_gmf+"_NAME"],
765
+ model_vh=config["GMF_"+crosspol_gmf+"_NAME"])
766
+
767
+ #  get windspeeds
768
+ xr_dataset['windspeed_co'] = np.abs(wind_co)
769
+ xr_dataset['windspeed_dual'] = np.abs(wind_dual)
770
+
616
771
  if dual_pol:
617
772
  xr_dataset = xr_dataset.assign(
618
773
  windspeed_cross=(['line', 'sample'], windspeed_cr))
619
- else :
774
+ else:
620
775
  xr_dataset['windspeed_cross'] = windspeed_cr
621
776
 
622
- xr_dataset, encoding = makeL2asOwi(xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf, config)
777
+ #  get winddirections
778
+ xr_dataset['winddir_co'] = (
779
+ 90 - (np.angle(-np.conj(wind_co), deg=True)) + xr_dataset.ground_heading) % 360
780
+
781
+ xr_dataset['winddir_dual'] = (
782
+ 90 - (np.angle(-np.conj(wind_dual), deg=True)) + xr_dataset.ground_heading) % 360
783
+ xr_dataset['winddir_cross'] = xr_dataset['winddir_dual'].copy()
784
+
785
+ xr_dataset, encoding = makeL2asOwi(
786
+ xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf, config)
623
787
 
624
788
  os.makedirs(os.path.dirname(out_file), exist_ok=True)
625
789
 
@@ -0,0 +1,24 @@
1
+ from yaml import load
2
+ import logging
3
+ import os
4
+ import grdwindinversion
5
+ from yaml import CLoader as Loader
6
+ local_config_potential_path = os.path.expanduser(
7
+ '~/.grdwindinversion/data_config.yaml')
8
+
9
+ if os.path.exists(local_config_potential_path):
10
+ config_path = local_config_potential_path
11
+ else:
12
+ config_path = os.path.join(os.path.dirname(
13
+ grdwindinversion.__file__), 'data_config.yaml')
14
+ logging.info('config path: %s', config_path)
15
+ stream = open(config_path, 'r')
16
+ conf = load(stream, Loader=Loader)
17
+
18
+
19
+ def getConf():
20
+ """
21
+ if local_config_potential_path exists it will superseed config_path
22
+ :return:
23
+ """
24
+ return conf
@@ -13,7 +13,7 @@ def processor_starting_point():
13
13
  description='Perform inversion from S1(L1-GRD) SAFE, L1-RCM, L1-RS2 ; using xsar/xsarsea tools')
14
14
  parser.add_argument('--input_file', help='input file path', required=True)
15
15
  parser.add_argument('--config_file',
16
- help='config file path [if not provided will take config file based on input file]',required=False)
16
+ help='config file path [if not provided will take config file based on input file]',required=True)
17
17
 
18
18
  parser.add_argument('--resolution',required=False, default='1000m', help='set resolution ["full" | "1000m" | "xXxm"]')
19
19
 
@@ -43,21 +43,8 @@ def processor_starting_point():
43
43
  # if '1SSH' in input_file or '1SDH' in input_file or '_HH_HV' in input_file:
44
44
  # raise Exception('this processor only handle acquisitions with VV or VV+VH polarization for now.')
45
45
 
46
- if args.config_file is None:
47
- if 'S1' in input_file:
48
- config_file = os.path.join(os.path.dirname(grdwindinversion.__file__),'config_S1.yaml')
49
- elif 'RCM' in input_file:
50
- config_file = os.path.join(os.path.dirname(grdwindinversion.__file__),'config_RCM.yaml')
51
- elif 'RS2' in input_file:
52
- config_file = os.path.join(os.path.dirname(grdwindinversion.__file__),'config_RS2.yaml')
53
- elif 'hy2b' in input_file:
54
- config_file = os.path.join(os.path.dirname(grdwindinversion.__file__),'config_hy2b.yaml')
55
- else:
56
- raise Exception('config data file cannot be defined using the input filename')
57
- else:
58
- config_file = args.config_file
59
-
60
-
46
+
47
+ config_file = args.config_file
61
48
  out_folder = args.outputdir
62
49
  resolution = args.resolution
63
50
  if resolution == "full":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: grdwindinversion
3
- Version: 0.2.3.post7
3
+ Version: 0.2.3.post9
4
4
  Summary: Package to perform Wind inversion from GRD Level-1 SAR images
5
5
  License: MIT
6
6
  Classifier: Development Status :: 2 - Pre-Alpha
@@ -33,10 +33,6 @@ docs/examples/wind-inversion-from-grd.ipynb
33
33
  grdwindinversion/.gitignore
34
34
  grdwindinversion/.travis.yml
35
35
  grdwindinversion/__init__.py
36
- grdwindinversion/config_RCM.yaml
37
- grdwindinversion/config_RS2.yaml
38
- grdwindinversion/config_S1.yaml
39
- grdwindinversion/config_hy2b.yaml
40
36
  grdwindinversion/config_prod.yaml
41
37
  grdwindinversion/config_prod_recal.yaml
42
38
  grdwindinversion/data_config.yaml
@@ -1,6 +0,0 @@
1
- RCM:
2
- GMF_VV_NAME: "cmod5n"
3
- GMF_VH_NAME: "gmf_rcm_noaa"
4
- dsig_VH_NAME: "gmf_s1_v2"
5
- apply_flattening: True
6
- recalibration: False
@@ -1,6 +0,0 @@
1
- RS2:
2
- GMF_VV_NAME: "cmod5n"
3
- GMF_VH_NAME: "gmf_rs2_v2"
4
- dsig_VH_NAME: "gmf_rs2_v2"
5
- apply_flattening: False
6
- recalibration: False
@@ -1,12 +0,0 @@
1
- S1A:
2
- GMF_VV_NAME: "cmod5n"
3
- GMF_VH_NAME: "gmf_s1_v2"
4
- dsig_VH_NAME: "gmf_s1_v2"
5
- apply_flattening: True
6
- recalibration: False
7
- S1B:
8
- GMF_VV_NAME: "cmod5n"
9
- GMF_VH_NAME: "gmf_s1_v2"
10
- dsig_VH_NAME: "gmf_s1_v2"
11
- apply_flattening: True
12
- recalibration: False
@@ -1,24 +0,0 @@
1
- S1A:
2
- GMF_VV_NAME: "cmod5n"
3
- GMF_VH_NAME: "gmf_hy2B"
4
- dsig_VH_NAME: "gmf_s1_v2"
5
- apply_flattening: True
6
- recalibration: False
7
- S1B:
8
- GMF_VV_NAME: "cmod5n"
9
- GMF_VH_NAME: "gmf_hy2B"
10
- dsig_VH_NAME: "gmf_s1_v2"
11
- apply_flattening: True
12
- recalibration: False
13
- RS2:
14
- GMF_VV_NAME: "cmod5n"
15
- GMF_VH_NAME: "gmf_hy2B"
16
- dsig_VH_NAME: "gmf_s1_v2"
17
- apply_flattening: False
18
- recalibration: False
19
- RCM:
20
- GMF_VV_NAME: "cmod5n"
21
- GMF_VH_NAME: "gmf_hy2B"
22
- dsig_VH_NAME: "gmf_s1_v2"
23
- apply_flattening: True
24
- recalibration: False
@@ -1,22 +0,0 @@
1
- from yaml import load
2
- import logging
3
- import os
4
- import grdwindinversion
5
- from yaml import CLoader as Loader
6
- local_config_potential_path = os.path.join(os.path.dirname(grdwindinversion.__file__), 'local_data_config.yaml')
7
-
8
- if os.path.exists(local_config_potential_path):
9
- config_path = local_config_potential_path
10
- else:
11
- config_path = os.path.join(os.path.dirname(grdwindinversion.__file__), 'data_config.yaml')
12
- # config_path = "./data_config.yaml"
13
- logging.info('config path: %s',config_path)
14
- stream = open(config_path, 'r')
15
- conf = load(stream, Loader=Loader)
16
- def getConf():
17
-
18
- """
19
- if grdwindinversion/local_data_config.yaml exists it will superseed grdwindinversion/data_config.yaml
20
- :return:
21
- """
22
- return conf