grdwindinversion 1.0.0__tar.gz → 1.0.1__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-1.0.0 → grdwindinversion-1.0.1}/.github/workflows/ci.yml +0 -6
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/PKG-INFO +1 -1
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/docs/configuration.rst +3 -34
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/docs/examples/streaks-display.ipynb +5 -7
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/docs/examples/wind-inversion-from-grd.ipynb +2 -2
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/docs/modules.rst +0 -8
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/docs/usage.rst +4 -4
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion/__init__.py +0 -2
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion/config_prod_recal.yaml +26 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion/config_prod_recal_streaks_nrcsmod.yaml +26 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion/config_prod_streaks.yaml +27 -1
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion/config_prod_streaks_nrcsmod.yaml +26 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion/config_prod_v3.yaml +26 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion/inversion.py +39 -27
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion/main.py +0 -3
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion/utils.py +103 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion.egg-info/PKG-INFO +1 -1
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion.egg-info/SOURCES.txt +11 -11
- grdwindinversion-1.0.1/tests/ci/__init__.py +1 -0
- {grdwindinversion-1.0.0/tests → grdwindinversion-1.0.1/tests/ci}/config_test.yaml +23 -4
- {grdwindinversion-1.0.0/tests → grdwindinversion-1.0.1/tests/ci}/test_grdwindinversion_ci.py +20 -11
- grdwindinversion-1.0.1/tests/unit/__init__.py +1 -0
- {grdwindinversion-1.0.0/tests → grdwindinversion-1.0.1/tests/unit}/test_ancillary.py +13 -17
- {grdwindinversion-1.0.0/tests → grdwindinversion-1.0.1/tests/unit}/test_config.py +16 -12
- {grdwindinversion-1.0.0/tests → grdwindinversion-1.0.1/tests/unit}/test_mask_functions.py +8 -9
- grdwindinversion-1.0.0/grdwindinversion/data_config.yaml +0 -25
- grdwindinversion-1.0.0/grdwindinversion/load_config.py +0 -30
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/.editorconfig +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/.gitattributes +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/.github/dependabot.yml +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/.github/workflows/build.yml +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/.github/workflows/publish.yml +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/.gitignore +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/.pre-commit-config.yaml +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/AUTHORS.rst +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/CONTRIBUTING.rst +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/HISTORY.rst +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/LICENSE +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/MANIFEST.in +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/Makefile +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/README.md +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/ci/requirements/docs.yaml +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/ci/requirements/environment.yaml +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/docs/Makefile +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/docs/_static/css/grdwindinversion.css +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/docs/algorithm.rst +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/docs/authors.rst +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/docs/conf.py +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/docs/contributing.rst +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/docs/history.rst +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/docs/index.rst +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/docs/installation.rst +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/docs/make.bat +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion/.github/ISSUE_TEMPLATE.md +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion/.gitignore +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion/gradientFeatures.py +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion/utils_memory.py +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion.egg-info/dependency_links.txt +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion.egg-info/entry_points.txt +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion.egg-info/requires.txt +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion.egg-info/top_level.txt +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/pyproject.toml +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/recipe/meta.yaml +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/requirements_dev.txt +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/requirements_doc.txt +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/setup.cfg +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/tests/__init__.py +0 -0
- {grdwindinversion-1.0.0/tests → grdwindinversion-1.0.1/tests/ci}/data_config_ci.yaml +0 -0
- {grdwindinversion-1.0.0/tests → grdwindinversion-1.0.1/tests/unit}/listing_rcm_safe.txt +0 -0
- {grdwindinversion-1.0.0/tests → grdwindinversion-1.0.1/tests/unit}/test_getOutputName.py +0 -0
- {grdwindinversion-1.0.0/tests → grdwindinversion-1.0.1/tests/unit}/test_simple_functions.py +0 -0
- {grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/tox.ini +0 -0
|
@@ -79,12 +79,6 @@ jobs:
|
|
|
79
79
|
echo "auxiliary_dir: ./test_data/auxiliary" >> ~/.xsar/config.yml
|
|
80
80
|
echo "path_dataframe_aux: ./test_data/auxiliary/active_aux.csv" >> ~/.xsar/config.yml
|
|
81
81
|
|
|
82
|
-
# Set up grdwindinversion configuration
|
|
83
|
-
- name: Setup grdwindinversion configuration
|
|
84
|
-
run: |
|
|
85
|
-
mkdir -p ~/.grdwindinversion
|
|
86
|
-
cp tests/data_config_ci.yaml ~/.grdwindinversion/data_config.yaml
|
|
87
|
-
|
|
88
82
|
# Run the tests
|
|
89
83
|
- name: Run tests
|
|
90
84
|
run: |
|
|
@@ -8,41 +8,10 @@ Configuration Files Implementation Guide
|
|
|
8
8
|
Overview
|
|
9
9
|
--------
|
|
10
10
|
|
|
11
|
-
The ``grdwindinversion`` configuration system uses
|
|
11
|
+
The ``grdwindinversion`` configuration system uses a **single YAML configuration file** that contains both data source paths and processing parameters.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
Configuration System Architecture
|
|
17
|
-
----------------------------------
|
|
18
|
-
|
|
19
|
-
Loading Hierarchy
|
|
20
|
-
~~~~~~~~~~~~~~~~~
|
|
21
|
-
|
|
22
|
-
The ``data_config.yaml`` file is loaded with the following priority:
|
|
23
|
-
|
|
24
|
-
.. code-block:: text
|
|
25
|
-
|
|
26
|
-
1. ~/.grdwindinversion/data_config.yaml (user local configuration)
|
|
27
|
-
2. ./local_data_config.yaml (project local configuration)
|
|
28
|
-
3. <package>/data_config.yaml (package default configuration)
|
|
29
|
-
|
|
30
|
-
Accessing Configuration
|
|
31
|
-
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
32
|
-
|
|
33
|
-
.. code-block:: python
|
|
34
|
-
|
|
35
|
-
from grdwindinversion.load_config import getConf
|
|
36
|
-
|
|
37
|
-
# Get the global configuration dictionary
|
|
38
|
-
config = getConf()
|
|
39
|
-
|
|
40
|
-
# Access data paths
|
|
41
|
-
ecmwf_path = config["ecmwf_0100_1h"]
|
|
42
|
-
nc_luts_path = config["nc_luts_path"]
|
|
43
|
-
|
|
44
|
-
data_config.yaml Structure
|
|
45
|
-
---------------------------
|
|
13
|
+
Configuration File Structure
|
|
14
|
+
-----------------------------
|
|
46
15
|
|
|
47
16
|
1. Meteorological Data Paths (ancillary)
|
|
48
17
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
@@ -213,14 +213,14 @@
|
|
|
213
213
|
" fig = plt.figure(figsize=(10, 9))\n",
|
|
214
214
|
" ax = plt.axes(projection=ccrs.PlateCarree())\n",
|
|
215
215
|
"\n",
|
|
216
|
-
" #
|
|
216
|
+
" # Compute u,v from streaks \n",
|
|
217
217
|
" u, v, u_norm, v_norm = get_uv_from_dir(streaks_dir)\n",
|
|
218
218
|
"\n",
|
|
219
219
|
" # Display streaks direction\n",
|
|
220
220
|
" #ax.quiver(longitude, latitude, u_norm, v_norm, edgecolors='k', norm=norm, pivot= 'mid', scale_units='xy', scale=4., zorder=10, width=0.1/25,transform = ccrs.PlateCarree(), color = 'red', label = 'owiWindStreaks')\n",
|
|
221
221
|
" ax.quiver(longitude, latitude, u_norm, v_norm, edgecolors='k', norm=norm, pivot= 'mid', scale_units='xy', scale=8., zorder=10, width=0.1/25,transform = ccrs.PlateCarree(), color = 'red', label = 'owiWindStreaks')\n",
|
|
222
222
|
"\n",
|
|
223
|
-
"
|
|
223
|
+
" # Display ancillary wind direction\n",
|
|
224
224
|
" #ax.quiver(lons, lats, u_norm_ancillary, v_norm_ancillary, edgecolors='k', norm=norm, pivot= 'mid', scale_units='xy', scale=4., zorder=10, width=0.1/25,transform = ccrs.PlateCarree(), color='blue', label = \"owiAncillaryWindDirection\")\n",
|
|
225
225
|
" ax.quiver(lons, lats, u_norm_ancillary, v_norm_ancillary, edgecolors='k', norm=norm, pivot= 'mid', scale_units='xy', scale=8., zorder=10, width=0.1/25,transform = ccrs.PlateCarree(), color='blue', label = \"owiAncillaryWindDirection\")\n",
|
|
226
226
|
"\n",
|
|
@@ -234,8 +234,6 @@
|
|
|
234
234
|
" lat_min, lat_max = np.nanmin(lats) - .2, np.nanmax(lats) + .7\n",
|
|
235
235
|
" ax.set_extent([lon_min, lon_max, lat_min, lat_max], crs=ccrs.PlateCarree())\n",
|
|
236
236
|
"\n",
|
|
237
|
-
"\n",
|
|
238
|
-
" # Configurer les axes\n",
|
|
239
237
|
" ax.set_xlabel('Longitude')\n",
|
|
240
238
|
" ax.set_ylabel('Latitude')\n",
|
|
241
239
|
" ax.set_aspect('equal', adjustable='box')\n",
|
|
@@ -300,9 +298,9 @@
|
|
|
300
298
|
"source": []
|
|
301
299
|
}
|
|
302
300
|
],
|
|
303
|
-
|
|
301
|
+
"metadata": {
|
|
304
302
|
"kernelspec": {
|
|
305
|
-
"display_name": "Python 3
|
|
303
|
+
"display_name": "Python 3",
|
|
306
304
|
"language": "python",
|
|
307
305
|
"name": "python3"
|
|
308
306
|
},
|
|
@@ -321,4 +319,4 @@
|
|
|
321
319
|
},
|
|
322
320
|
"nbformat": 4,
|
|
323
321
|
"nbformat_minor": 4
|
|
324
|
-
}
|
|
322
|
+
}
|
|
@@ -15,14 +15,6 @@ Wind Inversion
|
|
|
15
15
|
:members: inverse, makeL2, makeL2asOwi, getSensorMetaDataset, getOutputName, inverse_dsig_wspd, addMasks_toMeta, mergeLandMasks, processLandMask, getAncillary, preprocess, process_gradients, transform_winddir
|
|
16
16
|
:show-inheritance:
|
|
17
17
|
|
|
18
|
-
Configuration Management
|
|
19
|
-
------------------------
|
|
20
|
-
|
|
21
|
-
.. automodule:: grdwindinversion.load_config
|
|
22
|
-
:members:
|
|
23
|
-
:undoc-members:
|
|
24
|
-
:show-inheritance:
|
|
25
|
-
|
|
26
18
|
Gradient Features
|
|
27
19
|
-----------------
|
|
28
20
|
|
|
@@ -13,11 +13,11 @@ To use grdwindinversion in a project::
|
|
|
13
13
|
Configuration Setup
|
|
14
14
|
-------------------
|
|
15
15
|
|
|
16
|
-
To define
|
|
16
|
+
To define paths for ECMWF files and other data sources, create or copy a configuration file::
|
|
17
17
|
|
|
18
|
-
cp ./grdwindinversion/
|
|
19
|
-
# Then edit the file
|
|
20
|
-
vi ./
|
|
18
|
+
cp ./grdwindinversion/config_prod_v3.yaml ./my_config.yaml
|
|
19
|
+
# Then edit the file to match your local paths
|
|
20
|
+
vi ./my_config.yaml
|
|
21
21
|
|
|
22
22
|
See :doc:`configuration` for detailed configuration options.
|
|
23
23
|
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
from importlib.metadata import version
|
|
2
2
|
from grdwindinversion.inversion import inverse, makeL2, makeL2asOwi, getSensorMetaDataset
|
|
3
|
-
from grdwindinversion.load_config import getConf
|
|
4
3
|
|
|
5
4
|
__all__ = [
|
|
6
5
|
"inverse",
|
|
7
6
|
"makeL2",
|
|
8
7
|
"makeL2asOwi",
|
|
9
8
|
"getSensorMetaDataset",
|
|
10
|
-
"getConf",
|
|
11
9
|
"inversion",
|
|
12
10
|
]
|
|
13
11
|
|
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
unit_test_s1_product: "./sentinel-1a/L1/IW/S1A_IW_GRDH_1S/2021/252/S1A_IW_GRDH_1SDV_20210909T130650_20210909T130715_039605_04AE83_C34F.SAFE"
|
|
2
|
+
unit_test_rcm_product: "./l1/rcm/rcm-1/sclnd/2023/273/RCM1_OK2767220_PK2769320_1_SCLND_20230930_214014_VV_VH_GRD"
|
|
3
|
+
unit_test_rs2_product: "./L1/VV_VH/2022/247/RS2_OK141302_PK1242223_DK1208537_SCWA_20220904_093402_VV_VH_SGF"
|
|
4
|
+
|
|
5
|
+
masks:
|
|
6
|
+
land:
|
|
7
|
+
- name: "gshhsH"
|
|
8
|
+
path: "/home/loc-datawork-cersat-public/cache/project/sarwing/masks/gshhg-shp-2.3.7/GSHHS_shp/h/GSHHS_h_L1.shp"
|
|
9
|
+
|
|
10
|
+
ancillary_sources:
|
|
11
|
+
ecmwf:
|
|
12
|
+
- name: "ecmwf_0100_1h"
|
|
13
|
+
path: "/home/loc-datawork-cersat-public/provider/ecmwf/forecast/hourly/0100deg/netcdf_light/%Y/%j/ECMWF_FORECAST_0100_%Y%m%d%H%M_10U_10V.nc"
|
|
14
|
+
|
|
15
|
+
- name: "ecmwf_0125_1h"
|
|
16
|
+
path: "/home/loc-datawork-cersat-intranet/project/ecmwf/0.125deg/1h/forecasts/%Y/%j/ecmwf_%Y%m%d%H%M.nc"
|
|
17
|
+
|
|
18
|
+
era5:
|
|
19
|
+
- name: "era5_0250_1h"
|
|
20
|
+
path: "/home/ref-ecmwf/ERA5/%Y/%m/era_5-copernicus__%Y%m%d.nc"
|
|
21
|
+
|
|
22
|
+
sarwing_luts_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/v1.6/"
|
|
23
|
+
nc_luts_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/nc_luts"
|
|
24
|
+
lut_cmod7_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/v1.6/GMF_cmod7_official/cmod7_and_python_script"
|
|
25
|
+
lut_ms1ahw_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/v1.6/GMF_cmodms1ahw"
|
|
26
|
+
|
|
1
27
|
no_subdir: True
|
|
2
28
|
winddir_convention: "meteorological"
|
|
3
29
|
add_gradientsfeatures: False
|
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
unit_test_s1_product: "./sentinel-1a/L1/IW/S1A_IW_GRDH_1S/2021/252/S1A_IW_GRDH_1SDV_20210909T130650_20210909T130715_039605_04AE83_C34F.SAFE"
|
|
2
|
+
unit_test_rcm_product: "./l1/rcm/rcm-1/sclnd/2023/273/RCM1_OK2767220_PK2769320_1_SCLND_20230930_214014_VV_VH_GRD"
|
|
3
|
+
unit_test_rs2_product: "./L1/VV_VH/2022/247/RS2_OK141302_PK1242223_DK1208537_SCWA_20220904_093402_VV_VH_SGF"
|
|
4
|
+
|
|
5
|
+
masks:
|
|
6
|
+
land:
|
|
7
|
+
- name: "gshhsH"
|
|
8
|
+
path: "/home/loc-datawork-cersat-public/cache/project/sarwing/masks/gshhg-shp-2.3.7/GSHHS_shp/h/GSHHS_h_L1.shp"
|
|
9
|
+
|
|
10
|
+
ancillary_sources:
|
|
11
|
+
ecmwf:
|
|
12
|
+
- name: "ecmwf_0100_1h"
|
|
13
|
+
path: "/home/loc-datawork-cersat-public/provider/ecmwf/forecast/hourly/0100deg/netcdf_light/%Y/%j/ECMWF_FORECAST_0100_%Y%m%d%H%M_10U_10V.nc"
|
|
14
|
+
|
|
15
|
+
- name: "ecmwf_0125_1h"
|
|
16
|
+
path: "/home/loc-datawork-cersat-intranet/project/ecmwf/0.125deg/1h/forecasts/%Y/%j/ecmwf_%Y%m%d%H%M.nc"
|
|
17
|
+
|
|
18
|
+
era5:
|
|
19
|
+
- name: "era5_0250_1h"
|
|
20
|
+
path: "/home/ref-ecmwf/ERA5/%Y/%m/era_5-copernicus__%Y%m%d.nc"
|
|
21
|
+
|
|
22
|
+
sarwing_luts_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/v1.6/"
|
|
23
|
+
nc_luts_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/nc_luts"
|
|
24
|
+
lut_cmod7_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/v1.6/GMF_cmod7_official/cmod7_and_python_script"
|
|
25
|
+
lut_ms1ahw_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/v1.6/GMF_cmodms1ahw"
|
|
26
|
+
|
|
1
27
|
no_subdir: True
|
|
2
28
|
winddir_convention: "meteorological"
|
|
3
29
|
add_gradientsfeatures: True
|
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
unit_test_s1_product: "./sentinel-1a/L1/IW/S1A_IW_GRDH_1S/2021/252/S1A_IW_GRDH_1SDV_20210909T130650_20210909T130715_039605_04AE83_C34F.SAFE"
|
|
2
|
+
unit_test_rcm_product: "./l1/rcm/rcm-1/sclnd/2023/273/RCM1_OK2767220_PK2769320_1_SCLND_20230930_214014_VV_VH_GRD"
|
|
3
|
+
unit_test_rs2_product: "./L1/VV_VH/2022/247/RS2_OK141302_PK1242223_DK1208537_SCWA_20220904_093402_VV_VH_SGF"
|
|
4
|
+
|
|
5
|
+
masks:
|
|
6
|
+
land:
|
|
7
|
+
- name: "gshhsH"
|
|
8
|
+
path: "/home/loc-datawork-cersat-public/cache/project/sarwing/masks/gshhg-shp-2.3.7/GSHHS_shp/h/GSHHS_h_L1.shp"
|
|
9
|
+
|
|
10
|
+
ancillary_sources:
|
|
11
|
+
ecmwf:
|
|
12
|
+
- name: "ecmwf_0100_1h"
|
|
13
|
+
path: "/home/loc-datawork-cersat-public/provider/ecmwf/forecast/hourly/0100deg/netcdf_light/%Y/%j/ECMWF_FORECAST_0100_%Y%m%d%H%M_10U_10V.nc"
|
|
14
|
+
|
|
15
|
+
- name: "ecmwf_0125_1h"
|
|
16
|
+
path: "/home/loc-datawork-cersat-intranet/project/ecmwf/0.125deg/1h/forecasts/%Y/%j/ecmwf_%Y%m%d%H%M.nc"
|
|
17
|
+
|
|
18
|
+
era5:
|
|
19
|
+
- name: "era5_0250_1h"
|
|
20
|
+
path: "/home/ref-ecmwf/ERA5/%Y/%m/era_5-copernicus__%Y%m%d.nc"
|
|
21
|
+
|
|
22
|
+
sarwing_luts_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/v1.6/"
|
|
23
|
+
nc_luts_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/nc_luts"
|
|
24
|
+
lut_cmod7_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/v1.6/GMF_cmod7_official/cmod7_and_python_script"
|
|
25
|
+
lut_ms1ahw_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/v1.6/GMF_cmodms1ahw"
|
|
26
|
+
|
|
1
27
|
no_subdir: True
|
|
2
28
|
winddir_convention: "meteorological"
|
|
3
29
|
add_gradientsfeatures: True
|
|
@@ -110,4 +136,4 @@ RCM:
|
|
|
110
136
|
inc_step: 0.1
|
|
111
137
|
wspd_step: 0.1
|
|
112
138
|
phi_step: 1.0
|
|
113
|
-
resolution: "high"
|
|
139
|
+
resolution: "high"
|
{grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion/config_prod_streaks_nrcsmod.yaml
RENAMED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
unit_test_s1_product: "./sentinel-1a/L1/IW/S1A_IW_GRDH_1S/2021/252/S1A_IW_GRDH_1SDV_20210909T130650_20210909T130715_039605_04AE83_C34F.SAFE"
|
|
2
|
+
unit_test_rcm_product: "./l1/rcm/rcm-1/sclnd/2023/273/RCM1_OK2767220_PK2769320_1_SCLND_20230930_214014_VV_VH_GRD"
|
|
3
|
+
unit_test_rs2_product: "./L1/VV_VH/2022/247/RS2_OK141302_PK1242223_DK1208537_SCWA_20220904_093402_VV_VH_SGF"
|
|
4
|
+
|
|
5
|
+
masks:
|
|
6
|
+
land:
|
|
7
|
+
- name: "gshhsH"
|
|
8
|
+
path: "/home/loc-datawork-cersat-public/cache/project/sarwing/masks/gshhg-shp-2.3.7/GSHHS_shp/h/GSHHS_h_L1.shp"
|
|
9
|
+
|
|
10
|
+
ancillary_sources:
|
|
11
|
+
ecmwf:
|
|
12
|
+
- name: "ecmwf_0100_1h"
|
|
13
|
+
path: "/home/loc-datawork-cersat-public/provider/ecmwf/forecast/hourly/0100deg/netcdf_light/%Y/%j/ECMWF_FORECAST_0100_%Y%m%d%H%M_10U_10V.nc"
|
|
14
|
+
|
|
15
|
+
- name: "ecmwf_0125_1h"
|
|
16
|
+
path: "/home/loc-datawork-cersat-intranet/project/ecmwf/0.125deg/1h/forecasts/%Y/%j/ecmwf_%Y%m%d%H%M.nc"
|
|
17
|
+
|
|
18
|
+
era5:
|
|
19
|
+
- name: "era5_0250_1h"
|
|
20
|
+
path: "/home/ref-ecmwf/ERA5/%Y/%m/era_5-copernicus__%Y%m%d.nc"
|
|
21
|
+
|
|
22
|
+
sarwing_luts_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/v1.6/"
|
|
23
|
+
nc_luts_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/nc_luts"
|
|
24
|
+
lut_cmod7_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/v1.6/GMF_cmod7_official/cmod7_and_python_script"
|
|
25
|
+
lut_ms1ahw_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/v1.6/GMF_cmodms1ahw"
|
|
26
|
+
|
|
1
27
|
no_subdir: True
|
|
2
28
|
winddir_convention: "meteorological"
|
|
3
29
|
add_gradientsfeatures: True
|
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
unit_test_s1_product: "./sentinel-1a/L1/IW/S1A_IW_GRDH_1S/2021/252/S1A_IW_GRDH_1SDV_20210909T130650_20210909T130715_039605_04AE83_C34F.SAFE"
|
|
2
|
+
unit_test_rcm_product: "./l1/rcm/rcm-1/sclnd/2023/273/RCM1_OK2767220_PK2769320_1_SCLND_20230930_214014_VV_VH_GRD"
|
|
3
|
+
unit_test_rs2_product: "./L1/VV_VH/2022/247/RS2_OK141302_PK1242223_DK1208537_SCWA_20220904_093402_VV_VH_SGF"
|
|
4
|
+
|
|
5
|
+
masks:
|
|
6
|
+
land:
|
|
7
|
+
- name: "gshhsH"
|
|
8
|
+
path: "/home/loc-datawork-cersat-public/cache/project/sarwing/masks/gshhg-shp-2.3.7/GSHHS_shp/h/GSHHS_h_L1.shp"
|
|
9
|
+
|
|
10
|
+
ancillary_sources:
|
|
11
|
+
ecmwf:
|
|
12
|
+
- name: "ecmwf_0100_1h"
|
|
13
|
+
path: "/home/loc-datawork-cersat-public/provider/ecmwf/forecast/hourly/0100deg/netcdf_light/%Y/%j/ECMWF_FORECAST_0100_%Y%m%d%H%M_10U_10V.nc"
|
|
14
|
+
|
|
15
|
+
- name: "ecmwf_0125_1h"
|
|
16
|
+
path: "/home/loc-datawork-cersat-intranet/project/ecmwf/0.125deg/1h/forecasts/%Y/%j/ecmwf_%Y%m%d%H%M.nc"
|
|
17
|
+
|
|
18
|
+
era5:
|
|
19
|
+
- name: "era5_0250_1h"
|
|
20
|
+
path: "/home/ref-ecmwf/ERA5/%Y/%m/era_5-copernicus__%Y%m%d.nc"
|
|
21
|
+
|
|
22
|
+
sarwing_luts_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/v1.6/"
|
|
23
|
+
nc_luts_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/nc_luts"
|
|
24
|
+
lut_cmod7_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/v1.6/GMF_cmod7_official/cmod7_and_python_script"
|
|
25
|
+
lut_ms1ahw_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/v1.6/GMF_cmodms1ahw"
|
|
26
|
+
|
|
1
27
|
no_subdir: True
|
|
2
28
|
winddir_convention: "meteorological"
|
|
3
29
|
add_gradientsfeatures: False
|
|
@@ -15,10 +15,9 @@ from scipy.ndimage import binary_dilation
|
|
|
15
15
|
import re
|
|
16
16
|
import os
|
|
17
17
|
import logging
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
|
|
20
20
|
from grdwindinversion.utils import check_incidence_range, get_pol_ratio_name, timing, convert_polarization_name
|
|
21
|
-
from grdwindinversion.load_config import getConf
|
|
22
21
|
os.environ["OMP_NUM_THREADS"] = "1"
|
|
23
22
|
os.environ["OPENBLAS_NUM_THREADS"] = "1"
|
|
24
23
|
os.environ["MKL_NUM_THREADS"] = "1"
|
|
@@ -170,7 +169,7 @@ def getOutputName(
|
|
|
170
169
|
return out_file
|
|
171
170
|
|
|
172
171
|
|
|
173
|
-
def addMasks_toMeta(meta: xsar.BaseMeta) -> dict:
|
|
172
|
+
def addMasks_toMeta(meta: xsar.BaseMeta, conf: dict) -> dict:
|
|
174
173
|
"""
|
|
175
174
|
Add high-resolution masks (land, ice, lakes, etc.) from shapefiles to meta object.
|
|
176
175
|
|
|
@@ -192,6 +191,8 @@ def addMasks_toMeta(meta: xsar.BaseMeta) -> dict:
|
|
|
192
191
|
----------
|
|
193
192
|
meta : xsar.BaseMeta
|
|
194
193
|
Metadata object to add mask features to. Must have a set_mask_feature method.
|
|
194
|
+
conf : dict
|
|
195
|
+
Configuration dictionary containing masks definition
|
|
195
196
|
|
|
196
197
|
Returns
|
|
197
198
|
-------
|
|
@@ -210,7 +211,6 @@ def addMasks_toMeta(meta: xsar.BaseMeta) -> dict:
|
|
|
210
211
|
raise AttributeError(
|
|
211
212
|
f"Meta object of type {type(meta).__name__} must have a 'set_mask_feature' method")
|
|
212
213
|
|
|
213
|
-
conf = getConf()
|
|
214
214
|
masks_by_category = {}
|
|
215
215
|
|
|
216
216
|
# Check for 'masks' key
|
|
@@ -395,7 +395,7 @@ def processLandMask(xr_dataset, dilation_iterations=3, merged_masks=None):
|
|
|
395
395
|
xr_dataset.land_mask.attrs["history"] = new_history
|
|
396
396
|
|
|
397
397
|
|
|
398
|
-
def getAncillary(meta, ancillary_name
|
|
398
|
+
def getAncillary(meta, ancillary_name, conf):
|
|
399
399
|
"""
|
|
400
400
|
Map ancillary wind from "ecmwf" or "era5" or other sources.
|
|
401
401
|
This function is used to check if the model files are available and to map the model to the SAR data.
|
|
@@ -406,6 +406,8 @@ def getAncillary(meta, ancillary_name="ecmwf"):
|
|
|
406
406
|
meta: obj `xsar.BaseMeta` (one of the supported SAR mission)
|
|
407
407
|
ancillary_name: str
|
|
408
408
|
Name of the ancillary source (ecmwf or era5)
|
|
409
|
+
conf: dict
|
|
410
|
+
Configuration dictionary containing ancillary_sources
|
|
409
411
|
|
|
410
412
|
Returns
|
|
411
413
|
-------
|
|
@@ -414,8 +416,7 @@ def getAncillary(meta, ancillary_name="ecmwf"):
|
|
|
414
416
|
- map_model (dict): mapping of model variables to SAR data
|
|
415
417
|
- metadata (dict): ancillary metadata with 'source' and 'source_path' keys
|
|
416
418
|
"""
|
|
417
|
-
logging.debug("conf: %s",
|
|
418
|
-
conf = getConf()
|
|
419
|
+
logging.debug("conf: %s", conf)
|
|
419
420
|
if 'ancillary_sources' not in conf:
|
|
420
421
|
raise ValueError("Configuration must contain 'ancillary_sources'")
|
|
421
422
|
|
|
@@ -465,7 +466,7 @@ def getAncillary(meta, ancillary_name="ecmwf"):
|
|
|
465
466
|
# Log selection
|
|
466
467
|
if len(ancillary_sources) > 1:
|
|
467
468
|
logging.info(
|
|
468
|
-
f"Multiple {ancillary_name} models configured. Using {selected_name} (priority order)")
|
|
469
|
+
f"Multiple {ancillary_name} models configured. Using {selected_name} (with respect to priority order)")
|
|
469
470
|
else:
|
|
470
471
|
logging.info(
|
|
471
472
|
f"Only one {ancillary_name} model configured: using {selected_name}")
|
|
@@ -1002,6 +1003,11 @@ def preprocess(
|
|
|
1002
1003
|
if os.path.exists(config_path):
|
|
1003
1004
|
with open(config_path, "r") as file:
|
|
1004
1005
|
config_base = yaml.load(file, Loader=yaml.FullLoader)
|
|
1006
|
+
|
|
1007
|
+
# Validate configuration structure
|
|
1008
|
+
from grdwindinversion.utils import test_config
|
|
1009
|
+
test_config(config_base)
|
|
1010
|
+
|
|
1005
1011
|
try:
|
|
1006
1012
|
# check if sensor is in the config
|
|
1007
1013
|
config = config_base[sensor]
|
|
@@ -1015,7 +1021,7 @@ def preprocess(
|
|
|
1015
1021
|
meta = fct_meta(filename)
|
|
1016
1022
|
|
|
1017
1023
|
# Add masks to meta if configured (land, ice, lakes, etc.)
|
|
1018
|
-
masks_by_category = addMasks_toMeta(meta)
|
|
1024
|
+
masks_by_category = addMasks_toMeta(meta, config_base)
|
|
1019
1025
|
|
|
1020
1026
|
# si une des deux n'est pas VV VH HH HV on ne fait rien
|
|
1021
1027
|
if not all([pol in ["VV", "VH", "HH", "HV"] for pol in meta.pols.split(" ")]):
|
|
@@ -1086,7 +1092,8 @@ def preprocess(
|
|
|
1086
1092
|
raise FileExistsError("outfile %s already exists" % out_file)
|
|
1087
1093
|
|
|
1088
1094
|
ancillary_name = config["ancillary"]
|
|
1089
|
-
map_model, ancillary_metadata = getAncillary(
|
|
1095
|
+
map_model, ancillary_metadata = getAncillary(
|
|
1096
|
+
meta, ancillary_name, config_base)
|
|
1090
1097
|
if map_model is None:
|
|
1091
1098
|
raise Exception(
|
|
1092
1099
|
f"the weather model is not set `map_model` is None -> you probably don't have access to {ancillary_name} archive"
|
|
@@ -1212,10 +1219,10 @@ def preprocess(
|
|
|
1212
1219
|
nc_luts = [x for x in [model_co, model_cross] if x.startswith("nc_lut")]
|
|
1213
1220
|
|
|
1214
1221
|
if len(nc_luts) > 0:
|
|
1215
|
-
windspeed.register_nc_luts(
|
|
1222
|
+
windspeed.register_nc_luts(config_base["nc_luts_path"])
|
|
1216
1223
|
|
|
1217
1224
|
if model_co == "gmf_cmod7":
|
|
1218
|
-
windspeed.register_cmod7(
|
|
1225
|
+
windspeed.register_cmod7(config_base["lut_cmod7_path"])
|
|
1219
1226
|
# Step 2 - clean and prepare dataset
|
|
1220
1227
|
|
|
1221
1228
|
# variables to not keep in the L2
|
|
@@ -1275,8 +1282,7 @@ def preprocess(
|
|
|
1275
1282
|
xr_dataset.offboresight.attrs["standard_name"] = "offboresight"
|
|
1276
1283
|
|
|
1277
1284
|
# merge land masks
|
|
1278
|
-
|
|
1279
|
-
land_mask_strategy = conf.get("LAND_MASK_STRATEGY", "merge")
|
|
1285
|
+
land_mask_strategy = config_base.get("LAND_MASK_STRATEGY", "merge")
|
|
1280
1286
|
logging.info(f"land_mask_strategy = {land_mask_strategy}")
|
|
1281
1287
|
|
|
1282
1288
|
# Store masks_by_category in config for later cleanup
|
|
@@ -1292,11 +1298,10 @@ def preprocess(
|
|
|
1292
1298
|
processLandMask(xr_dataset, dilation_iterations=3,
|
|
1293
1299
|
merged_masks=merged_land_masks)
|
|
1294
1300
|
|
|
1295
|
-
logging.debug("mask is a copy of land_mask")
|
|
1296
|
-
|
|
1297
1301
|
# Create main mask from land_mask
|
|
1298
1302
|
# For now, mask uses the same values as land_mask
|
|
1299
1303
|
# Can be extended later to include ice (value 3) and other categories
|
|
1304
|
+
logging.debug("mask is a copy of land_mask")
|
|
1300
1305
|
xr_dataset["mask"] = xr.DataArray(xr_dataset.land_mask)
|
|
1301
1306
|
xr_dataset.mask.attrs = {}
|
|
1302
1307
|
xr_dataset.mask.attrs["long_name"] = "Mask of data"
|
|
@@ -1709,8 +1714,9 @@ def makeL2(
|
|
|
1709
1714
|
config["return_status"] = 99
|
|
1710
1715
|
|
|
1711
1716
|
if dsig_cr_step == "nrcs":
|
|
1712
|
-
|
|
1713
|
-
|
|
1717
|
+
if dual_pol:
|
|
1718
|
+
logging.info(
|
|
1719
|
+
"dsig_cr_step is nrcs : polarization are mixed at cost function step")
|
|
1714
1720
|
wind_co, wind_dual, windspeed_cr = inverse(
|
|
1715
1721
|
dual_pol,
|
|
1716
1722
|
inc=xr_dataset["incidence"],
|
|
@@ -1723,13 +1729,17 @@ def makeL2(
|
|
|
1723
1729
|
**kwargs,
|
|
1724
1730
|
)
|
|
1725
1731
|
elif dsig_cr_step == "wspd":
|
|
1726
|
-
|
|
1727
|
-
|
|
1732
|
+
if dual_pol:
|
|
1733
|
+
logging.info(
|
|
1734
|
+
"dsig_cr_step is wspd : polarization are mixed at winds speed step")
|
|
1728
1735
|
|
|
1729
|
-
if
|
|
1730
|
-
|
|
1736
|
+
if dual_pol:
|
|
1737
|
+
if apply_flattening:
|
|
1738
|
+
nesz_cross = xr_dataset["nesz_cross_flattened"]
|
|
1739
|
+
else:
|
|
1740
|
+
nesz_cross = xr_dataset.nesz.sel(pol=crosspol)
|
|
1731
1741
|
else:
|
|
1732
|
-
nesz_cross =
|
|
1742
|
+
nesz_cross = None
|
|
1733
1743
|
|
|
1734
1744
|
wind_co, wind_dual, windspeed_cr, alpha = inverse_dsig_wspd(
|
|
1735
1745
|
dual_pol,
|
|
@@ -1743,10 +1753,12 @@ def makeL2(
|
|
|
1743
1753
|
model_cross=model_cross,
|
|
1744
1754
|
**kwargs
|
|
1745
1755
|
)
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1756
|
+
if dual_pol and alpha is not None:
|
|
1757
|
+
xr_dataset["alpha"] = xr.DataArray(
|
|
1758
|
+
data=alpha, dims=xr_dataset["incidence"].dims, coords=xr_dataset["incidence"].coords)
|
|
1759
|
+
xr_dataset["alpha"].attrs["apply_flattening"] = str(
|
|
1760
|
+
apply_flattening)
|
|
1761
|
+
xr_dataset["alpha"].attrs["comments"] = "alpha used to ponderate copol and crosspol. this ponderation is done will combining wind speeds."
|
|
1750
1762
|
|
|
1751
1763
|
else:
|
|
1752
1764
|
raise ValueError(
|
|
@@ -20,7 +20,6 @@ def processor_starting_point():
|
|
|
20
20
|
|
|
21
21
|
from grdwindinversion.inversion import makeL2
|
|
22
22
|
from grdwindinversion.utils_memory import get_memory_usage
|
|
23
|
-
from grdwindinversion.load_config import config_path
|
|
24
23
|
import grdwindinversion
|
|
25
24
|
|
|
26
25
|
parser = argparse.ArgumentParser(
|
|
@@ -68,8 +67,6 @@ def processor_starting_point():
|
|
|
68
67
|
)
|
|
69
68
|
t0 = time.time()
|
|
70
69
|
|
|
71
|
-
logging.info("config path: %s", config_path)
|
|
72
|
-
|
|
73
70
|
input_file = args.input_file.rstrip("/")
|
|
74
71
|
logging.info("input file: %s", input_file)
|
|
75
72
|
|
|
@@ -154,3 +154,106 @@ def timing(logger=logger.debug):
|
|
|
154
154
|
return wrapper
|
|
155
155
|
|
|
156
156
|
return decorator
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def test_config(config):
|
|
160
|
+
"""
|
|
161
|
+
Validate configuration structure.
|
|
162
|
+
|
|
163
|
+
Checks that the configuration contains all required fields:
|
|
164
|
+
- ancillary_sources (with ecmwf or era5)
|
|
165
|
+
- nc_luts_path (required)
|
|
166
|
+
- lut_cmod7_path (optional - required only if using gmf_cmod7)
|
|
167
|
+
- lut_ms1ahw_path (optional - required only if using gmf_cmodms1ahw)
|
|
168
|
+
- masks (optional)
|
|
169
|
+
|
|
170
|
+
Note: If you use predefined LUTs (gmf_cmod7, gmf_cmodms1ahw, etc.),
|
|
171
|
+
they must be loaded with the corresponding path keywords:
|
|
172
|
+
- gmf_cmod7 requires lut_cmod7_path
|
|
173
|
+
- gmf_cmodms1ahw requires lut_ms1ahw_path
|
|
174
|
+
|
|
175
|
+
Parameters
|
|
176
|
+
----------
|
|
177
|
+
config : dict
|
|
178
|
+
Configuration dictionary to validate
|
|
179
|
+
|
|
180
|
+
Raises
|
|
181
|
+
------
|
|
182
|
+
ValueError
|
|
183
|
+
If configuration is missing required fields or has invalid structure
|
|
184
|
+
"""
|
|
185
|
+
# Check ancillary_sources
|
|
186
|
+
if 'ancillary_sources' not in config:
|
|
187
|
+
raise ValueError("Configuration must contain 'ancillary_sources'")
|
|
188
|
+
|
|
189
|
+
if not isinstance(config['ancillary_sources'], dict):
|
|
190
|
+
raise ValueError("'ancillary_sources' must be a dictionary")
|
|
191
|
+
|
|
192
|
+
if not config['ancillary_sources']:
|
|
193
|
+
raise ValueError("'ancillary_sources' must not be empty")
|
|
194
|
+
|
|
195
|
+
# Check that at least ecmwf or era5 is configured
|
|
196
|
+
has_ecmwf = 'ecmwf' in config['ancillary_sources']
|
|
197
|
+
has_era5 = 'era5' in config['ancillary_sources']
|
|
198
|
+
if not (has_ecmwf or has_era5):
|
|
199
|
+
raise ValueError(
|
|
200
|
+
"'ancillary_sources' must contain at least 'ecmwf' or 'era5'")
|
|
201
|
+
|
|
202
|
+
# Validate ancillary sources structure
|
|
203
|
+
for ancillary_type, sources in config['ancillary_sources'].items():
|
|
204
|
+
if not isinstance(sources, list):
|
|
205
|
+
raise ValueError(
|
|
206
|
+
f"'ancillary_sources.{ancillary_type}' must be a list")
|
|
207
|
+
if not sources:
|
|
208
|
+
raise ValueError(
|
|
209
|
+
f"'ancillary_sources.{ancillary_type}' must not be empty")
|
|
210
|
+
|
|
211
|
+
for source in sources:
|
|
212
|
+
if 'name' not in source:
|
|
213
|
+
raise ValueError(
|
|
214
|
+
f"Each source in 'ancillary_sources.{ancillary_type}' must have a 'name' field")
|
|
215
|
+
if 'path' not in source:
|
|
216
|
+
raise ValueError(
|
|
217
|
+
f"Each source in 'ancillary_sources.{ancillary_type}' must have a 'path' field")
|
|
218
|
+
# Check LUT paths
|
|
219
|
+
if 'nc_luts_path' not in config:
|
|
220
|
+
raise ValueError("Configuration must contain 'nc_luts_path'")
|
|
221
|
+
else:
|
|
222
|
+
logger.debug(f"nc_luts_path found: {config['nc_luts_path']}")
|
|
223
|
+
|
|
224
|
+
# Optional LUT paths (only needed if using specific GMFs)
|
|
225
|
+
if 'lut_cmod7_path' in config:
|
|
226
|
+
logger.debug(f"lut_cmod7_path found: {config['lut_cmod7_path']}")
|
|
227
|
+
if 'lut_ms1ahw_path' in config:
|
|
228
|
+
logger.debug(f"lut_ms1ahw_path found: {config['lut_ms1ahw_path']}")
|
|
229
|
+
|
|
230
|
+
# Validate masks structure if present (optional)
|
|
231
|
+
if 'masks' in config:
|
|
232
|
+
if not isinstance(config['masks'], dict):
|
|
233
|
+
raise ValueError("'masks' must be a dictionary")
|
|
234
|
+
|
|
235
|
+
for category, mask_list in config['masks'].items():
|
|
236
|
+
if not isinstance(mask_list, list):
|
|
237
|
+
raise ValueError(f"'masks.{category}' must be a list")
|
|
238
|
+
|
|
239
|
+
for mask in mask_list:
|
|
240
|
+
if 'name' not in mask:
|
|
241
|
+
raise ValueError(
|
|
242
|
+
f"Each mask in 'masks.{category}' must have a 'name' field")
|
|
243
|
+
if 'path' not in mask:
|
|
244
|
+
raise ValueError(
|
|
245
|
+
f"Each mask in 'masks.{category}' must have a 'path' field")
|
|
246
|
+
|
|
247
|
+
logger.debug(f"Masks configured: {list(config['masks'].keys())}")
|
|
248
|
+
else:
|
|
249
|
+
logger.info("No masks configured (optional)")
|
|
250
|
+
|
|
251
|
+
# Check which sensors are configured
|
|
252
|
+
supported_sensors = ['S1A', 'S1B', 'S1C', 'S1D', 'RS2', 'RCM']
|
|
253
|
+
configured_sensors = [sensor for sensor in supported_sensors if sensor in config]
|
|
254
|
+
if configured_sensors:
|
|
255
|
+
logger.info(f"Sensors configured: {', '.join(configured_sensors)}")
|
|
256
|
+
else:
|
|
257
|
+
logger.warning("No sensors configured - at least one sensor (S1A, S1B, S1C, S1D, RS2, RCM) should be present")
|
|
258
|
+
|
|
259
|
+
logger.info("Configuration validation passed")
|
|
@@ -41,10 +41,8 @@ grdwindinversion/config_prod_recal_streaks_nrcsmod.yaml
|
|
|
41
41
|
grdwindinversion/config_prod_streaks.yaml
|
|
42
42
|
grdwindinversion/config_prod_streaks_nrcsmod.yaml
|
|
43
43
|
grdwindinversion/config_prod_v3.yaml
|
|
44
|
-
grdwindinversion/data_config.yaml
|
|
45
44
|
grdwindinversion/gradientFeatures.py
|
|
46
45
|
grdwindinversion/inversion.py
|
|
47
|
-
grdwindinversion/load_config.py
|
|
48
46
|
grdwindinversion/main.py
|
|
49
47
|
grdwindinversion/utils.py
|
|
50
48
|
grdwindinversion/utils_memory.py
|
|
@@ -57,12 +55,14 @@ grdwindinversion.egg-info/top_level.txt
|
|
|
57
55
|
grdwindinversion/.github/ISSUE_TEMPLATE.md
|
|
58
56
|
recipe/meta.yaml
|
|
59
57
|
tests/__init__.py
|
|
60
|
-
tests/
|
|
61
|
-
tests/
|
|
62
|
-
tests/
|
|
63
|
-
tests/
|
|
64
|
-
tests/
|
|
65
|
-
tests/
|
|
66
|
-
tests/
|
|
67
|
-
tests/
|
|
68
|
-
tests/
|
|
58
|
+
tests/ci/__init__.py
|
|
59
|
+
tests/ci/config_test.yaml
|
|
60
|
+
tests/ci/data_config_ci.yaml
|
|
61
|
+
tests/ci/test_grdwindinversion_ci.py
|
|
62
|
+
tests/unit/__init__.py
|
|
63
|
+
tests/unit/listing_rcm_safe.txt
|
|
64
|
+
tests/unit/test_ancillary.py
|
|
65
|
+
tests/unit/test_config.py
|
|
66
|
+
tests/unit/test_getOutputName.py
|
|
67
|
+
tests/unit/test_mask_functions.py
|
|
68
|
+
tests/unit/test_simple_functions.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# CI tests package
|
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
unit_test_s1_product: "./test_data/L1/S1A_IW_GRDH_1SDV_20210909T130650_20210909T130715_039605_04AE83_C34F.SAFE"
|
|
2
|
+
unit_test_rcm_product: "./test_data/L1/RCM1_OK2767220_PK2769320_1_SCLND_20230930_214014_VV_VH_GRD"
|
|
3
|
+
unit_test_rs2_product: "./test_data/L1/RS2_OK141302_PK1242223_DK1208537_SCWA_20220904_093402_VV_VH_SGF"
|
|
4
|
+
|
|
5
|
+
masks:
|
|
6
|
+
land:
|
|
7
|
+
- name: "gshhg"
|
|
8
|
+
path: "./test_data/masks/gshhg-shp-2.3.7-h/GSHHS_shp/h/GSHHS_h_L1.shp"
|
|
9
|
+
|
|
10
|
+
ancillary_sources:
|
|
11
|
+
ecmwf:
|
|
12
|
+
- name: "ecmwf_0100_1h"
|
|
13
|
+
path: "./test_data/ECMWF/forecast/hourly/0100deg/netcdf_light/%Y/%j/ECMWF_FORECAST_0100_%Y%m%d%H%M_10U_10V.nc"
|
|
14
|
+
- name: "ecmwf_0125_1h"
|
|
15
|
+
path: "./test_data/ECMWF/0.125deg/1h/forecasts/%Y/%j/ecmwf_%Y%m%d%H%M.nc"
|
|
16
|
+
era5:
|
|
17
|
+
- name: "era5_0250_1h"
|
|
18
|
+
path: "./test_data/ERA5/%Y/%m/era_5-copernicus__%Y%m%d.nc"
|
|
19
|
+
|
|
20
|
+
nc_luts_path: "./test_data/GMFS/nc_luts"
|
|
21
|
+
lut_cmod7_path: "./test_data/GMFS/v1.6/GMF_cmod7_official/cmod7_and_python_script"
|
|
22
|
+
lut_ms1ahw_path: "./test_data/GMFS/v1.6/GMF_cmodms1ahw"
|
|
23
|
+
|
|
1
24
|
no_subdir: True
|
|
2
25
|
winddir_convention: "meteorological"
|
|
3
26
|
add_gradientsfeatures: False
|
|
@@ -111,7 +134,3 @@ RCM:
|
|
|
111
134
|
wspd_step: 0.1
|
|
112
135
|
phi_step: 1.0
|
|
113
136
|
resolution: "high"
|
|
114
|
-
|
|
115
|
-
unit_test_s1_product: "./test_data/L1/S1A_IW_GRDH_1SDV_20210909T130650_20210909T130715_039605_04AE83_C34F.SAFE"
|
|
116
|
-
unit_test_rcm_product: "./test_data/L1/RCM1_OK2767220_PK2769320_1_SCLND_20230930_214014_VV_VH_GRD"
|
|
117
|
-
unit_test_rs2_product: "./test_data/L1/RS2_OK141302_PK1242223_DK1208537_SCWA_20220904_093402_VV_VH_SGF"
|
{grdwindinversion-1.0.0/tests → grdwindinversion-1.0.1/tests/ci}/test_grdwindinversion_ci.py
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
2
|
import os
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
import yaml
|
|
4
5
|
from grdwindinversion.inversion import makeL2
|
|
5
6
|
import xsar
|
|
6
|
-
from grdwindinversion.load_config import getConf
|
|
7
7
|
|
|
8
8
|
# What must be done by the tests:
|
|
9
9
|
# - Download L1 data
|
|
@@ -15,13 +15,26 @@ from grdwindinversion.load_config import getConf
|
|
|
15
15
|
# - For recal : download auxiliary files
|
|
16
16
|
#
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
rcm_path = getConf()['unit_test_rcm_product']
|
|
20
|
-
rs2_path = getConf()['unit_test_rs2_product']
|
|
21
|
-
print('S1_path', S1_path)
|
|
18
|
+
|
|
22
19
|
|
|
23
20
|
|
|
24
21
|
def test_makeL2_generation():
|
|
22
|
+
|
|
23
|
+
outdir = "./out_test_data"
|
|
24
|
+
os.makedirs(outdir, exist_ok=True)
|
|
25
|
+
|
|
26
|
+
config_dir = os.path.dirname(__file__)
|
|
27
|
+
config_path = os.path.join(config_dir, "config_test.yaml")
|
|
28
|
+
|
|
29
|
+
# Load config to get test product paths
|
|
30
|
+
with open(config_path, 'r') as f:
|
|
31
|
+
config = yaml.load(f, Loader=yaml.FullLoader)
|
|
32
|
+
|
|
33
|
+
S1_path = config['unit_test_s1_product']
|
|
34
|
+
rcm_path = config['unit_test_rcm_product']
|
|
35
|
+
rs2_path = config['unit_test_rs2_product']
|
|
36
|
+
print('S1_path', S1_path)
|
|
37
|
+
|
|
25
38
|
l1_files = [
|
|
26
39
|
S1_path,
|
|
27
40
|
rcm_path,
|
|
@@ -32,11 +45,7 @@ def test_makeL2_generation():
|
|
|
32
45
|
# "/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"
|
|
33
46
|
# ]
|
|
34
47
|
|
|
35
|
-
outdir = "./out_test_data"
|
|
36
|
-
os.makedirs(outdir, exist_ok=True)
|
|
37
48
|
|
|
38
|
-
config_dir = os.path.dirname(__file__)
|
|
39
|
-
config_path = os.path.join(config_dir, "config_test.yaml")
|
|
40
49
|
|
|
41
50
|
for f in l1_files:
|
|
42
51
|
# Run the makeL2 function
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Unit tests package
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
import unittest
|
|
3
|
-
from unittest.mock import Mock
|
|
3
|
+
from unittest.mock import Mock
|
|
4
4
|
import pandas as pd
|
|
5
5
|
import tempfile
|
|
6
6
|
import os
|
|
@@ -19,13 +19,12 @@ class TestGetAncillary(unittest.TestCase):
|
|
|
19
19
|
self.mock_meta.rasters = pd.DataFrame(
|
|
20
20
|
columns=['get_function', 'resource'])
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
def test_single_ecmwf_0100_1h_model(self, mock_get_conf):
|
|
22
|
+
def test_single_ecmwf_0100_1h_model(self):
|
|
24
23
|
"""
|
|
25
24
|
When only ecmwf_0100_1h is configured,
|
|
26
25
|
function should work without requiring ecmwf_0125_1h
|
|
27
26
|
"""
|
|
28
|
-
|
|
27
|
+
conf = {
|
|
29
28
|
'ancillary_sources': {
|
|
30
29
|
'ecmwf': [
|
|
31
30
|
{'name': 'ecmwf_0100_1h', 'path': '/path/to/ecmwf_0100'}
|
|
@@ -47,19 +46,18 @@ class TestGetAncillary(unittest.TestCase):
|
|
|
47
46
|
|
|
48
47
|
try:
|
|
49
48
|
map_model, metadata = getAncillary(
|
|
50
|
-
self.mock_meta, ancillary_name='ecmwf')
|
|
49
|
+
self.mock_meta, ancillary_name='ecmwf', conf=conf)
|
|
51
50
|
# Should not raise error
|
|
52
51
|
assert True
|
|
53
52
|
except (KeyError, ValueError) as e:
|
|
54
53
|
pytest.fail(f"Should handle single model, but raised error: {e}")
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
def test_single_ecmwf_0125_1h_model(self, mock_get_conf):
|
|
55
|
+
def test_single_ecmwf_0125_1h_model(self):
|
|
58
56
|
"""
|
|
59
57
|
When only ecmwf_0125_1h is configured,
|
|
60
58
|
function should work without requiring ecmwf_0100_1h
|
|
61
59
|
"""
|
|
62
|
-
|
|
60
|
+
conf = {
|
|
63
61
|
'ancillary_sources': {
|
|
64
62
|
'ecmwf': [
|
|
65
63
|
{'name': 'ecmwf_0125_1h', 'path': '/path/to/ecmwf_0125'}
|
|
@@ -81,14 +79,13 @@ class TestGetAncillary(unittest.TestCase):
|
|
|
81
79
|
|
|
82
80
|
try:
|
|
83
81
|
map_model, metadata = getAncillary(
|
|
84
|
-
self.mock_meta, ancillary_name='ecmwf')
|
|
82
|
+
self.mock_meta, ancillary_name='ecmwf', conf=conf)
|
|
85
83
|
# Should not raise error
|
|
86
84
|
assert True
|
|
87
85
|
except (KeyError, ValueError) as e:
|
|
88
86
|
pytest.fail(f"Should handle single model, but raised error: {e}")
|
|
89
87
|
|
|
90
|
-
|
|
91
|
-
def test_both_models_priority_ecmwf_0100_1h(self, mock_get_conf):
|
|
88
|
+
def test_both_models_priority_ecmwf_0100_1h(self):
|
|
92
89
|
"""
|
|
93
90
|
When both models are configured and both files exist on disk,
|
|
94
91
|
ecmwf_0100_1h should be selected (more recent and precise)
|
|
@@ -101,7 +98,7 @@ class TestGetAncillary(unittest.TestCase):
|
|
|
101
98
|
|
|
102
99
|
try:
|
|
103
100
|
# Configure both models
|
|
104
|
-
|
|
101
|
+
conf = {
|
|
105
102
|
'ancillary_sources': {
|
|
106
103
|
'ecmwf': [
|
|
107
104
|
{'name': 'ecmwf_0100_1h', 'path': '/path/to/ecmwf_0100'},
|
|
@@ -127,7 +124,7 @@ class TestGetAncillary(unittest.TestCase):
|
|
|
127
124
|
|
|
128
125
|
# Call the function
|
|
129
126
|
map_model, metadata = getAncillary(
|
|
130
|
-
self.mock_meta, ancillary_name='ecmwf')
|
|
127
|
+
self.mock_meta, ancillary_name='ecmwf', conf=conf)
|
|
131
128
|
|
|
132
129
|
# Verify that ecmwf_0100_1h is selected (not ecmwf_0125_1h)
|
|
133
130
|
assert map_model is not None, "map_model should not be None"
|
|
@@ -148,13 +145,12 @@ class TestGetAncillary(unittest.TestCase):
|
|
|
148
145
|
if os.path.exists(file_0125):
|
|
149
146
|
os.remove(file_0125)
|
|
150
147
|
|
|
151
|
-
|
|
152
|
-
def test_era5_model(self, mock_get_conf):
|
|
148
|
+
def test_era5_model(self):
|
|
153
149
|
"""
|
|
154
150
|
When era5_0250_1h is configured,
|
|
155
151
|
function should work correctly
|
|
156
152
|
"""
|
|
157
|
-
|
|
153
|
+
conf = {
|
|
158
154
|
'ancillary_sources': {
|
|
159
155
|
'era5': [
|
|
160
156
|
{'name': 'era5_0250_1h', 'path': '/path/to/era5_0250'}
|
|
@@ -178,7 +174,7 @@ class TestGetAncillary(unittest.TestCase):
|
|
|
178
174
|
|
|
179
175
|
# Call the function
|
|
180
176
|
map_model, metadata = getAncillary(
|
|
181
|
-
self.mock_meta, ancillary_name='era5')
|
|
177
|
+
self.mock_meta, ancillary_name='era5', conf=conf)
|
|
182
178
|
|
|
183
179
|
# Verify ERA5 is selected
|
|
184
180
|
assert map_model is not None, "map_model should not be None"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import unittest
|
|
2
2
|
import yaml
|
|
3
3
|
import os
|
|
4
|
-
|
|
4
|
+
import grdwindinversion
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class TestConfigStructure(unittest.TestCase):
|
|
@@ -9,7 +9,13 @@ class TestConfigStructure(unittest.TestCase):
|
|
|
9
9
|
|
|
10
10
|
def setUp(self):
|
|
11
11
|
"""Load configuration for testing."""
|
|
12
|
-
|
|
12
|
+
# Load config_prod_v3.yaml as an example of the complete config format
|
|
13
|
+
config_path = os.path.join(
|
|
14
|
+
os.path.dirname(grdwindinversion.__file__),
|
|
15
|
+
"config_prod_v3.yaml"
|
|
16
|
+
)
|
|
17
|
+
with open(config_path, 'r') as f:
|
|
18
|
+
self.config = yaml.safe_load(f)
|
|
13
19
|
|
|
14
20
|
def test_ancillary_sources_exists(self):
|
|
15
21
|
"""Test that ancillary_sources exists in configuration (mandatory)."""
|
|
@@ -82,29 +88,27 @@ class TestConfigStructure(unittest.TestCase):
|
|
|
82
88
|
self.assertIsInstance(source['path'], str,
|
|
83
89
|
f"Mask source path in '{category}' must be a string")
|
|
84
90
|
|
|
85
|
-
def
|
|
86
|
-
"""Test that the
|
|
87
|
-
import grdwindinversion
|
|
91
|
+
def test_config_prod_v3_file_exists(self):
|
|
92
|
+
"""Test that the config_prod_v3.yaml example file exists in the package."""
|
|
88
93
|
config_path = os.path.join(
|
|
89
94
|
os.path.dirname(grdwindinversion.__file__),
|
|
90
|
-
'
|
|
95
|
+
'config_prod_v3.yaml'
|
|
91
96
|
)
|
|
92
97
|
self.assertTrue(os.path.exists(config_path),
|
|
93
|
-
f"
|
|
98
|
+
f"Example config file should exist at {config_path}")
|
|
94
99
|
|
|
95
|
-
def
|
|
96
|
-
"""Test that the
|
|
97
|
-
import grdwindinversion
|
|
100
|
+
def test_config_prod_v3_valid_yaml(self):
|
|
101
|
+
"""Test that the config_prod_v3.yaml file is valid YAML."""
|
|
98
102
|
config_path = os.path.join(
|
|
99
103
|
os.path.dirname(grdwindinversion.__file__),
|
|
100
|
-
'
|
|
104
|
+
'config_prod_v3.yaml'
|
|
101
105
|
)
|
|
102
106
|
|
|
103
107
|
with open(config_path, 'r') as f:
|
|
104
108
|
try:
|
|
105
109
|
yaml.safe_load(f)
|
|
106
110
|
except yaml.YAMLError as e:
|
|
107
|
-
self.fail(f"
|
|
111
|
+
self.fail(f"Config file is not valid YAML: {e}")
|
|
108
112
|
|
|
109
113
|
|
|
110
114
|
if __name__ == '__main__':
|
|
@@ -53,10 +53,9 @@ class TestMergeLandMasks:
|
|
|
53
53
|
class TestAddMasksToMeta:
|
|
54
54
|
"""Core tests for addMasks_toMeta function"""
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
def test_add_single_land_mask(self, mock_get_config):
|
|
56
|
+
def test_add_single_land_mask(self):
|
|
58
57
|
"""Test the main use case: adding one mask"""
|
|
59
|
-
|
|
58
|
+
conf = {
|
|
60
59
|
'masks': {
|
|
61
60
|
'land': [
|
|
62
61
|
{'name': 'gshhsH', 'path': '/path/to/mask.shp'}
|
|
@@ -65,7 +64,7 @@ class TestAddMasksToMeta:
|
|
|
65
64
|
}
|
|
66
65
|
mock_meta = Mock()
|
|
67
66
|
|
|
68
|
-
result = addMasks_toMeta(mock_meta)
|
|
67
|
+
result = addMasks_toMeta(mock_meta, conf)
|
|
69
68
|
|
|
70
69
|
assert result == {'land': ['gshhsH']}
|
|
71
70
|
mock_meta.set_mask_feature.assert_called_once_with(
|
|
@@ -74,14 +73,14 @@ class TestAddMasksToMeta:
|
|
|
74
73
|
def test_add_mask_without_set_mask_feature_method(self):
|
|
75
74
|
"""Test validation: meta must have set_mask_feature method"""
|
|
76
75
|
mock_meta = Mock(spec=[])
|
|
76
|
+
conf = {}
|
|
77
77
|
|
|
78
78
|
with pytest.raises(AttributeError, match="must have a 'set_mask_feature' method"):
|
|
79
|
-
addMasks_toMeta(mock_meta)
|
|
79
|
+
addMasks_toMeta(mock_meta, conf)
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
def test_add_mask_with_file_error(self, mock_get_config):
|
|
81
|
+
def test_add_mask_with_file_error(self):
|
|
83
82
|
"""Test resilience: file errors are caught without crashing"""
|
|
84
|
-
|
|
83
|
+
conf = {
|
|
85
84
|
'masks': {
|
|
86
85
|
'land': [
|
|
87
86
|
{'name': 'bad_mask', 'path': '/nonexistent.shp'}
|
|
@@ -92,7 +91,7 @@ class TestAddMasksToMeta:
|
|
|
92
91
|
mock_meta.set_mask_feature.side_effect = FileNotFoundError(
|
|
93
92
|
"File not found")
|
|
94
93
|
|
|
95
|
-
result = addMasks_toMeta(mock_meta)
|
|
94
|
+
result = addMasks_toMeta(mock_meta, conf)
|
|
96
95
|
|
|
97
96
|
# Should not crash, just skip the failed mask
|
|
98
97
|
assert result == {'land': []}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
unit_test_s1_product: "./sentinel-1a/L1/IW/S1A_IW_GRDH_1S/2021/252/S1A_IW_GRDH_1SDV_20210909T130650_20210909T130715_039605_04AE83_C34F.SAFE"
|
|
2
|
-
unit_test_rcm_product: "./l1/rcm/rcm-1/sclnd/2023/273/RCM1_OK2767220_PK2769320_1_SCLND_20230930_214014_VV_VH_GRD"
|
|
3
|
-
unit_test_rs2_product: "./L1/VV_VH/2022/247/RS2_OK141302_PK1242223_DK1208537_SCWA_20220904_093402_VV_VH_SGF"
|
|
4
|
-
|
|
5
|
-
masks:
|
|
6
|
-
land:
|
|
7
|
-
- name: "gshhsH"
|
|
8
|
-
path: "/home/vincelhx/Téléchargements/gshhg-shp-2.3.7/GSHHS_shp/h/GSHHS_h_L1.shp"
|
|
9
|
-
|
|
10
|
-
ancillary_sources:
|
|
11
|
-
ecmwf:
|
|
12
|
-
- name: "ecmwf_0100_1h"
|
|
13
|
-
path: "/home/loc-datawork-cersat-public/provider/ecmwf/forecast/hourly/0100deg/netcdf_light/%Y/%j/ECMWF_FORECAST_0100_%Y%m%d%H%M_10U_10V.nc"
|
|
14
|
-
|
|
15
|
-
- name: "ecmwf_0125_1h"
|
|
16
|
-
path: "/home/loc-datawork-cersat-intranet/project/ecmwf/0.125deg/1h/forecasts/%Y/%j/ecmwf_%Y%m%d%H%M.nc"
|
|
17
|
-
|
|
18
|
-
era5:
|
|
19
|
-
- name: "era5_0250_1h"
|
|
20
|
-
path: "/home/ref-ecmwf/ERA5/%Y/%m/era_5-copernicus__%Y%m%d.nc"
|
|
21
|
-
|
|
22
|
-
sarwing_luts_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/v1.6/"
|
|
23
|
-
nc_luts_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/nc_luts"
|
|
24
|
-
lut_cmod7_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/v1.6/GMF_cmod7_official/cmod7_and_python_script"
|
|
25
|
-
lut_ms1ahw_path: "/home/loc-datawork-cersat-public/cache/project/sarwing/GMFS/v1.6/GMF_cmodms1ahw"
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
from yaml import load
|
|
2
|
-
import logging
|
|
3
|
-
import os
|
|
4
|
-
import grdwindinversion
|
|
5
|
-
from yaml import CLoader as Loader
|
|
6
|
-
|
|
7
|
-
local_config_potential_path1 = os.path.expanduser(
|
|
8
|
-
"~/.grdwindinversion/data_config.yaml"
|
|
9
|
-
)
|
|
10
|
-
local_config_potential_path2 = os.path.join(
|
|
11
|
-
os.path.dirname(grdwindinversion.__file__), "local_data_config.yaml"
|
|
12
|
-
)
|
|
13
|
-
if os.path.exists(local_config_potential_path1):
|
|
14
|
-
config_path = local_config_potential_path1
|
|
15
|
-
elif os.path.exists(local_config_potential_path2):
|
|
16
|
-
config_path = local_config_potential_path2
|
|
17
|
-
else:
|
|
18
|
-
config_path = os.path.join(
|
|
19
|
-
os.path.dirname(grdwindinversion.__file__), "data_config.yaml"
|
|
20
|
-
)
|
|
21
|
-
stream = open(config_path, "r")
|
|
22
|
-
conf = load(stream, Loader=Loader)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def getConf():
|
|
26
|
-
"""
|
|
27
|
-
if local_config_potential_path exists it will superseed config_path
|
|
28
|
-
:return:
|
|
29
|
-
"""
|
|
30
|
-
return conf
|
|
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
|
|
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-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion/.github/ISSUE_TEMPLATE.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{grdwindinversion-1.0.0 → grdwindinversion-1.0.1}/grdwindinversion.egg-info/entry_points.txt
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
|