Skip to main content

NetCDF Extraction Processor

Introduction

ESA PAL includes a tool called "Biomass L0 extraction tool",  a Command-Line Interface (CLI) tool designed by Aresys to extract Biomass Level 0 data. 

The tool starts from a couple of input BIOMASS L0S / L0M products, plus corresponding auxiliary files (AUX_ATT, AUX_ORB, AUX_TEC and AUX_INS), and generates an output extracted L0 product in NetCDF format. The main development driver for this tool has been to give users access to BIOMASS L0 data (and corresponding metadata) without the need to decode and decompress them starting from their original format. 

The structure of a sample NetCDF file is the following:

  • SAR RAW data, divided per polarization, with the corresponding timing metadata
  • Internal calibration data, divided per polarization, with the corresponding timing metadata
  • On-board temperature monitoring data
  • Platform data (satellite position, velocity and attitude quaternions)
  • Instrument data (carrier frequency and transmitted pulse)
  • Main product metadata

netcdf BIO_S2_RAW__0S_20260202T142610_20260202T142807_T_G01_M01_CDR_T____F027_01_DM86GE {
types:
  compound fcomplex {
    float real ;
    float imag ;
  }; // fcomplex

// global attributes:
                :description = "BIOMASS Extracted L0 Product" ;
                :product_name = "BIO_S2_RAW__0S_20260202T142610_20260202T142807_T_G01_M01_CDR_T____F027_01_DM86GE" ;
                :mission = "BIOMASS" ;
                :mission_phase_id = "TOMOGRAPHIC" ;
                :instrument_configuration_id = 0US ;
                :datatake_id = 33556775ULL ;
                :orbit_number = 4096US ;
                :orbit_direction = "DESCENDING" ;
                :orbit_drift_flag = "True" ;
                :global_coverage_id = 1US ;
                :major_cycle_id = 1US ;
                :repeat_cycle_id = -2s ;
                :track_number = 24US ;
                :slice_number = 27US ;
                :product_type = "L0" ;
                :swath = "S2" ;
                :baseline_id = 1US ;
                :slice_status = "NOMINAL" ;
                :sensing_start_time = "2026-02-02T14:26:09.630000" ;
                :sensing_stop_time = "2026-02-02T14:28:06.646000" ;
                :validity_start_time = "2026-02-02T14:26:09.630000" ;
                :validity_stop_time = "2026-02-02T14:28:06.646000" ;
                :file_originator = "ARESYS" ;
                :file_origination_date = "2026-04-24T11:45:37.440575" ;
                :nodata_value = -9999.f ;
                :reference_azimuth_time = "2026-02-02T14:26:52.154650" ;

group: sar_data {
  // this group contains the SAR RAW data, divided per polarization, with the corresponding timing metadata
  // data and metadata are already decoded and (for data) decompressed
  // data are expressed as 2D arrays in the slant-range/azimuth time domain
  // in addition are provided also arrays describing PRF, SWP and SWL variations along azimuth time
  // note that azimuth times are provided as relative ones (i.e. float values) with respect to reference_azimuth_time global attribute (which is an absolute time in ISO 8601 datetime format)

  // group attributes:
                :description = "SAR data" ;

  group: HH {
    dimensions:
        azimuth_time = 6750 ;
        range_time = 1917 ;
    variables:
        float azimuth_time(azimuth_time) ;
                azimuth_time:units = "s" ;
        float range_time(range_time) ;
                range_time:units = "s" ;
        fcomplex data(azimuth_time, range_time) ;
        float prf_change(azimuth_time) ;
                prf_change:units = "Hz" ;
        float swp_change(azimuth_time) ;
                swp_change:units = "s" ;
        float swl_change(azimuth_time) ;
                swl_change:units = "s" ;

    // group attributes:
                :description = "SAR data (H/H polarization)" ;
    } // group HH

  group: HV {
    dimensions:
        azimuth_time = 6750 ;
        range_time = 1917 ;
    variables:
        float azimuth_time(azimuth_time) ;
                azimuth_time:units = "s" ;
        float range_time(range_time) ;
                range_time:units = "s" ;
        fcomplex data(azimuth_time, range_time) ;
        float prf_change(azimuth_time) ;
                prf_change:units = "Hz" ;
        float swp_change(azimuth_time) ;
                swp_change:units = "s" ;
        float swl_change(azimuth_time) ;
                swl_change:units = "s" ;

    // group attributes:
                :description = "SAR data (H/V polarization)" ;
    } // group HV

  group: VH {
    dimensions:
        azimuth_time = 6750 ;
        range_time = 1917 ;
    variables:
        float azimuth_time(azimuth_time) ;
                azimuth_time:units = "s" ;
        float range_time(range_time) ;
                range_time:units = "s" ;
        fcomplex data(azimuth_time, range_time) ;
        float prf_change(azimuth_time) ;
                prf_change:units = "Hz" ;
        float swp_change(azimuth_time) ;
                swp_change:units = "s" ;
        float swl_change(azimuth_time) ;
                swl_change:units = "s" ;

    // group attributes:
                :description = "SAR data (V/H polarization)" ;
    } // group VH

  group: VV {
    dimensions:
        azimuth_time = 6750 ;
        range_time = 1917 ;
    variables:
        float azimuth_time(azimuth_time) ;
                azimuth_time:units = "s" ;
        float range_time(range_time) ;
                range_time:units = "s" ;
        fcomplex data(azimuth_time, range_time) ;
        float prf_change(azimuth_time) ;
                prf_change:units = "Hz" ;
        float swp_change(azimuth_time) ;
                swp_change:units = "s" ;
        float swl_change(azimuth_time) ;
                swl_change:units = "s" ;

    // group attributes:
                :description = "SAR data (V/V polarization)" ;
    } // group VV
  } // group sar_data

group: calibration_data {
  // this group contains the internal calibration data, divided per polarization, with the corresponding timing metadata
  // data and metadata are already decoded and (for data) decompressed
  // data are expressed as 2D arrays in the slant-range/azimuth time domain
  // in addition is provided also an array with the calibration types of each calibration pulse (then with the same cardinality of azimuth dimension)
  // note that azimuth times are provided as relative ones (i.e. float values) with respect to reference_azimuth_time global attribute (which is an absolute time in ISO 8601 datetime format)

  // group attributes:
                :description = "Calibration data" ;

  group: HH {
    dimensions:
        azimuth_time = 514 ;
        range_time = 1916 ;
    variables:
        float azimuth_time(azimuth_time) ;
                azimuth_time:units = "s" ;
        float range_time(range_time) ;
                range_time:units = "s" ;
        string signal_type(azimuth_time) ;
        fcomplex data(azimuth_time, range_time) ;

    // group attributes:
                :description = "Calibration data (H/H polarization)" ;
    } // group HH

  group: VV {
    dimensions:
        azimuth_time = 514 ;
        range_time = 1916 ;
    variables:
        float azimuth_time(azimuth_time) ;
                azimuth_time:units = "s" ;
        float range_time(range_time) ;
                range_time:units = "s" ;
        string signal_type(azimuth_time) ;
        fcomplex data(azimuth_time, range_time) ;

    // group attributes:
                :description = "Calibration data (V/V polarization)" ;
    } // group VV
  } // group calibration_data

group: temperature_data {
  // this group contains the on-board temperature monitoring data
  // data are already decoded
  // data are expressed as a 2D array in the temperature ID/azimuth time domain (it means that for each temperature ID the variation along azimuth time is provided)
  // note that azimuth times are provided as relative ones (i.e. float values) with respect to reference_azimuth_time global attribute (which is an absolute time in ISO 8601 datetime format)

  dimensions:
        azimuth_time = 381 ;
        temperature_id = 58 ;
  variables:
        float azimuth_time(azimuth_time) ;
                azimuth_time:units = "s" ;
        string temperature_id(temperature_id) ;
        float data(azimuth_time, temperature_id) ;
                data :units = "C" ;

  // group attributes:
                :description = "Temperature data" ;
  } // group temperature_data

group: platform_data {
  // this group contains the platform data (satellite position, velocity and attitude quaternions)
  // data are already decoded
  // data are expressed as 2D arrays in the coordinate/azimuth time domain (coordinate are X,Y,Z for position and velocity and Q0, Q1, Q2, Q3 for quaternions)
  // note that azimuth times are provided as relative ones (i.e. float values) with respect to reference_azimuth_time global attribute (which is an absolute time in ISO 8601 datetime format)

  dimensions:
        azimuth_time = 397 ;
        state_vector_number = 3 ;
        quaternion_number = 4 ;
  variables:
        float azimuth_time(azimuth_time) ;
                azimuth_time:units = "s" ;
        float position(azimuth_time, state_vector_number) ;
                position:units = "m" ;
        float velocity(azimuth_time, state_vector_number) ;
                velocity:units = "m/s" ;
        float quaternion(azimuth_time, quaternion_number) ;

  // group attributes:
                :description = "Platform data" ;
  } // group platform_data

group: instrument_data {
  // this group contains the instrument data (carrier frequency and transmitted pulse parameters)
  // data are already decoded

  // group attributes:
                :description = "Instrument data" ;
                :carrier_frequency = 4.35e+08f ;
                :pulse_direction = "UP" ;
                :pulse_length = 4.116207e-05f ;
                :pulse_bandwidth = 6000000.f ;
                :pulse_sampling_rate = 7565218.f ;
                :pulse_start_frequency = -3000000.f ;
                :pulse_start_phase = 0.f ;
  } // group instrument_data
}

Using the L0 Extraction Tool in Coding

Installation

To install the tool, it is recommended to first create a new Python environment and activate it:

conda create --name my-env-name python=3.12
source activate my-env-name

Then, the package can be installed with Conda:

conda install biomass-bps::bps-l0_extraction_tool

Usage

The tool help can be displayed with the following command line:

bps_l0_extraction_tool --help

To execute it, you can refer to the following command line:

bps_l0_extraction_tool --l0s <path to input L0S product>
                       --l0m <path to input L0M product>
                       --aux_orb <path to input AUX_ORB product>
                       --aux_att <path to input AUX_ATT product>
                       --aux_ins <path to input AUX_INS product>
                       --start <path to start time of interest (optional)>
                       --stop <path to stop time of interest (optional)>
                       --out <path to output folder>

Here below an example:

bps_l0_extraction_tool --l0s /path/to/BIO_S2_RAW__0S_20260202T142610_20260202T142807_T_G01_M01_CDR_T____F027_01_DM86GE
                       --l0m /path/to/BIO_S2_RAW__0M_20260202T142414_20260202T143036_T_G01_M01_CDR_T____F____01_DM8EO9
                       --aux_orb /path/to/BIO_AUX_ORB____20260202T142359_20260202T143035_01_DM8EQA
                       --aux_att /path/to/BIO_AUX_ATT____20260202T142359_20260202T143035_01_DM8EQA
                       --aux_ins /path/to/BIO_AUX_INS____20250522T000000_20261231T000000_01_DLXTTI
                       --start 02-FEB-2026\ 14:26:52.468597
                       --stop 02-FEB-2026\ 14:27:17.457920
                       --out /path/to/l0_extraction_tool_output_folder

All the inputs are mandatory except for start and stop times of interest. If they are provided, only the portion of the L0S product inside this time window is extracted. If they are not provided, the entire L0S product is extracted.

At the beginning of the processing the existance of all the inputs is checked (then also the output folder shall exist).

The output product (NetCDF file) and all the intermediate data are written in this folder. Before exiting, the processor automatically removes all the intermediate data. The output product is a single NetCDF file with the same name of input L0S product and with .nc extension.

Using the L0 Extraction Tool in Processing

The same tool has been implemented also in Processing, allowing you to run it systematically and in background. The processor is called "NetCDF File Extractor":

Screenshot 2026-07-17 160643.png

To run the NetCDF File Extractor processor, you need to select two Biomass products from the catalog, a start and stop date (not mandatory) and your personal access token:

  • RAW_0S product: Biomass Level 0 product of product type "RAW__0S", selected from catalog
  • AUX_INS product: the corresponding auxiliary file of product type "AUX_INS", selected from catalog
  • NetCDF start date: extraction start time of interest, with format DD-MON-YYYY hh:mm:ss.xxxxxx
  • NetCDF stop date: extraction stop time of interest, with format DD-MON-YYYY hh:mm:ss.xxxxxx
  • Personal access token: your personal access token, generated from the Biomass MAAP main page

Screenshot 2026-07-17 160757.png

Also in this case, if the start and stop date are not provided, the processor will extract the entire product. Your access token is required because the processor automatically downloads all the other needed products (RAW__0M, AUX_ATT, AUX_ORB and AUX_TEC).