Skip to content

Commit

Permalink
ENH: Handling of Sentinel-1 SM products.
Browse files Browse the repository at this point in the history
  • Loading branch information
remi-braun committed Dec 1, 2023
1 parent aecfcd9 commit b3d6e1a
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- **ENH: Handle Python 3.12. ([#113](https://github.com/sertit/eoreader/issues/113))**
- **ENH: Guard against S1 COG format, not yet handled by SNAP.**
- **ENH: Calibration step for `Capella` products now exists in ESA SNAP. Add it in pre-processing.**
- **ENH: Handling of Sentinel-1 SM products.**
- FIX: Fix jpg, png... quicklooks management when plotting
- FIX: Fix an `xarray` issue when trying to compute percentiles when stacking bands
- CI: Update pre-commit hooks
Expand Down
6 changes: 6 additions & 0 deletions CI/SCRIPTS_SNAP/test_all_sat_end_to_end_on_disk.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,12 @@ def test_s1_slc_zip_core():
test_s1_slc_zip_core()


@dask_env
def test_s1_slc_sm():
"""Function testing the support of Sentinel-1 constellation"""
_test_core_sar("*S1*_S4_SLC*.SAFE")


@dask_env
def test_s1_grdh():
"""Function testing the support of Sentinel-1 constellation"""
Expand Down
144 changes: 144 additions & 0 deletions eoreader/data/cplx_s1_sm_preprocess_default.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<graph id="Graph">
<version>1.0</version>
<node id="Read">
<operator>Read</operator>
<sources/>
<parameters class="com.bc.ceres.binding.dom.XppDomElement">
<file>${file}</file>
<formatName>SENTINEL-1</formatName>
</parameters>
</node>

<node id="ThermalNoiseRemoval">
<operator>ThermalNoiseRemoval</operator>
<sources>
<sourceProduct refid="Read"/>
</sources>
<parameters class="com.bc.ceres.binding.dom.XppDomElement">
<selectedPolarisations/>
<removeThermalNoise>true</removeThermalNoise>
<reIntroduceThermalNoise>false</reIntroduceThermalNoise>
</parameters>
</node>

<node id="Calibration">
<operator>Calibration</operator>
<sources>
<sourceProduct refid="ThermalNoiseRemoval"/>
</sources>
<parameters class="com.bc.ceres.binding.dom.XppDomElement">
<sourceBands/>
<auxFile>Latest Auxiliary File</auxFile>
<externalAuxFile/>
<outputImageInComplex>false</outputImageInComplex>
<outputImageScaleInDb>false</outputImageScaleInDb>
<createGammaBand>false</createGammaBand>
<createBetaBand>false</createBetaBand>
<selectedPolarisations>${calib_pola}</selectedPolarisations>
<outputSigmaBand>true</outputSigmaBand>
<outputGammaBand>false</outputGammaBand>
<outputBetaBand>false</outputBetaBand>
</parameters>
</node>

<node id="Multilook">
<operator>Multilook</operator>
<sources>
<sourceProduct refid="Calibration"/>
</sources>
<parameters class="com.bc.ceres.binding.dom.XppDomElement">
<sourceBands/>
<nRgLooks>2</nRgLooks>
<nAzLooks>2</nAzLooks>
<outputIntensity>true</outputIntensity>
<grSquarePixel>true</grSquarePixel>
</parameters>
</node>


<node id="Terrain-Correction">
<operator>Terrain-Correction</operator>
<sources>
<sourceProduct refid="Multilook"/>
</sources>
<parameters class="com.bc.ceres.binding.dom.XppDomElement">
<sourceBands/>
<demName>${dem_name}</demName>
<externalDEMFile>${dem_path}</externalDEMFile>
<externalDEMNoDataValue>0.0</externalDEMNoDataValue>
<externalDEMApplyEGM>true</externalDEMApplyEGM>
<demResamplingMethod>BILINEAR_INTERPOLATION</demResamplingMethod>
<imgResamplingMethod>BILINEAR_INTERPOLATION</imgResamplingMethod>
<pixelSpacingInMeter>${res_m}</pixelSpacingInMeter>
<pixelSpacingInDegree>${res_deg}</pixelSpacingInDegree>
<mapProjection>${crs}</mapProjection>
<alignToStandardGrid>false</alignToStandardGrid>
<standardGridOriginX>0.0</standardGridOriginX>
<standardGridOriginY>0.0</standardGridOriginY>
<nodataValueAtSea>false</nodataValueAtSea>
<saveDEM>false</saveDEM>
<saveLatLon>false</saveLatLon>
<saveIncidenceAngleFromEllipsoid>false</saveIncidenceAngleFromEllipsoid>
<saveLocalIncidenceAngle>false</saveLocalIncidenceAngle>
<saveProjectedLocalIncidenceAngle>false</saveProjectedLocalIncidenceAngle>
<saveSelectedSourceBand>true</saveSelectedSourceBand>
<applyRadiometricNormalization>false</applyRadiometricNormalization>
<saveSigmaNought>false</saveSigmaNought>
<saveGammaNought>false</saveGammaNought>
<saveBetaNought>false</saveBetaNought>
<incidenceAngleForSigma0>Use projected local incidence angle from DEM</incidenceAngleForSigma0>
<incidenceAngleForGamma0>Use projected local incidence angle from DEM</incidenceAngleForGamma0>
<auxFile>Latest Auxiliary File</auxFile>
<externalAuxFile/>
</parameters>
</node>

<node id="LinearToFromdB">
<operator>LinearToFromdB</operator>
<sources>
<sourceProduct refid="Terrain-Correction"/>
</sources>
<parameters class="com.bc.ceres.binding.dom.XppDomElement">
<sourceBands/>
</parameters>
</node>

<node id="Write">
<operator>Write</operator>
<sources>
<sourceProduct refid="LinearToFromdB"/>
</sources>
<parameters class="com.bc.ceres.binding.dom.XppDomElement">
<file>${out}</file>
<formatName>BEAM-DIMAP</formatName>
</parameters>
</node>

<applicationData id="Presentation">
<Description/>
<node id="Read">
<displayPosition x="7.0" y="131.0"/>
</node>
<node id="Calibration">
<displayPosition x="43.0" y="188.0"/>
</node>
<node id="Terrain-Correction">
<displayPosition x="143.0" y="265.0"/>
</node>
<node id="LinearToFromdB">
<displayPosition x="256.0" y="299.0"/>
</node>
<node id="Multilook">
<displayPosition x="108.0" y="224.0"/>
</node>
<node id="Write">
<displayPosition x="461.0" y="307.0"/>
</node>
<node id="ThermalNoiseRemoval">
<displayPosition x="205.0" y="136.0"/>
</node>
<node id="TOPSAR-Deburst">
<displayPosition x="277.0" y="173.0"/>
</node>
</applicationData>
</graph>
6 changes: 2 additions & 4 deletions eoreader/products/optical/s2_e84_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -1013,13 +1013,11 @@ def _get_path(self, file_id: str, ext="tif") -> str:

def _read_mtd(self) -> (etree._Element, dict):
"""
Read Landsat metadata as:
- :code:`pandas.DataFrame` whatever its collection is (by default for collection 1)
- XML root + its namespace if the product is retrieved from the 2nd collection (by default for collection 2)
Read mtd.
Args:
force_pd (bool): If collection 2, return a pandas.DataFrame instead of an XML root + namespace
Returns:
Tuple[Union[pd.DataFrame, etree._Element], dict]:
Metadata as a Pandas.DataFrame or as (etree._Element, dict): Metadata XML root and its namespaces
Expand Down
9 changes: 4 additions & 5 deletions eoreader/products/sar/s1_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,14 +312,13 @@ def _set_sensor_mode(self) -> None:
if not mode:
raise InvalidProductError("mode not found in metadata!")

# Mono swath SM
if mode in ["S1", "S2", "S3", "S4", "S5", "S6"]:
mode = "SM"

# Get sensor mode
self.sensor_mode = S1SensorMode.from_value(mode)

# Discard invalid sensor mode
if self.sensor_mode != S1SensorMode.IW:
raise NotImplementedError(
f"For now, only IW sensor mode is used in EOReader processes: {self.name}"
)
if not self.sensor_mode:
raise InvalidProductError(
f"Invalid {self.constellation.value} name: {self.name}"
Expand Down
11 changes: 6 additions & 5 deletions eoreader/products/sar/sar_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -713,11 +713,12 @@ def _pre_process_sar(self, band: sab, pixel_size: float = None, **kwargs) -> str
)

else:
sat = (
"s1"
if self.constellation_id == Constellation.S1.name
else "sar"
)
if self.constellation_id == Constellation.S1.name:
sat = "s1"
if self.sensor_mode.value == "SM":
sat += "_sm"
else:
sat = "sar"
spt = (
"grd"
if self.sar_prod_type == SarProductType.GDRG
Expand Down
4 changes: 2 additions & 2 deletions eoreader/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ class Constellation(ListEnum):


CONSTELLATION_REGEX = {
Constellation.S1: r"S1[AB]_(IW|EW|SM|WV)_(RAW|SLC|GRD|OCN)[FHM_]_[0-2]S[SD][HV]_\d{8}T\d{6}_\d{8}T\d{6}_\d{6}_.{11}(_COG|)",
Constellation.S1: r"S1[AB]_(IW|EW|SM|WV|S\d)_(RAW|SLC|GRD|OCN)[FHM_]_[0-2]S[SD][HV]_\d{8}T\d{6}_\d{8}T\d{6}_\d{6}_.{11}(_COG|)",
Constellation.S2: r"S2[AB]_MSIL(1C|2A)_\d{8}T\d{6}_N\d{4}_R\d{3}_T\d{2}\w{3}_\d{8}T\d{6}",
# Element84 : S2A_31UDQ_20230714_0_L2A, Sinergise: 0 or 1...
Constellation.S2_E84: r"S2[AB]_\d{2}\w{3}_\d{8}_\d_L(1C|2A)",
Expand Down Expand Up @@ -273,7 +273,7 @@ class Constellation(ListEnum):
Constellation.S1: {
"nested": 1,
# File that can be found at any level (product/**/file)
"regex": r".*s1[ab]-(iw|ew|sm|wv)\d*-(raw|slc|grd|ocn)-[hv]{2}-\d{8}t\d{6}-\d{8}t\d{6}-\d{6}-\w{6}-\d{3}(-cog|)\.xml",
"regex": r".*s1[ab]-(iw|ew|sm|wv|s\d)\d*-(raw|slc|grd|ocn)-[hv]{2}-\d{8}t\d{6}-\d{8}t\d{6}-\d{6}-\w{6}-\d{3}(-cog|)\.xml",
},
Constellation.S2: {"nested": 3, "regex": r"MTD_TL.xml"},
Constellation.S2_E84: rf"{CONSTELLATION_REGEX[Constellation.S2_E84]}\.json",
Expand Down

0 comments on commit b3d6e1a

Please sign in to comment.