Skip to content

Commit f30bedc

Browse files
authored
Merge pull request #107 from vincelhx/main
l2 nomenclature + tests + path documentation
2 parents 81d55d1 + 7af8d09 commit f30bedc

File tree

5 files changed

+153
-47
lines changed

5 files changed

+153
-47
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
Package to perform Wind inversion from GRD Level-1 SAR images
66

77
- Free software: MIT license
8-
- Documentation: https://grdwindinversion.readthedocs.io.
8+
- Documentation: https://cerweb.ifremer.fr/datarmor/doc_sphinx/grdwindinversion/index.html.
99

1010
## Usage
1111

grdwindinversion/inversion.py

Lines changed: 19 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from scipy.ndimage import binary_dilation
1515
import re
1616
import string
17-
from grdwindinversion.utils import check_incidence_range, get_pol_ratio_name, timing
17+
from grdwindinversion.utils import check_incidence_range, get_pol_ratio_name, timing, convert_polarization_name
1818
from grdwindinversion.load_config import getConf
1919
import logging
2020
import os
@@ -101,8 +101,9 @@ def getOutputName(
101101
"(...)_(..)_(...)(.)_(.)(.)(..)_(........T......)_(........T......)_(......)_(......)_(....).SAFE"
102102
)
103103
template = string.Template(
104-
"${MISSIONID}_${BEAM}_${PRODUCT}${RESOLUTION}_${LEVEL}${CLASS}${POL}_${STARTDATE}_${STOPDATE}_${ORBIT}_${TAKEID}_${PRODID}.SAFE"
104+
"${MISSIONID}_${SWATH}_${PRODUCT}${RESOLUTION}_${LEVEL}${CLASS}${POLARIZATION}_${STARTDATE}_${STOPDATE}_${ORBIT}_${TAKEID}_${PRODID}.SAFE"
105105
)
106+
# S1A_IW_GRDH_1SDV_20210909T130650_20210909T130715_039605_04AE83_C34F
106107
match = regex.match(basename_match)
107108
if not match:
108109
raise AttributeError(
@@ -111,51 +112,55 @@ def getOutputName(
111112

112113
(
113114
MISSIONID,
114-
BEAM,
115+
SWATH,
115116
PRODUCT,
116117
RESOLUTION,
117118
LEVEL,
118119
CLASS,
119-
POL,
120+
POLARIZATION,
120121
STARTDATE,
121122
STOPDATE,
122123
ORBIT,
123124
TAKEID,
124125
PRODID,
125126
) = match.groups()
126-
new_format = f"{MISSIONID.lower()}-{BEAM.lower()}-owi-xx-{STARTDATE.lower()}-{STOPDATE.lower()}-{ORBIT}-{TAKEID}.nc"
127+
# last two terms of polarization are removed
128+
new_format = f"{MISSIONID.lower()}-{SWATH.lower()}-owi-{POLARIZATION.lower()}-{STARTDATE.lower()}-{STOPDATE.lower()}-{ORBIT}-{TAKEID}.nc"
127129
elif sensor == "RS2":
128130
regex = re.compile(
129131
"(RS2)_OK([0-9]+)_PK([0-9]+)_DK([0-9]+)_(....)_(........)_(......)_(.._?.?.?)_(S.F)"
130132
)
133+
# RS2_OK141302_PK1242223_DK1208537_SCWA_20220904_093402_VV_VH_SGF
131134
template = string.Template(
132-
"${MISSIONID}_OK${DATA1}_PK${DATA2}_DK${DATA3}_${DATA4}_${DATE}_${TIME}_${POLARIZATION}_${LAST}"
135+
"${MISSIONID}_OK${DATA1}_PK${DATA2}_DK${DATA3}_${SWATH}_${DATE}_${TIME}_${POLARIZATION}_${LAST}"
133136
)
134137
match = regex.match(basename_match)
135138
if not match:
136139
raise AttributeError(
137140
f"RC2 file {basename_match} does not match the expected pattern"
138141
)
139142

140-
MISSIONID, DATA1, DATA2, DATA3, DATA4, DATE, TIME, POLARIZATION, LAST = (
143+
MISSIONID, DATA1, DATA2, DATA3, SWATH, DATE, TIME, POLARIZATION, LAST = (
141144
match.groups()
142145
)
143-
new_format = f"{MISSIONID.lower()}--owi-xx-{meta_start_date.lower()}-{meta_stop_date.lower()}-_____-_____.nc"
146+
new_format = f"{MISSIONID.lower()}-{SWATH.lower()}-owi-{convert_polarization_name(POLARIZATION)}-{meta_start_date.lower()}-{meta_stop_date.lower()}-_____-_____.nc"
144147
elif sensor == "RCM":
145148

146149
regex = re.compile(
147150
r"(RCM[0-9])_OK([0-9]+)_PK([0-9]+)_([0-9]+)_([A-Z0-9]+)_(\d{8})_(\d{6})_([A-Z]{2}(?:_[A-Z]{2})?)_([A-Z]+)$"
148151
)
152+
# RCM1_OK2767220_PK2769320_1_SCLND_20230930_214014_VV_VH_GRD
153+
149154
match = regex.match(basename_match)
150155
if not match:
151156
raise AttributeError(
152157
f"RCM file {basename_match} does not match the expected pattern"
153158
)
154159

155-
MISSIONID, DATA1, DATA2, DATA3, BEAM, DATE, TIME, POLARIZATION, PRODUCT = (
160+
MISSIONID, DATA1, DATA2, DATA3, SWATH, DATE, TIME, POLARIZATION, PRODUCT = (
156161
match.groups()
157162
)
158-
new_format = f"{MISSIONID.lower()}-{BEAM.lower()}-owi-xx-{meta_start_date.lower()}-{meta_stop_date.lower()}-_____-_____.nc"
163+
new_format = f"{MISSIONID.lower()}-{SWATH.lower()}-owi-{convert_polarization_name(POLARIZATION)}-{meta_start_date.lower()}-{meta_stop_date.lower()}-_____-_____.nc"
159164

160165
else:
161166
raise ValueError(
@@ -1074,35 +1079,8 @@ def preprocess(
10741079
)
10751080

10761081
if (recalibration) & ("SENTINEL" in sensor_longname):
1077-
xr_dataset.attrs["path_aux_pp1_new"] = os.path.basename(
1078-
os.path.dirname(
1079-
os.path.dirname(
1080-
xsar_dataset.datatree["recalibration"].attrs["path_aux_pp1_new"]
1081-
)
1082-
)
1083-
)
1084-
xr_dataset.attrs["path_aux_cal_new"] = os.path.basename(
1085-
os.path.dirname(
1086-
os.path.dirname(
1087-
xsar_dataset.datatree["recalibration"].attrs["path_aux_cal_new"]
1088-
)
1089-
)
1090-
)
1091-
1092-
xr_dataset.attrs["path_aux_pp1_old"] = os.path.basename(
1093-
os.path.dirname(
1094-
os.path.dirname(
1095-
xsar_dataset.datatree["recalibration"].attrs["path_aux_pp1_old"]
1096-
)
1097-
)
1098-
)
1099-
xr_dataset.attrs["path_aux_cal_old"] = os.path.basename(
1100-
os.path.dirname(
1101-
os.path.dirname(
1102-
xsar_dataset.datatree["recalibration"].attrs["path_aux_cal_old"]
1103-
)
1104-
)
1105-
)
1082+
xr_dataset.attrs["aux_cal_recal"] = xsar_dataset.datatree["recalibration"].attrs["aux_cal_new"]
1083+
xr_dataset.attrs["aux_pp1_recal"] = xsar_dataset.datatree["recalibration"].attrs["aux_pp1_new"]
11061084

11071085
if add_nrcs_model:
11081086
# add timing
@@ -1477,20 +1455,15 @@ def makeL2(
14771455
"coverage": xr_dataset.attrs["coverage"],
14781456
}
14791457

1480-
for recalib_attrs in [
1481-
"path_aux_pp1_new",
1482-
"path_aux_pp1_old",
1483-
"path_aux_cal_new",
1484-
"path_aux_cal_old",
1485-
]:
1458+
for recalib_attrs in ["aux_pp1_recal", "aux_pp1", "aux_cal_recal", "aux_cal"]:
14861459
if recalib_attrs in xr_dataset.attrs:
14871460
attrs[recalib_attrs] = xr_dataset.attrs[recalib_attrs]
14881461

14891462
for arg in ["passDirection", "orbit_pass"]:
14901463
if arg in xr_dataset.attrs:
14911464
attrs["passDirection"] = xr_dataset.attrs[arg]
14921465

1493-
_S1_added_attrs = ["ipf", "platform_heading"]
1466+
_S1_added_attrs = ["ipf_version", "platform_heading"]
14941467
_RCM_added_attrs = ["productId"]
14951468

14961469
for sup_attr in _S1_added_attrs + _RCM_added_attrs:

grdwindinversion/utils.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,31 @@
1818
mem_monitor = False
1919

2020

21+
def convert_polarization_name(pol):
22+
"""
23+
Convert polarization name to the format used in the output filename
24+
25+
Parameters
26+
----------
27+
pol : str
28+
polarization name
29+
30+
Returns
31+
-------
32+
str
33+
polarization name in the format used in the output filename (dv/dh/sv/sh/xx)
34+
"""
35+
if pol == "VV_VH":
36+
return "dv"
37+
elif pol == "HH_HV":
38+
return "dh"
39+
elif pol == "VV":
40+
return "sv"
41+
elif pol == "HH":
42+
return "sh"
43+
else:
44+
return "xx"
45+
2146
def check_incidence_range(incidence, models, **kwargs):
2247
"""
2348
Check if the incidence range of the dataset is within the range of the LUT of the model.

tests/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
"""Unit test package for grdwindinversion."""
2+
3+

tests/test_simple_functions.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import os
2+
import xsar
3+
4+
from grdwindinversion.inversion import getOutputName, getSensorMetaDataset
5+
6+
safes = ['S1A_IW_GRDH_1SDV_20210909T130650_20210909T130715_039605_04AE83_C34F.SAFE',
7+
'S1A_IW_GRDH_1SDH_20210101T102321_20210101T102346_035943_0435C4_D007.SAFE',
8+
'S1A_IW_GRDH_1SSV_20170105T225242_20170105T225311_014703_017ED0_584D.SAFE',
9+
'RCM1_OK2767220_PK2769320_1_SCLND_20230930_214014_VV_VH_GRD',
10+
'RCM2_OK2917789_PK2920112_1_SCLNA_20240125_195613_VV_VH_GRD',
11+
'RS2_OK141302_PK1242223_DK1208537_SCWA_20220904_093402_VV_VH_SGF',
12+
'S1A_EW_GRDM_1SDV_20230908T092521_20230908T092624_050234_060BF1_6E7A.SAFE',
13+
'S1A_IW_GRDH_1SDV_20150315T053621_20150315T053646_005038_006529_57CA.SAFE',
14+
'S1B_IW_GRDH_1SDV_20171117T164022_20171117T164047_008324_00EBB3_15F1.SAFE',
15+
'RCM3_OK2463574_PK2465310_1_SCLNA_20230303_063504_VV_VH_GRD',
16+
'RS2_OK97458_PK855025_DK787000_SCWA_20160912_212842_VV_VH_SGF',
17+
'RS2_OK97458_PK855025_DK787000_SCWA_20160912_212842_VV_SGF']
18+
19+
outfiles = ['s1a-iw-owi-dv-20210909t130650-20210909t130715-039605-04AE83.nc',
20+
's1a-iw-owi-dh-20210101t102321-20210101t102346-035943-0435C4.nc',
21+
's1a-iw-owi-sv-20170105t225242-20170105t225311-014703-017ED0.nc',
22+
'rcm1-sclnd-owi-dv-20230930t214011-20230930t214127-_____-_____.nc',
23+
'rcm2-sclna-owi-dv-20240125t195611-20240125t195726-_____-_____.nc',
24+
'rs2-scwa-owi-dv-20220904t093402-20220904t093518-_____-_____.nc',
25+
's1a-ew-owi-dv-20230908t092521-20230908t092624-050234-060BF1.nc',
26+
's1a-iw-owi-dv-20150315t053621-20150315t053646-005038-006529.nc',
27+
's1b-iw-owi-dv-20171117t164022-20171117t164047-008324-00EBB3.nc',
28+
'rcm3-sclna-owi-dv-20230303t063449-20230303t063629-_____-_____.nc',
29+
'rs2-scwa-owi-dv-20160912t212842-20160912t212958-_____-_____.nc',
30+
'rs2-scwa-owi-sv-20160912t212842-20160912t212958-_____-_____.nc',]
31+
32+
sensors = ['S1A', 'S1A', 'S1A', 'RCM', 'RCM',
33+
'RS2', 'S1A', 'S1A', 'S1B', 'RCM', 'RS2', 'RS2']
34+
35+
long_sensor_names = [
36+
'SENTINEL-1 A', 'SENTINEL-1 A', 'SENTINEL-1 A', 'RADARSAT Constellation 1', 'RADARSAT Constellation 2',
37+
'RADARSAT-2', 'SENTINEL-1 A', 'SENTINEL-1 A', 'SENTINEL-1 B', 'RADARSAT Constellation 3', 'RADARSAT-2', 'RADARSAT-2'
38+
]
39+
meta_functions = [
40+
xsar.Sentinel1Meta, xsar.Sentinel1Meta, xsar.Sentinel1Meta, xsar.RcmMeta, xsar.RcmMeta,
41+
xsar.RadarSat2Meta, xsar.Sentinel1Meta, xsar.Sentinel1Meta, xsar.Sentinel1Meta, xsar.RcmMeta, xsar.RadarSat2Meta, xsar.RadarSat2Meta,]
42+
dataset_functions = [
43+
xsar.Sentinel1Dataset, xsar.Sentinel1Dataset, xsar.Sentinel1Dataset, xsar.RcmDataset, xsar.RcmDataset,
44+
xsar.RadarSat2Dataset, xsar.Sentinel1Dataset, xsar.Sentinel1Dataset, xsar.Sentinel1Dataset, xsar.RcmDataset, xsar.RadarSat2Dataset, xsar.RadarSat2Dataset
45+
]
46+
47+
start_dates = ['20210909t130650',
48+
'20210101t102321',
49+
'20170105t225242',
50+
'20230930t214011',
51+
'20240125t195611',
52+
'20220904t093402',
53+
'20230908t092521',
54+
'20150315t053621',
55+
'20171117t164022',
56+
'20230303t063449',
57+
'20160912t212842',
58+
'20160912t212842']
59+
60+
61+
stop_dates = ['20210909t130715',
62+
'20210101t102346',
63+
'20170105t225311',
64+
'20230930t214127',
65+
'20240125t195726',
66+
'20220904t093518',
67+
'20230908t092624',
68+
'20150315t053646',
69+
'20171117t164047',
70+
'20230303t063629',
71+
'20160912t212958',
72+
'20160912t212958']
73+
74+
75+
def test_function_getSensorMetaDataset():
76+
"""
77+
Test getSensorMetaDataset function for S1A/B RCM and RS2
78+
"""
79+
80+
for idx_safe, safe in enumerate(safes):
81+
output = (sensors[idx_safe], long_sensor_names[idx_safe],
82+
meta_functions[idx_safe], dataset_functions[idx_safe])
83+
84+
result = getSensorMetaDataset(safe)
85+
86+
assert output == result, f"Expected {output}, got {result}"
87+
88+
89+
def test_function_getOutputName():
90+
"""
91+
Test getOutputName function for S1A/B RCM and RS2
92+
"""
93+
94+
for idx_safe, safe in enumerate(safes):
95+
sensor = sensors[idx_safe]
96+
start_date = start_dates[idx_safe]
97+
stop_date = stop_dates[idx_safe]
98+
output = outfiles[idx_safe]
99+
100+
result = getOutputName(safe, "", sensor, start_date, stop_date, False)
101+
102+
assert output == result, f"Expected {output}, got {result}"
103+
104+
105+
if __name__ == '__main__':
106+
test_function_getSensorMetaDataset()

0 commit comments

Comments
 (0)