Skip to content

Zarr v3 Write Example (Fortran)

This example demonstrates writing a 2D sea surface temperature (SST) field (360 × 180: lon × lat) to a Zarr v3 store using the NCZarr fallback mode from Fortran.

What It Does

  1. Initializes AMIO with a manifest targeting the zarr3 backend
  2. Opens a dataset for writing
  3. Populates a 2D real(c_double) array with synthetic SST data
  4. Writes the array using amio_write_array (auto-detects AMIO_DTYPE_F64)
  5. Flushes and closes

Source Code

examples/fortran/example_zarr_write.f90
!> @file example_zarr_write.f90
!> @brief Example: Write a 2D sea surface temperature field to Zarr v3 using AMIO (Fortran).
!>
!> This example demonstrates writing a 2D double-precision array
!> (sea surface temperature, 360 x 180: lon x lat) to a Zarr v3 store
!> using the NCZarr fallback mode from Fortran.
!>
!> Build (via CMake):
!>   Linked against AMIO::amio_fortran
!>
!> Run:
!>   ./example_zarr_write_f90

program example_zarr_write
    use, intrinsic :: iso_c_binding, only: &
        c_ptr, c_null_ptr, c_int32_t, c_int64_t, c_double, c_char, c_null_char
    use amio_mod
    implicit none

    ! Grid dimensions: 1-degree global ocean grid
    integer, parameter :: NLON = 360   ! longitude points
    integer, parameter :: NLAT = 180   ! latitude points

    ! AMIO handles
    type(c_ptr) :: core
    type(c_ptr) :: dataset
    type(c_ptr) :: io_handle
    integer(c_int32_t) :: rc

    ! Data array (double precision for SST)
    real(c_double), allocatable, target :: sst(:, :)

    ! Local variables
    integer :: i, j
    real(c_double) :: lat, lon, base_sst

    write (*, '(A)') 'AMIO Zarr v3 (NCZarr) Write Example (Fortran)'
    write (*, '(A)') '=============================================='
    write (*, '(A,I0,A,I0,A)') &
        'Writing 2D SST field (', NLON, ' x ', NLAT, ') to Zarr v3 store'
    write (*, *)

    ! -------------------------------------------------------------------
    ! Step 1: Initialize AMIO with the zarr3 manifest.
    ! -------------------------------------------------------------------
    write (*, '(A)') 'Step 1: Initializing AMIO (Zarr v3 / NCZarr mode)...'
    rc = amio_init('examples/manifests/zarr3_manifest.yaml'//c_null_char, core)
    call check_amio(rc, 'amio_init')
    write (*, '(A)') '  AMIO initialized.'

    ! -------------------------------------------------------------------
    ! Step 2: Open a dataset for writing.
    ! -------------------------------------------------------------------
    write (*, '(A)') 'Step 2: Opening Zarr dataset for writing...'
    rc = amio_open_dataset(core, &
                           'examples/manifests/zarr3_manifest.yaml'//c_null_char, &
                           AMIO_MODE_WRITE, dataset)
    call check_amio(rc, 'amio_open_dataset')
    write (*, '(A)') '  Dataset opened.'

    ! -------------------------------------------------------------------
    ! Step 3: Allocate and fill the SST array.
    !
    ! Generate a realistic SST pattern with warm equatorial waters
    ! and cold polar waters.
    ! -------------------------------------------------------------------
    write (*, '(A)') 'Step 3: Generating synthetic SST data...'
    allocate (sst(NLON, NLAT))

    do j = 1, NLAT
        lat = -90.0_c_double + real(j - 1, c_double) + 0.5_c_double
        ! Base SST: warm at equator, cold at poles
        base_sst = 300.0_c_double - 29.0_c_double * (lat * lat) / (90.0_c_double * 90.0_c_double)
        do i = 1, NLON
            lon = real(i - 1, c_double) + 0.5_c_double
            sst(i, j) = base_sst
            ! Add small longitudinal variation
            sst(i, j) = sst(i, j) + 0.5_c_double * sin(lon * 0.1_c_double) * &
                        cos(lat * 0.15_c_double)
            ! Clamp to physical range
            sst(i, j) = max(271.15_c_double, min(308.15_c_double, sst(i, j)))
        end do
    end do

    write (*, '(A,F7.2,A,F7.2,A)') '  SST data generated: range ~ [', &
        minval(sst), ', ', maxval(sst), '] K'

    ! -------------------------------------------------------------------
    ! Step 4: Write the 2D SST array using the convenience subroutine.
    !
    ! amio_write_array detects real(c_double) and uses AMIO_DTYPE_F64.
    ! -------------------------------------------------------------------
    write (*, '(A)') 'Step 4: Writing SST field...'
    call amio_write_f64_2d(dataset, 'sea_surface_temperature'//c_null_char, &
                           sst, io_handle, rc)
    call check_amio(rc, 'amio_write_array(sst)')
    write (*, '(A)') '  Write enqueued.'

    ! -------------------------------------------------------------------
    ! Step 5: Flush to ensure the write completes.
    ! -------------------------------------------------------------------
    write (*, '(A)') 'Step 5: Flushing...'
    rc = amio_flush(dataset, 0_c_int64_t)
    call check_amio(rc, 'amio_flush')
    write (*, '(A)') '  Flush complete.'

    ! -------------------------------------------------------------------
    ! Step 6: Close and finalize.
    ! -------------------------------------------------------------------
    write (*, '(A)') 'Step 6: Closing dataset and finalizing...'
    rc = amio_close_dataset(dataset)
    call check_amio(rc, 'amio_close_dataset')

    rc = amio_finalize(core)
    call check_amio(rc, 'amio_finalize')
    write (*, '(A)') '  Done.'

    deallocate (sst)

    write (*, *)
    write (*, '(A)') 'SST field written to Zarr v3 store.'

contains

    !> @brief Check an AMIO return code and stop on failure.
    subroutine check_amio(status, context)
        integer(c_int32_t), intent(in) :: status
        character(len=*), intent(in) :: context

        if (status /= AMIO_OK) then
            write (*, '(A,A,A,I0,A)') 'AMIO error in ', context, &
                ' (code ', status, ')'
            error stop 'AMIO operation failed'
        end if
    end subroutine check_amio

end program example_zarr_write
Inline source (if includes are not configured)
program example_zarr_write
    use, intrinsic :: iso_c_binding
    use amio_mod
    implicit none

    integer, parameter :: NLON = 360, NLAT = 180
    type(c_ptr) :: core, dataset, io_handle
    integer(c_int32_t) :: rc
    real(c_double), allocatable, target :: sst(:,:)

    rc = amio_init('examples/manifests/zarr3_manifest.yaml' // c_null_char, core)
    rc = amio_open_dataset(core, &
        'examples/manifests/zarr3_manifest.yaml' // c_null_char, &
        AMIO_MODE_WRITE, dataset)

    allocate(sst(NLON, NLAT))
    ! ... fill with synthetic SST data ...

    call amio_write_array(dataset, 'sea_surface_temperature' // c_null_char, &
                          sst, io_handle, rc)

    rc = amio_flush(dataset, 0_c_int64_t)
    rc = amio_close_dataset(dataset)
    rc = amio_finalize(core)
    deallocate(sst)
end program example_zarr_write

Key Points

Double Precision Detection

The amio_write_array generic interface detects real(c_double) arrays and automatically uses AMIO_DTYPE_F64. No manual dtype specification is needed.

Build

Via CMake (linked against AMIO::amio_fortran):

cmake --build build --target example_zarr_write_f90
./build/examples/fortran/example_zarr_write_f90