grdwindinversion 0.2.3.post13__tar.gz → 0.2.3.post15__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.
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/.github/workflows/publish.yml +6 -6
- {grdwindinversion-0.2.3.post13/grdwindinversion.egg-info → grdwindinversion-0.2.3.post15}/PKG-INFO +1 -1
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion/config_prod.yaml +17 -5
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion/config_prod_recal.yaml +1 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion/inversion.py +107 -53
- grdwindinversion-0.2.3.post15/grdwindinversion/streaks.py +79 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15/grdwindinversion.egg-info}/PKG-INFO +1 -1
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion.egg-info/SOURCES.txt +2 -0
- grdwindinversion-0.2.3.post15/recipe/meta.yaml +34 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/.editorconfig +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/.github/dependabot.yml +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/.gitignore +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/.pre-commit-config.yaml +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/AUTHORS.rst +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/CONTRIBUTING.rst +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/HISTORY.rst +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/LICENSE +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/MANIFEST.in +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/Makefile +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/README.md +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/ci/requirements/docs.yaml +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/ci/requirements/environment.yaml +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/docs/Makefile +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/docs/_static/css/grdwindinversion.css +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/docs/algorithm.rst +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/docs/authors.rst +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/docs/conf.py +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/docs/contributing.rst +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/docs/examples/wind-inversion-from-grd.ipynb +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/docs/history.rst +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/docs/index.rst +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/docs/installation.rst +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/docs/make.bat +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/docs/modules.rst +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/docs/readme.rst +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/docs/usage.rst +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion/.github/ISSUE_TEMPLATE.md +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion/.gitignore +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion/.travis.yml +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion/__init__.py +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion/data_config.yaml +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion/load_config.py +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion/main.py +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion/utils.py +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion.egg-info/dependency_links.txt +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion.egg-info/entry_points.txt +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion.egg-info/requires.txt +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion.egg-info/top_level.txt +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/pyproject.toml +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/requirements_dev.txt +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/requirements_doc.txt +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/setup.cfg +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/tests/__init__.py +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/tests/test_grdwindinversion.py +0 -0
- {grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/tox.ini +0 -0
{grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/.github/workflows/publish.yml
RENAMED
|
@@ -11,9 +11,9 @@ jobs:
|
|
|
11
11
|
if: github.repository == 'umr-lops/grdwindinversion'
|
|
12
12
|
steps:
|
|
13
13
|
- name: Checkout
|
|
14
|
-
uses: actions/checkout@
|
|
14
|
+
uses: actions/checkout@v4
|
|
15
15
|
- name: Set up Python
|
|
16
|
-
uses: actions/setup-python@
|
|
16
|
+
uses: actions/setup-python@v5
|
|
17
17
|
with:
|
|
18
18
|
python-version: "3.x"
|
|
19
19
|
- name: Install dependencies
|
|
@@ -22,12 +22,12 @@ jobs:
|
|
|
22
22
|
python -m pip install build twine
|
|
23
23
|
- name: Build
|
|
24
24
|
run: |
|
|
25
|
-
python -m build --sdist --outdir dist/ .
|
|
25
|
+
python -m build --sdist --wheel --outdir dist/ .
|
|
26
26
|
- name: Check the built archives
|
|
27
27
|
run: |
|
|
28
28
|
twine check dist/*
|
|
29
29
|
- name: Upload build artifacts
|
|
30
|
-
uses: actions/upload-artifact@
|
|
30
|
+
uses: actions/upload-artifact@v4
|
|
31
31
|
with:
|
|
32
32
|
name: packages
|
|
33
33
|
path: dist/*
|
|
@@ -45,10 +45,10 @@ jobs:
|
|
|
45
45
|
|
|
46
46
|
steps:
|
|
47
47
|
- name: Download build artifacts
|
|
48
|
-
uses: actions/download-artifact@
|
|
48
|
+
uses: actions/download-artifact@v4
|
|
49
49
|
with:
|
|
50
50
|
name: packages
|
|
51
51
|
path: dist/
|
|
52
52
|
|
|
53
53
|
- name: Publish to PyPI
|
|
54
|
-
uses: pypa/gh-action-pypi-publish@
|
|
54
|
+
uses: pypa/gh-action-pypi-publish@81e9d935c883d0b210363ab89cf05f3894778450
|
{grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion/config_prod.yaml
RENAMED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
no_subdir: True
|
|
1
2
|
S1A:
|
|
2
3
|
GMF_VV_NAME: "gmf_cmod5n"
|
|
3
4
|
GMF_VH_NAME: "gmf_s1_v2"
|
|
@@ -5,6 +6,10 @@ S1A:
|
|
|
5
6
|
apply_flattening: True
|
|
6
7
|
recalibration: False
|
|
7
8
|
ancillary: "ecmwf"
|
|
9
|
+
inc_step: 0.1
|
|
10
|
+
wspd_step: 0.1
|
|
11
|
+
phi_step: 1.0
|
|
12
|
+
resolution: "high"
|
|
8
13
|
S1B:
|
|
9
14
|
GMF_VV_NAME: "gmf_cmod5n"
|
|
10
15
|
GMF_VH_NAME: "gmf_s1_v2"
|
|
@@ -12,6 +17,10 @@ S1B:
|
|
|
12
17
|
apply_flattening: True
|
|
13
18
|
recalibration: False
|
|
14
19
|
ancillary: "ecmwf"
|
|
20
|
+
inc_step: 0.1
|
|
21
|
+
wspd_step: 0.1
|
|
22
|
+
phi_step: 1.0
|
|
23
|
+
resolution: "high"
|
|
15
24
|
RS2:
|
|
16
25
|
GMF_VV_NAME: "gmf_cmod5n"
|
|
17
26
|
GMF_VH_NAME: "gmf_rs2_v2"
|
|
@@ -19,6 +28,10 @@ RS2:
|
|
|
19
28
|
apply_flattening: False
|
|
20
29
|
recalibration: False
|
|
21
30
|
ancillary: "ecmwf"
|
|
31
|
+
inc_step: 0.1
|
|
32
|
+
wspd_step: 0.1
|
|
33
|
+
phi_step: 1.0
|
|
34
|
+
resolution: "high"
|
|
22
35
|
RCM:
|
|
23
36
|
GMF_VV_NAME: "gmf_cmod5n"
|
|
24
37
|
GMF_VH_NAME: "gmf_rcm_noaa"
|
|
@@ -26,8 +39,7 @@ RCM:
|
|
|
26
39
|
apply_flattening: True
|
|
27
40
|
recalibration: False
|
|
28
41
|
ancillary: "ecmwf"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
resolution: "high"
|
|
42
|
+
inc_step: 0.1
|
|
43
|
+
wspd_step: 0.1
|
|
44
|
+
phi_step: 1.0
|
|
45
|
+
resolution: "high"
|
{grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion/inversion.py
RENAMED
|
@@ -15,6 +15,7 @@ from scipy.ndimage import binary_dilation
|
|
|
15
15
|
import re
|
|
16
16
|
import string
|
|
17
17
|
import os
|
|
18
|
+
from grdwindinversion.streaks import get_streaks
|
|
18
19
|
from grdwindinversion.load_config import getConf
|
|
19
20
|
# optional debug messages
|
|
20
21
|
import logging
|
|
@@ -49,7 +50,7 @@ def getSensorMetaDataset(filename):
|
|
|
49
50
|
raise ValueError("must be S1A|S1B|RS2|RCM, got filename %s" % filename)
|
|
50
51
|
|
|
51
52
|
|
|
52
|
-
def getOutputName2(input_file, outdir, sensor, meta):
|
|
53
|
+
def getOutputName2(input_file, outdir, sensor, meta, subdir=True):
|
|
53
54
|
"""
|
|
54
55
|
Create output filename for L2-GRD product
|
|
55
56
|
|
|
@@ -84,21 +85,14 @@ def getOutputName2(input_file, outdir, sensor, meta):
|
|
|
84
85
|
match = regex.match(basename_match)
|
|
85
86
|
MISSIONID, BEAM, PRODUCT, RESOLUTION, LEVEL, CLASS, POL, STARTDATE, STOPDATE, ORBIT, TAKEID, PRODID = match.groups()
|
|
86
87
|
new_format = f"{MISSIONID.lower()}-{BEAM.lower()}-owi-xx-{STARTDATE.lower()}-{STOPDATE.lower()}-{ORBIT}-{TAKEID}.nc"
|
|
87
|
-
out_file = os.path.join(outdir, basename, new_format)
|
|
88
|
-
return out_file
|
|
89
|
-
|
|
90
88
|
elif sensor == 'RS2':
|
|
91
89
|
regex = re.compile(
|
|
92
90
|
"(RS2)_OK([0-9]+)_PK([0-9]+)_DK([0-9]+)_(....)_(........)_(......)_(.._?.?.?)_(S.F)")
|
|
93
91
|
template = string.Template(
|
|
94
92
|
"${MISSIONID}_OK${DATA1}_PK${DATA2}_DK${DATA3}_${DATA4}_${DATE}_${TIME}_${POLARIZATION}_${LAST}")
|
|
95
93
|
match = regex.match(basename_match)
|
|
96
|
-
|
|
97
94
|
MISSIONID, DATA1, DATA2, DATA3, DATA4, DATE, TIME, POLARIZATION, LAST = match.groups()
|
|
98
95
|
new_format = f"{MISSIONID.lower()}--owi-xx-{meta_start_date.lower()}-{meta_stop_date.lower()}-_____-_____.nc"
|
|
99
|
-
out_file = os.path.join(outdir, basename, new_format)
|
|
100
|
-
return out_file
|
|
101
|
-
|
|
102
96
|
elif sensor == 'RCM':
|
|
103
97
|
regex = re.compile(
|
|
104
98
|
"([A-Z0-9]+)_OK([0-9]+)_PK([0-9]+)_(.*?)_(.*?)_(.*?)_(.*?)_(.*?)_(.*?)_(.*?)")
|
|
@@ -107,13 +101,16 @@ def getOutputName2(input_file, outdir, sensor, meta):
|
|
|
107
101
|
match = regex.match(basename_match)
|
|
108
102
|
MISSIONID, DATA1, DATA2, DATA3, DATA4, DATE, TIME, POLARIZATION1, POLARIZATION2, LAST = match.groups()
|
|
109
103
|
new_format = f"{MISSIONID.lower()}--owi-xx-{meta_start_date.lower()}-{meta_stop_date.lower()}-_____-_____.nc"
|
|
110
|
-
out_file = os.path.join(outdir, basename, new_format)
|
|
111
|
-
return out_file
|
|
112
|
-
|
|
113
104
|
else:
|
|
114
105
|
raise ValueError(
|
|
115
106
|
"sensor must be S1A|S1B|RS2|RCM, got sensor %s" % sensor)
|
|
116
107
|
|
|
108
|
+
if subdir:
|
|
109
|
+
out_file = os.path.join(outdir, basename, new_format)
|
|
110
|
+
else:
|
|
111
|
+
out_file = os.path.join(outdir, new_format)
|
|
112
|
+
return out_file
|
|
113
|
+
|
|
117
114
|
|
|
118
115
|
def getAncillary(meta, ancillary_name='ecmwf'):
|
|
119
116
|
"""
|
|
@@ -227,7 +224,7 @@ def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_v
|
|
|
227
224
|
sigma0 to be inverted for dualpol
|
|
228
225
|
ancillary_wind=: xarray.DataArray (numpy.complex28)
|
|
229
226
|
ancillary wind
|
|
230
|
-
| (for example ecmwf winds), in **GMF convention** (-np.conj included),
|
|
227
|
+
| (for example ecmwf winds), in **GMF convention** (-np.conj included),
|
|
231
228
|
dsig_cr=: float or xarray.DataArray
|
|
232
229
|
parameters used for
|
|
233
230
|
|
|
@@ -284,7 +281,7 @@ def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_v
|
|
|
284
281
|
return wind_co, None, None
|
|
285
282
|
|
|
286
283
|
|
|
287
|
-
def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol):
|
|
284
|
+
def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol, add_streaks):
|
|
288
285
|
"""
|
|
289
286
|
Rename xr_dataset variables and attributes to match naming convention.
|
|
290
287
|
|
|
@@ -322,6 +319,7 @@ def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol):
|
|
|
322
319
|
'winddir_co': 'owiWindDirection_co',
|
|
323
320
|
'ancillary_wind_speed': 'owiAncillaryWindSpeed',
|
|
324
321
|
'ancillary_wind_direction': 'owiAncillaryWindDirection',
|
|
322
|
+
'sigma0_detrend': 'owiNrcs_detrend'
|
|
325
323
|
})
|
|
326
324
|
|
|
327
325
|
if "offboresight" in xr_dataset:
|
|
@@ -350,6 +348,9 @@ def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol):
|
|
|
350
348
|
xr_dataset.owiNrcs.attrs['long_name'] = 'Normalized Radar Cross Section'
|
|
351
349
|
xr_dataset.owiNrcs.attrs['definition'] = 'owiNrcs_no_noise_correction - owiNesz'
|
|
352
350
|
|
|
351
|
+
xr_dataset['owiMask_Nrcs'] = xr_dataset['sigma0_mask'].sel(pol=copol)
|
|
352
|
+
xr_dataset.owiMask_Nrcs.attrs = xr_dataset.sigma0_mask.attrs
|
|
353
|
+
|
|
353
354
|
# NESZ & DSIG
|
|
354
355
|
xr_dataset = xr_dataset.assign(
|
|
355
356
|
owiNesz=(['line', 'sample'], xr_dataset.nesz.sel(pol=copol).values))
|
|
@@ -395,14 +396,20 @@ def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol):
|
|
|
395
396
|
'winddir_dual': 'owiWindDirection',
|
|
396
397
|
'windspeed_cross': 'owiWindSpeed_cross',
|
|
397
398
|
'windspeed_dual': 'owiWindSpeed',
|
|
399
|
+
'sigma0_detrend_cross': 'owiNrcs_detrend_cross'
|
|
398
400
|
})
|
|
399
401
|
# nrcs cross
|
|
400
402
|
xr_dataset['owiNrcs_cross'] = xr_dataset['sigma0_ocean'].sel(
|
|
401
403
|
pol=crosspol)
|
|
404
|
+
|
|
402
405
|
xr_dataset.owiNrcs_cross.attrs['units'] = 'm^2 / m^2'
|
|
403
406
|
xr_dataset.owiNrcs_cross.attrs['long_name'] = 'Normalized Radar Cross Section'
|
|
404
407
|
xr_dataset.owiNrcs_cross.attrs['definition'] = 'owiNrcs_cross_no_noise_correction - owiNesz_cross'
|
|
405
408
|
|
|
409
|
+
xr_dataset['owiMask_Nrcs_cross'] = xr_dataset['sigma0_mask'].sel(
|
|
410
|
+
pol=crosspol)
|
|
411
|
+
xr_dataset.owiMask_Nrcs_cross.attrs = xr_dataset.sigma0_mask.attrs
|
|
412
|
+
|
|
406
413
|
# nesz cross
|
|
407
414
|
xr_dataset = xr_dataset.assign(owiNesz_cross=(
|
|
408
415
|
['line', 'sample'], xr_dataset.nesz.sel(pol=crosspol).values)) # no flattening
|
|
@@ -429,6 +436,11 @@ def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol):
|
|
|
429
436
|
|
|
430
437
|
xr_dataset.owiNrcs_cross.attrs['definition'] = 'owiNrcs_cross_no_noise_correction_recalibrated - owiNesz_cross'
|
|
431
438
|
|
|
439
|
+
if add_streaks:
|
|
440
|
+
xr_dataset = xr_dataset.rename({
|
|
441
|
+
'streaks_direction': 'owiStreaksDirection',
|
|
442
|
+
})
|
|
443
|
+
|
|
432
444
|
# other variables
|
|
433
445
|
|
|
434
446
|
xr_dataset['owiWindQuality'] = xr.full_like(xr_dataset.owiNrcs, 0)
|
|
@@ -487,7 +499,7 @@ def makeL2asOwi(xr_dataset, dual_pol, copol, crosspol):
|
|
|
487
499
|
return xr_dataset, encoding
|
|
488
500
|
|
|
489
501
|
|
|
490
|
-
def preprocess(filename, outdir, config_path, overwrite=False, resolution='1000m'):
|
|
502
|
+
def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False, resolution='1000m'):
|
|
491
503
|
"""
|
|
492
504
|
Main function to generate L2 product.
|
|
493
505
|
|
|
@@ -507,7 +519,7 @@ def preprocess(filename, outdir, config_path, overwrite=False, resolution='1000m
|
|
|
507
519
|
Returns
|
|
508
520
|
-------
|
|
509
521
|
xarray.Dataset
|
|
510
|
-
final dataset
|
|
522
|
+
final dataset
|
|
511
523
|
"""
|
|
512
524
|
|
|
513
525
|
sensor, sensor_longname, fct_meta, fct_dataset = getSensorMetaDataset(
|
|
@@ -529,16 +541,19 @@ def preprocess(filename, outdir, config_path, overwrite=False, resolution='1000m
|
|
|
529
541
|
|
|
530
542
|
recalibration = config["recalibration"]
|
|
531
543
|
meta = fct_meta(filename)
|
|
532
|
-
|
|
544
|
+
|
|
545
|
+
no_subdir_cfg = config_base.get("no_subdir", False)
|
|
546
|
+
out_file = getOutputName2(filename, outdir, sensor,
|
|
547
|
+
meta, subdir=not no_subdir_cfg)
|
|
533
548
|
|
|
534
549
|
if os.path.exists(out_file) and overwrite is False:
|
|
535
|
-
raise FileExistsError("
|
|
550
|
+
raise FileExistsError("outfile %s already exists" % out_file)
|
|
536
551
|
|
|
537
552
|
ancillary_name = config["ancillary"]
|
|
538
553
|
map_model = getAncillary(meta, ancillary_name)
|
|
539
554
|
if map_model is None:
|
|
540
555
|
raise Exception(
|
|
541
|
-
f
|
|
556
|
+
f"the weather model is not set `map_model` is None -> you probably don't have access to {ancillary_name} archive")
|
|
542
557
|
|
|
543
558
|
try:
|
|
544
559
|
if ((recalibration) & ("SENTINEL" in sensor_longname)):
|
|
@@ -592,6 +607,25 @@ def preprocess(filename, outdir, config_path, overwrite=False, resolution='1000m
|
|
|
592
607
|
copol_gmf = 'HH'
|
|
593
608
|
crosspol_gmf = 'VH'
|
|
594
609
|
|
|
610
|
+
model_vv = config["GMF_"+copol_gmf+"_NAME"]
|
|
611
|
+
model_vh = config["GMF_"+crosspol_gmf+"_NAME"]
|
|
612
|
+
|
|
613
|
+
# need to load gmfs before inversion
|
|
614
|
+
gmfs_impl = [x for x in [model_vv, model_vh] if "gmf_" in x]
|
|
615
|
+
windspeed.gmfs.GmfModel.activate_gmfs_impl(gmfs_impl)
|
|
616
|
+
sarwings_luts = [x for x in [model_vv, model_vh]
|
|
617
|
+
if x.startswith("sarwing_lut_")]
|
|
618
|
+
|
|
619
|
+
if len(sarwings_luts) > 0:
|
|
620
|
+
windspeed.register_sarwing_luts(getConf()["sarwing_luts_path"])
|
|
621
|
+
|
|
622
|
+
nc_luts = [x for x in [model_vv, model_vh] if x.startswith("nc_lut")]
|
|
623
|
+
|
|
624
|
+
if len(nc_luts) > 0:
|
|
625
|
+
windspeed.register_nc_luts(getConf()["nc_luts_path"])
|
|
626
|
+
|
|
627
|
+
if (model_vv == "gmf_cmod7"):
|
|
628
|
+
windspeed.register_cmod7(getConf()["lut_cmod7_path"])
|
|
595
629
|
# Step 2 - clean and prepare dataset
|
|
596
630
|
|
|
597
631
|
# variables to not keep in the L2
|
|
@@ -681,21 +715,32 @@ def preprocess(filename, outdir, config_path, overwrite=False, resolution='1000m
|
|
|
681
715
|
# nrcs processing
|
|
682
716
|
xr_dataset['sigma0_ocean'] = xr.where(xr_dataset['mask'], np.nan,
|
|
683
717
|
xr_dataset['sigma0'].compute()).transpose(*xr_dataset['sigma0'].dims)
|
|
684
|
-
xr_dataset['sigma0_ocean'] = xr.where(
|
|
685
|
-
xr_dataset['sigma0_ocean'] <= 0, np.nan, xr_dataset['sigma0_ocean'])
|
|
686
|
-
|
|
687
718
|
xr_dataset['sigma0_ocean'].attrs = xr_dataset['sigma0'].attrs
|
|
688
|
-
# we forced it to
|
|
689
|
-
xr_dataset['sigma0_ocean'].attrs['comment'] = "clipped, no values <=0"
|
|
719
|
+
# we forced it to 1e-15
|
|
720
|
+
xr_dataset['sigma0_ocean'].attrs['comment'] = "clipped, no values <=0 ; 1e-15 instread"
|
|
721
|
+
|
|
722
|
+
# rajout d'un mask pour les valeurs <=0:
|
|
723
|
+
xr_dataset['sigma0_mask'] = xr.where(
|
|
724
|
+
xr_dataset['sigma0_ocean'] <= 0, 1, 0).transpose(*xr_dataset['sigma0'].dims)
|
|
725
|
+
xr_dataset.sigma0_mask.attrs['valid_range'] = np.array([0, 1])
|
|
726
|
+
xr_dataset.sigma0_mask.attrs['flag_values'] = np.array([0, 1])
|
|
727
|
+
xr_dataset.sigma0_mask.attrs['flag_meanings'] = 'valid no_valid'
|
|
728
|
+
xr_dataset['sigma0_ocean'] = xr.where(
|
|
729
|
+
xr_dataset['sigma0_ocean'] <= 0, 1e-15, xr_dataset['sigma0_ocean'])
|
|
690
730
|
|
|
691
731
|
xr_dataset['sigma0_ocean_raw'] = xr.where(xr_dataset['mask'], np.nan,
|
|
692
732
|
xr_dataset['sigma0_raw'].compute()).transpose(*xr_dataset['sigma0_raw'].dims)
|
|
693
|
-
|
|
694
|
-
xr_dataset['sigma0_ocean_raw'] <= 0, np.nan, xr_dataset['sigma0_ocean_raw'])
|
|
733
|
+
|
|
695
734
|
xr_dataset['sigma0_ocean_raw'].attrs = xr_dataset['sigma0_raw'].attrs
|
|
696
735
|
|
|
736
|
+
xr_dataset['sigma0_detrend'] = xsarsea.sigma0_detrend(
|
|
737
|
+
xr_dataset.sigma0.sel(pol=copol), xr_dataset.incidence, model=model_vv)
|
|
738
|
+
|
|
697
739
|
# processing
|
|
698
740
|
if dual_pol:
|
|
741
|
+
|
|
742
|
+
xr_dataset['sigma0_detrend_cross'] = xsarsea.sigma0_detrend(
|
|
743
|
+
xr_dataset.sigma0.sel(pol=crosspol), xr_dataset.incidence, model=model_vh)
|
|
699
744
|
if config["apply_flattening"]:
|
|
700
745
|
xr_dataset = xr_dataset.assign(nesz_cross_final=(
|
|
701
746
|
['line', 'sample'], windspeed.nesz_flattening(xr_dataset.nesz.sel(pol=crosspol), xr_dataset.incidence)))
|
|
@@ -721,24 +766,50 @@ def preprocess(filename, outdir, config_path, overwrite=False, resolution='1000m
|
|
|
721
766
|
sigma0_ocean_cross = None
|
|
722
767
|
dsig_cross = 0.1 # default value set in xsarsea
|
|
723
768
|
|
|
724
|
-
model_vv = config["GMF_"+copol_gmf+"_NAME"]
|
|
725
|
-
model_vh = config["GMF_"+crosspol_gmf+"_NAME"]
|
|
726
|
-
|
|
727
769
|
if ((recalibration) & ("SENTINEL" in sensor_longname)):
|
|
728
|
-
xr_dataset["path_aux_pp1_new"] = os.path.basename(os.path.dirname(
|
|
770
|
+
xr_dataset.attrs["path_aux_pp1_new"] = os.path.basename(os.path.dirname(
|
|
729
771
|
os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_pp1_new'])))
|
|
730
|
-
xr_dataset["path_aux_cal_new"] = os.path.basename(os.path.dirname(
|
|
772
|
+
xr_dataset.attrs["path_aux_cal_new"] = os.path.basename(os.path.dirname(
|
|
731
773
|
os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_cal_new'])))
|
|
732
774
|
|
|
733
|
-
xr_dataset["path_aux_pp1_old"] = os.path.basename(os.path.dirname(
|
|
775
|
+
xr_dataset.attrs["path_aux_pp1_old"] = os.path.basename(os.path.dirname(
|
|
734
776
|
os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_pp1_old'])))
|
|
735
|
-
xr_dataset["path_aux_cal_old"] = os.path.basename(os.path.dirname(
|
|
777
|
+
xr_dataset.attrs["path_aux_cal_old"] = os.path.basename(os.path.dirname(
|
|
736
778
|
os.path.dirname(xsar_dataset.datatree['recalibration'].attrs['path_aux_cal_old'])))
|
|
737
779
|
|
|
780
|
+
if add_streaks:
|
|
781
|
+
xsar_dataset_100 = fct_dataset(
|
|
782
|
+
meta, resolution='100m')
|
|
783
|
+
xr_dataset_100 = xsar_dataset_100.datatree['measurement'].to_dataset()
|
|
784
|
+
xr_dataset_100 = xr_dataset_100.rename(map_model)
|
|
785
|
+
|
|
786
|
+
# adding sigma0 detrend
|
|
787
|
+
xr_dataset_100['sigma0_detrend'] = xsarsea.sigma0_detrend(
|
|
788
|
+
xr_dataset_100.sigma0.sel(pol=copol), xr_dataset_100.incidence, model=model_vv)
|
|
789
|
+
|
|
790
|
+
xr_dataset_100['sigma0_detrend_cross'] = xsarsea.sigma0_detrend(
|
|
791
|
+
xr_dataset_100.sigma0.sel(pol=crosspol), xr_dataset_100.incidence, model=model_vh)
|
|
792
|
+
|
|
793
|
+
sigma0_detrend_combined = xr.concat(
|
|
794
|
+
[xr_dataset_100['sigma0_detrend'],
|
|
795
|
+
xr_dataset_100['sigma0_detrend_cross']],
|
|
796
|
+
dim='pol'
|
|
797
|
+
)
|
|
798
|
+
sigma0_detrend_combined['pol'] = [copol, crosspol]
|
|
799
|
+
|
|
800
|
+
xr_dataset_100['sigma0_detrend'] = sigma0_detrend_combined
|
|
801
|
+
xr_dataset_100.land_mask.values = binary_dilation(xr_dataset_100['land_mask'].values.astype('uint8'),
|
|
802
|
+
structure=np.ones((3, 3), np.uint8), iterations=3)
|
|
803
|
+
xr_dataset_100['sigma0_detrend'] = xr.where(
|
|
804
|
+
xr_dataset_100['land_mask'], np.nan, xr_dataset_100['sigma0'].compute()).transpose(*xr_dataset_100['sigma0'].dims)
|
|
805
|
+
|
|
806
|
+
xr_dataset['streaks_direction'] = get_streaks(
|
|
807
|
+
xr_dataset, xr_dataset_100)
|
|
808
|
+
|
|
738
809
|
return xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf, model_vv, model_vh, sigma0_ocean_cross, dsig_cross, sensor_longname, out_file, config
|
|
739
810
|
|
|
740
811
|
|
|
741
|
-
def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, resolution='1000m'):
|
|
812
|
+
def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add_streaks=False, resolution='1000m'):
|
|
742
813
|
"""
|
|
743
814
|
Main function to generate L2 product.
|
|
744
815
|
|
|
@@ -766,7 +837,7 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, res
|
|
|
766
837
|
"""
|
|
767
838
|
|
|
768
839
|
xr_dataset, dual_pol, copol, crosspol, copol_gmf, crosspol_gmf, model_vv, model_vh, sigma0_ocean_cross, dsig_cross, sensor_longname, out_file, config = preprocess(
|
|
769
|
-
filename, outdir, config_path, overwrite, resolution)
|
|
840
|
+
filename, outdir, config_path, overwrite, add_streaks, resolution)
|
|
770
841
|
|
|
771
842
|
kwargs = {
|
|
772
843
|
"inc_step_lr": config.pop("inc_step_lr", None),
|
|
@@ -778,23 +849,6 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, res
|
|
|
778
849
|
"resolution": config.pop("resolution", None),
|
|
779
850
|
}
|
|
780
851
|
|
|
781
|
-
# need to load gmfs before
|
|
782
|
-
|
|
783
|
-
gmfs_impl = [x for x in [model_vv, model_vh] if "gmf_" in x]
|
|
784
|
-
windspeed.gmfs.GmfModel.activate_gmfs_impl(gmfs_impl)
|
|
785
|
-
sarwings_luts = [x for x in [model_vv, model_vh]
|
|
786
|
-
if x.startswith("sarwing_lut_")]
|
|
787
|
-
if len(sarwings_luts) > 0:
|
|
788
|
-
windspeed.register_sarwing_luts(getConf()["sarwing_luts_path"])
|
|
789
|
-
|
|
790
|
-
nc_luts = [x for x in [model_vv, model_vh] if x.startswith("nc_lut")]
|
|
791
|
-
|
|
792
|
-
if len(nc_luts) > 0:
|
|
793
|
-
windspeed.register_nc_luts(getConf()["nc_luts_path"])
|
|
794
|
-
|
|
795
|
-
if (model_vv == "gmf_cmod7"):
|
|
796
|
-
windspeed.register_cmod7(getConf()["lut_cmod7_path"])
|
|
797
|
-
|
|
798
852
|
wind_co, wind_dual, windspeed_cr = inverse(dual_pol,
|
|
799
853
|
inc=xr_dataset['incidence'],
|
|
800
854
|
sigma0=xr_dataset['sigma0_ocean'].sel(
|
|
@@ -857,7 +911,7 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, res
|
|
|
857
911
|
xr_dataset["winddir_cross"].attrs["model"] = "No model used ; content is a copy of dualpol wind direction"
|
|
858
912
|
|
|
859
913
|
xr_dataset, encoding = makeL2asOwi(
|
|
860
|
-
xr_dataset, dual_pol, copol, crosspol)
|
|
914
|
+
xr_dataset, dual_pol, copol, crosspol, add_streaks=add_streaks)
|
|
861
915
|
|
|
862
916
|
# add attributes
|
|
863
917
|
firstMeasurementTime = None
|
|
@@ -910,7 +964,7 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, res
|
|
|
910
964
|
}
|
|
911
965
|
|
|
912
966
|
for recalib_attrs in ["path_aux_pp1_new", 'path_aux_pp1_old', "path_aux_cal_new", "path_aux_cal_old"]:
|
|
913
|
-
if recalib_attrs in xr_dataset:
|
|
967
|
+
if recalib_attrs in xr_dataset.attrs:
|
|
914
968
|
attrs[recalib_attrs] = xr_dataset.attrs[recalib_attrs]
|
|
915
969
|
|
|
916
970
|
# new one to match convention
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import xarray as xr
|
|
2
|
+
import xsarsea.gradients
|
|
3
|
+
import xarray as xr
|
|
4
|
+
from scipy.ndimage import binary_dilation
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_streaks(xr_dataset, xr_dataset_100):
|
|
9
|
+
"""
|
|
10
|
+
Get the streaks from the wind field.
|
|
11
|
+
|
|
12
|
+
Parameters
|
|
13
|
+
----------
|
|
14
|
+
xr_dataset : xarray.Dataset
|
|
15
|
+
dataset at user resolution.
|
|
16
|
+
xr_dataset_100 : xarray.Dataset
|
|
17
|
+
dataset at 100m resolution.
|
|
18
|
+
|
|
19
|
+
Returns
|
|
20
|
+
-------
|
|
21
|
+
xarray.Dataset
|
|
22
|
+
Extract wind direction from Koch Method using xsarsea tools.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
# return empy dataArray, waiting for solution
|
|
26
|
+
return xr.DataArray(data=np.nan * np.ones([len(xr_dataset.coords[dim]) for dim in ['line','sample']]),
|
|
27
|
+
dims=['line','sample'],
|
|
28
|
+
coords=[xr_dataset.coords[dim] for dim in ['line','sample']])
|
|
29
|
+
#
|
|
30
|
+
|
|
31
|
+
"""
|
|
32
|
+
gradients = xsarsea.gradients.Gradients(xr_dataset_100['sigma0_detrend'], windows_sizes=[
|
|
33
|
+
1600, 3200], downscales_factors=[1, 2], window_step=1)
|
|
34
|
+
|
|
35
|
+
# get gradients histograms as an xarray dataset
|
|
36
|
+
hist = gradients.histogram
|
|
37
|
+
|
|
38
|
+
# get orthogonals gradients
|
|
39
|
+
hist['angles'] = hist['angles'] + np.pi/2
|
|
40
|
+
|
|
41
|
+
# mean
|
|
42
|
+
hist_mean = hist.mean(['downscale_factor', 'window_size', 'pol'])
|
|
43
|
+
|
|
44
|
+
# smooth
|
|
45
|
+
hist_mean_smooth = hist_mean.copy()
|
|
46
|
+
hist_mean_smooth['weight'] = xsarsea.gradients.circ_smooth(
|
|
47
|
+
hist_mean['weight'])
|
|
48
|
+
|
|
49
|
+
# smooth only
|
|
50
|
+
# hist_smooth = hist.copy()
|
|
51
|
+
# hist_smooth['weight'] = xsarsea.gradients.circ_smooth(hist_smooth['weight'])
|
|
52
|
+
|
|
53
|
+
# select histogram peak
|
|
54
|
+
iangle = hist_mean_smooth['weight'].fillna(0).argmax(dim='angles')
|
|
55
|
+
streaks_dir = hist_mean_smooth.angles.isel(angles=iangle)
|
|
56
|
+
streaks_weight = hist_mean_smooth['weight'].isel(angles=iangle)
|
|
57
|
+
streaks = xr.merge(
|
|
58
|
+
[dict(angle=streaks_dir, weight=streaks_weight)]).drop('angles')
|
|
59
|
+
|
|
60
|
+
# streaks are [0, pi]. Remove ambiguity with anciallary wind
|
|
61
|
+
ancillary_wind = xr_dataset_100['ancillary_wind'].sel(line=streaks.line,
|
|
62
|
+
sample=streaks.sample,
|
|
63
|
+
method='nearest').compute()
|
|
64
|
+
streaks_c = streaks['weight'] * np.exp(1j * streaks['angle'])
|
|
65
|
+
diff_angle = xr.apply_ufunc(np.angle, ancillary_wind / streaks_c)
|
|
66
|
+
streaks_c = xr.where(np.abs(diff_angle) > np.pi/2, -streaks_c, streaks_c)
|
|
67
|
+
streaks['weight'] = np.abs(streaks_c)
|
|
68
|
+
streaks['angle'] = xr.apply_ufunc(np.angle, streaks_c)
|
|
69
|
+
|
|
70
|
+
streaks_dir = xr.apply_ufunc(
|
|
71
|
+
np.angle, streaks_c.interp(line=xr_dataset.line, sample=xr_dataset.sample))
|
|
72
|
+
streaks_dir = xr.where(
|
|
73
|
+
xr_dataset['land_mask'], np.nan, streaks_dir)
|
|
74
|
+
streaks_dir.attrs['comment'] = 'angle in radians, anticlockwise, 0=line'
|
|
75
|
+
streaks_dir.attrs['description'] = 'wind direction estimated from local gradient, and direction ambiguity removed with ancillary wind'
|
|
76
|
+
|
|
77
|
+
return streaks_dir
|
|
78
|
+
|
|
79
|
+
"""
|
|
@@ -39,6 +39,7 @@ grdwindinversion/data_config.yaml
|
|
|
39
39
|
grdwindinversion/inversion.py
|
|
40
40
|
grdwindinversion/load_config.py
|
|
41
41
|
grdwindinversion/main.py
|
|
42
|
+
grdwindinversion/streaks.py
|
|
42
43
|
grdwindinversion/utils.py
|
|
43
44
|
grdwindinversion.egg-info/PKG-INFO
|
|
44
45
|
grdwindinversion.egg-info/SOURCES.txt
|
|
@@ -47,5 +48,6 @@ grdwindinversion.egg-info/entry_points.txt
|
|
|
47
48
|
grdwindinversion.egg-info/requires.txt
|
|
48
49
|
grdwindinversion.egg-info/top_level.txt
|
|
49
50
|
grdwindinversion/.github/ISSUE_TEMPLATE.md
|
|
51
|
+
recipe/meta.yaml
|
|
50
52
|
tests/__init__.py
|
|
51
53
|
tests/test_grdwindinversion.py
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
package:
|
|
2
|
+
name: "grdwindinversion"
|
|
3
|
+
version: {{ environ.get('GIT_DESCRIBE_TAG', 0)}}
|
|
4
|
+
|
|
5
|
+
source:
|
|
6
|
+
path: ../.
|
|
7
|
+
|
|
8
|
+
build:
|
|
9
|
+
noarch: python
|
|
10
|
+
number: 0
|
|
11
|
+
script: {{ PYTHON }} -m pip install . --no-deps -vv
|
|
12
|
+
|
|
13
|
+
requirements:
|
|
14
|
+
build:
|
|
15
|
+
- python >=3.9,<3.11
|
|
16
|
+
- setuptools_scm
|
|
17
|
+
- setuptools
|
|
18
|
+
|
|
19
|
+
run:
|
|
20
|
+
- python >=3.9,<3.11
|
|
21
|
+
- xsar
|
|
22
|
+
- xsarsea
|
|
23
|
+
- "xarray==2024.2.0"
|
|
24
|
+
- xarray-datatree
|
|
25
|
+
- "rioxarray<=0.15.5"
|
|
26
|
+
- "numpy<=1.26"
|
|
27
|
+
- pyyaml
|
|
28
|
+
- scipy
|
|
29
|
+
- fsspec
|
|
30
|
+
- aiohttp
|
|
31
|
+
|
|
32
|
+
about:
|
|
33
|
+
home: https://github.com/umr-lops/grdwindinversion
|
|
34
|
+
summary: 'python library to compute wind speed from GRD SAR images'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/ci/requirements/environment.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion/.travis.yml
RENAMED
|
File without changes
|
{grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion/__init__.py
RENAMED
|
File without changes
|
{grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion/data_config.yaml
RENAMED
|
File without changes
|
{grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/grdwindinversion/load_config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{grdwindinversion-0.2.3.post13 → grdwindinversion-0.2.3.post15}/tests/test_grdwindinversion.py
RENAMED
|
File without changes
|
|
File without changes
|