@@ -25,7 +25,7 @@ def get_metadata(gdal_dataset: gdal.Dataset) -> Dict[str, Any]:
2525 :param gdal_dataset: Dataset with metadata
2626 :return: Dictionary with metadata attributes
2727 """
28- attributes : dict [str , Any ] = dict ()
28+ attributes : dict [str , Any ] = {}
2929 process_general_metadata (gdal_dataset , attributes )
3030 process_records_metadata (gdal_dataset , attributes )
3131 process_derived_subdatasets_metadata (gdal_dataset , attributes )
@@ -35,35 +35,36 @@ def get_metadata(gdal_dataset: gdal.Dataset) -> Dict[str, Any]:
3535 return attributes
3636
3737
38- def open_asar_dataset (filepath : str | os .PathLike [Any ] | ReadBuffer [Any ] | AbstractDataStore ) -> xr .Dataset :
38+ def open_asar_dataset (filename_or_obj : str | os .PathLike [Any ] | ReadBuffer [
39+ Any ] | bytes | memoryview | AbstractDataStore ) -> xr .Dataset :
3940 """
4041 Open an ASAR dataset and converts it into an xarray Dataset.
4142
4243 This function reads the metadata and pixel data from the given ASAR dataset file,
4344 processes the metadata into attributes, and constructs an xarray Dataset.
4445
45- :param filepath : The path to the ASAR dataset file. It can be a string,
46+ :param filename_or_obj : The path to the ASAR dataset file. It can be a string,
4647 a PathLike object, a ReadBuffer, or an AbstractDataStore.
4748 :return: An xarray Dataset containing the pixel data and metadata attributes.
4849 :raises NotImplementedError: If the filepath is not a string.
4950 """
50- if not isinstance (filepath , str ):
51- raise NotImplementedError (f'Filepath type { type (filepath )} is not supported' )
51+ if not isinstance (filename_or_obj , str ):
52+ raise NotImplementedError (f'Filepath type { type (filename_or_obj )} is not supported' )
5253
53- logger .debug ('Opening ASAR dataset {}' , filepath )
54+ logger .debug ('Opening ASAR dataset {}' , filename_or_obj )
5455
5556 # Open the dataset using a custom reader
56- gdal_dataset : gdal .Dataset = reader .get_gdal_dataset (filepath )
57+ gdal_dataset : gdal .Dataset = reader .get_gdal_dataset (filename_or_obj )
5758
5859 # Extract metadata attributes
5960 metadata = get_metadata (gdal_dataset )
6061
6162 # Duplicate, read directly from file, as gdal does not parse some necessary metadata
6263
63- metadata ["direct_parse" ] = envisat_direct .parse_direct (filepath , metadata )
64+ metadata ["direct_parse" ] = envisat_direct .parse_direct (filename_or_obj , metadata )
6465
6566 # Create an xarray Dataset with pixel data and metadata attributes
66- dataset : xr .Dataset = create_dataset (metadata , filepath )
67+ dataset : xr .Dataset = create_dataset (metadata , filename_or_obj )
6768
6869 return dataset
6970
@@ -89,10 +90,16 @@ def create_dataset(metadata: dict[str, Any], filepath: str) -> xr.Dataset:
8990 range_sampling_rate = metadata ["records" ]["main_processing_params" ]["range_samp_rate" ]
9091 image_slant_range_time = metadata ["direct_parse" ]["slant_time_first" ] * 1e-9
9192
92- if metadata ["sph_descriptor" ] == "Image Mode SLC Image" :
93+ range_pixel_spacing = metadata ["records" ]["main_processing_params" ]["range_spacing" ]
94+
95+ product_str = metadata ["sph_descriptor" ]
96+
97+ if product_str == "Image Mode SLC Image" :
9398 product_type = "SLC"
99+ elif product_str == "Image Mode Precision Image" :
100+ product_type = "GRD"
94101 else :
95- raise RuntimeError ("Only Image mode SLC files(IMS) supported for now" )
102+ raise RuntimeError ("Only Image mode files supported (IMS & IMP ) supported for now" )
96103
97104 attrs = {
98105 "family_name" : "Envisat" ,
@@ -106,8 +113,7 @@ def create_dataset(metadata: dict[str, Any], filepath: str) -> xr.Dataset:
106113 "product_type" : product_type ,
107114 "start_time" : product_first_line_utc_time ,
108115 "stop_time" : product_last_line_utc_time ,
109- "range_pixel_spacing" : metadata ["range_spacing" ],
110- "azimuth_pixel_spacing" : metadata ["azimuth_spacing" ],
116+ "range_pixel_spacing" : metadata ["range_spacing" ],
111117 "radar_frequency" : metadata ["records" ]["main_processing_params" ]["radar_freq" ] / 1e9 ,
112118 "ascending_node_time" : "" ,
113119 "azimuth_pixel_spacing" : metadata ["records" ]["main_processing_params" ]["azimuth_spacing" ],
@@ -116,15 +122,14 @@ def create_dataset(metadata: dict[str, Any], filepath: str) -> xr.Dataset:
116122 "azimuth_time_interval" : azimuth_time_interval ,
117123 "image_slant_range_time" : image_slant_range_time ,
118124 "range_sampling_rate" : range_sampling_rate ,
119- "incidence_angle_mid_swath" : metadata ["direct_parse" ]["incidence_angle_center" ] * 2 * math .pi / 360 ,
125+ "incidence_angle_mid_swath" : metadata ["direct_parse" ]["incidence_angle_center" ] * 2 * math .pi / 360 ,
120126 "metadata" : metadata
121127 }
122128
123129 azimuth_time = compute_azimuth_time (
124130 product_first_line_utc_time , product_last_line_utc_time , number_of_lines
125131 )
126132
127-
128133 swap_dims = {"line" : "azimuth_time" , "pixel" : "slant_range_time" }
129134
130135 coords : dict [str , Any ] = {
@@ -140,12 +145,34 @@ def create_dataset(metadata: dict[str, Any], filepath: str) -> xr.Dataset:
140145 ),
141146 }
142147
143- slant_range_time = np .linspace (
144- image_slant_range_time ,
145- image_slant_range_time + (number_of_samples - 1 ) / range_sampling_rate ,
146- number_of_samples ,
147- )
148- coords ["slant_range_time" ] = ("pixel" , slant_range_time )
148+ if product_type == "SLC" :
149+ slant_range_time = np .linspace (
150+ image_slant_range_time ,
151+ image_slant_range_time + (number_of_samples - 1 ) / range_sampling_rate ,
152+ number_of_samples ,
153+ )
154+ coords ["slant_range_time" ] = ("pixel" , slant_range_time )
155+ else :
156+
157+ # generate slant range times from ground ranges for ground range products
158+ # this is easier due to the Envisat only having GRSR metadata unlike Sentinel1
159+ # however xarray/Sarsen handle GRD conversion differently for S1
160+ ground_range = np .linspace (
161+ 0 ,
162+ range_pixel_spacing * (number_of_samples - 1 ),
163+ number_of_samples ,
164+ )
165+
166+ # numpy polyval expects the polynomial top be highest ranked first
167+ coeffs = list (reversed (metadata ["direct_parse" ]["grsr_coeffs" ]))
168+
169+ slant_ranges = np .polyval (coeffs , ground_range )
170+ slant_ranges *= 2
171+
172+ c = 299792458
173+ slant_range_times = slant_ranges / c
174+
175+ coords ["slant_range_time" ] = ("pixel" , slant_range_times )
149176
150177 data = xr .open_dataarray (filepath , engine = 'rasterio' )
151178 data .encoding .clear ()
@@ -168,19 +195,17 @@ def get_chirp_parameters(dataset: gdal.Dataset) -> dict[str, Any]:
168195 :return: dictionary with chirp parameters.
169196 """
170197 metadata = dataset .GetMetadata (domain = 'RECORDS' )
171- params : dict [str , Any ] = dict ()
198+ params : dict [str , Any ] = {
199+ 'zero_doppler_time' : utils .get_envisat_time (metadata .get ('CHIRP_PARAMS_ADS_ZERO_DOPPLER_TIME' )),
200+ 'attach_flag' : bool (int (metadata .get ('CHIRP_PARAMS_ADS_ATTACH_FLAG' , '0' ))),
201+ 'beam_id' : metadata .get ('CHIRP_PARAMS_ADS_BEAM_ID' ), 'polarisation' : metadata .get ('CHIRP_PARAMS_ADS_POLAR' ),
202+ 'chirp' : {}}
172203 # Non-float values
173- params ['zero_doppler_time' ] = utils .get_envisat_time (metadata .get ('CHIRP_PARAMS_ADS_ZERO_DOPPLER_TIME' ))
174- params ['attach_flag' ] = bool (int (metadata .get ('CHIRP_PARAMS_ADS_ATTACH_FLAG' , '0' )))
175- params ['beam_id' ] = metadata .get ('CHIRP_PARAMS_ADS_BEAM_ID' )
176- params ['polarisation' ] = metadata .get ('CHIRP_PARAMS_ADS_POLAR' )
177- params ['chirp' ] = dict ()
178204 for key , value in metadata .items ():
179205 if 'CHIRP_PARAMS_ADS_CHIRP' in key :
180206 new_key = key .replace ('CHIRP_PARAMS_ADS_CHIRP_' , '' ).lower ()
181207 params ['chirp' ][new_key ] = float (value )
182208
183- #params['elev_corr_factor'] = float(metadata.get('CHIRP_PARAMS_ADS_ELEV_CORR_FACTOR'))
184209 params ['cal_pulse_info' ] = get_chirp_cal_pulse_info (metadata )
185210
186211 return params
0 commit comments