grdwindinversion 0.2.3.post6__tar.gz → 0.2.3.post8__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.post6/grdwindinversion.egg-info → grdwindinversion-0.2.3.post8}/PKG-INFO +1 -1
  2. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/grdwindinversion/config_prod.yaml +4 -4
  3. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/grdwindinversion/config_prod_recal.yaml +4 -8
  4. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/grdwindinversion/inversion.py +358 -209
  5. grdwindinversion-0.2.3.post8/grdwindinversion/load_config.py +24 -0
  6. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/grdwindinversion/main.py +3 -16
  7. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8/grdwindinversion.egg-info}/PKG-INFO +1 -1
  8. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/grdwindinversion.egg-info/SOURCES.txt +0 -4
  9. grdwindinversion-0.2.3.post6/grdwindinversion/config_RCM.yaml +0 -6
  10. grdwindinversion-0.2.3.post6/grdwindinversion/config_RS2.yaml +0 -6
  11. grdwindinversion-0.2.3.post6/grdwindinversion/config_S1.yaml +0 -12
  12. grdwindinversion-0.2.3.post6/grdwindinversion/config_hy2b.yaml +0 -24
  13. grdwindinversion-0.2.3.post6/grdwindinversion/load_config.py +0 -22
  14. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/.editorconfig +0 -0
  15. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/.github/dependabot.yml +0 -0
  16. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/.github/workflows/publish.yml +0 -0
  17. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/.gitignore +0 -0
  18. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/.pre-commit-config.yaml +0 -0
  19. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/AUTHORS.rst +0 -0
  20. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/CONTRIBUTING.rst +0 -0
  21. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/HISTORY.rst +0 -0
  22. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/LICENSE +0 -0
  23. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/MANIFEST.in +0 -0
  24. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/Makefile +0 -0
  25. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/README.md +0 -0
  26. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/ci/requirements/docs.yaml +0 -0
  27. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/ci/requirements/environment.yaml +0 -0
  28. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/docs/Makefile +0 -0
  29. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/docs/_static/css/grdwindinversion.css +0 -0
  30. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/docs/algorithm.rst +0 -0
  31. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/docs/authors.rst +0 -0
  32. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/docs/conf.py +0 -0
  33. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/docs/contributing.rst +0 -0
  34. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/docs/examples/wind-inversion-from-grd.ipynb +0 -0
  35. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/docs/history.rst +0 -0
  36. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/docs/index.rst +0 -0
  37. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/docs/installation.rst +0 -0
  38. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/docs/make.bat +0 -0
  39. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/docs/modules.rst +0 -0
  40. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/docs/readme.rst +0 -0
  41. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/docs/usage.rst +0 -0
  42. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/grdwindinversion/.github/ISSUE_TEMPLATE.md +0 -0
  43. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/grdwindinversion/.gitignore +0 -0
  44. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/grdwindinversion/.travis.yml +0 -0
  45. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/grdwindinversion/__init__.py +0 -0
  46. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/grdwindinversion/data_config.yaml +0 -0
  47. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/grdwindinversion/utils.py +0 -0
  48. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/grdwindinversion.egg-info/dependency_links.txt +0 -0
  49. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/grdwindinversion.egg-info/entry_points.txt +0 -0
  50. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/grdwindinversion.egg-info/requires.txt +0 -0
  51. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/grdwindinversion.egg-info/top_level.txt +0 -0
  52. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/pyproject.toml +0 -0
  53. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/requirements_dev.txt +0 -0
  54. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/requirements_doc.txt +0 -0
  55. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/setup.cfg +0 -0
  56. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/tests/__init__.py +0 -0
  57. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/tests/test_grdwindinversion.py +0 -0
  58. {grdwindinversion-0.2.3.post6 → grdwindinversion-0.2.3.post8}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: grdwindinversion
3
- Version: 0.2.3.post6
3
+ Version: 0.2.3.post8
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
@@ -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,92 +116,180 @@ 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.
122
+ This function is used to check if the ECMWF files are available and to map the model to the SAR data.
111
123
 
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)
124
+ Parameters
125
+ ----------
126
+ meta: obj `xsar.BaseMeta` (one of the supported SAR mission)
118
127
 
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]
123
- 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
128
- 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']}
128
+ Returns
129
+ -------
130
+ dict
131
+ map model to SAR data
132
+ """
153
133
 
154
- else:
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
+ """
155
180
  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']}
181
+ else:
182
+ map_model = {'%s_%s' % (ecmwf_name, uv): 'model_%s' %
183
+ uv for uv in ['U10', 'V10']}
159
184
 
160
- return map_model
185
+ return map_model
186
+
187
+ else:
188
+ raise ValueError("ancillary_name must be ecmwf, got %s" %
189
+ ancillary_name)
161
190
 
162
191
 
163
192
  def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_vv, model_vh):
193
+ """
194
+ Invert sigma0 to retrieve wind using model (lut or gmf).
195
+
196
+ Parameters
197
+ ----------
198
+ dual_pol: bool
199
+ True if dualpol, False if singlepol
200
+ inc: xarray.DataArray
201
+ incidence angle
202
+ sigma0: xarray.DataArray
203
+ sigma0 to be inverted
204
+ sigma0_dual: xarray.DataArray
205
+ sigma0 to be inverted for dualpol
206
+ ancillary_wind=: xarray.DataArray (numpy.complex28)
207
+ ancillary wind
208
+ | (for example ecmwf winds), in **model convention**
209
+ dsig_cr=: float or xarray.DataArray
210
+ parameters used for
211
+
212
+ | `Jsig_cr=((sigma0_gmf - sigma0) / dsig_cr) ** 2`
213
+ model_vv=: str
214
+ model to use for VV or HH polarization.
215
+ model_vh=: str
216
+ model to use for VH or HV polarization.
217
+
218
+ Returns
219
+ -------
220
+ xarray.DataArray or tuple
221
+ inverted wind in **gmf convention** .
222
+
223
+ See Also
224
+ --------
225
+ xsarsea documentation
226
+ https://cyclobs.ifremer.fr/static/sarwing_datarmor/xsarsea/examples/windspeed_inversion.html
227
+ """
164
228
  logging.debug("inversion")
165
- # 4 - Inversion
166
- windspeeds = windspeed.invert_from_model(
229
+
230
+ # add potential missing gmfs (only cmod7 & ms1ahw)
231
+
232
+ if (model_vv == "gmf_cmod7"):
233
+ windspeed.register_cmod7(getConf()["lut_cmod7_path"])
234
+
235
+ if (model_vh == "sarwing_lut_cmodms1ahw"):
236
+ windspeed.register_one_sarwing_lut(getConf()["lut_ms1ahw_path"])
237
+
238
+ winds = windspeed.invert_from_model(
167
239
  inc,
168
240
  sigma0,
169
241
  sigma0_dual,
170
- # ancillary_wind=-np.conj(xsar_dataset.dataset['ancillary_wind']),
171
- ancillary_wind=-ancillary_wind,
242
+ ancillary_wind=-np.conj(ancillary_wind),
172
243
  dsig_cr=dsig_cr,
173
244
  model=(model_vv, model_vh))
174
- if dual_pol:
175
- windspeed_co, windspeed_dual = windspeeds
176
- else:
177
- windspeed_co = windspeeds
178
245
 
179
246
  if dual_pol:
180
- windspeed_cr = windspeed.invert_from_model(
247
+ wind_co, wind_dual = winds
248
+
249
+ wind_cross = windspeed.invert_from_model(
181
250
  inc.values,
182
251
  sigma0_dual.values,
183
- # ancillary_wind=-np.conj(xsar_dataset.dataset['ancillary_wind']),
184
252
  dsig_cr=dsig_cr.values,
185
253
  model=model_vh)
186
254
 
187
- return np.abs(windspeed_co), np.abs(windspeed_dual), np.abs(windspeed_cr)
188
-
189
- return windspeed_co, None, None
190
-
255
+ return wind_co, wind_dual, wind_cross
256
+ else:
257
+ wind_co = winds
191
258
 
259
+ return wind_co, None, None
192
260
 
193
261
 
194
262
  def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf, config):
195
- # rename to match sarwing naming
263
+ """
264
+ Rename xr_dataset variables and attributes to match naming convention.
265
+
266
+ Parameters
267
+ ----------
268
+ xr_dataset: xarray.Dataset
269
+ dataset to rename
270
+ dual_pol: bool
271
+ True if dualpol, False if singlepol
272
+ copol: str
273
+ copolarization name
274
+ crosspol: str
275
+ crosspolarization name
276
+ copol_gmf: str
277
+ copolarization GMF name
278
+ crosspol_gmf: str
279
+ crosspolarization GMF name
280
+ config: dict
281
+ configuration file
282
+
283
+ Returns
284
+ -------
285
+ xarray.Dataset
286
+ final dataset
287
+ dict
288
+ encoding dict
289
+
290
+ See Also
291
+ --------
292
+ """
196
293
 
197
294
  xr_dataset = xr_dataset.rename({
198
295
  'longitude': 'owiLon',
@@ -201,14 +298,17 @@ def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf,
201
298
  'elevation': 'owiElevationAngle',
202
299
  'ground_heading': 'owiHeading',
203
300
  'land_mask': 'owiLandFlag',
204
- 'mask' : 'owiMask',
205
- 'dsig_cross': 'owiDsig_cross',
301
+ 'offboresight': 'owiOffBoresightAngle',
302
+ 'mask': 'owiMask',
206
303
  'windspeed_co': 'owiWindSpeed_co',
207
304
  'windspeed_cross': 'owiWindSpeed_cross',
208
305
  'windspeed_dual': 'owiWindSpeed',
209
- 'nesz_cross_final' : 'owiNesz_cross_final',
306
+ 'winddir_co': 'owiWindDirection_co',
307
+ 'winddir_cross': 'owiWindDirection_cross',
308
+ 'winddir_dual': 'owiWindDirection',
309
+ 'ancillary_wind_speed': 'owiEcmwfWindSpeed',
310
+ 'ancillary_wind_direction': 'owiEcmwfWindDirection',
210
311
  })
211
-
212
312
  xr_dataset['owiNrcs'] = xr_dataset['sigma0_ocean'].sel(pol=copol)
213
313
  xr_dataset.owiNrcs.attrs = xr_dataset.sigma0_ocean.attrs
214
314
  xr_dataset.owiNrcs.attrs['units'] = 'm^2 / m^2'
@@ -227,27 +327,33 @@ def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf,
227
327
  xr_dataset.owiNrcs_no_noise_correction.attrs[
228
328
  'long_name'] = 'Normalized Radar Cross Section ; no noise correction applied'
229
329
  xr_dataset.owiNrcs_no_noise_correction.attrs[
230
- 'comment'] = 'owiNrcs_no_noise_correction ; no recalibration'
231
-
330
+ 'comment'] = 'owiNrcs_no_noise_correction ; no recalibration'
331
+
332
+ if 'swath_number' in xr_dataset:
333
+ xr_dataset = xr_dataset.rename({
334
+ 'swath_number': 'owiSwathNumber',
335
+ 'swath_number_flag': 'owiSwathNumberFlag'
336
+ })
337
+
232
338
  if "sigma0_raw__corrected" in xr_dataset:
233
- xr_dataset['owiNrcs_no_noise_correction_recalibrated'] = xr_dataset['sigma0_raw__corrected'].sel(pol=copol)
339
+ xr_dataset['owiNrcs_no_noise_correction_recalibrated'] = xr_dataset['sigma0_raw__corrected'].sel(
340
+ pol=copol)
234
341
  xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs = xr_dataset.sigma0_raw__corrected.attrs
235
342
  xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs['units'] = 'm^2 / m^2'
236
343
  xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs[
237
344
  'long_name'] = 'Normalized Radar Cross Section, no noise correction applied'
238
345
  xr_dataset.owiNrcs_no_noise_correction_recalibrated.attrs[
239
- 'comment'] = 'owiNrcs_no_noise_correction ; recalibrated with kersten method'
240
-
346
+ 'comment'] = 'owiNrcs_no_noise_correction ; recalibrated with kersten method'
347
+
241
348
  xr_dataset.owiNrcs.attrs['definition'] = 'owiNrcs_no_noise_correction_recalibrated - owiNesz'
242
349
 
243
-
350
+ if dual_pol:
351
+
244
352
  xr_dataset = xr_dataset.rename({
245
- 'swath_number' : 'owiSwathNumber',
246
- 'swath_number_flag' : 'owiSwathNumberFlag'
353
+ 'dsig_cross': 'owiDsig_cross',
354
+ 'nesz_cross_final': 'owiNesz_cross_final'
247
355
  })
248
356
 
249
-
250
- if dual_pol:
251
357
  xr_dataset['owiNrcs_cross'] = xr_dataset['sigma0_ocean'].sel(
252
358
  pol=crosspol)
253
359
  xr_dataset.owiNrcs_cross.attrs['units'] = 'm^2 / m^2'
@@ -266,37 +372,35 @@ def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf,
266
372
  'long_name'] = 'Normalized Radar Cross Section, no noise correction applied'
267
373
 
268
374
  if "sigma0_raw__corrected" in xr_dataset:
269
- xr_dataset['owiNrcs_cross_no_noise_correction_recalibrated'] = xr_dataset['sigma0_raw__corrected'].sel(pol=crosspol)
375
+ xr_dataset['owiNrcs_cross_no_noise_correction_recalibrated'] = xr_dataset['sigma0_raw__corrected'].sel(
376
+ pol=crosspol)
270
377
  xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs = xr_dataset.sigma0_raw__corrected.attrs
271
378
  xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs['units'] = 'm^2 / m^2'
272
379
  xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs[
273
380
  'long_name'] = 'Normalized Radar Cross Section ; no noise correction applied'
274
381
  xr_dataset.owiNrcs_cross_no_noise_correction_recalibrated.attrs[
275
- 'comment'] = 'owiNrcs_cross_no_noise_correction ; recalibrated with kersten method'
276
-
382
+ 'comment'] = 'owiNrcs_cross_no_noise_correction ; recalibrated with kersten method'
383
+
277
384
  xr_dataset.owiNrcs_cross.attrs['definition'] = 'owiNrcs_cross_no_noise_correction_recalibrated - owiNesz_cross'
278
385
 
279
-
280
-
281
386
  xr_dataset["owiWindSpeed_co"].attrs["comment"] = xr_dataset["owiWindSpeed_co"].attrs["comment"].replace(
282
387
  "wind speed and direction", "wind speed")
283
388
 
389
+ xr_dataset["owiWindDirection_co"].attrs["comment"] = "wind direction in meteorological convention, 0=North, 90=East"
390
+
284
391
  if dual_pol:
285
392
  xr_dataset["owiWindSpeed"].attrs["comment"] = xr_dataset["owiWindSpeed"].attrs["comment"].replace(
286
393
  "wind speed and direction", "wind speed")
394
+ xr_dataset["owiWindDirection"].attrs["comment"] = "wind direction in meteorological convention, 0=North, 90=East"
287
395
 
288
396
  xr_dataset["owiWindSpeed_cross"].attrs['comment'] = "wind speed inverted from model %s (%s)" % (
289
397
  crosspol_gmf, crosspol)
290
398
 
399
+ xr_dataset["owiWindDirection_cross"].attrs["comment"] = "wind direction in meteorological convention, 0=North, 90=East, copied from dualpol"
400
+
291
401
  xr_dataset.owiWindSpeed_cross.attrs['model'] = crosspol_gmf
292
402
  xr_dataset.owiWindSpeed_cross.attrs['units'] = 'm/s'
293
403
 
294
- xr_dataset = xr_dataset.assign(
295
- owiEcmwfWindSpeed=(['line', 'sample'], np.abs(xr_dataset['ancillary_wind'].data)))
296
- xr_dataset = xr_dataset.assign(
297
- owiEcmwfWindDirection=(['line', 'sample'], np.angle(xr_dataset['ancillary_wind'])))
298
- xr_dataset['owiEcmwfWindDirection'].attrs['comment'] = 'angle in radians, anticlockwise, 0=sample'
299
-
300
404
  xr_dataset['owiWindQuality'] = xr.full_like(xr_dataset.owiNrcs, 0)
301
405
  xr_dataset['owiWindQuality'].attrs[
302
406
  'long_name'] = "Quality flag taking into account the consistency_between_wind_inverted_and_NRCS_and_Doppler_measured"
@@ -317,14 +421,14 @@ def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf,
317
421
 
318
422
  xr_dataset = xr_dataset.rename(
319
423
  {"line": "owiAzSize", "sample": "owiRaSize"})
320
-
321
-
322
- xr_dataset = xr_dataset.drop_vars(['sigma0_ocean', 'sigma0', 'sigma0_ocean_raw','sigma0_raw', 'ancillary_wind','nesz','spatial_ref'])
424
+
425
+ xr_dataset = xr_dataset.drop_vars(
426
+ ['sigma0_ocean', 'sigma0', 'sigma0_ocean_raw', 'sigma0_raw', 'ancillary_wind', 'nesz', 'spatial_ref'])
323
427
  if 'sigma0_raw__corrected' in xr_dataset:
324
428
  xr_dataset = xr_dataset.drop_vars(["sigma0_raw__corrected"])
325
429
  xr_dataset = xr_dataset.drop_dims(['pol'])
326
-
327
- #attrs
430
+
431
+ # attrs
328
432
 
329
433
  xr_dataset.compute()
330
434
 
@@ -334,50 +438,44 @@ def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf,
334
438
  if "approx_transform" in xr_dataset.attrs:
335
439
  del xr_dataset.attrs["approx_transform"]
336
440
 
337
- xr_dataset.attrs["TITLE"] = "Sentinel-1 OWI Component"
338
- xr_dataset.attrs["missionPhase"] = "Test"
339
- xr_dataset.attrs["polarisation"] = xr_dataset.pols
340
- xr_dataset.attrs["acquisitionStation"] = "/"
341
- xr_dataset.attrs["softwareVersion"] = "/"
342
- xr_dataset.attrs["pythonVersion"] = str(
343
- sys.version_info.major)+'.'+str(sys.version_info.minor)
344
- xr_dataset.attrs["polarisationRatio"] = "/"
345
- xr_dataset.attrs["l2ProcessingUtcTime"] = datetime.datetime.now().strftime(
441
+ xr_dataset.attrs["TITLE"] = "Sentinel-1 OWI Component"
442
+ xr_dataset.attrs["missionPhase"] = "Test"
443
+ xr_dataset.attrs["acquisitionStation"] = "/"
444
+ xr_dataset.attrs["softwareVersion"] = "/"
445
+ xr_dataset.attrs["pythonVersion"] = str(
446
+ sys.version_info.major)+'.'+str(sys.version_info.minor)
447
+ xr_dataset.attrs["polarisationRatio"] = "/"
448
+ xr_dataset.attrs["l2ProcessingUtcTime"] = datetime.datetime.now().strftime(
449
+ "%Y-%m-%dT%H:%M:%SZ")
450
+ xr_dataset.attrs["processingCenter"] = "/"
451
+ try:
452
+ xr_dataset.attrs["firstMeasurementTime"] = datetime.datetime.strptime(xr_dataset.attrs['start_date'],
453
+ "%Y-%m-%d %H:%M:%S.%f").strftime(
346
454
  "%Y-%m-%dT%H:%M:%SZ")
347
- xr_dataset.attrs["processingCenter"] = "/"
348
- try:
349
- xr_dataset.attrs["firstMeasurementTime"] = datetime.datetime.strptime(xr_dataset.attrs['start_date'],
350
- "%Y-%m-%d %H:%M:%S.%f").strftime(
351
- "%Y-%m-%dT%H:%M:%SZ")
352
- xr_dataset.attrs["lastMeasurementTime"] = datetime.datetime.strptime(xr_dataset.attrs['stop_date'],
353
- "%Y-%m-%d %H:%M:%S.%f").strftime(
354
- "%Y-%m-%dT%H:%M:%SZ")
355
- except:
356
- xr_dataset.attrs["firstMeasurementTime"] = datetime.datetime.strptime(xr_dataset.attrs['start_date'],
357
- "%Y-%m-%d %H:%M:%S").strftime(
358
- "%Y-%m-%dT%H:%M:%SZ")
359
- xr_dataset.attrs["lastMeasurementTime"] = datetime.datetime.strptime(xr_dataset.attrs['stop_date'],
360
- "%Y-%m-%d %H:%M:%S").strftime(
361
- "%Y-%m-%dT%H:%M:%SZ")
362
- xr_dataset.attrs["clmSource"] = "/"
363
- xr_dataset.attrs["bathySource"] = "/"
364
- xr_dataset.attrs['oswAlgorithmName'] = 'grdwindinversion'
365
- xr_dataset.attrs["owiAlgorithmVersion"] = grdwindinversion.__version__
366
- xr_dataset.attrs["gmf"] = config['GMF_'+copol_gmf+'_NAME'] + \
367
- ", " + config["GMF_"+crosspol_gmf+"_NAME"]
368
- xr_dataset.attrs["iceSource"] = "/"
369
- xr_dataset.attrs["owiNoiseCorrection"] = "False"
370
- xr_dataset.attrs["inversionTabGMF"] = config['GMF_'+copol_gmf +
371
- '_NAME'] + ", " + config["GMF_"+crosspol_gmf+"_NAME"]
372
- xr_dataset.attrs["wnf_3km_average"] = "/"
373
- xr_dataset.attrs["owiWindSpeedSrc"] = "owiWindSpeed"
374
- xr_dataset.attrs["owiWindDirectionSrc"] = "/"
375
-
376
- for var in xr_dataset.variables:
377
- if "history" in xr_dataset[var].attrs:
378
- del xr_dataset[var].attrs["history"]
379
-
380
-
455
+ xr_dataset.attrs["lastMeasurementTime"] = datetime.datetime.strptime(xr_dataset.attrs['stop_date'],
456
+ "%Y-%m-%d %H:%M:%S.%f").strftime(
457
+ "%Y-%m-%dT%H:%M:%SZ")
458
+ except:
459
+ xr_dataset.attrs["firstMeasurementTime"] = datetime.datetime.strptime(xr_dataset.attrs['start_date'],
460
+ "%Y-%m-%d %H:%M:%S").strftime(
461
+ "%Y-%m-%dT%H:%M:%SZ")
462
+ xr_dataset.attrs["lastMeasurementTime"] = datetime.datetime.strptime(xr_dataset.attrs['stop_date'],
463
+ "%Y-%m-%d %H:%M:%S").strftime(
464
+ "%Y-%m-%dT%H:%M:%SZ")
465
+ xr_dataset.attrs["clmSource"] = "/"
466
+ xr_dataset.attrs["bathySource"] = "/"
467
+ xr_dataset.attrs['oswAlgorithmName'] = 'grdwindinversion'
468
+ xr_dataset.attrs["owiAlgorithmVersion"] = grdwindinversion.__version__
469
+ xr_dataset.attrs["gmf"] = config['GMF_'+copol_gmf+'_NAME'] + \
470
+ ", " + config["GMF_"+crosspol_gmf+"_NAME"]
471
+ xr_dataset.attrs["iceSource"] = "/"
472
+ xr_dataset.attrs["owiNoiseCorrection"] = "False"
473
+ xr_dataset.attrs["inversionTabGMF"] = config['GMF_'+copol_gmf +
474
+ '_NAME'] + ", " + config["GMF_"+crosspol_gmf+"_NAME"]
475
+ xr_dataset.attrs["wnf_3km_average"] = "/"
476
+ xr_dataset.attrs["owiWindSpeedSrc"] = "owiWindSpeed"
477
+ xr_dataset.attrs["owiWindDirectionSrc"] = "/"
478
+
381
479
  table_fillValue = {
382
480
  "owiWindQuality": -1,
383
481
  "owiHeading": 9999.99,
@@ -390,43 +488,51 @@ def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf,
390
488
  "owiWindSpeed_co": -9999.0,
391
489
  "owiWindSpeed_cross": -9999.0,
392
490
  }
393
-
491
+
394
492
  encoding = {}
395
493
  for var in list(set(xr_dataset.coords.keys()) | set(xr_dataset.keys())):
396
494
  encoding[var] = {}
397
495
  try:
398
- # sarwing_ds[var].attrs["_FillValue"] = table_fillValue[var]
399
496
  encoding[var].update({'_FillValue': table_fillValue[var]})
400
497
  except:
401
- # Nouvelles variables..
402
498
  if (var in ["owiWindSpeed_co", "owiWindSpeed_cross", "owiWindSpeed"]):
403
- # sarwing_ds[var].attrs["_FillValue"] = -9999.0
404
499
  encoding[var].update({'_FillValue': -9999.0})
405
500
  else:
406
501
  encoding[var].update({'_FillValue': None})
407
502
 
408
503
  xr_dataset.attrs["xsar_version"] = xsar.__version__
409
504
  xr_dataset.attrs["xsarsea_version"] = xsarsea.__version__
410
-
505
+
411
506
  return xr_dataset, encoding
412
507
 
413
508
 
414
509
  def makeL2(filename, out_folder, config_path, overwrite=False, generateCSV=True, resolution='1000m'):
415
510
  """
416
-
417
- :param filename: str
418
- :param out_folder: str
419
- :param config_path: str
420
- :param overwrite: bool True -> existing files will be overwritten
421
- :return:
422
- out_file: str
423
- xr_dataset: xarray.Dataset final dataset with wind speed variables
511
+ Main function to generate L2 product.
512
+
513
+ Parameters
514
+ ----------
515
+ filename : str
516
+ input filename
517
+ out_folder : str
518
+ output folder
519
+ config_path : str
520
+ configuration file path
521
+ overwrite : bool, optional
522
+ overwrite existing file
523
+ generateCSV : bool, optional
524
+ generate CSV file
525
+ resolution : str, optional
526
+ working resolution
527
+
528
+ Returns
529
+ -------
530
+ str
531
+ output filename
532
+ xarray.Dataset
533
+ final dataset
424
534
  """
425
535
 
426
- # final xr.Dataset
427
-
428
- #  Step 1 - load L1 product
429
-
430
536
  sensor, sensor_longname, fct_meta, fct_dataset = getSensorMetaDataset(
431
537
  filename)
432
538
 
@@ -442,58 +548,65 @@ def makeL2(filename, out_folder, config_path, overwrite=False, generateCSV=True,
442
548
  else:
443
549
  raise FileNotFoundError(
444
550
  'config_path do not exists, got %s ' % config_path)
445
-
551
+
446
552
  recalibration = config["recalibration"]
447
- if recalibration:
448
- aux_config_name=config["aux_config_name"]
449
-
450
553
  meta = fct_meta(filename)
451
554
  out_file = getOutputName2(filename, out_folder, sensor, meta)
452
555
 
453
-
454
556
  if os.path.exists(out_file) and overwrite is False:
455
- logging.info("out_file %s exists" % out_file)
557
+ logging.info("out_file %s exists ; returning empty Dataset" % out_file)
456
558
  return out_file, xr.Dataset()
457
559
 
458
- # get ancillary wind from ECMWF
459
- map_model = getAncillary(meta)
560
+ map_model = getAncillary(meta, ancillary_name=config["ancillary"])
460
561
  if map_model is None:
461
562
  raise Exception(
462
563
  'the weather model is not set `map_model` is None -> you probably don"t have access to ECMWF archive')
463
564
 
464
565
  try:
465
566
  if ((recalibration) & ("SENTINEL" in sensor_longname)):
466
- logging.info('recalibration is True : Kersten formula is applied')
567
+ logging.info(
568
+ f'recalibration is {recalibration} : Kersten formula is applied')
467
569
  xsar_dataset = fct_dataset(
468
- meta, resolution=resolution, recalibration=recalibration, aux_config_name = aux_config_name)
570
+ meta, resolution=resolution, recalibration=recalibration)
469
571
  xr_dataset = xsar_dataset.datatree['measurement'].to_dataset()
470
- xr_dataset = xr_dataset.merge(xsar_dataset.datatree["recalibration"].to_dataset()[['swath_number','swath_number_flag','sigma0_raw__corrected']])
471
-
572
+ xr_dataset = xr_dataset.merge(xsar_dataset.datatree["recalibration"].to_dataset()[
573
+ ['swath_number', 'swath_number_flag', 'sigma0_raw__corrected']])
574
+
472
575
  else:
473
576
  logging.info(
474
- 'recalibration is True : Kersten formula is not applied')
577
+ f'recalibration is {recalibration} : Kersten formula is not applied')
475
578
  if ("SENTINEL" in sensor_longname):
476
- xsar_dataset = fct_dataset(meta, resolution=resolution,recalibration=recalibration)
579
+ xsar_dataset = fct_dataset(
580
+ meta, resolution=resolution, recalibration=recalibration)
477
581
  xr_dataset = xsar_dataset.datatree['measurement'].to_dataset()
478
- xr_dataset = xr_dataset.merge(xsar_dataset.datatree["recalibration"].to_dataset()[['swath_number','swath_number_flag']])
582
+ xr_dataset = xr_dataset.merge(xsar_dataset.datatree["recalibration"].to_dataset()[
583
+ ['swath_number', 'swath_number_flag']])
479
584
 
480
- else:
585
+ else:
481
586
  xsar_dataset = fct_dataset(meta, resolution=resolution)
482
587
  xr_dataset = xsar_dataset.datatree['measurement'].to_dataset()
483
588
 
484
-
485
589
  xr_dataset = xr_dataset.rename(map_model)
486
590
  # add attributes
487
591
  xr_dataset.attrs = xsar_dataset.dataset.attrs
488
592
  xr_dataset.attrs['L1_path'] = xr_dataset.attrs.pop('name')
489
593
  xr_dataset.attrs["sourceProduct"] = sensor
490
594
  xr_dataset.attrs["missionName"] = sensor_longname
491
-
595
+ if ((recalibration) & ("SENTINEL" in sensor_longname)):
596
+ xr_dataset.attrs["path_aux_pp1_new"] = os.path.basename(os.path.dirname(
597
+ os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_pp1_new'])))
598
+ xr_dataset.attrs["path_aux_cal_new"] = os.path.basename(os.path.dirname(
599
+ os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_cal_new'])))
600
+
601
+ xr_dataset.attrs["path_aux_pp1_old"] = os.path.basename(os.path.dirname(
602
+ os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_pp1_old'])))
603
+ xr_dataset.attrs["path_aux_cal_old"] = os.path.basename(os.path.dirname(
604
+ os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_cal_old'])))
605
+
492
606
  except Exception as e:
493
607
  logging.info('%s', traceback.format_exc())
494
608
  logging.error(e)
495
609
  sys.exit(-1)
496
-
497
610
 
498
611
  # defining dual_pol, and gmfs by channel
499
612
  if len(xr_dataset.pol.values) == 2:
@@ -547,11 +660,33 @@ def makeL2(filename, out_folder, config_path, overwrite=False, generateCSV=True,
547
660
  xr_dataset.mask.attrs['flag_meanings'] = 'valid land ice no_valid'
548
661
 
549
662
  # ANCILLARY
550
- xr_dataset['ancillary_wind'] = (xr_dataset.model_U10 + 1j * xr_dataset.model_V10) * np.exp(
551
- 1j * np.deg2rad(xr_dataset.ground_heading))
663
+ xr_dataset['ancillary_wind_direction'] = (
664
+ 90. - np.rad2deg(np.arctan2(xr_dataset.model_V10, xr_dataset.model_U10)) + 180) % 360
665
+
666
+ xr_dataset['ancillary_wind_direction'] = xr.where(xr_dataset['mask'], np.nan,
667
+ xr_dataset['ancillary_wind_direction'].compute()).transpose(
668
+ *xr_dataset['ancillary_wind_direction'].dims)
669
+ xr_dataset['ancillary_wind_direction'].attrs = {}
670
+ xr_dataset['ancillary_wind_direction'].attrs['units'] = 'degrees_north'
671
+ xr_dataset['ancillary_wind_direction'].attrs[
672
+ 'long_name'] = 'ECMWF Wind direction (meteorological convention)'
673
+ xr_dataset['ancillary_wind_direction'].attrs['standart_name'] = 'wind_direction'
674
+
675
+ xr_dataset['ancillary_wind_speed'] = np.sqrt(
676
+ xr_dataset['model_U10']**2+xr_dataset['model_V10']**2)
677
+ xr_dataset['ancillary_wind_speed'] = xr.where(xr_dataset['mask'], np.nan,
678
+ xr_dataset['ancillary_wind_speed'].compute()).transpose(
679
+ *xr_dataset['ancillary_wind_speed'].dims)
680
+ xr_dataset['ancillary_wind_speed'].attrs = {}
681
+ xr_dataset['ancillary_wind_speed'].attrs['units'] = 'm s^-1'
682
+ xr_dataset['ancillary_wind_speed'].attrs[
683
+ 'long_name'] = 'ECMWF Wind speed'
684
+ xr_dataset['ancillary_wind_speed'].attrs['standart_name'] = 'wind_speed'
685
+
552
686
  xr_dataset['ancillary_wind'] = xr.where(xr_dataset['mask'], np.nan,
553
- xr_dataset['ancillary_wind'].compute()).transpose(
554
- *xr_dataset['ancillary_wind'].dims)
687
+ (xr_dataset.ancillary_wind_speed * np.exp(1j * xsarsea.dir_geo_to_sample(xr_dataset.ancillary_wind_direction, xr_dataset.ground_heading))).compute()).transpose(
688
+ *xr_dataset['ancillary_wind_speed'].dims)
689
+
555
690
  xr_dataset.attrs['ancillary_source'] = xr_dataset['model_U10'].attrs['history'].split('decoded: ')[
556
691
  1].strip()
557
692
  xr_dataset = xr_dataset.drop_vars(['model_U10', 'model_V10'])
@@ -561,7 +696,7 @@ def makeL2(filename, out_folder, config_path, overwrite=False, generateCSV=True,
561
696
  xr_dataset['sigma0'].compute()).transpose(*xr_dataset['sigma0'].dims)
562
697
  xr_dataset['sigma0_ocean'] = xr.where(
563
698
  xr_dataset['sigma0_ocean'] <= 0, np.nan, xr_dataset['sigma0_ocean'])
564
-
699
+
565
700
  xr_dataset['sigma0_ocean'].attrs = xr_dataset['sigma0'].attrs
566
701
 
567
702
  xr_dataset['sigma0_ocean_raw'] = xr.where(xr_dataset['mask'], np.nan,
@@ -594,23 +729,37 @@ def makeL2(filename, out_folder, config_path, overwrite=False, generateCSV=True,
594
729
  sigma0_ocean_cross = None
595
730
  dsig_cross = 0.1 # default value set in xsarsea
596
731
 
597
- windspeed_co, windspeed_dual, windspeed_cr = inverse(dual_pol,
598
- inc=xr_dataset.incidence,
599
- sigma0=xr_dataset['sigma0_ocean'].sel(
600
- pol=copol),
601
- sigma0_dual=sigma0_ocean_cross,
602
- ancillary_wind=xr_dataset['ancillary_wind'],
603
- dsig_cr=dsig_cross,
604
- model_vv=config["GMF_" +
605
- copol_gmf+"_NAME"],
606
- model_vh=config["GMF_"+crosspol_gmf+"_NAME"])
607
-
608
- xr_dataset['windspeed_co'] = windspeed_co
609
- xr_dataset['windspeed_dual'] = windspeed_dual
610
- xr_dataset = xr_dataset.assign(
611
- windspeed_cross=(['line', 'sample'], windspeed_cr))
732
+ wind_co, wind_dual, windspeed_cr = inverse(dual_pol,
733
+ inc=xr_dataset.incidence,
734
+ sigma0=xr_dataset['sigma0_ocean'].sel(
735
+ pol=copol),
736
+ sigma0_dual=sigma0_ocean_cross,
737
+ ancillary_wind=xr_dataset['ancillary_wind'],
738
+ dsig_cr=dsig_cross,
739
+ model_vv=config["GMF_" +
740
+ copol_gmf+"_NAME"],
741
+ model_vh=config["GMF_"+crosspol_gmf+"_NAME"])
742
+
743
+ #  get windspeeds
744
+ xr_dataset['windspeed_co'] = np.abs(wind_co)
745
+ xr_dataset['windspeed_dual'] = np.abs(wind_dual)
746
+
747
+ if dual_pol:
748
+ xr_dataset = xr_dataset.assign(
749
+ windspeed_cross=(['line', 'sample'], windspeed_cr))
750
+ else:
751
+ xr_dataset['windspeed_cross'] = windspeed_cr
752
+
753
+ #  get winddirections
754
+ xr_dataset['winddir_co'] = (
755
+ 90 - (np.angle(-np.conj(wind_co), deg=True)) + xr_dataset.ground_heading) % 360
756
+
757
+ xr_dataset['winddir_dual'] = (
758
+ 90 - (np.angle(-np.conj(wind_dual), deg=True)) + xr_dataset.ground_heading) % 360
759
+ xr_dataset['winddir_cross'] = xr_dataset['winddir_dual'].copy()
612
760
 
613
- xr_dataset, encoding = makeL2asOwi(xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf, config)
761
+ xr_dataset, encoding = makeL2asOwi(
762
+ xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf, config)
614
763
 
615
764
  os.makedirs(os.path.dirname(out_file), exist_ok=True)
616
765
 
@@ -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.post6
3
+ Version: 0.2.3.post8
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