Skip to content

Commit 5a99c19

Browse files
authored
Merge pull request #15 from vincelhx/main
added a dataset in the datatree for antennaPattern
2 parents d2628fc + e1057a4 commit 5a99c19

File tree

2 files changed

+208
-5
lines changed

2 files changed

+208
-5
lines changed

safe_s1/metadata.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ def __init__(self, name, backend_kwargs=None):
100100
'calibration_luts': self.get_calibration_luts,
101101
'noise_azimuth_raw': self.get_noise_azi_raw,
102102
'noise_range_raw': self.get_noise_range_raw,
103+
'antenna_pattern':self.antenna_pattern,
104+
'swath_merging': self.swath_merging
103105
}
104106
self.dt = datatree.DataTree.from_dict(self._dict)
105107
assert self.dt==self.datatree
@@ -496,6 +498,25 @@ def bursts(self):
496498
describe=True)
497499
return bursts
498500

501+
@property
502+
def antenna_pattern(self):
503+
ds = self.xml_parser.get_compound_var(self.files['annotation'].iloc[0], 'antenna_pattern')
504+
ds.attrs['history'] = self.xml_parser.get_compound_var(self.files['annotation'].iloc[0], 'antenna_pattern',
505+
describe=True)
506+
return ds
507+
508+
@property
509+
def swath_merging(self):
510+
if 'GRD' in self.product:
511+
512+
ds = self.xml_parser.get_compound_var(self.files['annotation'].iloc[0], 'swath_merging')
513+
ds.attrs['history'] = self.xml_parser.get_compound_var(self.files['annotation'].iloc[0], 'swath_merging',
514+
describe=True)
515+
else :
516+
ds = xr.Dataset()
517+
518+
return ds
519+
499520
@property
500521
def multidataset(self):
501522
"""

safe_s1/sentinel1_xml_mappings.py

Lines changed: 187 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,10 @@ def list_poly_from_list_string_coords(str_coords_list):
148148
'satellite': (scalar, '//safe:platform/safe:number'),
149149
'start_date': (date_converter, '//safe:acquisitionPeriod/safe:startTime'),
150150
'stop_date': (date_converter, '//safe:acquisitionPeriod/safe:stopTime'),
151-
'aux_cal': (scalar,
152-
'//metadataSection/metadataObject/metadataWrap/xmlData/safe:processing/safe:resource/safe:processing/safe:resource[@role="AUX_CAL"]/@name'),
151+
152+
'aux_cal': (scalar, '//metadataSection/metadataObject/metadataWrap/xmlData/safe:processing/safe:resource/safe:processing/safe:resource[@role="AUX_CAL"]/@name'),
153+
'aux_pp1': (scalar, '//metadataSection/metadataObject/metadataWrap/xmlData/safe:processing/safe:resource/safe:processing/safe:resource[@role="AUX_PP1"]/@name'),
154+
153155
'aux_cal_sl2': (scalar,'//metadataSection/metadataObject/metadataWrap/xmlData/safe:processing/safe:resource[@role="AUX_CAL"]/@name'),
154156
'annotation_files': (
155157
normpath, '/xfdu:XFDU/dataObjectSection/*[@repID="s1Level1ProductSchema"]/byteStream/fileLocation/@href'),
@@ -302,8 +304,32 @@ def list_poly_from_list_string_coords(str_coords_list):
302304
'fmrate_azimuthFmRatePolynomial': (
303305
list_of_float_1D_array_from_string,
304306
'//product/generalAnnotation/azimuthFmRateList/azimuthFmRate/azimuthFmRatePolynomial'),
305-
306-
},
307+
308+
'ap_azimuthTime': (
309+
datetime64_array, '/product/antennaPattern/antennaPatternList/antennaPattern/azimuthTime'),
310+
'ap_roll' : (float_array, '/product/antennaPattern/antennaPatternList/antennaPattern/roll'),
311+
'ap_swath' : (lambda x: np.array(x), '/product/antennaPattern/antennaPatternList/antennaPattern/swath'),
312+
313+
'ap_elevationAngle': (
314+
list_of_float_1D_array_from_string, '/product/antennaPattern/antennaPatternList/antennaPattern/elevationAngle'),
315+
'ap_incidenceAngle': (
316+
list_of_float_1D_array_from_string, '/product/antennaPattern/antennaPatternList/antennaPattern/incidenceAngle'),
317+
'ap_slantRangeTime': (
318+
list_of_float_1D_array_from_string, '/product/antennaPattern/antennaPatternList/antennaPattern/slantRangeTime'),
319+
'ap_terrainHeight': (
320+
float_array, '/product/antennaPattern/antennaPatternList/antennaPattern/terrainHeight'),
321+
'ap_elevationPattern' : (
322+
list_of_float_1D_array_from_string, '/product/antennaPattern/antennaPatternList/antennaPattern/elevationPattern'),
323+
324+
'sm_nbPerSwat': (int_array, '/product/swathMerging/swathMergeList/swathMerge/swathBoundsList/@count'),
325+
'sm_swath' : (lambda x: np.array(x), '/product/swathMerging/swathMergeList/swathMerge/swath'),
326+
'sm_azimuthTime' : (datetime64_array, '/product/swathMerging/swathMergeList/swathMerge/swathBoundsList/swathBounds/azimuthTime'),
327+
'sm_firstAzimuthLine' : (int_array, '/product/swathMerging/swathMergeList/swathMerge/swathBoundsList/swathBounds/firstAzimuthLine'),
328+
'sm_lastAzimuthLine' : (int_array, '/product/swathMerging/swathMergeList/swathMerge/swathBoundsList/swathBounds/lastAzimuthLine'),
329+
'sm_firstRangeSample' : (int_array, '/product/swathMerging/swathMergeList/swathMerge/swathBoundsList/swathBounds/firstRangeSample'),
330+
'sm_lastRangeSample' : (int_array, '/product/swathMerging/swathMergeList/swathMerge/swathBoundsList/swathBounds/lastRangeSample'),
331+
332+
},
307333
'xsd': {'all': (str, '/xsd:schema/xsd:complexType/xsd:sequence/xsd:element/xsd:annotation/xsd:documentation'),
308334
'names': (str, '/xsd:schema/xsd:complexType/xsd:sequence/xsd:element/@name'),
309335
'sensingtime': (str, '/xsd:schema/xsd:complexType/xsd:sequence/xsd:element/sensingTime')
@@ -694,6 +720,7 @@ def doppler_centroid_estimates(nb_dcestimate,
694720
'source': xpath_mappings['annotation']['dc_rmserrAboveThres'][
695721
1]},
696722
coords={'azimuthTime': dc_azimuth_time})
723+
697724
return ds
698725

699726

@@ -716,6 +743,147 @@ def geolocation_grid(line, sample, values):
716743
values = np.reshape(values, shape)
717744
return xr.DataArray(values, dims=['line', 'sample'], coords={'line': line, 'sample': sample})
718745

746+
def antenna_pattern(ap_swath,ap_roll,ap_azimuthTime,ap_terrainHeight,ap_elevationAngle,ap_elevationPattern,ap_incidenceAngle,ap_slantRangeTime):
747+
"""
748+
749+
Parameters
750+
----------
751+
ap_swath
752+
ap_roll
753+
ap_azimuthTime
754+
ap_terrainHeight
755+
ap_elevationAngle
756+
ap_elevationPattern
757+
ap_incidenceAngle
758+
ap_slantRangeTime
759+
760+
Returns
761+
-------
762+
xarray.DataSet
763+
"""
764+
# Fonction to convert string 'EW1' ou 'IW3' as int
765+
def convert_to_int(swath):
766+
return int(swath[-1])
767+
vectorized_convert = np.vectorize(convert_to_int)
768+
swathNumber = vectorized_convert(ap_swath)
769+
770+
dim_azimuthTime = max(np.bincount(swathNumber))
771+
dim_slantRangeTime = max(array.shape[0] for array in ap_elevationAngle)
772+
773+
include_roll = len(ap_roll) != 0
774+
775+
# Create 2Ds arrays
776+
elevAngle2d = np.full((len(ap_elevationAngle), dim_slantRangeTime), np.nan)
777+
gain2d = np.full((len(ap_elevationPattern), dim_slantRangeTime), np.nan)
778+
slantRangeTime2d = np.full((len(ap_slantRangeTime), dim_slantRangeTime), np.nan)
779+
incAngle2d = np.full((len(ap_incidenceAngle), dim_slantRangeTime), np.nan)
780+
781+
782+
for i in range(len(ap_elevationAngle)):
783+
elevAngle2d[i, :ap_elevationAngle[i].shape[0]] = ap_elevationAngle[i]
784+
785+
if ap_elevationAngle[i].shape[0] != ap_elevationPattern[i].shape[0] :
786+
gain2d[i, :ap_elevationAngle[i].shape[0]] = np.sqrt(ap_elevationPattern[i][::2]**2+ap_elevationPattern[i][1::2]**2)
787+
else:
788+
#logging.warn("antenna pattern is not given in complex values. You probably use an old file\n" + e)
789+
gain2d[i, :ap_elevationAngle[i].shape[0]] = ap_elevationPattern[i]
790+
791+
slantRangeTime2d[i, :ap_slantRangeTime[i].shape[0]] = ap_slantRangeTime[i]
792+
incAngle2d[i, :ap_incidenceAngle[i].shape[0]] = ap_incidenceAngle[i]
793+
794+
795+
swath_number_2d = np.full((len(np.unique(swathNumber)), dim_azimuthTime), np.nan)
796+
roll_angle_2d = np.full((len(np.unique(swathNumber)), dim_azimuthTime), np.nan)
797+
azimuthTime_2d = np.full((len(np.unique(swathNumber)), dim_azimuthTime), np.nan)
798+
terrainHeight_2d = np.full((len(np.unique(swathNumber)), dim_azimuthTime), np.nan)
799+
800+
slantRangeTime_2d = np.full((len(np.unique(swathNumber)), dim_slantRangeTime), np.nan)
801+
802+
elevationAngle_3d = np.full((len(np.unique(swathNumber)), dim_azimuthTime, dim_slantRangeTime), np.nan)
803+
incidenceAngle_3d = np.full((len(np.unique(swathNumber)), dim_azimuthTime, dim_slantRangeTime), np.nan)
804+
gain3d = np.full((len(np.unique(swathNumber)), dim_azimuthTime, dim_slantRangeTime), np.nan)
805+
806+
807+
for i, swath_number in enumerate(np.unique(swathNumber)):
808+
length_dim0 = len(ap_azimuthTime[swathNumber == swath_number])
809+
swath_number_2d[i, :length_dim0] = swathNumber[swathNumber == swath_number]
810+
azimuthTime_2d[i, :length_dim0] = ap_azimuthTime[swathNumber == swath_number]
811+
terrainHeight_2d[i, :length_dim0] = ap_terrainHeight[swathNumber == swath_number]
812+
slantRangeTime_2d[i, :] = slantRangeTime2d[i, :]
813+
814+
if include_roll:
815+
roll_angle_2d[i, :length_dim0] = ap_roll[swathNumber == swath_number]
816+
817+
for j in range(0, dim_slantRangeTime):
818+
elevationAngle_3d[i,:length_dim0,j]=elevAngle2d[swathNumber == swath_number,j]
819+
incidenceAngle_3d[i,:length_dim0,j]=incAngle2d[swathNumber == swath_number,j]
820+
gain3d[i,:length_dim0,j]=gain2d[swathNumber == swath_number,j]
821+
822+
azimuthTime_2d = azimuthTime_2d.astype('datetime64[ns]')
823+
824+
# return a Dataset
825+
ds = xr.Dataset({
826+
'slantRangeTime' : (['swath_nb', 'dim_slantRangeTime'], slantRangeTime_2d),
827+
'swath' : (['swath_nb', 'dim_azimuthTime'], swath_number_2d),
828+
'roll' : (['swath_nb', 'dim_azimuthTime'], roll_angle_2d),
829+
'azimuthTime' : (['swath_nb', 'dim_azimuthTime'], azimuthTime_2d),
830+
'terrainHeight' : (['swath_nb', 'dim_azimuthTime'], terrainHeight_2d),
831+
'elevationAngle' : (['swath_nb', 'dim_azimuthTime','dim_slantRangeTime'],elevationAngle_3d),
832+
'incidenceAngle' : (['swath_nb', 'dim_azimuthTime','dim_slantRangeTime'],incidenceAngle_3d),
833+
'gain' : (['swath_nb', 'dim_azimuthTime','dim_slantRangeTime'],gain3d),
834+
},
835+
coords={'swath_nb': np.unique(swathNumber)}
836+
)
837+
ds.attrs["dim_azimuthTime"] = "max dimension of azimuthTime for a swath"
838+
ds.attrs["dim_slantRangeTime"] = "max dimension of slantRangeTime for a swath"
839+
ds.attrs["comment"] = "The antenna pattern data set record contains a list of vectors of the \
840+
antenna elevation pattern values that have been updated along track\
841+
and used to correct the radiometry during image processing."
842+
ds.attrs["example"] = "for example, if swath Y is smaller than swath X, user has to remove nan to get the dims of the swath"
843+
ds.attrs["source"] = "Sentinel-1 Product Specification"
844+
845+
return ds
846+
847+
def swath_merging(sm_swath,sm_nbPerSwat,sm_azimuthTime,sm_firstAzimuthLine,sm_lastAzimuthLine,sm_firstRangeSample,sm_lastRangeSample):
848+
"""
849+
850+
Parameters
851+
----------
852+
sm_swath
853+
sm_nbPerSwat
854+
sm_azimuthTime
855+
sm_firstAzimuthLine
856+
sm_lastAzimuthLine
857+
sm_firstRangeSample
858+
sm_lastRangeSample
859+
860+
Returns
861+
-------
862+
xarray.DataSet
863+
"""
864+
# Fonction to convert string 'EW1' ou 'IW3' as int
865+
def convert_to_int(swath):
866+
return int(swath[-1])
867+
vectorized_convert = np.vectorize(convert_to_int)
868+
repeated_swaths = np.repeat(sm_swath, sm_nbPerSwat)
869+
swathNumber = vectorized_convert(repeated_swaths)
870+
871+
ds = xr.Dataset({
872+
'swaths' : (['dim_azimuthTime'], swathNumber),
873+
'azimuthTime' : (['dim_azimuthTime'], sm_azimuthTime),
874+
'firstAzimuthLine' : (['dim_azimuthTime'], sm_firstAzimuthLine),
875+
'lastAzimuthLine' : (['dim_azimuthTime'], sm_lastAzimuthLine),
876+
'firstRangeSample' : (['dim_azimuthTime'], sm_firstRangeSample),
877+
'lastRangeSample' : (['dim_azimuthTime'], sm_lastRangeSample),
878+
},
879+
)
880+
ds.attrs["comment"] = "The swath merging data set record contains information about how \
881+
multiple swaths were stitched together to form one large contiguous \
882+
swath. This data set record only applies to IW and EW GRD \
883+
products"
884+
ds.attrs["source"] = "Sentinel-1 Product Specification"
885+
886+
return ds
719887

720888
# dict of compounds variables.
721889
# compounds variables are variables composed of several variables.
@@ -732,7 +900,8 @@ def geolocation_grid(line, sample, values):
732900
'start_date': 'manifest.start_date',
733901
'stop_date': 'manifest.stop_date',
734902
'footprints': 'manifest.footprints',
735-
'aux_cal': 'manifest.aux_cal'
903+
'aux_cal': 'manifest.aux_cal',
904+
'aux_pp1': 'manifest.aux_pp1'
736905
},
737906
'safe_attributes_sl2': {
738907
'ipf_version': 'manifest.ipf_version',
@@ -856,4 +1025,17 @@ def geolocation_grid(line, sample, values):
8561025

8571026
),
8581027
},
1028+
'antenna_pattern': {
1029+
'func': antenna_pattern,
1030+
'args': ('annotation.ap_swath','annotation.ap_roll','annotation.ap_azimuthTime','annotation.ap_terrainHeight',
1031+
'annotation.ap_elevationAngle','annotation.ap_elevationPattern','annotation.ap_incidenceAngle',
1032+
'annotation.ap_slantRangeTime'
1033+
)
1034+
},
1035+
'swath_merging': {
1036+
'func': swath_merging,
1037+
'args': ('annotation.sm_swath','annotation.sm_nbPerSwat','annotation.sm_azimuthTime','annotation.sm_firstAzimuthLine',
1038+
'annotation.sm_lastAzimuthLine','annotation.sm_firstRangeSample','annotation.sm_lastRangeSample'
1039+
)
1040+
},
8591041
}

0 commit comments

Comments
 (0)