GDAL multidimensional tools

Downloading and extracting information using GDAL multidimensional API

Using gdal mdim convert

Extracting NOAA Global Forecast System (GFS) data available from https://registry.opendata.aws/noaa-gfs-bdp-pds/

$ gdal mdim convert "/vsis3/noaa-gfs-bdp-pds/gdas.20260519/00/atmos/gdas.t00z.sfcanl.nc" --config AWS_NO_SIGN_REQUEST=YES --array /tmp2m --output 20260519_00_tmp2m.nc

$ gdal mdim convert "/vsis3/noaa-gfs-bdp-pds/gdas.20260519/06/atmos/gdas.t06z.sfcanl.nc" --config AWS_NO_SIGN_REQUEST=YES --array /tmp2m --output 20260519_06_tmp2m.nc

Warning

The above may only work properly on Linux due to limitations in the netCDF driver regarding working with files in /vsi virtual file systems, hence the converted files 20260519_00_tmp2m.nc and 20260519_06_tmp2m.nc are provided in the input datasets.

Inspecting

Using gdal mdim info

Let's have a look:

$ gdal mdim info 20260519_00_tmp2m.nc
"time": {
  "full_name": "/time",
  "datatype": "Float64",
  "dimensions": [
    "/time"
  ],
  "dimension_size": [
    1
  ],
  "attributes": {
    "calendar": "JULIAN",
    "calendar_type": "JULIAN",
    "cartesian_axis": "T",
    "long_name": "time"
  },
  "unit": "hours since 2026-05-19 00:00:00"
}
$ gdal mdim info 20260519_06_tmp2m.nc
"time": {
  "full_name": "/time",
  "datatype": "Float64",
  "dimensions": [
    "/time"
  ],
  "dimension_size": [
    1
  ],
  "attributes": {
    "calendar": "JULIAN",
    "calendar_type": "JULIAN",
    "cartesian_axis": "T",
    "long_name": "time"
  },
  "unit": "hours since 2026-05-19 06:00:00"
}

We are going to modify the "time" (single) value of 20260519_06_tmp2m.nc so it is relative to "hours since 2026-05-19 00:00:00" by first creating a multidimensional VRT

$ gdal mdim convert 20260519_06_tmp2m.nc 20260519_06_tmp2m.vrt
$ cp 20260519_06_tmp2m.vrt 20260519_06_tmp2m_mod.vrt

And modifying the time array as following:

<Array name="time">
  <DataType>Float64</DataType>
  <DimensionRef ref="time" />
  <Unit>hours since 2026-05-19 00:00:00</Unit>
  <InlineValuesWithValueElement><Value>6</Value></InlineValuesWithValueElement>
  <Attribute name="calendar">
    <DataType>String</DataType>
    <Value>JULIAN</Value>
  </Attribute>
  <Attribute name="calendar_type">
    <DataType>String</DataType>
    <Value>JULIAN</Value>
  </Attribute>
  <Attribute name="cartesian_axis">
    <DataType>String</DataType>
    <Value>T</Value>
  </Attribute>
  <Attribute name="long_name">
    <DataType>String</DataType>
    <Value>time</Value>
  </Attribute>
</Array>

Now we can convert it back to netCDF:

$ gdal mdim convert 20260519_06_tmp2m_mod.vrt 20260519_06_tmp2m_mod.nc

Mosaicing / creating a 3D cube

Using gdal mdim mosaic

$ gdal mdim mosaic 20260519_00_tmp2m.nc 20260519_06_tmp2m_mod.nc 20260519_00_06_tmp2m.zarr --format Zarr

$ gdal mdim info 20260519_00_06_tmp2m.zarr
Output
{
  "type": "group",
  "driver": "Zarr",
  "name": "/",
  "dimensions": [
    {
      "name": "grid_xt",
      "full_name": "/grid_xt",
      "size": 3072,
      "indexing_variable": {
        "grid_xt": {
          "full_name": "/grid_xt",
          "datatype": "Float64",
          "dimensions": [
            "/grid_xt"
          ],
          "dimension_size": [
            3072
          ],
          "block_size": [
            3072
          ],
          "attributes": {
            "cartesian_axis": "X",
            "long_name": "T-cell longitude"
          }
        }
      }
    },
    {
      "name": "grid_yt",
      "full_name": "/grid_yt",
      "size": 1536,
      "indexing_variable": {
        "grid_yt": {
          "full_name": "/grid_yt",
          "datatype": "Float64",
          "dimensions": [
            "/grid_yt"
          ],
          "dimension_size": [
            1536
          ],
          "block_size": [
            1536
          ],
          "attributes": {
            "cartesian_axis": "Y",
            "long_name": "T-cell latitude"
          }
        }
      }
    },
    {
      "name": "time",
      "full_name": "/time",
      "size": 2,
      "indexing_variable": {
        "time": {
          "full_name": "/time",
          "datatype": "Float64",
          "dimensions": [
            "/time"
          ],
          "dimension_size": [
            2
          ],
          "block_size": [
            2
          ],
          "attributes": {
            "calendar": "JULIAN",
            "calendar_type": "JULIAN",
            "cartesian_axis": "T",
            "long_name": "time"
          }
        }
      }
    }
  ],
  "arrays": {
    "grid_xt": {
      "full_name": "/grid_xt",
      "datatype": "Float64",
      "dimensions": [
        "/grid_xt"
      ],
      "dimension_size": [
        3072
      ],
      "block_size": [
        3072
      ],
      "attributes": {
        "cartesian_axis": "X",
        "long_name": "T-cell longitude"
      }
    },
    "grid_yt": {
      "full_name": "/grid_yt",
      "datatype": "Float64",
      "dimensions": [
        "/grid_yt"
      ],
      "dimension_size": [
        1536
      ],
      "block_size": [
        1536
      ],
      "attributes": {
        "cartesian_axis": "Y",
        "long_name": "T-cell latitude"
      }
    },
    "time": {
      "full_name": "/time",
      "datatype": "Float64",
      "dimensions": [
        "/time"
      ],
      "dimension_size": [
        2
      ],
      "block_size": [
        2
      ],
      "attributes": {
        "calendar": "JULIAN",
        "calendar_type": "JULIAN",
        "cartesian_axis": "T",
        "long_name": "time"
      }
    },
    "tmp2m": {
      "full_name": "/tmp2m",
      "datatype": "Float32",
      "dimensions": [
        "/time",
        "/grid_yt",
        "/grid_xt"
      ],
      "dimension_size": [
        2,
        1536,
        3072
      ],
      "block_size": [
        1,
        768,
        1536
      ],
      "attributes": {
        "cell_methods": "time: point",
        "long_name": "2m temperature",
        "missing": 9.99e+20,
        "output_file": "sfc"
      },
      "unit": "K"
    }
  }
}