Examples#

The following runnable examples are available in the repository’s example/ directory.

Write a NetCDF file#

This example creates a one-dimensional temperature variable and writes it to example.nc.

program write_netcdf_example
  use, non_intrinsic :: nc4f
  implicit none (type, external)

  real :: values(3) = [1.0, 2.0, 3.0]
  type(variable_type) :: temperature

  temperature = datarray("temperature", values, ["time".dim.3])
  call to_netcdf("example.nc", temperature)
end program write_netcdf_example

Read a NetCDF file#

After running the write example, this program opens example.nc, reads the temperature variable, and extracts its values into a Fortran pointer.

program read_netcdf_example
  use, non_intrinsic :: nc4f
  implicit none (type, external)

  type(netcdf_type) :: nc
  type(variable_type) :: temperature
  real, pointer :: values(:)

  nc = open_netcdf("example.nc", "r")
  temperature = get_variable(nc, "temperature")
  call extract(temperature, values)
  call close_netcdf(nc)

  print *, values
end program read_netcdf_example

Temperature read/write#

This example writes station air temperatures with CF-style metadata, then reopens the file and extracts the values into a Fortran pointer.

program temperature_example

  use, non_intrinsic :: nc4f
  implicit none (type, external)

  real, parameter :: temperature(3) = [289.4, 290.1, 288.7]
  real, pointer :: temperature_vals(:)
  type(netcdf_type) :: nc
  type(variable_type) :: temperature_write, temperature_read

  temperature_write = datarray( &
    & "temperature", temperature, dims=["station".dim.3], &
    & atts=["units".att."K", "long_name".att."Near-surface air temperature"])
  call to_netcdf("temperature.nc", temperature_write)

  nc = open_netcdf("temperature.nc", "r")
  temperature_read = get_variable(nc, "temperature")
  call close_netcdf(nc)
  call extract(temperature_read, temperature_vals)

  print *, temperature_read
  print *, temperature_vals

end program temperature_example

Mandelbrot set#

This example constructs a two-dimensional Mandelbrot iteration-count field and writes it, along with coordinate variables and metadata, to a NetCDF file.

program mandelbrot_example

  use, intrinsic :: iso_fortran_env, only: real64
  use, non_intrinsic :: nc4f
  implicit none (type, external)

  real(real64), parameter :: REAL_MIN = -2.0_real64
  real(real64), parameter :: REAL_MAX = 1.0_real64
  real(real64), parameter :: IMAG_MIN = -1.5_real64
  real(real64), parameter :: IMAG_MAX = 1.5_real64
  real(real64), parameter :: STEP = 0.003_real64

  integer :: m, n, i, j
  real(real64), allocatable :: axis_i(:), axis_r(:)
  integer, allocatable :: values(:, :)
  type(dimension_type) :: imag_dim, real_dim
  type(variable_type) :: vars(3)

  axis_r = arange(REAL_MIN, REAL_MAX, STEP)
  axis_i = arange(IMAG_MIN, IMAG_MAX, STEP)
  m = size(axis_r)
  n = size(axis_i)

  allocate (values(m, n))
  do concurrent (j = 1:n, i = 1:m) shared(values)
    values(i, j) = mandelbrot(cmplx(axis_r(i), axis_i(j), kind=real64))
  end do

  real_dim = "real".dim.m
  imag_dim = "imaginary".dim.n

  vars(1) = datarray("real", axis_r, [real_dim], atts=[ &
    & "valid_min".att.minval(axis_r), &
    & "valid_max".att.maxval(axis_r), &
    & "long_name".att."Real Axis"])
  vars(2) = datarray("imaginary", axis_i, [imag_dim], atts=[ &
    & "valid_min".att.minval(axis_i), &
    & "valid_max".att.maxval(axis_i), &
    & "long_name".att."Imaginary Axis"])
  vars(3) = datarray("count", values, [real_dim, imag_dim], atts=[ &
    & "coordinates".att."real imaginary", &
    & "units".att."dimensionless", &
    & "long_name".att."Mandelbrot escape iteration count"])

  print "(dt)", vars
  call to_netcdf("mandelbrot.nc", vars, atts=["title".att."Mandelbrot Set"])

contains

  !> Return evenly spaced values from `start` through `end`.
  pure function arange(start, end, step) result(arr)
    !> First value in the returned sequence.
    real(real64), intent(in) :: start
    !> Last value in the returned sequence.
    real(real64), intent(in) :: end
    !> Spacing between consecutive values.
    real(real64), intent(in) :: step
    !> Evenly spaced sequence including both endpoints.
    real(real64), allocatable :: arr(:)
    integer :: n, i

    n = nint((end - start) / step) + 1
    allocate (arr(n))

    do i = 1, n
      arr(i) = start + step*real(i - 1, real64)
    end do
    arr(n) = end
  end function arange

  !> Perform the mandelbrot operation.
  integer recursive elemental function mandelbrot( &
    & z, zp, niter, niter_max) result(val)
    !> Complex point whose escape iteration count is calculated.
    complex(kind=real64), intent(in) :: z
    !> Current orbit value for recursive calls.
    complex(kind=real64), intent(in), optional :: zp
    !> Number of iterations already completed.
    integer, intent(in), optional :: niter
    !> Maximum number of iterations before the point is considered bounded.
    integer, intent(in), optional :: niter_max
    complex(kind=real64) :: a
    integer :: n, n_max

    if (present(zp)) then
      a = zp
    else
      a = cmplx(0.0, 0.0, kind=real64)
    end if

    if (present(niter)) then
      n = niter
    else
      n = 0
    end if

    if (present(niter_max)) then
      n_max = niter_max
    else
      n_max = 10000
    end if

    if (n == n_max .or. abs(a) > 2.0) then
      val = n
    else
      val = mandelbrot(z, a * a + z, n + 1, n_max)
    end if
  end function mandelbrot

end program mandelbrot_example