Skip to main content

SNAP processing

s1bursts relies on ESA SNAP for the SAR and InSAR processing. This page describes the steps SNAP applies to a burst, how to inspect them for your own settings, which SNAP problems s1bursts corrects, and how the supported SNAP versions differ.

The processing steps

Each product runs through a fixed chain of SNAP operators, called a processing graph. s1bursts builds the graph from the product’s settings object, so the settings decide which steps run and with which parameters. The RTC backscatter graph has eight steps with the default settings:

Step What it does Settings
Apply-Orbit-File Replaces the predicted satellite orbit with the precise one
ThermalNoiseRemoval Removes the instrument’s own noise
Calibration Converts the raw values to beta-0 radar brightness
TOPSAR-Deburst Keeps only the burst’s valid lines and samples, dropping the empty margin around it
Multilook Averages neighboring pixels to reduce noise and runtime multilook (None skips it)
Terrain-Flattening Corrects brightness for the slope of the terrain (RTC only) dem_oversampling, additional_overlap, DEM settings
ReplaceZerosWithNoData Marks the empty border of the burst as missing (why) replace_zeros_with_nan (False skips it)
Terrain-Correction Places every pixel on the map, using the DEM grid_spacing, img_resampling, align_to_standard_grid, DEM settings

The DEM settings are dem, dem_resampling and, for an external DEM, external_dem_nodata and external_dem_apply_egm.

The GTC graph of GTCConfig is the same without Terrain-Flattening. Coherence compares two acquisitions, so its graph differs. Both acquisitions get precise orbits, then Back-Geocoding aligns the second onto the first pixel by pixel, using the DEM. Coherence estimates the similarity of the two within a moving window, set by window. TOPSAR-Deburst, ReplaceZerosWithNoData and Terrain-Correction then run as in the backscatter graph. The coherence graph has no noise removal, calibration or multilooking.

Inspect a graph

Every settings object can show the graph it produces, as a diagram or as the XML file that SNAP runs, to check what your settings change.

As a diagram

to_mermaid() returns the graph as text in the Mermaid diagram language. In a notebook, the mermaid-py package draws it. Install it separately, since s1bursts does not depend on it:

from mermaid import Mermaid
from s1bursts import RTCConfig

config = RTCConfig(grid_spacing=20)
Mermaid(config.to_mermaid())

mermaid-py draws the diagram through the online mermaid.ink service. Without internet access, paste the text into a mermaid code block on GitHub or in Quarto instead. For RTCConfig(grid_spacing=20), the graph looks like this:

flowchart TD
    source[/"source"/]
    Apply-Orbit-File["Apply-Orbit-File"]
    Calibration["Calibration"]
    Multilook["Multilook"]
    ReplaceZerosWithNoData["ReplaceZerosWithNoData"]
    TOPSAR-Deburst["TOPSAR-Deburst"]
    Terrain-Correction["Terrain-Correction"]
    Terrain-Flattening["Terrain-Flattening"]
    ThermalNoiseRemoval["ThermalNoiseRemoval"]
    source --> Apply-Orbit-File
    Apply-Orbit-File --> ThermalNoiseRemoval
    ThermalNoiseRemoval --> Calibration
    Calibration --> TOPSAR-Deburst
    TOPSAR-Deburst --> Multilook
    Multilook --> Terrain-Flattening
    Terrain-Flattening --> ReplaceZerosWithNoData
    ReplaceZerosWithNoData --> Terrain-Correction

As XML

to_xml() returns the graph in the XML format of SNAP’s Graph Processing Tool (GPT), with every parameter SNAP receives:

xml = config.to_xml()
<graph id="Graph">
  <version>1.0</version>
  <node id="Apply-Orbit-File">
    <operator>Apply-Orbit-File</operator>
    <sources>
      <sourceProduct>${source}</sourceProduct>
    </sources>
    <parameters class="com.bc.ceres.binding.dom.XppDomElement">
      <orbitType>Sentinel Precise (Auto Download)</orbitType>
      <polyDegree>3</polyDegree>
      <continueOnFail>false</continueOnFail>
    </parameters>
  </node>
  <node id="ThermalNoiseRemoval">
    <operator>ThermalNoiseRemoval</operator>
    <sources>
      <sourceProduct refid="Apply-Orbit-File" />
    </sources>
    <parameters class="com.bc.ceres.binding.dom.XppDomElement">
      <selectedPolarisations />
      <removeThermalNoise>true</removeThermalNoise>
      <outputNoise>false</outputNoise>
      <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 />
      <outputSigmaBand>false</outputSigmaBand>
      <outputGammaBand>false</outputGammaBand>
      <outputBetaBand>true</outputBetaBand>
    </parameters>
  </node>
  <node id="TOPSAR-Deburst">
    <operator>TOPSAR-Deburst</operator>
    <sources>
      <sourceProduct refid="Calibration" />
    </sources>
    <parameters class="com.bc.ceres.binding.dom.XppDomElement">
      <selectedPolarisations />
    </parameters>
  </node>
  <node id="Multilook">
    <operator>Multilook</operator>
    <sources>
      <sourceProduct refid="TOPSAR-Deburst" />
    </sources>
    <parameters class="com.bc.ceres.binding.dom.XppDomElement">
      <sourceBands />
      <nRgLooks>5</nRgLooks>
      <nAzLooks>1</nAzLooks>
      <outputIntensity>true</outputIntensity>
      <grSquarePixel>false</grSquarePixel>
    </parameters>
  </node>
  <node id="Terrain-Flattening">
    <operator>Terrain-Flattening</operator>
    <sources>
      <sourceProduct refid="Multilook" />
    </sources>
    <parameters class="com.bc.ceres.binding.dom.XppDomElement">
      <sourceBands />
      <demName>Copernicus 30m Global DEM</demName>
      <demResamplingMethod>BILINEAR_INTERPOLATION</demResamplingMethod>
      <externalDEMFile />
      <externalDEMNoDataValue>0.0</externalDEMNoDataValue>
      <externalDEMApplyEGM>false</externalDEMApplyEGM>
      <outputSimulatedImage>true</outputSimulatedImage>
      <outputSigma0>false</outputSigma0>
      <nodataValueAtSea>true</nodataValueAtSea>
      <additionalOverlap>0.2</additionalOverlap>
      <oversamplingMultiple>1.0</oversamplingMultiple>
    </parameters>
  </node>
  <node id="ReplaceZerosWithNoData">
    <operator>BandMaths</operator>
    <sources>
      <sourceProduct refid="Terrain-Flattening" />
    </sources>
    <parameters class="com.bc.ceres.binding.dom.XppDomElement">
      <targetBands>
        <targetBand>
          <name>gamma0</name>
          <type>float32</type>
          <expression>Gamma0_${swath}_${polarization} &gt; 0 ? Gamma0_${swath}_${polarization} : -1099511627776.0</expression>
          <noDataValue>-1099511627776.0</noDataValue>
        </targetBand>
        <targetBand>
          <name>scattering_area</name>
          <type>float32</type>
          <expression>simulatedImage &gt; 0 ? simulatedImage : -1099511627776.0</expression>
          <noDataValue>-1099511627776.0</noDataValue>
        </targetBand>
      </targetBands>
      <variables />
    </parameters>
  </node>
  <node id="Terrain-Correction">
    <operator>Terrain-Correction</operator>
    <sources>
      <sourceProduct refid="ReplaceZerosWithNoData" />
    </sources>
    <parameters class="com.bc.ceres.binding.dom.XppDomElement">
      <sourceBands />
      <demName>Copernicus 30m Global DEM</demName>
      <externalDEMFile />
      <externalDEMNoDataValue>0.0</externalDEMNoDataValue>
      <externalDEMApplyEGM>false</externalDEMApplyEGM>
      <demResamplingMethod>BILINEAR_INTERPOLATION</demResamplingMethod>
      <imgResamplingMethod>BILINEAR_INTERPOLATION</imgResamplingMethod>
      <pixelSpacingInMeter>20.0</pixelSpacingInMeter>
      <mapProjection>${crs}</mapProjection>
      <alignToStandardGrid>true</alignToStandardGrid>
      <standardGridOriginX>10.0</standardGridOriginX>
      <standardGridOriginY>10.0</standardGridOriginY>
      <nodataValueAtSea>true</nodataValueAtSea>
      <saveDEM>false</saveDEM>
      <saveLatLon>false</saveLatLon>
      <saveIncidenceAngleFromEllipsoid>false</saveIncidenceAngleFromEllipsoid>
      <saveLocalIncidenceAngle>false</saveLocalIncidenceAngle>
      <saveProjectedLocalIncidenceAngle>false</saveProjectedLocalIncidenceAngle>
      <saveSelectedSourceBand>true</saveSelectedSourceBand>
      <saveLayoverShadowMask>false</saveLayoverShadowMask>
      <outputComplex>false</outputComplex>
      <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>
</graph>

The graph leaves two placeholders, ${source} for the burst file and ${crs} for the UTM zone. s1bursts fills them in for every burst it processes, which is why the UTM zone is passed to the create_* methods rather than stored in the settings. CoherenceConfig returns its graph the same way, with ${primary} and ${secondary} in place of ${source}.

For your SNAP version

The coherence graph differs slightly between SNAP 13 and 14. Without a version, s1bursts builds the graph for SNAP 13. Pass the version of your installation to see the exact graph that processing runs:

from s1bursts import CoherenceConfig, SNAPConfig

version = SNAPConfig().resolved_snap_version
xml = CoherenceConfig().to_xml(snap_version=version)

Corrections s1bursts applies

s1bursts works around four SNAP problems, so you do not need to:

  • External DEMs are read half a pixel off (forum report). prepare_dem_for_snap() shifts the DEM to compensate, but only before the 14.0.2 update of SNAP’s DEM module, which fixed it.
  • DEM heights use the wrong sea-level model (forum report). SNAP knows only the EGM96 model, even for DEMs based on another. prepare_dem_for_snap() converts external DEM heights itself (see Using an external DEM). The built-in Copernicus DEM is affected too. To avoid it, download the Copernicus DEM and prepare it as an external DEM with source_crs="EPSG:4326+3855".
  • Burst edges come out too dark (forum report). SNAP mixes the empty border of the input into the edge pixels during terrain correction, which leaves dark seams along the burst edges. s1bursts marks that border as missing before terrain correction.
  • Areas without DEM coverage become zeros. Where the DEM has no data, for example over the sea at the edge of a burst, SNAP can write zeros instead of missing values. s1bursts turns these into NaN.

SNAP versions

s1bursts works with SNAP 13 and 14. It reads the installed version and adapts the graphs to it, so the same code runs on either. The version is recorded in every product’s PROCESSING_SOFTWARE_VERSION tag. An existing product of another version is not skipped, and products of two versions are not combined into one composite.

NoteKeep one SNAP version per study

SNAP versions give slightly different results for the same burst, so a time series that switches version contains an artificial step. Between SNAP 13 and 14, backscatter differs by a median of about 0.05 dB and coherence by about 0.004 on average.

SNAP 14 also adds two coherence options, exposed as CoherenceConfig.correct_coherence_bias and remove_local_phase_ramp. Both are off by default and need SNAP 14 or newer. Products record them in the COHERENCE_BIAS_CORRECTED and LOCAL_PHASE_RAMP_REMOVED tags: false under SNAP 13, and N/A when the SNAP version could not be determined, since SNAP 14 then applies its own default, which corrects the bias.

Validation

s1bursts products are checked against products of the same bursts from independent processors: backscatter against OPERA RTC-S1 from NASA/JPL, and coherence against ASF HyP3 burst InSAR products. Both use the same Copernicus DEM, so the comparison tests the processing itself. The comparisons are tests in the repository, test_opera_validation.py and test_insar_validation.py. REFERENCE.md describes the reference products and what each test checks.