grdwindinversion 0.2.3.post15__tar.gz → 0.2.4__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.4/.github/workflows/ci.yml +98 -0
- {grdwindinversion-0.2.3.post15/grdwindinversion.egg-info → grdwindinversion-0.2.4}/PKG-INFO +1 -1
- grdwindinversion-0.2.4/grdwindinversion/config_prod.yaml +46 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion/inversion.py +179 -77
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion/main.py +1 -1
- grdwindinversion-0.2.4/grdwindinversion/utils.py +83 -0
- grdwindinversion-0.2.3.post15/grdwindinversion/utils.py → grdwindinversion-0.2.4/grdwindinversion/utils_memory.py +8 -4
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4/grdwindinversion.egg-info}/PKG-INFO +1 -1
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion.egg-info/SOURCES.txt +4 -1
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/recipe/meta.yaml +3 -0
- grdwindinversion-0.2.3.post15/grdwindinversion/config_prod.yaml → grdwindinversion-0.2.4/tests/config_test.yaml +1 -0
- grdwindinversion-0.2.4/tests/test_grdwindinversion_ci.py +55 -0
- grdwindinversion-0.2.3.post15/tests/test_grdwindinversion.py +0 -20
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/.editorconfig +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/.github/dependabot.yml +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/.github/workflows/publish.yml +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/.gitignore +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/.pre-commit-config.yaml +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/AUTHORS.rst +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/CONTRIBUTING.rst +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/HISTORY.rst +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/LICENSE +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/MANIFEST.in +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/Makefile +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/README.md +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/ci/requirements/docs.yaml +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/ci/requirements/environment.yaml +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/docs/Makefile +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/docs/_static/css/grdwindinversion.css +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/docs/algorithm.rst +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/docs/authors.rst +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/docs/conf.py +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/docs/contributing.rst +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/docs/examples/wind-inversion-from-grd.ipynb +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/docs/history.rst +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/docs/index.rst +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/docs/installation.rst +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/docs/make.bat +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/docs/modules.rst +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/docs/readme.rst +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/docs/usage.rst +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion/.github/ISSUE_TEMPLATE.md +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion/.gitignore +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion/.travis.yml +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion/__init__.py +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion/config_prod_recal.yaml +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion/data_config.yaml +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion/load_config.py +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion/streaks.py +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion.egg-info/dependency_links.txt +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion.egg-info/entry_points.txt +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion.egg-info/requires.txt +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion.egg-info/top_level.txt +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/pyproject.toml +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/requirements_dev.txt +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/requirements_doc.txt +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/setup.cfg +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/tests/__init__.py +0 -0
- {grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/tox.ini +0 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
name: CI Workflow for grdwindinversion
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
branches:
|
|
9
|
+
- main
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
timeout-minutes: 360 # 6 hours limit for the job
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
# Checkout the code
|
|
18
|
+
- name: Checkout code
|
|
19
|
+
uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- uses: mamba-org/setup-micromamba@v1
|
|
22
|
+
with:
|
|
23
|
+
micromamba-version: "1.5.9-1" # any version from https://github.com/mamba-org/micromamba-releases
|
|
24
|
+
channels: tcevaer, conda-forge, defaults
|
|
25
|
+
init-shell: bash
|
|
26
|
+
post-cleanup: "all"
|
|
27
|
+
|
|
28
|
+
- name: Create environment and install tools
|
|
29
|
+
run: micromamba create -n grdwind_env pytest conda-build boa python=3.10 -y -c tcevaer -c conda-forge
|
|
30
|
+
|
|
31
|
+
- name: Build package
|
|
32
|
+
run: |
|
|
33
|
+
cd recipe
|
|
34
|
+
eval "$(micromamba shell hook --shell bash)"
|
|
35
|
+
micromamba activate grdwind_env
|
|
36
|
+
conda mambabuild . -c tcevaer -c conda-forge
|
|
37
|
+
|
|
38
|
+
# Install the built package into the environment
|
|
39
|
+
- name: Install the built package
|
|
40
|
+
run: |
|
|
41
|
+
eval "$(micromamba shell hook --shell bash)"
|
|
42
|
+
micromamba activate grdwind_env
|
|
43
|
+
conda install --use-local grdwindinversion -y -c tcevaer -c conda-forge
|
|
44
|
+
|
|
45
|
+
# Cache the test data if previously downloaded (up to 10 GB limit for the cache)
|
|
46
|
+
# WARNING : modify the key if the data is modified !!
|
|
47
|
+
- name: Cache test data
|
|
48
|
+
uses: actions/cache@v4
|
|
49
|
+
id: cache
|
|
50
|
+
with:
|
|
51
|
+
path: ./test_data
|
|
52
|
+
key: test-data-v3
|
|
53
|
+
restore-keys: test-data-v3
|
|
54
|
+
|
|
55
|
+
# Download test data if not already cached
|
|
56
|
+
- name: Download test data
|
|
57
|
+
if: steps.cache.outputs.cache-hit != 'true' # Only download if cache miss
|
|
58
|
+
run: |
|
|
59
|
+
mkdir -p ./test_data/
|
|
60
|
+
wget https://cloud.ifremer.fr/index.php/s/ExLQ2TnYAqozPWE/download -O /tmp/ecmwf.zip
|
|
61
|
+
unzip /tmp/ecmwf.zip -d ./test_data/
|
|
62
|
+
wget https://cloud.ifremer.fr/index.php/s/kRgdOOPsjoZieZR/download -O /tmp/l1.zip
|
|
63
|
+
unzip /tmp/l1.zip -d ./test_data/
|
|
64
|
+
timeout-minutes: 200 # Adjust depending on the size of your data
|
|
65
|
+
|
|
66
|
+
# Set up xsar configuration
|
|
67
|
+
- name: Setup xsar configuration
|
|
68
|
+
run: |
|
|
69
|
+
mkdir -p ~/.xsar
|
|
70
|
+
echo "data_dir: /tmp" > ~/.xsar/config.yaml
|
|
71
|
+
echo "auxiliary_dir: ./test_data/auxiliary" >> ~/.xsar/config.yaml
|
|
72
|
+
echo "path_dataframe_aux: ./test_data/auxiliary/active_aux.csv" >> ~/.xsar/config.yaml
|
|
73
|
+
|
|
74
|
+
# Set up grdwindinversion configuration
|
|
75
|
+
- name: Setup grdwindinversion configuration
|
|
76
|
+
run: |
|
|
77
|
+
mkdir -p ~/.grdwindinversion
|
|
78
|
+
echo "'ecmwf_0100_1h': ./test_data/ECMWF/forecast/hourly/0100deg/netcdf_light/%Y/%j/ECMWF_FORECAST_0100_%Y%m%d%H%M_10U_10V.nc" > ~/.grdwindinversion/data_config.yaml
|
|
79
|
+
echo "'ecmwf_0125_1h': ./test_data/ECMWF/0.125deg/1h/forecasts/%Y/%j/ecmwf_%Y%m%d%H%M.nc" >> ~/.grdwindinversion/data_config.yaml
|
|
80
|
+
#echo "'sarwing_luts_path': './test_data/GMFS/v1.6/'" >> ~/.grdwindinversion/data_config.yaml
|
|
81
|
+
#echo "'nc_luts_path': ./test_data/GMFS/nc_luts" >> ~/.grdwindinversion/data_config.yaml
|
|
82
|
+
#echo "'lut_cmod7_path': './test_data/GMFS/v1.6/GMF_cmod7_official/cmod7_and_python_script'" >> ~/.grdwindinversion/data_config.yaml
|
|
83
|
+
#echo "'lut_ms1ahw_path': './test_data/GMFS/v1.6/GMF_cmodms1ahw'" >> ~/.grdwindinversion/data_config.yaml
|
|
84
|
+
|
|
85
|
+
# Run the tests
|
|
86
|
+
- name: Run tests
|
|
87
|
+
run: |
|
|
88
|
+
eval "$(micromamba shell hook --shell bash)"
|
|
89
|
+
micromamba activate grdwind_env
|
|
90
|
+
pytest
|
|
91
|
+
|
|
92
|
+
# Optionally, upload test artifacts (NetCDF files or logs) if needed
|
|
93
|
+
#- name: Upload test artifacts
|
|
94
|
+
# if: failure() # Only upload on failure
|
|
95
|
+
# uses: actions/upload-artifact@v2
|
|
96
|
+
# with:
|
|
97
|
+
# name: test-output
|
|
98
|
+
# path: ./test_output/
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
no_subdir: True
|
|
2
|
+
winddir_convention: "meteorological"
|
|
3
|
+
S1A:
|
|
4
|
+
GMF_VV_NAME: "gmf_cmod5n"
|
|
5
|
+
GMF_VH_NAME: "gmf_s1_v2"
|
|
6
|
+
dsig_VH_NAME: "gmf_s1_v2"
|
|
7
|
+
apply_flattening: True
|
|
8
|
+
recalibration: False
|
|
9
|
+
ancillary: "ecmwf"
|
|
10
|
+
inc_step: 0.1
|
|
11
|
+
wspd_step: 0.1
|
|
12
|
+
phi_step: 1.0
|
|
13
|
+
resolution: "high"
|
|
14
|
+
S1B:
|
|
15
|
+
GMF_VV_NAME: "gmf_cmod5n"
|
|
16
|
+
GMF_VH_NAME: "gmf_s1_v2"
|
|
17
|
+
dsig_VH_NAME: "gmf_s1_v2"
|
|
18
|
+
apply_flattening: True
|
|
19
|
+
recalibration: False
|
|
20
|
+
ancillary: "ecmwf"
|
|
21
|
+
inc_step: 0.1
|
|
22
|
+
wspd_step: 0.1
|
|
23
|
+
phi_step: 1.0
|
|
24
|
+
resolution: "high"
|
|
25
|
+
RS2:
|
|
26
|
+
GMF_VV_NAME: "gmf_cmod5n"
|
|
27
|
+
GMF_VH_NAME: "gmf_rs2_v2"
|
|
28
|
+
dsig_VH_NAME: "gmf_rs2_v2"
|
|
29
|
+
apply_flattening: False
|
|
30
|
+
recalibration: False
|
|
31
|
+
ancillary: "ecmwf"
|
|
32
|
+
inc_step: 0.1
|
|
33
|
+
wspd_step: 0.1
|
|
34
|
+
phi_step: 1.0
|
|
35
|
+
resolution: "high"
|
|
36
|
+
RCM:
|
|
37
|
+
GMF_VV_NAME: "gmf_cmod5n"
|
|
38
|
+
GMF_VH_NAME: "gmf_rcm_noaa"
|
|
39
|
+
dsig_VH_NAME: "gmf_s1_v2"
|
|
40
|
+
apply_flattening: True
|
|
41
|
+
recalibration: False
|
|
42
|
+
ancillary: "ecmwf"
|
|
43
|
+
inc_step: 0.1
|
|
44
|
+
wspd_step: 0.1
|
|
45
|
+
phi_step: 1.0
|
|
46
|
+
resolution: "high"
|
|
@@ -16,6 +16,7 @@ import re
|
|
|
16
16
|
import string
|
|
17
17
|
import os
|
|
18
18
|
from grdwindinversion.streaks import get_streaks
|
|
19
|
+
from grdwindinversion.utils import check_incidence_range, get_pol_ratio_name
|
|
19
20
|
from grdwindinversion.load_config import getConf
|
|
20
21
|
# optional debug messages
|
|
21
22
|
import logging
|
|
@@ -97,10 +98,10 @@ def getOutputName2(input_file, outdir, sensor, meta, subdir=True):
|
|
|
97
98
|
regex = re.compile(
|
|
98
99
|
"([A-Z0-9]+)_OK([0-9]+)_PK([0-9]+)_(.*?)_(.*?)_(.*?)_(.*?)_(.*?)_(.*?)_(.*?)")
|
|
99
100
|
template = string.Template(
|
|
100
|
-
"${MISSIONID}_OK${DATA1}_PK${DATA2}_${DATA3}_${
|
|
101
|
+
"${MISSIONID}_OK${DATA1}_PK${DATA2}_${DATA3}_${BEAM_MODE}_${DATE}_${TIME}_${POLARIZATION1}_${POLARIZATION2}_${PRODUCT}")
|
|
101
102
|
match = regex.match(basename_match)
|
|
102
|
-
MISSIONID, DATA1, DATA2, DATA3,
|
|
103
|
-
new_format = f"{MISSIONID.lower()}
|
|
103
|
+
MISSIONID, DATA1, DATA2, DATA3, BEAM_MODE, DATE, TIME, POLARIZATION1, POLARIZATION2, LAST = match.groups()
|
|
104
|
+
new_format = f"{MISSIONID.lower()}-{BEAM_MODE.lower()}-owi-xx-{meta_start_date.lower()}-{meta_stop_date.lower()}-_____-_____.nc"
|
|
104
105
|
else:
|
|
105
106
|
raise ValueError(
|
|
106
107
|
"sensor must be S1A|S1B|RS2|RCM, got sensor %s" % sensor)
|
|
@@ -208,7 +209,7 @@ def getAncillary(meta, ancillary_name='ecmwf'):
|
|
|
208
209
|
ancillary_name)
|
|
209
210
|
|
|
210
211
|
|
|
211
|
-
def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr,
|
|
212
|
+
def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_co, model_cross, **kwargs):
|
|
212
213
|
"""
|
|
213
214
|
Invert sigma0 to retrieve wind using model (lut or gmf).
|
|
214
215
|
|
|
@@ -224,20 +225,20 @@ def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_v
|
|
|
224
225
|
sigma0 to be inverted for dualpol
|
|
225
226
|
ancillary_wind=: xarray.DataArray (numpy.complex28)
|
|
226
227
|
ancillary wind
|
|
227
|
-
| (for example ecmwf winds), in **
|
|
228
|
+
| (for example ecmwf winds), in **ANTENNA convention**,
|
|
228
229
|
dsig_cr=: float or xarray.DataArray
|
|
229
230
|
parameters used for
|
|
230
231
|
|
|
231
232
|
| `Jsig_cr=((sigma0_gmf - sigma0) / dsig_cr) ** 2`
|
|
232
|
-
|
|
233
|
+
model_co=: str
|
|
233
234
|
model to use for VV or HH polarization.
|
|
234
|
-
|
|
235
|
+
model_cross=: str
|
|
235
236
|
model to use for VH or HV polarization.
|
|
236
237
|
|
|
237
238
|
Returns
|
|
238
239
|
-------
|
|
239
240
|
xarray.DataArray or tuple
|
|
240
|
-
inverted wind in **
|
|
241
|
+
inverted wind in ** antenna convention** .
|
|
241
242
|
|
|
242
243
|
See Also
|
|
243
244
|
--------
|
|
@@ -248,12 +249,12 @@ def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_v
|
|
|
248
249
|
|
|
249
250
|
list_mods = windspeed.available_models().index.tolist(
|
|
250
251
|
) + windspeed.available_models().alias.tolist() + [None]
|
|
251
|
-
if
|
|
252
|
+
if model_co not in list_mods:
|
|
252
253
|
raise ValueError(
|
|
253
|
-
f"
|
|
254
|
-
if
|
|
254
|
+
f"model_co {model_co} not in windspeed.available_models() : not going further")
|
|
255
|
+
if model_cross not in list_mods:
|
|
255
256
|
raise ValueError(
|
|
256
|
-
f"
|
|
257
|
+
f"model_cross {model_cross} not in windspeed.available_models() : not going further")
|
|
257
258
|
|
|
258
259
|
winds = windspeed.invert_from_model(
|
|
259
260
|
inc,
|
|
@@ -261,7 +262,7 @@ def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_v
|
|
|
261
262
|
sigma0_dual,
|
|
262
263
|
ancillary_wind=ancillary_wind,
|
|
263
264
|
dsig_cr=dsig_cr,
|
|
264
|
-
model=(
|
|
265
|
+
model=(model_co, model_cross),
|
|
265
266
|
**kwargs)
|
|
266
267
|
|
|
267
268
|
if dual_pol:
|
|
@@ -271,7 +272,7 @@ def inverse(dual_pol, inc, sigma0, sigma0_dual, ancillary_wind, dsig_cr, model_v
|
|
|
271
272
|
inc.values,
|
|
272
273
|
sigma0_dual.values,
|
|
273
274
|
dsig_cr=dsig_cr.values,
|
|
274
|
-
model=
|
|
275
|
+
model=model_cross,
|
|
275
276
|
**kwargs)
|
|
276
277
|
|
|
277
278
|
return wind_co, wind_dual, wind_cross
|
|
@@ -532,6 +533,7 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False
|
|
|
532
533
|
Loader=yaml.FullLoader
|
|
533
534
|
)
|
|
534
535
|
try:
|
|
536
|
+
# check if sensor is in the config
|
|
535
537
|
config = config_base[sensor]
|
|
536
538
|
except Exception:
|
|
537
539
|
raise KeyError("sensor %s not in this config" % sensor)
|
|
@@ -543,6 +545,19 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False
|
|
|
543
545
|
meta = fct_meta(filename)
|
|
544
546
|
|
|
545
547
|
no_subdir_cfg = config_base.get("no_subdir", False)
|
|
548
|
+
config["no_subdir"] = no_subdir_cfg
|
|
549
|
+
|
|
550
|
+
if "winddir_convention" in config_base:
|
|
551
|
+
winddir_convention = config_base["winddir_convention"]
|
|
552
|
+
else:
|
|
553
|
+
winddir_convention = "meteorological"
|
|
554
|
+
logging.warning(
|
|
555
|
+
f'Using meteorological convention because "winddir_convention" was not found in config.')
|
|
556
|
+
config["winddir_convention"] = winddir_convention
|
|
557
|
+
|
|
558
|
+
# creating a dictionnary of parameters
|
|
559
|
+
config["l2_params"] = {}
|
|
560
|
+
|
|
546
561
|
out_file = getOutputName2(filename, outdir, sensor,
|
|
547
562
|
meta, subdir=not no_subdir_cfg)
|
|
548
563
|
|
|
@@ -607,24 +622,34 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False
|
|
|
607
622
|
copol_gmf = 'HH'
|
|
608
623
|
crosspol_gmf = 'VH'
|
|
609
624
|
|
|
610
|
-
|
|
611
|
-
|
|
625
|
+
model_co = config["GMF_"+copol_gmf+"_NAME"]
|
|
626
|
+
model_cross = config["GMF_"+crosspol_gmf+"_NAME"]
|
|
627
|
+
|
|
628
|
+
# register paramaters in config
|
|
629
|
+
config["l2_params"]["dual_pol"] = dual_pol
|
|
630
|
+
config["l2_params"]["copol"] = copol
|
|
631
|
+
config["l2_params"]["crosspol"] = crosspol
|
|
632
|
+
config["l2_params"]["copol_gmf"] = copol_gmf
|
|
633
|
+
config["l2_params"]["crosspol_gmf"] = crosspol_gmf
|
|
634
|
+
config["l2_params"]["model_co"] = model_co
|
|
635
|
+
config["l2_params"]["model_cross"] = model_cross
|
|
636
|
+
config["sensor_longname"] = sensor_longname
|
|
612
637
|
|
|
613
638
|
# need to load gmfs before inversion
|
|
614
|
-
gmfs_impl = [x for x in [
|
|
639
|
+
gmfs_impl = [x for x in [model_co, model_cross] if "gmf_" in x]
|
|
615
640
|
windspeed.gmfs.GmfModel.activate_gmfs_impl(gmfs_impl)
|
|
616
|
-
sarwings_luts = [x for x in [
|
|
641
|
+
sarwings_luts = [x for x in [model_co, model_cross]
|
|
617
642
|
if x.startswith("sarwing_lut_")]
|
|
618
643
|
|
|
619
644
|
if len(sarwings_luts) > 0:
|
|
620
645
|
windspeed.register_sarwing_luts(getConf()["sarwing_luts_path"])
|
|
621
646
|
|
|
622
|
-
nc_luts = [x for x in [
|
|
647
|
+
nc_luts = [x for x in [model_co, model_cross] if x.startswith("nc_lut")]
|
|
623
648
|
|
|
624
649
|
if len(nc_luts) > 0:
|
|
625
650
|
windspeed.register_nc_luts(getConf()["nc_luts_path"])
|
|
626
651
|
|
|
627
|
-
if (
|
|
652
|
+
if (model_co == "gmf_cmod7"):
|
|
628
653
|
windspeed.register_cmod7(getConf()["lut_cmod7_path"])
|
|
629
654
|
# Step 2 - clean and prepare dataset
|
|
630
655
|
|
|
@@ -690,7 +715,7 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False
|
|
|
690
715
|
xr_dataset['ancillary_wind_direction'].attrs = {}
|
|
691
716
|
xr_dataset['ancillary_wind_direction'].attrs['units'] = 'degrees_north'
|
|
692
717
|
xr_dataset['ancillary_wind_direction'].attrs[
|
|
693
|
-
'long_name'] = f'{ancillary_name} wind direction
|
|
718
|
+
'long_name'] = f'{ancillary_name} wind direction in meteorological convention (clockwise, from), ex: 0°=from north, 90°=from east'
|
|
694
719
|
xr_dataset['ancillary_wind_direction'].attrs['standart_name'] = 'wind_direction'
|
|
695
720
|
|
|
696
721
|
xr_dataset['ancillary_wind_speed'] = np.sqrt(
|
|
@@ -705,7 +730,7 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False
|
|
|
705
730
|
xr_dataset['ancillary_wind_speed'].attrs['standart_name'] = 'wind_speed'
|
|
706
731
|
|
|
707
732
|
xr_dataset['ancillary_wind'] = xr.where(xr_dataset['mask'], np.nan,
|
|
708
|
-
(xr_dataset.ancillary_wind_speed * np.exp(1j * xsarsea.
|
|
733
|
+
(xr_dataset.ancillary_wind_speed * np.exp(1j * xsarsea.dir_meteo_to_sample(xr_dataset.ancillary_wind_direction, xr_dataset.ground_heading))).compute()).transpose(
|
|
709
734
|
*xr_dataset['ancillary_wind_speed'].dims)
|
|
710
735
|
|
|
711
736
|
xr_dataset.attrs['ancillary_source'] = xr_dataset['model_U10'].attrs['history'].split('decoded: ')[
|
|
@@ -734,13 +759,13 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False
|
|
|
734
759
|
xr_dataset['sigma0_ocean_raw'].attrs = xr_dataset['sigma0_raw'].attrs
|
|
735
760
|
|
|
736
761
|
xr_dataset['sigma0_detrend'] = xsarsea.sigma0_detrend(
|
|
737
|
-
xr_dataset.sigma0.sel(pol=copol), xr_dataset.incidence, model=
|
|
762
|
+
xr_dataset.sigma0.sel(pol=copol), xr_dataset.incidence, model=model_co)
|
|
738
763
|
|
|
739
764
|
# processing
|
|
740
765
|
if dual_pol:
|
|
741
766
|
|
|
742
767
|
xr_dataset['sigma0_detrend_cross'] = xsarsea.sigma0_detrend(
|
|
743
|
-
xr_dataset.sigma0.sel(pol=crosspol), xr_dataset.incidence, model=
|
|
768
|
+
xr_dataset.sigma0.sel(pol=crosspol), xr_dataset.incidence, model=model_cross)
|
|
744
769
|
if config["apply_flattening"]:
|
|
745
770
|
xr_dataset = xr_dataset.assign(nesz_cross_final=(
|
|
746
771
|
['line', 'sample'], windspeed.nesz_flattening(xr_dataset.nesz.sel(pol=crosspol), xr_dataset.incidence)))
|
|
@@ -756,15 +781,14 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False
|
|
|
756
781
|
xr_dataset.nesz_cross_final.attrs['long_name'] = 'Noise Equivalent SigmaNaught'
|
|
757
782
|
|
|
758
783
|
# dsig
|
|
759
|
-
sigma0_ocean_cross = xr_dataset['sigma0_ocean'].sel(pol=crosspol)
|
|
760
784
|
xr_dataset["dsig_cross"] = windspeed.get_dsig(config["dsig_"+crosspol_gmf+"_NAME"], xr_dataset.incidence,
|
|
761
|
-
|
|
785
|
+
xr_dataset['sigma0_ocean'].sel(pol=crosspol), xr_dataset.nesz_cross_final)
|
|
762
786
|
|
|
763
787
|
xr_dataset.dsig_cross.attrs['comment'] = 'variable used to ponderate copol and crosspol'
|
|
764
|
-
dsig_cross =
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
788
|
+
xr_dataset.dsig_cross.attrs['formula_used'] = config["dsig_" +
|
|
789
|
+
crosspol_gmf+"_NAME"]
|
|
790
|
+
xr_dataset.dsig_cross.attrs['apply_flattening'] = str(
|
|
791
|
+
config["apply_flattening"])
|
|
768
792
|
|
|
769
793
|
if ((recalibration) & ("SENTINEL" in sensor_longname)):
|
|
770
794
|
xr_dataset.attrs["path_aux_pp1_new"] = os.path.basename(os.path.dirname(
|
|
@@ -785,19 +809,21 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False
|
|
|
785
809
|
|
|
786
810
|
# adding sigma0 detrend
|
|
787
811
|
xr_dataset_100['sigma0_detrend'] = xsarsea.sigma0_detrend(
|
|
788
|
-
xr_dataset_100.sigma0.sel(pol=copol), xr_dataset_100.incidence, model=
|
|
812
|
+
xr_dataset_100.sigma0.sel(pol=copol), xr_dataset_100.incidence, model=model_co)
|
|
789
813
|
|
|
790
|
-
|
|
791
|
-
xr_dataset_100
|
|
814
|
+
if dual_pol:
|
|
815
|
+
xr_dataset_100['sigma0_detrend_cross'] = xsarsea.sigma0_detrend(
|
|
816
|
+
xr_dataset_100.sigma0.sel(pol=crosspol), xr_dataset_100.incidence, model=model_cross)
|
|
792
817
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
818
|
+
sigma0_detrend_combined = xr.concat(
|
|
819
|
+
[xr_dataset_100['sigma0_detrend'],
|
|
820
|
+
xr_dataset_100['sigma0_detrend_cross']],
|
|
821
|
+
dim='pol'
|
|
822
|
+
)
|
|
823
|
+
sigma0_detrend_combined['pol'] = [copol, crosspol]
|
|
824
|
+
|
|
825
|
+
xr_dataset_100['sigma0_detrend'] = sigma0_detrend_combined
|
|
799
826
|
|
|
800
|
-
xr_dataset_100['sigma0_detrend'] = sigma0_detrend_combined
|
|
801
827
|
xr_dataset_100.land_mask.values = binary_dilation(xr_dataset_100['land_mask'].values.astype('uint8'),
|
|
802
828
|
structure=np.ones((3, 3), np.uint8), iterations=3)
|
|
803
829
|
xr_dataset_100['sigma0_detrend'] = xr.where(
|
|
@@ -806,7 +832,7 @@ def preprocess(filename, outdir, config_path, overwrite=False, add_streaks=False
|
|
|
806
832
|
xr_dataset['streaks_direction'] = get_streaks(
|
|
807
833
|
xr_dataset, xr_dataset_100)
|
|
808
834
|
|
|
809
|
-
return xr_dataset,
|
|
835
|
+
return xr_dataset, out_file, config
|
|
810
836
|
|
|
811
837
|
|
|
812
838
|
def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add_streaks=False, resolution='1000m'):
|
|
@@ -836,9 +862,26 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add
|
|
|
836
862
|
final dataset
|
|
837
863
|
"""
|
|
838
864
|
|
|
839
|
-
xr_dataset,
|
|
865
|
+
xr_dataset, out_file, config = preprocess(
|
|
840
866
|
filename, outdir, config_path, overwrite, add_streaks, resolution)
|
|
841
867
|
|
|
868
|
+
model_co = config["l2_params"]["model_co"]
|
|
869
|
+
model_cross = config["l2_params"]["model_cross"]
|
|
870
|
+
copol = config["l2_params"]["copol"]
|
|
871
|
+
crosspol = config["l2_params"]["crosspol"]
|
|
872
|
+
copol_gmf = config["l2_params"]["copol_gmf"]
|
|
873
|
+
crosspol_gmf = config["l2_params"]["crosspol_gmf"]
|
|
874
|
+
dual_pol = config["l2_params"]["dual_pol"]
|
|
875
|
+
ancillary_name = config["ancillary"]
|
|
876
|
+
sensor_longname = config["sensor_longname"]
|
|
877
|
+
|
|
878
|
+
if dual_pol:
|
|
879
|
+
sigma0_ocean_cross = xr_dataset['sigma0_ocean'].sel(pol=crosspol)
|
|
880
|
+
dsig_cross = xr_dataset['dsig_cross']
|
|
881
|
+
else:
|
|
882
|
+
sigma0_ocean_cross = None
|
|
883
|
+
dsig_cross = 0.1 # default value set in xsarsea
|
|
884
|
+
|
|
842
885
|
kwargs = {
|
|
843
886
|
"inc_step_lr": config.pop("inc_step_lr", None),
|
|
844
887
|
"wpsd_step_lr": config.pop("wspd_step_lr", None),
|
|
@@ -849,6 +892,11 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add
|
|
|
849
892
|
"resolution": config.pop("resolution", None),
|
|
850
893
|
}
|
|
851
894
|
|
|
895
|
+
logging.info("Checking incidence range within LUTS incidence range")
|
|
896
|
+
# warning if incidence is out of lut incidence range
|
|
897
|
+
inc_check_co, inc_check_cross = check_incidence_range(
|
|
898
|
+
xr_dataset['incidence'], [model_co, model_cross], **kwargs)
|
|
899
|
+
|
|
852
900
|
wind_co, wind_dual, windspeed_cr = inverse(dual_pol,
|
|
853
901
|
inc=xr_dataset['incidence'],
|
|
854
902
|
sigma0=xr_dataset['sigma0_ocean'].sel(
|
|
@@ -856,60 +904,61 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add
|
|
|
856
904
|
sigma0_dual=sigma0_ocean_cross,
|
|
857
905
|
ancillary_wind=xr_dataset['ancillary_wind'],
|
|
858
906
|
dsig_cr=dsig_cross,
|
|
859
|
-
|
|
860
|
-
|
|
907
|
+
model_co=model_co,
|
|
908
|
+
model_cross=model_cross,
|
|
861
909
|
** kwargs)
|
|
910
|
+
wind_co.compute()
|
|
862
911
|
|
|
863
912
|
# windspeed_co
|
|
864
913
|
xr_dataset['windspeed_co'] = np.abs(wind_co)
|
|
865
914
|
xr_dataset["windspeed_co"].attrs["units"] = "m.s⁻1"
|
|
866
915
|
xr_dataset["windspeed_co"].attrs["long_name"] = "Wind speed inverted from model %s (%s)" % (
|
|
867
|
-
|
|
916
|
+
model_co, copol)
|
|
868
917
|
xr_dataset["windspeed_co"].attrs["standart_name"] = "wind_speed"
|
|
869
918
|
xr_dataset["windspeed_co"].attrs["model"] = wind_co.attrs["model"]
|
|
870
919
|
del xr_dataset["windspeed_co"].attrs['comment']
|
|
871
920
|
|
|
872
921
|
# winddir_co
|
|
873
|
-
xr_dataset['winddir_co'] = (
|
|
874
|
-
|
|
875
|
-
xr_dataset[
|
|
876
|
-
xr_dataset["winddir_co"].attrs["long_name"] = "Wind direction in meteorological convention, 0=North, 90=East, inverted from model %s (%s)" % (
|
|
877
|
-
model_vv, copol)
|
|
878
|
-
xr_dataset["winddir_co"].attrs["standart_name"] = "wind_direction"
|
|
879
|
-
xr_dataset["winddir_co"].attrs["model"] = wind_co.attrs["model"]
|
|
922
|
+
xr_dataset['winddir_co'] = transform_winddir(
|
|
923
|
+
wind_co, xr_dataset.ground_heading, winddir_convention=config["winddir_convention"])
|
|
924
|
+
xr_dataset['winddir_co'].attrs["model"] = "%s (%s)" % (model_co, copol)
|
|
880
925
|
|
|
881
926
|
# windspeed_dual / windspeed_cr / /winddir_dual / winddir_cr
|
|
882
|
-
if dual_pol:
|
|
927
|
+
if dual_pol and wind_dual is not None:
|
|
928
|
+
wind_dual.compute()
|
|
883
929
|
xr_dataset['windspeed_dual'] = np.abs(wind_dual)
|
|
884
930
|
xr_dataset["windspeed_dual"].attrs["units"] = "m.s⁻1"
|
|
885
931
|
xr_dataset["windspeed_dual"].attrs["long_name"] = "Wind speed inverted from model %s (%s) & %s (%s)" % (
|
|
886
|
-
|
|
932
|
+
model_co, copol, model_cross, crosspol)
|
|
887
933
|
xr_dataset["windspeed_dual"].attrs["standart_name"] = "wind_speed"
|
|
888
934
|
xr_dataset["windspeed_dual"].attrs["model"] = wind_dual.attrs["model"]
|
|
889
935
|
del xr_dataset["windspeed_dual"].attrs['comment']
|
|
890
936
|
|
|
891
|
-
xr_dataset['winddir_dual'] = (
|
|
892
|
-
|
|
893
|
-
xr_dataset[
|
|
894
|
-
|
|
895
|
-
model_vv, copol, model_vh, crosspol)
|
|
896
|
-
xr_dataset["winddir_dual"].attrs["standart_name"] = "wind_direction"
|
|
897
|
-
xr_dataset["winddir_dual"].attrs["model"] = wind_dual.attrs["model"]
|
|
937
|
+
xr_dataset['winddir_dual'] = transform_winddir(
|
|
938
|
+
wind_dual, xr_dataset.ground_heading, winddir_convention=config["winddir_convention"])
|
|
939
|
+
xr_dataset['winddir_dual'].attrs["model"] = "%s (%s) & %s (%s)" % (
|
|
940
|
+
model_co, copol, model_cross, crosspol)
|
|
898
941
|
|
|
899
942
|
xr_dataset = xr_dataset.assign(
|
|
900
943
|
windspeed_cross=(['line', 'sample'], windspeed_cr))
|
|
901
944
|
xr_dataset["windspeed_cross"].attrs["units"] = "m.s⁻1"
|
|
902
945
|
xr_dataset["windspeed_cross"].attrs["long_name"] = "Wind Speed inverted from model %s (%s)" % (
|
|
903
|
-
|
|
946
|
+
model_cross, crosspol)
|
|
904
947
|
xr_dataset["windspeed_cross"].attrs["standart_name"] = "wind_speed"
|
|
905
|
-
xr_dataset["windspeed_cross"].attrs["model"] = "%s" % (
|
|
948
|
+
xr_dataset["windspeed_cross"].attrs["model"] = "%s" % (model_cross)
|
|
906
949
|
|
|
907
950
|
xr_dataset['winddir_cross'] = xr_dataset['winddir_dual'].copy()
|
|
908
|
-
xr_dataset[
|
|
909
|
-
xr_dataset["winddir_cross"].attrs["long_name"] = "Wind direction in meteorological convention, 0=North, 90=East, copied from dualpol"
|
|
910
|
-
xr_dataset["winddir_cross"].attrs["standart_name"] = "wind_direction"
|
|
951
|
+
xr_dataset['winddir_cross'].attrs = xr_dataset['winddir_dual'].attrs
|
|
911
952
|
xr_dataset["winddir_cross"].attrs["model"] = "No model used ; content is a copy of dualpol wind direction"
|
|
912
953
|
|
|
954
|
+
if config["winddir_convention"] == "oceanographic":
|
|
955
|
+
attrs = xr_dataset['ancillary_wind_direction'].attrs
|
|
956
|
+
xr_dataset['ancillary_wind_direction'] = xsarsea.dir_meteo_to_oceano(
|
|
957
|
+
xr_dataset['ancillary_wind_direction'])
|
|
958
|
+
xr_dataset['ancillary_wind_direction'].attrs = attrs
|
|
959
|
+
xr_dataset['ancillary_wind_direction'].attrs[
|
|
960
|
+
"long_name"] = f"{ancillary_name} wind direction in oceanographic convention (clockwise, to), ex: 0°=to north, 90°=to east"
|
|
961
|
+
|
|
913
962
|
xr_dataset, encoding = makeL2asOwi(
|
|
914
963
|
xr_dataset, dual_pol, copol, crosspol, add_streaks=add_streaks)
|
|
915
964
|
|
|
@@ -943,7 +992,7 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add
|
|
|
943
992
|
"xsar_version": xsar.__version__,
|
|
944
993
|
"xsarsea_version": xsarsea.__version__,
|
|
945
994
|
"pythonVersion": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
|
|
946
|
-
"polarisationRatio":
|
|
995
|
+
"polarisationRatio": get_pol_ratio_name(model_co),
|
|
947
996
|
"l2ProcessingUtcTime": datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ"),
|
|
948
997
|
"processingCenter": "IFREMER",
|
|
949
998
|
"firstMeasurementTime": firstMeasurementTime,
|
|
@@ -960,25 +1009,32 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add
|
|
|
960
1009
|
"wnf_3km_average": "False",
|
|
961
1010
|
"owiWindSpeedSrc": "owiWindSpeed",
|
|
962
1011
|
"owiWindDirectionSrc": "/",
|
|
963
|
-
"ancillary_source": xr_dataset.attrs['ancillary_source']
|
|
1012
|
+
"ancillary_source": xr_dataset.attrs['ancillary_source'],
|
|
1013
|
+
"winddir_convention": config["winddir_convention"],
|
|
1014
|
+
"incidence_within_lut_copol_incidence_range": str(inc_check_co),
|
|
1015
|
+
"incidence_within_lut_crosspol_incidence_range": str(inc_check_cross),
|
|
1016
|
+
"swath": xr_dataset.attrs['swath'],
|
|
1017
|
+
"footprint": xr_dataset.attrs['footprint'],
|
|
1018
|
+
"coverage": xr_dataset.attrs['coverage'],
|
|
1019
|
+
|
|
964
1020
|
}
|
|
965
1021
|
|
|
966
1022
|
for recalib_attrs in ["path_aux_pp1_new", 'path_aux_pp1_old', "path_aux_cal_new", "path_aux_cal_old"]:
|
|
967
1023
|
if recalib_attrs in xr_dataset.attrs:
|
|
968
1024
|
attrs[recalib_attrs] = xr_dataset.attrs[recalib_attrs]
|
|
969
1025
|
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1026
|
+
for arg in ["passDirection", "orbit_pass"]:
|
|
1027
|
+
if arg in xr_dataset.attrs:
|
|
1028
|
+
attrs["passDirection"] = xr_dataset.attrs[arg]
|
|
1029
|
+
|
|
1030
|
+
_S1_added_attrs = ["ipf", "platform_heading"]
|
|
1031
|
+
_RCM_added_attrs = ["productId"]
|
|
975
1032
|
|
|
976
|
-
for sup_attr in _S1_added_attrs +
|
|
1033
|
+
for sup_attr in _S1_added_attrs + _RCM_added_attrs:
|
|
977
1034
|
if sup_attr in xr_dataset.attrs:
|
|
978
1035
|
attrs[sup_attr] = xr_dataset.attrs[sup_attr]
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
attrs[var] = str(attrs[var])
|
|
1036
|
+
|
|
1037
|
+
attrs['footprint'] = str(attrs['footprint'])
|
|
982
1038
|
|
|
983
1039
|
# add in kwargs in attrs
|
|
984
1040
|
for key in kwargs:
|
|
@@ -1000,3 +1056,49 @@ def makeL2(filename, outdir, config_path, overwrite=False, generateCSV=True, add
|
|
|
1000
1056
|
logging.info("OK for %s ", os.path.basename(filename))
|
|
1001
1057
|
|
|
1002
1058
|
return out_file, xr_dataset
|
|
1059
|
+
|
|
1060
|
+
|
|
1061
|
+
def transform_winddir(wind_cpx, ground_heading, winddir_convention='meteorological'):
|
|
1062
|
+
"""
|
|
1063
|
+
|
|
1064
|
+
Parameters
|
|
1065
|
+
----------
|
|
1066
|
+
wind_cpx : xr.DataArray | np.complex64
|
|
1067
|
+
complex wind, relative to antenna, anticlockwise
|
|
1068
|
+
|
|
1069
|
+
ground_heading : xr.DataArray
|
|
1070
|
+
heading angle in degrees
|
|
1071
|
+
|
|
1072
|
+
winddir_convention : str
|
|
1073
|
+
wind direction convention to use, either 'meteorological' or 'oceanographic'
|
|
1074
|
+
|
|
1075
|
+
Returns
|
|
1076
|
+
-------
|
|
1077
|
+
xr.DataArray
|
|
1078
|
+
wind direction in degrees in the selected convention with appropriate long_name attribute
|
|
1079
|
+
"""
|
|
1080
|
+
# to meteo winddir_convention
|
|
1081
|
+
dataArray = xsarsea.dir_sample_to_meteo(
|
|
1082
|
+
np.angle(wind_cpx, deg=True), ground_heading)
|
|
1083
|
+
long_name = "Wind direction in meteorological convention (clockwise, from), ex: 0°=from north, 90°=from east"
|
|
1084
|
+
|
|
1085
|
+
if winddir_convention == "meteorological":
|
|
1086
|
+
# do nothing
|
|
1087
|
+
pass
|
|
1088
|
+
elif winddir_convention == "oceanographic":
|
|
1089
|
+
# to oceano winddir_convention
|
|
1090
|
+
dataArray = xsarsea.dir_meteo_to_oceano(dataArray)
|
|
1091
|
+
long_name = "Wind direction in oceanographic convention (clockwise, to), ex: 0°=to north, 90°=to east"
|
|
1092
|
+
else:
|
|
1093
|
+
# warning
|
|
1094
|
+
logging.warning(
|
|
1095
|
+
f"wind direction convention {winddir_convention} is not supported, using meteorological",)
|
|
1096
|
+
long_name = "Wind direction in meteorological convention (clockwise, from), ex: 0°=from north, 90°=from east"
|
|
1097
|
+
|
|
1098
|
+
dataArray = xsarsea.dir_to_360(dataArray)
|
|
1099
|
+
dataArray.attrs = {}
|
|
1100
|
+
dataArray.attrs["units"] = "degrees_north"
|
|
1101
|
+
dataArray.attrs["long_name"] = long_name
|
|
1102
|
+
dataArray.attrs["standart_name"] = "wind_direction"
|
|
1103
|
+
|
|
1104
|
+
return dataArray
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import xsarsea
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def check_incidence_range(incidence, models, **kwargs):
|
|
6
|
+
"""
|
|
7
|
+
Check if the incidence range of the dataset is within the range of the LUT of the model.
|
|
8
|
+
If not, warn the user : inversion will be approximate.
|
|
9
|
+
|
|
10
|
+
Parameters
|
|
11
|
+
----------
|
|
12
|
+
incidence : xr.DataArray
|
|
13
|
+
incidence angle in degrees
|
|
14
|
+
models : list of str
|
|
15
|
+
list of model names
|
|
16
|
+
|
|
17
|
+
Returns
|
|
18
|
+
-------
|
|
19
|
+
list of bool
|
|
20
|
+
for each model,
|
|
21
|
+
True if the incidence range is within the range of the LUT of the model (correct)
|
|
22
|
+
False otherwise
|
|
23
|
+
"""
|
|
24
|
+
if isinstance(models, str):
|
|
25
|
+
models = [models]
|
|
26
|
+
elif not isinstance(models, list):
|
|
27
|
+
raise TypeError("models should be a string or a list of strings")
|
|
28
|
+
|
|
29
|
+
rets = []
|
|
30
|
+
for model_name in models:
|
|
31
|
+
lut_range = xsarsea.windspeed.get_model(model_name).inc_range
|
|
32
|
+
if 'inc_range' in kwargs:
|
|
33
|
+
logging.debug(
|
|
34
|
+
f"GMF {model_name} inc_range will be changed by kwargs to {kwargs['inc_range']}")
|
|
35
|
+
lut_range = kwargs['inc_range']
|
|
36
|
+
|
|
37
|
+
inc_range = [incidence.values.min(), incidence.values.max()]
|
|
38
|
+
if (inc_range[0] >= lut_range[0] and inc_range[1] <= lut_range[1]):
|
|
39
|
+
rets.append(True)
|
|
40
|
+
else:
|
|
41
|
+
logging.warn(
|
|
42
|
+
f"incidence range {inc_range} is not within the range of the LUT of the model {model_name} {lut_range} : inversion will be approximate using LUT minmium|maximum incidences")
|
|
43
|
+
rets.append(False)
|
|
44
|
+
|
|
45
|
+
return rets
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def get_pol_ratio_name(model_co):
|
|
49
|
+
"""
|
|
50
|
+
Return polarization ration name of copol model
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
model_co : str
|
|
55
|
+
copol model name
|
|
56
|
+
|
|
57
|
+
Returns
|
|
58
|
+
-------
|
|
59
|
+
str
|
|
60
|
+
if pol = 'HH', return polarization ratio name ; else return '/'
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
model = xsarsea.windspeed.get_model(model_co)
|
|
64
|
+
if model.pol == 'HH':
|
|
65
|
+
try:
|
|
66
|
+
import re
|
|
67
|
+
|
|
68
|
+
def check_format(s):
|
|
69
|
+
pattern = r'^([a-zA-Z0-9]+)_R(high|low)_hh_([a-zA-Z0-9_]+)$'
|
|
70
|
+
match = re.match(pattern, s)
|
|
71
|
+
if match:
|
|
72
|
+
vvgmf, res, polrationame = match.groups()
|
|
73
|
+
return polrationame
|
|
74
|
+
else:
|
|
75
|
+
logging.warn(
|
|
76
|
+
f"String format is not correct for polarization ratio name = {s}\nReturning '/'")
|
|
77
|
+
return "/"
|
|
78
|
+
get_pol_ratio_name = check_format(model_co)
|
|
79
|
+
return get_pol_ratio_name
|
|
80
|
+
except AttributeError:
|
|
81
|
+
return "not_written_in_lut"
|
|
82
|
+
else:
|
|
83
|
+
return '/'
|
|
@@ -19,10 +19,14 @@ def get_memory_usage(unit='Go', var='ru_maxrss', force_psutil=False):
|
|
|
19
19
|
on_purpose_error
|
|
20
20
|
import resource
|
|
21
21
|
mems = {}
|
|
22
|
-
mems['ru_maxrss'] = resource.getrusage(
|
|
23
|
-
|
|
24
|
-
mems['
|
|
25
|
-
|
|
22
|
+
mems['ru_maxrss'] = resource.getrusage(
|
|
23
|
+
resource.RUSAGE_SELF).ru_maxrss / factor
|
|
24
|
+
mems['ru_ixrss'] = resource.getrusage(
|
|
25
|
+
resource.RUSAGE_SELF).ru_ixrss / factor
|
|
26
|
+
mems['ru_idrss'] = resource.getrusage(
|
|
27
|
+
resource.RUSAGE_SELF).ru_idrss / factor
|
|
28
|
+
mems['ru_isrss'] = resource.getrusage(
|
|
29
|
+
resource.RUSAGE_SELF).ru_isrss / factor
|
|
26
30
|
mems['current'] = getCurrentMemoryUsage() / factor
|
|
27
31
|
# memory_used_go = resource.getrusage(resource.RUSAGE_SELF).get(var) /factor
|
|
28
32
|
memory_used_go = mems[var]
|
{grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion.egg-info/SOURCES.txt
RENAMED
|
@@ -13,6 +13,7 @@ requirements_dev.txt
|
|
|
13
13
|
requirements_doc.txt
|
|
14
14
|
tox.ini
|
|
15
15
|
.github/dependabot.yml
|
|
16
|
+
.github/workflows/ci.yml
|
|
16
17
|
.github/workflows/publish.yml
|
|
17
18
|
ci/requirements/docs.yaml
|
|
18
19
|
ci/requirements/environment.yaml
|
|
@@ -41,6 +42,7 @@ grdwindinversion/load_config.py
|
|
|
41
42
|
grdwindinversion/main.py
|
|
42
43
|
grdwindinversion/streaks.py
|
|
43
44
|
grdwindinversion/utils.py
|
|
45
|
+
grdwindinversion/utils_memory.py
|
|
44
46
|
grdwindinversion.egg-info/PKG-INFO
|
|
45
47
|
grdwindinversion.egg-info/SOURCES.txt
|
|
46
48
|
grdwindinversion.egg-info/dependency_links.txt
|
|
@@ -50,4 +52,5 @@ grdwindinversion.egg-info/top_level.txt
|
|
|
50
52
|
grdwindinversion/.github/ISSUE_TEMPLATE.md
|
|
51
53
|
recipe/meta.yaml
|
|
52
54
|
tests/__init__.py
|
|
53
|
-
tests/
|
|
55
|
+
tests/config_test.yaml
|
|
56
|
+
tests/test_grdwindinversion_ci.py
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import os
|
|
3
|
+
import urllib.request
|
|
4
|
+
from grdwindinversion.inversion import makeL2
|
|
5
|
+
|
|
6
|
+
# What must be done by the tests:
|
|
7
|
+
# - Download L1 data
|
|
8
|
+
# - Download needed GMFs
|
|
9
|
+
# - Download ECMWF data
|
|
10
|
+
# -
|
|
11
|
+
# - Setup data-config pour xsar et grdwindinversion
|
|
12
|
+
#
|
|
13
|
+
# - For recal : download auxiliary files
|
|
14
|
+
#
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_makeL2_generation():
|
|
18
|
+
l1_files = [
|
|
19
|
+
"./test_data/L1/S1A_IW_GRDH_1SDV_20210909T130650_20210909T130715_039605_04AE83_C34F.SAFE",
|
|
20
|
+
"./test_data/L1/RCM1_OK2767220_PK2769320_1_SCLND_20230930_214014_VV_VH_GRD",
|
|
21
|
+
"./test_data/L1/RS2_OK141302_PK1242223_DK1208537_SCWA_20220904_093402_VV_VH_SGF"
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
# l1_files = [
|
|
25
|
+
# "/home/datawork-cersat-public/cache/project/mpc-sentinel1/data/esa/sentinel-1a/L1/IW/S1A_IW_GRDH_1S/2021/252/S1A_IW_GRDH_1SDV_20210909T130650_20210909T130715_039605_04AE83_C34F.SAFE"
|
|
26
|
+
# ]
|
|
27
|
+
|
|
28
|
+
outdir = "./out_test_data"
|
|
29
|
+
os.makedirs(outdir, exist_ok=True)
|
|
30
|
+
|
|
31
|
+
config_dir = os.path.dirname(__file__)
|
|
32
|
+
config_path = os.path.join(config_dir, "config_test.yaml")
|
|
33
|
+
|
|
34
|
+
for f in l1_files:
|
|
35
|
+
# Run the makeL2 function
|
|
36
|
+
print(f)
|
|
37
|
+
output_nc_file, dataset = makeL2(
|
|
38
|
+
filename=f,
|
|
39
|
+
outdir=outdir,
|
|
40
|
+
config_path=config_path,
|
|
41
|
+
overwrite=True, # Set to True to ensure a clean run
|
|
42
|
+
generateCSV=False, # Disable CSV generation for now
|
|
43
|
+
add_streaks=False,
|
|
44
|
+
resolution="1000m",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Check if the output file (NetCDF) is generated
|
|
48
|
+
assert os.path.exists(
|
|
49
|
+
output_nc_file), f"NetCDF output file not created for {f}"
|
|
50
|
+
|
|
51
|
+
# Optionally, check the dataset has content
|
|
52
|
+
assert dataset is not None, f"No dataset generated for {f}"
|
|
53
|
+
assert (
|
|
54
|
+
"owiWindSpeed" in dataset.variables
|
|
55
|
+
), "Expected variable 'owiWindSpeed' missing in the dataset"
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
|
|
3
|
-
"""Tests for `grdwindinversion` package."""
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import unittest
|
|
7
|
-
import grdwindinversion
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class TestGrdwindinversion(unittest.TestCase):
|
|
11
|
-
"""Tests for `grdwindinversion` package."""
|
|
12
|
-
|
|
13
|
-
def setUp(self):
|
|
14
|
-
"""Set up test fixtures, if any."""
|
|
15
|
-
|
|
16
|
-
def tearDown(self):
|
|
17
|
-
"""Tear down test fixtures, if any."""
|
|
18
|
-
|
|
19
|
-
def test_000_something(self):
|
|
20
|
-
"""Test something."""
|
|
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.post15 → grdwindinversion-0.2.4}/docs/_static/css/grdwindinversion.css
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/docs/examples/wind-inversion-from-grd.ipynb
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
|
{grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion/.github/ISSUE_TEMPLATE.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion/config_prod_recal.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion.egg-info/requires.txt
RENAMED
|
File without changes
|
{grdwindinversion-0.2.3.post15 → grdwindinversion-0.2.4}/grdwindinversion.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|