grdwindinversion 0.2.7__py3-none-any.whl → 0.3.2__py3-none-any.whl
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/config_prod.yaml +6 -0
- grdwindinversion/config_prod_recal.yaml +7 -3
- grdwindinversion/config_prod_recal_streaks_nrcsmod.yaml +48 -0
- grdwindinversion/config_prod_streaks.yaml +52 -0
- grdwindinversion/config_prod_streaks_nrcsmod.yaml +52 -0
- grdwindinversion/data_config.yaml +7 -4
- grdwindinversion/gradientFeatures.py +448 -0
- grdwindinversion/inversion.py +259 -75
- grdwindinversion/load_config.py +7 -4
- grdwindinversion/utils.py +40 -0
- grdwindinversion-0.3.2.dist-info/METADATA +67 -0
- grdwindinversion-0.3.2.dist-info/RECORD +22 -0
- grdwindinversion/streaks.py +0 -79
- grdwindinversion-0.2.7.dist-info/METADATA +0 -83
- grdwindinversion-0.2.7.dist-info/RECORD +0 -19
- {grdwindinversion-0.2.7.dist-info → grdwindinversion-0.3.2.dist-info}/AUTHORS.rst +0 -0
- {grdwindinversion-0.2.7.dist-info → grdwindinversion-0.3.2.dist-info}/LICENSE +0 -0
- {grdwindinversion-0.2.7.dist-info → grdwindinversion-0.3.2.dist-info}/WHEEL +0 -0
- {grdwindinversion-0.2.7.dist-info → grdwindinversion-0.3.2.dist-info}/entry_points.txt +0 -0
- {grdwindinversion-0.2.7.dist-info → grdwindinversion-0.3.2.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
no_subdir: True
|
|
2
2
|
winddir_convention: "meteorological"
|
|
3
|
+
add_gradientsfeatures: False
|
|
4
|
+
add_nrcs_model: False
|
|
3
5
|
S1A:
|
|
6
|
+
GMF_HH_NAME: "nc_lut_gmf_cmod5n_Rhigh_hh_mouche1"
|
|
4
7
|
GMF_VV_NAME: "gmf_cmod5n"
|
|
5
8
|
GMF_VH_NAME: "gmf_s1_v2"
|
|
6
9
|
dsig_VH_NAME: "gmf_s1_v2"
|
|
@@ -12,6 +15,7 @@ S1A:
|
|
|
12
15
|
phi_step: 1.0
|
|
13
16
|
resolution: "high"
|
|
14
17
|
S1B:
|
|
18
|
+
GMF_HH_NAME: "nc_lut_gmf_cmod5n_Rhigh_hh_mouche1"
|
|
15
19
|
GMF_VV_NAME: "gmf_cmod5n"
|
|
16
20
|
GMF_VH_NAME: "gmf_s1_v2"
|
|
17
21
|
dsig_VH_NAME: "gmf_s1_v2"
|
|
@@ -23,6 +27,7 @@ S1B:
|
|
|
23
27
|
phi_step: 1.0
|
|
24
28
|
resolution: "high"
|
|
25
29
|
RS2:
|
|
30
|
+
GMF_HH_NAME: "nc_lut_gmf_cmod5n_Rhigh_hh_mouche1"
|
|
26
31
|
GMF_VV_NAME: "gmf_cmod5n"
|
|
27
32
|
GMF_VH_NAME: "gmf_rs2_v2"
|
|
28
33
|
dsig_VH_NAME: "gmf_rs2_v2"
|
|
@@ -34,6 +39,7 @@ RS2:
|
|
|
34
39
|
phi_step: 1.0
|
|
35
40
|
resolution: "high"
|
|
36
41
|
RCM:
|
|
42
|
+
GMF_HH_NAME: "nc_lut_gmf_cmod5n_Rhigh_hh_mouche1"
|
|
37
43
|
GMF_VV_NAME: "gmf_cmod5n"
|
|
38
44
|
GMF_VH_NAME: "gmf_rcm_noaa"
|
|
39
45
|
dsig_VH_NAME: "gmf_s1_v2"
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
no_subdir: True
|
|
2
2
|
S1A:
|
|
3
|
+
GMF_HH_NAME: "nc_lut_gmf_cmod5n_Rhigh_hh_mouche1"
|
|
3
4
|
GMF_VV_NAME: "gmf_cmod5n"
|
|
4
5
|
GMF_VH_NAME: "gmf_s1_v2"
|
|
5
6
|
dsig_VH_NAME: "gmf_s1_v2"
|
|
6
7
|
apply_flattening: True
|
|
7
8
|
recalibration: True
|
|
8
9
|
ancillary: "ecmwf"
|
|
9
|
-
inc_step: 0.
|
|
10
|
-
wspd_step: 0.
|
|
11
|
-
phi_step:
|
|
10
|
+
inc_step: 0.3
|
|
11
|
+
wspd_step: 0.3
|
|
12
|
+
phi_step: 2.0
|
|
12
13
|
resolution: "high"
|
|
13
14
|
S1B:
|
|
15
|
+
GMF_HH_NAME: "nc_lut_gmf_cmod5n_Rhigh_hh_mouche1"
|
|
14
16
|
GMF_VV_NAME: "gmf_cmod5n"
|
|
15
17
|
GMF_VH_NAME: "gmf_s1_v2"
|
|
16
18
|
dsig_VH_NAME: "gmf_s1_v2"
|
|
@@ -22,6 +24,7 @@ S1B:
|
|
|
22
24
|
phi_step: 1.0
|
|
23
25
|
resolution: "high"
|
|
24
26
|
RS2:
|
|
27
|
+
GMF_HH_NAME: "nc_lut_gmf_cmod5n_Rhigh_hh_mouche1"
|
|
25
28
|
GMF_VV_NAME: "gmf_cmod5n"
|
|
26
29
|
GMF_VH_NAME: "gmf_rs2_v2"
|
|
27
30
|
dsig_VH_NAME: "gmf_rs2_v2"
|
|
@@ -33,6 +36,7 @@ RS2:
|
|
|
33
36
|
phi_step: 1.0
|
|
34
37
|
resolution: "high"
|
|
35
38
|
RCM:
|
|
39
|
+
GMF_HH_NAME: "nc_lut_gmf_cmod5n_Rhigh_hh_mouche1"
|
|
36
40
|
GMF_VV_NAME: "gmf_cmod5n"
|
|
37
41
|
GMF_VH_NAME: "gmf_rcm_noaa"
|
|
38
42
|
dsig_VH_NAME: "gmf_s1_v2"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
no_subdir: True
|
|
2
|
+
winddir_convention: "meteorological"
|
|
3
|
+
add_gradientsfeatures: True
|
|
4
|
+
add_nrcs_model: True
|
|
5
|
+
S1A:
|
|
6
|
+
GMF_VV_NAME: "gmf_cmod5n"
|
|
7
|
+
GMF_VH_NAME: "gmf_s1_v2"
|
|
8
|
+
dsig_VH_NAME: "gmf_s1_v2"
|
|
9
|
+
apply_flattening: True
|
|
10
|
+
recalibration: True
|
|
11
|
+
ancillary: "ecmwf"
|
|
12
|
+
inc_step: 0.1
|
|
13
|
+
wspd_step: 0.1
|
|
14
|
+
phi_step: 1.0
|
|
15
|
+
resolution: "high"
|
|
16
|
+
S1B:
|
|
17
|
+
GMF_VV_NAME: "gmf_cmod5n"
|
|
18
|
+
GMF_VH_NAME: "gmf_s1_v2"
|
|
19
|
+
dsig_VH_NAME: "gmf_s1_v2"
|
|
20
|
+
apply_flattening: True
|
|
21
|
+
recalibration: True
|
|
22
|
+
ancillary: "ecmwf"
|
|
23
|
+
inc_step: 0.1
|
|
24
|
+
wspd_step: 0.1
|
|
25
|
+
phi_step: 1.0
|
|
26
|
+
resolution: "high"
|
|
27
|
+
RS2:
|
|
28
|
+
GMF_VV_NAME: "gmf_cmod5n"
|
|
29
|
+
GMF_VH_NAME: "gmf_rs2_v2"
|
|
30
|
+
dsig_VH_NAME: "gmf_rs2_v2"
|
|
31
|
+
apply_flattening: False
|
|
32
|
+
recalibration: True
|
|
33
|
+
ancillary: "ecmwf"
|
|
34
|
+
inc_step: 0.1
|
|
35
|
+
wspd_step: 0.1
|
|
36
|
+
phi_step: 1.0
|
|
37
|
+
resolution: "high"
|
|
38
|
+
RCM:
|
|
39
|
+
GMF_VV_NAME: "gmf_cmod5n"
|
|
40
|
+
GMF_VH_NAME: "gmf_rcm_noaa"
|
|
41
|
+
dsig_VH_NAME: "gmf_s1_v2"
|
|
42
|
+
apply_flattening: True
|
|
43
|
+
recalibration: True
|
|
44
|
+
ancillary: "ecmwf"
|
|
45
|
+
inc_step: 0.1
|
|
46
|
+
wspd_step: 0.1
|
|
47
|
+
phi_step: 1.0
|
|
48
|
+
resolution: "high"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
no_subdir: True
|
|
2
|
+
winddir_convention: "meteorological"
|
|
3
|
+
add_gradientsfeatures: True
|
|
4
|
+
add_nrcs_model: False
|
|
5
|
+
S1A:
|
|
6
|
+
GMF_HH_NAME: "nc_lut_gmf_cmod5n_Rhigh_hh_mouche1"
|
|
7
|
+
GMF_VV_NAME: "gmf_cmod5n"
|
|
8
|
+
GMF_VH_NAME: "gmf_s1_v2"
|
|
9
|
+
dsig_VH_NAME: "gmf_s1_v2"
|
|
10
|
+
apply_flattening: True
|
|
11
|
+
recalibration: False
|
|
12
|
+
ancillary: "ecmwf"
|
|
13
|
+
inc_step: 0.1
|
|
14
|
+
wspd_step: 0.1
|
|
15
|
+
phi_step: 1.0
|
|
16
|
+
resolution: "high"
|
|
17
|
+
S1B:
|
|
18
|
+
GMF_HH_NAME: "nc_lut_gmf_cmod5n_Rhigh_hh_mouche1"
|
|
19
|
+
GMF_VV_NAME: "gmf_cmod5n"
|
|
20
|
+
GMF_VH_NAME: "gmf_s1_v2"
|
|
21
|
+
dsig_VH_NAME: "gmf_s1_v2"
|
|
22
|
+
apply_flattening: True
|
|
23
|
+
recalibration: False
|
|
24
|
+
ancillary: "ecmwf"
|
|
25
|
+
inc_step: 0.1
|
|
26
|
+
wspd_step: 0.1
|
|
27
|
+
phi_step: 1.0
|
|
28
|
+
resolution: "high"
|
|
29
|
+
RS2:
|
|
30
|
+
GMF_HH_NAME: "nc_lut_gmf_cmod5n_Rhigh_hh_mouche1"
|
|
31
|
+
GMF_VV_NAME: "gmf_cmod5n"
|
|
32
|
+
GMF_VH_NAME: "gmf_rs2_v2"
|
|
33
|
+
dsig_VH_NAME: "gmf_rs2_v2"
|
|
34
|
+
apply_flattening: False
|
|
35
|
+
recalibration: False
|
|
36
|
+
ancillary: "ecmwf"
|
|
37
|
+
inc_step: 0.1
|
|
38
|
+
wspd_step: 0.1
|
|
39
|
+
phi_step: 1.0
|
|
40
|
+
resolution: "high"
|
|
41
|
+
RCM:
|
|
42
|
+
GMF_HH_NAME: "nc_lut_gmf_cmod5n_Rhigh_hh_mouche1"
|
|
43
|
+
GMF_VV_NAME: "gmf_cmod5n"
|
|
44
|
+
GMF_VH_NAME: "gmf_rcm_noaa"
|
|
45
|
+
dsig_VH_NAME: "gmf_s1_v2"
|
|
46
|
+
apply_flattening: True
|
|
47
|
+
recalibration: False
|
|
48
|
+
ancillary: "ecmwf"
|
|
49
|
+
inc_step: 0.1
|
|
50
|
+
wspd_step: 0.1
|
|
51
|
+
phi_step: 1.0
|
|
52
|
+
resolution: "high"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
no_subdir: True
|
|
2
|
+
winddir_convention: "meteorological"
|
|
3
|
+
add_gradientsfeatures: True
|
|
4
|
+
add_nrcs_model: True
|
|
5
|
+
S1A:
|
|
6
|
+
GMF_HH_NAME: "nc_lut_gmf_cmod5n_Rhigh_hh_mouche1"
|
|
7
|
+
GMF_VV_NAME: "gmf_cmod5n"
|
|
8
|
+
GMF_VH_NAME: "gmf_s1_v2"
|
|
9
|
+
dsig_VH_NAME: "gmf_s1_v2"
|
|
10
|
+
apply_flattening: True
|
|
11
|
+
recalibration: False
|
|
12
|
+
ancillary: "ecmwf"
|
|
13
|
+
inc_step: 0.1
|
|
14
|
+
wspd_step: 0.1
|
|
15
|
+
phi_step: 1.0
|
|
16
|
+
resolution: "high"
|
|
17
|
+
S1B:
|
|
18
|
+
GMF_HH_NAME: "nc_lut_gmf_cmod5n_Rhigh_hh_mouche1"
|
|
19
|
+
GMF_VV_NAME: "gmf_cmod5n"
|
|
20
|
+
GMF_VH_NAME: "gmf_s1_v2"
|
|
21
|
+
dsig_VH_NAME: "gmf_s1_v2"
|
|
22
|
+
apply_flattening: True
|
|
23
|
+
recalibration: False
|
|
24
|
+
ancillary: "ecmwf"
|
|
25
|
+
inc_step: 0.1
|
|
26
|
+
wspd_step: 0.1
|
|
27
|
+
phi_step: 1.0
|
|
28
|
+
resolution: "high"
|
|
29
|
+
RS2:
|
|
30
|
+
GMF_HH_NAME: "nc_lut_gmf_cmod5n_Rhigh_hh_mouche1"
|
|
31
|
+
GMF_VV_NAME: "gmf_cmod5n"
|
|
32
|
+
GMF_VH_NAME: "gmf_rs2_v2"
|
|
33
|
+
dsig_VH_NAME: "gmf_rs2_v2"
|
|
34
|
+
apply_flattening: False
|
|
35
|
+
recalibration: False
|
|
36
|
+
ancillary: "ecmwf"
|
|
37
|
+
inc_step: 0.1
|
|
38
|
+
wspd_step: 0.1
|
|
39
|
+
phi_step: 1.0
|
|
40
|
+
resolution: "high"
|
|
41
|
+
RCM:
|
|
42
|
+
GMF_HH_NAME: "nc_lut_gmf_cmod5n_Rhigh_hh_mouche1"
|
|
43
|
+
GMF_VV_NAME: "gmf_cmod5n"
|
|
44
|
+
GMF_VH_NAME: "gmf_rcm_noaa"
|
|
45
|
+
dsig_VH_NAME: "gmf_s1_v2"
|
|
46
|
+
apply_flattening: True
|
|
47
|
+
recalibration: False
|
|
48
|
+
ancillary: "ecmwf"
|
|
49
|
+
inc_step: 0.1
|
|
50
|
+
wspd_step: 0.1
|
|
51
|
+
phi_step: 1.0
|
|
52
|
+
resolution: "high"
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
'ecmwf_0100_1h': '../ecmwf/forecast/hourly/0100deg/netcdf_light_REPRO_tree/%Y/%j/ECMWF_FORECAST_0100_%Y%m%d%H%M_10U_10V.nc'
|
|
2
|
+
'ecmwf_0125_1h': '../ecmwf/0.125deg/1h/forecasts/%Y/%j/ecmwf_%Y%m%d%H%M.nc'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
unit_test_s1_product: './sentinel-1a/L1/IW/S1A_IW_GRDH_1S/2021/252/S1A_IW_GRDH_1SDV_20210909T130650_20210909T130715_039605_04AE83_C34F.SAFE'
|
|
6
|
+
unit_test_rcm_product: './l1/rcm/rcm-1/sclnd/2023/273/RCM1_OK2767220_PK2769320_1_SCLND_20230930_214014_VV_VH_GRD'
|
|
7
|
+
unit_test_rs2_product: './L1/VV_VH/2022/247/RS2_OK141302_PK1242223_DK1208537_SCWA_20220904_093402_VV_VH_SGF'
|
|
3
8
|
|
|
4
|
-
'ecmwf_0100_1h': '/home/datawork-cersat-public/provider/ecmwf/forecast/hourly/0100deg/netcdf_light_REPRO_tree/%Y/%j/ECMWF_FORECAST_0100_%Y%m%d%H%M_10U_10V.nc'
|
|
5
|
-
'ecmwf_0125_1h': '/home/datawork-cersat-intranet/project/ecmwf/0.125deg/1h/forecasts/%Y/%j/ecmwf_%Y%m%d%H%M.nc'
|
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
import xsarsea.gradients
|
|
2
|
+
import cv2
|
|
3
|
+
import xarray as xr
|
|
4
|
+
import xarray as xr
|
|
5
|
+
from scipy.ndimage import binary_dilation
|
|
6
|
+
import numpy as np
|
|
7
|
+
import logging
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
logger = logging.getLogger('grdwindinversion.gradientFeatures')
|
|
11
|
+
logger.addHandler(logging.NullHandler())
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class GradientFeatures:
|
|
15
|
+
def __init__(self, xr_dataset, xr_dataset_100, windows_sizes, downscales_factors, window_step=1):
|
|
16
|
+
"""
|
|
17
|
+
Initialize variables and xsarsea.gradients.Gradients.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
xr_dataset : xarray.Dataset
|
|
22
|
+
xarray.Dataset containing the SAR data.
|
|
23
|
+
xr_dataset_100 : xarray.Dataset
|
|
24
|
+
xarray.Dataset containing the 100m resolution SAR data.
|
|
25
|
+
windows_sizes : list
|
|
26
|
+
List of window sizes for gradient computation.
|
|
27
|
+
downscales_factors : list
|
|
28
|
+
List of downscale factors for gradient computation.
|
|
29
|
+
window_step : int
|
|
30
|
+
Step size for the window (default is 1).
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
None
|
|
35
|
+
"""
|
|
36
|
+
self.xr_dataset = xr_dataset
|
|
37
|
+
self.xr_dataset_100 = xr_dataset_100
|
|
38
|
+
self.windows_sizes = windows_sizes
|
|
39
|
+
self.downscales_factors = downscales_factors
|
|
40
|
+
self.window_step = window_step
|
|
41
|
+
self.gradients = None
|
|
42
|
+
self.hist = None
|
|
43
|
+
self._compute_gradients()
|
|
44
|
+
|
|
45
|
+
def _compute_gradients(self):
|
|
46
|
+
"""
|
|
47
|
+
Instantiate the gradients object and compute the histogram.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
None
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
None
|
|
56
|
+
|
|
57
|
+
"""
|
|
58
|
+
self.gradients = xsarsea.gradients.Gradients(
|
|
59
|
+
self.xr_dataset_100['sigma0_detrend'],
|
|
60
|
+
windows_sizes=self.windows_sizes,
|
|
61
|
+
downscales_factors=self.downscales_factors,
|
|
62
|
+
window_step=self.window_step
|
|
63
|
+
)
|
|
64
|
+
self.hist = self.gradients.histogram
|
|
65
|
+
# Get orthogonal gradients
|
|
66
|
+
self.hist['angles'] = self.hist['angles'] + np.pi / 2
|
|
67
|
+
|
|
68
|
+
def get_heterogeneity_mask(self, config):
|
|
69
|
+
"""
|
|
70
|
+
Compute the heterogeneity mask.
|
|
71
|
+
|
|
72
|
+
Parameters
|
|
73
|
+
----------
|
|
74
|
+
config : dict
|
|
75
|
+
Configuration parameters.
|
|
76
|
+
|
|
77
|
+
Returns
|
|
78
|
+
-------
|
|
79
|
+
dict
|
|
80
|
+
Dictionary containing the dataArrays related toheterogeneity mask.
|
|
81
|
+
|
|
82
|
+
"""
|
|
83
|
+
dual_pol = config["l2_params"]["dual_pol"]
|
|
84
|
+
|
|
85
|
+
new_dataArrays = {}
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
|
|
89
|
+
sigma0_400_co = [da.sigma0 for da in self.gradients.gradients_list if (
|
|
90
|
+
da.sigma0["pol"] == config["l2_params"]["copol"] and da.sigma0.downscale_factor == 4)][0]
|
|
91
|
+
sigs = [sigma0_400_co]
|
|
92
|
+
|
|
93
|
+
if dual_pol:
|
|
94
|
+
sigma0_800_cross = [da.sigma0 for da in self.gradients.gradients_list if (
|
|
95
|
+
da.sigma0["pol"] == config["l2_params"]["crosspol"] and da.sigma0.downscale_factor == 8)][0]
|
|
96
|
+
sigs.append(sigma0_800_cross)
|
|
97
|
+
|
|
98
|
+
filters = {}
|
|
99
|
+
for sig in sigs:
|
|
100
|
+
|
|
101
|
+
pol = sig["pol"].values
|
|
102
|
+
res = 100 * sig.downscale_factor.values
|
|
103
|
+
|
|
104
|
+
# delete useless coords : could be problematic to have it later
|
|
105
|
+
if 'downscale_factor' in sig.coords:
|
|
106
|
+
sig = sig.reset_coords("downscale_factor", drop=True)
|
|
107
|
+
|
|
108
|
+
if 'window_size' in sig.coords:
|
|
109
|
+
sig = sig.reset_coords("window_size", drop=True)
|
|
110
|
+
# mask
|
|
111
|
+
sig = xr.where(sig <= 0, 1e-15, sig)
|
|
112
|
+
|
|
113
|
+
# map incidence for detrend
|
|
114
|
+
incidence = xr.DataArray(data=cv2.resize(
|
|
115
|
+
self.xr_dataset_100.incidence.values, sig.shape[::-1], cv2.INTER_NEAREST), dims=sig.dims, coords=sig.coords)
|
|
116
|
+
|
|
117
|
+
sigma0_detrend = xsarsea.sigma0_detrend(sig, incidence)
|
|
118
|
+
|
|
119
|
+
filter_name = str(res)+"_"+str(pol)
|
|
120
|
+
I = sigma0_detrend
|
|
121
|
+
f1, f2, f3, f4, f = xsarsea.gradients.filtering_parameters(I)
|
|
122
|
+
filters[filter_name] = f
|
|
123
|
+
|
|
124
|
+
thresholds = [0.78] # < is unusable
|
|
125
|
+
if dual_pol:
|
|
126
|
+
# Seuil pour crosspol si dual_pol est activé
|
|
127
|
+
thresholds.append(0.71)
|
|
128
|
+
|
|
129
|
+
for idx_filter, filter in enumerate(filters):
|
|
130
|
+
# interp to user resolution and map on dataset grid
|
|
131
|
+
new_dataArrays[filter] = filters[filter].interp(
|
|
132
|
+
line=self.xr_dataset.line, sample=self.xr_dataset.sample, method="nearest")
|
|
133
|
+
new_dataArrays[filter+"_mask"] = xr.where(
|
|
134
|
+
new_dataArrays[filter] > thresholds[idx_filter], True, False)
|
|
135
|
+
|
|
136
|
+
varname_400_copol_mask = f'400_{config["l2_params"]["copol"]}_mask'
|
|
137
|
+
varname_800_crosspol_mask = f'800_{config["l2_params"]["crosspol"]}_mask'
|
|
138
|
+
|
|
139
|
+
# Cas 0 : no heterogeneity
|
|
140
|
+
new_dataArrays["heterogeneity_mask"] = xr.full_like(
|
|
141
|
+
new_dataArrays[varname_400_copol_mask], 0)
|
|
142
|
+
|
|
143
|
+
if dual_pol:
|
|
144
|
+
# Cas 3 : Dual-polarization
|
|
145
|
+
new_dataArrays["heterogeneity_mask"] = xr.where(
|
|
146
|
+
new_dataArrays[varname_400_copol_mask] & new_dataArrays[varname_800_crosspol_mask], 3, new_dataArrays["heterogeneity_mask"])
|
|
147
|
+
|
|
148
|
+
# Cas 1 : Co-polarization only
|
|
149
|
+
new_dataArrays["heterogeneity_mask"] = xr.where(
|
|
150
|
+
new_dataArrays[varname_400_copol_mask] & ~new_dataArrays[varname_800_crosspol_mask], 1, new_dataArrays["heterogeneity_mask"])
|
|
151
|
+
|
|
152
|
+
# Cas 2 : Cross-polarization only
|
|
153
|
+
new_dataArrays["heterogeneity_mask"] = xr.where(
|
|
154
|
+
~new_dataArrays[varname_400_copol_mask] & new_dataArrays[varname_800_crosspol_mask], 2, new_dataArrays["heterogeneity_mask"])
|
|
155
|
+
|
|
156
|
+
# Attributes
|
|
157
|
+
new_dataArrays["heterogeneity_mask"].attrs["valid_range"] = np.array([
|
|
158
|
+
0, 3])
|
|
159
|
+
new_dataArrays["heterogeneity_mask"].attrs["flag_values"] = np.array([
|
|
160
|
+
0, 1, 2, 3])
|
|
161
|
+
new_dataArrays["heterogeneity_mask"].attrs["flag_meanings"] = (
|
|
162
|
+
"homogeneous_NRCS, heterogeneous_from_co-polarization_NRCS, "
|
|
163
|
+
"heterogeneous_from_cross-polarization_NRCS, heterogeneous_from_dual-polarization_NRCS"
|
|
164
|
+
)
|
|
165
|
+
else:
|
|
166
|
+
# no crosspol
|
|
167
|
+
new_dataArrays["heterogeneity_mask"] = xr.where(
|
|
168
|
+
new_dataArrays[varname_400_copol_mask], 1, new_dataArrays["heterogeneity_mask"])
|
|
169
|
+
|
|
170
|
+
# Attributs pour le cas single-pol
|
|
171
|
+
new_dataArrays["heterogeneity_mask"].attrs["valid_range"] = np.array([
|
|
172
|
+
0, 1])
|
|
173
|
+
new_dataArrays["heterogeneity_mask"].attrs["flag_values"] = np.array([
|
|
174
|
+
0, 1])
|
|
175
|
+
new_dataArrays["heterogeneity_mask"].attrs["flag_meanings"] = (
|
|
176
|
+
"homogeneous_NRCS, heterogeneous_from_co-polarization_NRCS"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
# Attributs généraux
|
|
180
|
+
new_dataArrays["heterogeneity_mask"].attrs["long_name"] = "Quality flag taking into account the local heterogeneity"
|
|
181
|
+
return new_dataArrays
|
|
182
|
+
|
|
183
|
+
except Exception as e:
|
|
184
|
+
logging.error("Error in get_heterogeneity_mask: %s", e)
|
|
185
|
+
|
|
186
|
+
new_dataArrays["heterogeneity_mask"] = xr.DataArray(data=np.nan * np.ones([len(self.xr_dataset.coords[dim]) for dim in ['line', 'sample']]),
|
|
187
|
+
dims=[
|
|
188
|
+
'line', 'sample'],
|
|
189
|
+
coords=[self.xr_dataset.coords[dim]
|
|
190
|
+
for dim in ['line', 'sample']],
|
|
191
|
+
attrs={"comment": "no heterogeneity mask found"})
|
|
192
|
+
|
|
193
|
+
return new_dataArrays
|
|
194
|
+
|
|
195
|
+
def _remove_ambiguity(self, streaks):
|
|
196
|
+
"""
|
|
197
|
+
Remove direction ambiguity using ancillary wind data.
|
|
198
|
+
|
|
199
|
+
Parameters
|
|
200
|
+
----------
|
|
201
|
+
streaks : xarray.Dataset
|
|
202
|
+
Dataset containing the streaks.
|
|
203
|
+
|
|
204
|
+
Returns
|
|
205
|
+
-------
|
|
206
|
+
xarray.Dataset
|
|
207
|
+
Dataset containing the streaks with ambiguity removed.
|
|
208
|
+
"""
|
|
209
|
+
|
|
210
|
+
# Load ancillary wind in antenna convention
|
|
211
|
+
ancillary_wind = self.xr_dataset['ancillary_wind'].interp(
|
|
212
|
+
line=streaks.line,
|
|
213
|
+
sample=streaks.sample,
|
|
214
|
+
method='nearest'
|
|
215
|
+
).compute()
|
|
216
|
+
|
|
217
|
+
# Convert angles to complex numbers
|
|
218
|
+
streaks_c = streaks['weight'] * np.exp(1j * streaks['angle'])
|
|
219
|
+
# Calculate the difference in angle
|
|
220
|
+
diff_angle = xr.apply_ufunc(np.angle, ancillary_wind / streaks_c)
|
|
221
|
+
|
|
222
|
+
# Remove ambiguity
|
|
223
|
+
streaks_c = xr.where(np.abs(diff_angle) > np.pi /
|
|
224
|
+
2, -streaks_c, streaks_c)
|
|
225
|
+
|
|
226
|
+
# Update streaks with corrected values
|
|
227
|
+
streaks['weight'] = np.abs(streaks_c)
|
|
228
|
+
streaks['angle'] = xr.apply_ufunc(np.angle, streaks_c)
|
|
229
|
+
return streaks
|
|
230
|
+
|
|
231
|
+
def convert_to_meteo_convention(self, streaks):
|
|
232
|
+
"""
|
|
233
|
+
Convert wind direction to meteorological convention by creating a new 'angle' DataArray.
|
|
234
|
+
|
|
235
|
+
Parameters
|
|
236
|
+
----------
|
|
237
|
+
streaks : xarray.Dataset
|
|
238
|
+
Dataset containing the streaks.
|
|
239
|
+
|
|
240
|
+
Returns
|
|
241
|
+
-------
|
|
242
|
+
xarray.Dataset
|
|
243
|
+
Dataset containing the streaks with wind direction in meteorological convention.
|
|
244
|
+
|
|
245
|
+
"""
|
|
246
|
+
streaks_meteo = self.xr_dataset[['longitude', 'latitude', 'ground_heading', 'ancillary_wind']].interp(
|
|
247
|
+
line=streaks.line,
|
|
248
|
+
sample=streaks.sample,
|
|
249
|
+
method='nearest')
|
|
250
|
+
|
|
251
|
+
streaks_meteo['angle'] = xsarsea.dir_sample_to_meteo(
|
|
252
|
+
np.rad2deg(streaks['angle']), streaks_meteo['ground_heading'])
|
|
253
|
+
streaks_meteo['angle'].attrs[
|
|
254
|
+
'winddir_convention'] = "Wind direction in meteorological convention (clockwise, from), ex: 0°=from north, 90°=from east"
|
|
255
|
+
|
|
256
|
+
return streaks_meteo
|
|
257
|
+
|
|
258
|
+
def streaks_smooth_mean(self):
|
|
259
|
+
"""
|
|
260
|
+
Compute streaks by smoothing the histograms first and then computing the mean.
|
|
261
|
+
|
|
262
|
+
Parameters
|
|
263
|
+
----------
|
|
264
|
+
None
|
|
265
|
+
|
|
266
|
+
Returns
|
|
267
|
+
-------
|
|
268
|
+
xarray.DataArray
|
|
269
|
+
DataArray containing the streaks.
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
try:
|
|
273
|
+
hist_smooth = self.hist.copy()
|
|
274
|
+
hist_smooth['weight'] = xsarsea.gradients.circ_smooth(
|
|
275
|
+
hist_smooth['weight'])
|
|
276
|
+
|
|
277
|
+
# Compute the mean across 'downscale_factor', 'window_size', and 'pol'
|
|
278
|
+
hist_smooth_mean = hist_smooth.mean(
|
|
279
|
+
['downscale_factor', 'window_size', 'pol'])
|
|
280
|
+
|
|
281
|
+
# Select histogram peak
|
|
282
|
+
iangle_smooth_mean = hist_smooth_mean['weight'].fillna(
|
|
283
|
+
0).argmax(dim='angles')
|
|
284
|
+
streaks_dir_smooth_mean = hist_smooth_mean['angles'].isel(
|
|
285
|
+
angles=iangle_smooth_mean)
|
|
286
|
+
streaks_weight_smooth_mean = hist_smooth_mean['weight'].isel(
|
|
287
|
+
angles=iangle_smooth_mean)
|
|
288
|
+
|
|
289
|
+
# Combine angles and weights into a dataset
|
|
290
|
+
streaks_smooth_mean = xr.Dataset({
|
|
291
|
+
'angle': streaks_dir_smooth_mean,
|
|
292
|
+
'weight': streaks_weight_smooth_mean
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
# Remove 'angles' coordinate
|
|
296
|
+
streaks_smooth_mean = streaks_smooth_mean.reset_coords(
|
|
297
|
+
'angles', drop=True)
|
|
298
|
+
|
|
299
|
+
# Remove ambiguity with ancillary wind
|
|
300
|
+
streaks_smooth_mean = self._remove_ambiguity(
|
|
301
|
+
streaks_smooth_mean)
|
|
302
|
+
|
|
303
|
+
# Convert to meteo convention
|
|
304
|
+
streaks_smooth_mean = self.convert_to_meteo_convention(
|
|
305
|
+
streaks_smooth_mean)
|
|
306
|
+
|
|
307
|
+
# Set attributes
|
|
308
|
+
streaks_smooth_mean['angle'].attrs['description'] = 'Wind direction estimated from local gradient; histograms smoothed first, then mean computed'
|
|
309
|
+
|
|
310
|
+
return streaks_smooth_mean
|
|
311
|
+
|
|
312
|
+
except Exception as e:
|
|
313
|
+
logging.error("Error in streaks_smooth_mean: %s", e)
|
|
314
|
+
|
|
315
|
+
streaks_dir_smooth_mean_interp = xr.DataArray(data=np.nan * np.ones([len(self.xr_dataset.coords[dim]) for dim in ['line', 'sample']]),
|
|
316
|
+
dims=[
|
|
317
|
+
'line', 'sample'],
|
|
318
|
+
coords=[self.xr_dataset.coords[dim]
|
|
319
|
+
for dim in ['line', 'sample']],
|
|
320
|
+
attrs={"comment": "no streaks_smooth_mean found"})
|
|
321
|
+
|
|
322
|
+
return streaks_dir_smooth_mean_interp
|
|
323
|
+
|
|
324
|
+
def streaks_mean_smooth(self):
|
|
325
|
+
"""
|
|
326
|
+
Compute streaks by meaning the histograms first and then smoothing.
|
|
327
|
+
|
|
328
|
+
Parameters
|
|
329
|
+
----------
|
|
330
|
+
None
|
|
331
|
+
|
|
332
|
+
Returns
|
|
333
|
+
-------
|
|
334
|
+
xarray.DataArray
|
|
335
|
+
DataArray containing the streaks.
|
|
336
|
+
"""
|
|
337
|
+
try:
|
|
338
|
+
# Compute the mean of the histograms
|
|
339
|
+
hist_mean = self.hist.copy().mean(
|
|
340
|
+
['downscale_factor', 'window_size', 'pol'])
|
|
341
|
+
|
|
342
|
+
# Smooth the mean histogram
|
|
343
|
+
hist_mean_smooth = hist_mean.copy()
|
|
344
|
+
hist_mean_smooth['weight'] = xsarsea.gradients.circ_smooth(
|
|
345
|
+
hist_mean['weight'])
|
|
346
|
+
|
|
347
|
+
# Select histogram peak
|
|
348
|
+
iangle_mean_smooth = hist_mean_smooth['weight'].fillna(
|
|
349
|
+
0).argmax(dim='angles')
|
|
350
|
+
streaks_dir_mean_smooth = hist_mean_smooth['angles'].isel(
|
|
351
|
+
angles=iangle_mean_smooth)
|
|
352
|
+
streaks_weight_mean_smooth = hist_mean_smooth['weight'].isel(
|
|
353
|
+
angles=iangle_mean_smooth)
|
|
354
|
+
|
|
355
|
+
# Combine angles and weights into a dataset
|
|
356
|
+
streaks_mean_smooth = xr.Dataset({
|
|
357
|
+
'angle': streaks_dir_mean_smooth,
|
|
358
|
+
'weight': streaks_weight_mean_smooth
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
# Remove 'angles' coordinate
|
|
362
|
+
streaks_mean_smooth = streaks_mean_smooth.reset_coords(
|
|
363
|
+
'angles', drop=True)
|
|
364
|
+
|
|
365
|
+
# Remove ambiguity with ancillary wind
|
|
366
|
+
streaks_mean_smooth = self._remove_ambiguity(
|
|
367
|
+
streaks_mean_smooth)
|
|
368
|
+
|
|
369
|
+
# Convert to meteo convention
|
|
370
|
+
streaks_mean_smooth = self.convert_to_meteo_convention(
|
|
371
|
+
streaks_mean_smooth)
|
|
372
|
+
|
|
373
|
+
# Set attributes
|
|
374
|
+
streaks_mean_smooth['angle'].attrs['description'] = 'Wind direction estimated from local gradient; histograms mean first, then smooth computed'
|
|
375
|
+
|
|
376
|
+
return streaks_mean_smooth
|
|
377
|
+
|
|
378
|
+
except Exception as e:
|
|
379
|
+
logging.error("Error in streaks_mean_smooth: %s", e)
|
|
380
|
+
|
|
381
|
+
streaks_mean_smooth = xr.DataArray(data=np.nan * np.ones([len(self.xr_dataset.coords[dim]) for dim in ['line', 'sample']]),
|
|
382
|
+
dims=[
|
|
383
|
+
'line', 'sample'],
|
|
384
|
+
coords=[self.xr_dataset.coords[dim]
|
|
385
|
+
for dim in ['line', 'sample']],
|
|
386
|
+
attrs={"comment": "no streaks_mean_smooth found"})
|
|
387
|
+
|
|
388
|
+
return streaks_mean_smooth
|
|
389
|
+
|
|
390
|
+
def streaks_individual(self):
|
|
391
|
+
"""
|
|
392
|
+
Compute streaks by smoothing the histogram.
|
|
393
|
+
|
|
394
|
+
Parameters
|
|
395
|
+
----------
|
|
396
|
+
None
|
|
397
|
+
|
|
398
|
+
Returns
|
|
399
|
+
-------
|
|
400
|
+
xarray.DataArray
|
|
401
|
+
DataArray containing the individual streaks for each window_size, downscale_factor, polarisation (no combination).
|
|
402
|
+
"""
|
|
403
|
+
try:
|
|
404
|
+
# Compute the mean of the histograms
|
|
405
|
+
hist_smooth = self.hist.copy()
|
|
406
|
+
hist_smooth['weight'] = xsarsea.gradients.circ_smooth(
|
|
407
|
+
hist_smooth['weight'])
|
|
408
|
+
|
|
409
|
+
# Select histogram peak for each individual solution
|
|
410
|
+
iangle_individual = hist_smooth['weight'].fillna(
|
|
411
|
+
0).argmax(dim='angles')
|
|
412
|
+
streaks_dir_individual = hist_smooth['angles'].isel(
|
|
413
|
+
angles=iangle_individual)
|
|
414
|
+
streaks_weight_individual = hist_smooth['weight'].isel(
|
|
415
|
+
angles=iangle_individual)
|
|
416
|
+
# Combine angles and weights into a dataset
|
|
417
|
+
streaks_individual = xr.Dataset({
|
|
418
|
+
'angle': streaks_dir_individual,
|
|
419
|
+
'weight': streaks_weight_individual
|
|
420
|
+
})
|
|
421
|
+
# Remove 'angles' coordinate
|
|
422
|
+
streaks_individual = streaks_individual.reset_coords(
|
|
423
|
+
'angles', drop=True)
|
|
424
|
+
|
|
425
|
+
# Remove ambiguity with ancillary wind for each individual solution
|
|
426
|
+
streaks_individual = self._remove_ambiguity(
|
|
427
|
+
streaks_individual)
|
|
428
|
+
|
|
429
|
+
# Convert to meteo convention
|
|
430
|
+
streaks_individual = self.convert_to_meteo_convention(
|
|
431
|
+
streaks_individual)
|
|
432
|
+
|
|
433
|
+
# Set attributes
|
|
434
|
+
streaks_individual['angle'].attrs['description'] = 'Wind direction estimated from local gradient for each individual solution; histograms smoothed individually'
|
|
435
|
+
|
|
436
|
+
return streaks_individual
|
|
437
|
+
|
|
438
|
+
except Exception as e:
|
|
439
|
+
logging.error("Error in streaks_individual: %s", e)
|
|
440
|
+
|
|
441
|
+
streaks_individual = xr.DataArray(data=np.nan * np.ones([len(self.xr_dataset.coords[dim]) for dim in ['line', 'sample']]),
|
|
442
|
+
dims=[
|
|
443
|
+
'line', 'sample'],
|
|
444
|
+
coords=[self.xr_dataset.coords[dim]
|
|
445
|
+
for dim in ['line', 'sample']],
|
|
446
|
+
attrs={"comment": "no streaks_individual found"})
|
|
447
|
+
|
|
448
|
+
return streaks_individual
|