ETSF_IO library - documentation pages

### TABLE OF CONTENTS

- etsf_io_low_copy_all_att
- etsf_io_low_open_create
- etsf_io_low_open_modify
- etsf_io_low_write_dim

## etsf_io_low_copy_all_att

[ Top ] [ etsf_io_low_write_group ] [ Methods ]

NAME

etsf_io_low_copy_all_att

FUNCTION

Copy all attributes from the given variable of the given file to an other variable (of a different file, but not necessary). The variable ids from and to can be either valid variables or etsf_io_low_global_att.

INPUTS

- ncid_from = a NetCDF handler, opened with read access.
- ncid_to = a NetCDF handler, opened with write access.
- ncvarid_from = a NetCDF variable id with attributes to copy.
- ncvarid_to = a NetCDF variable id to copy the attributes to.

OUTPUT

- lstat = .true. if the file has been read without error.
- error_data <type(etsf_io_low_error)> = (optional) location to store error data.

SOURCE

      subroutine etsf_io_low_copy_all_att(ncid_from, ncid_to, ncvarid_from, &
           & ncvarid_to, lstat, error_data)
        integer, intent(in)                            :: ncid_from, ncid_to
        integer, intent(in)                            :: ncvarid_from, ncvarid_to
        logical, intent(out)                           :: lstat
        type(etsf_io_low_error), intent(out), optional :: error_data

        character(len = *), parameter :: me = "etsf_io_low_copy_all_att"
        type(etsf_io_low_var_infos) :: var_infos
        integer :: i, s, n
        character(len = NF90_MAX_NAME) :: ncname

        lstat = .true.
        if (ncvarid_from /= etsf_io_low_global_att) then
           if (present(error_data)) then
              call read_var_infos_id(ncid_from, ncvarid_from, var_infos, lstat, &
                   & error_data = error_data, dim_name = .false., att_name = .true.)
              if (.not. lstat) call etsf_io_low_error_update(error_data, me)
           else
              call read_var_infos_id(ncid_from, ncvarid_from, var_infos, lstat, &
                   & dim_name = .false., att_name = .true.)
           end if
           if (.not. lstat) return
        else
           s = nf90_inquire(ncid_from, nAttributes = n)
           if (s /= nf90_noerr) then
              if (present(error_data)) then
                 call etsf_io_low_error_set(error_data, ERROR_MODE_INQ, ERROR_TYPE_ATT, &
                      & me, tgtname = "global attributes", errid = s, &
                      & errmess = nf90_strerror(s))
              end if
              lstat = .false.
              return
           end if
           if (n > 0) then
              allocate(var_infos%ncattnames(1:n))
              do i = 1, n, 1
                 s = nf90_inq_attname(ncid_from, etsf_io_low_global_att, i, ncname)
                 if (s /= nf90_noerr) then
                    if (present(error_data)) then
                       call etsf_io_low_error_set(error_data, ERROR_MODE_INQ, &
                            & ERROR_TYPE_ATT, me, tgtid = i, errid = s, &
                            & errmess = nf90_strerror(s))
                    end if
                    call etsf_io_low_free_var_infos(var_infos)
                    lstat = .false.
                    return
                 end if
                 write(var_infos%ncattnames(i), "(A)") ncname(1:min(80, len(ncname)))
              end do
           end if
        end if

        if (associated(var_infos%ncattnames)) then
           do i = 1, size(var_infos%ncattnames, 1), 1
              s = nf90_copy_att(ncid_from, ncvarid_from, trim(var_infos%ncattnames(i)), &
                   & ncid_to, ncvarid_to)
              if (s /= nf90_noerr) then
                 if (present(error_data)) then
                    call etsf_io_low_error_set(error_data, ERROR_MODE_COPY, ERROR_TYPE_ATT, &
                         & me, tgtname = trim(var_infos%ncattnames(i)), errid = s, &
                         & errmess = nf90_strerror(s))
                 end if
                 lstat = .false.
                 exit
              end if
           end do
        end if
        call etsf_io_low_free_var_infos(var_infos)
      end subroutine etsf_io_low_copy_all_att

## etsf_io_low_open_create

[ Top ] [ etsf_io_low_file_group ] [ Methods ]

NAME

etsf_io_low_open_create

FUNCTION

This method is used to open a NetCDF file. The file should not already exist. The ETSF header for the created file is automatically added by this method. When finished, the file handled by @ncid, is in define mode, which means that dimensions (see etsf_io_low_write_dim()), variables (see etsf_io_low_def_var()) and attributes (see etsf_io_low_write_att()) can be defined. To use etsf_io_low_write_var(), the file should be switched to data mode using etsf_io_low_set_write_mode().

If title or history are given and are too long, they will be truncated.

If one wants to modify an already existing file, one should use etsf_io_low_open_modify() instead.

INPUTS

- filename = the path to the file to open.
- version = the number of version to be created.
- title = (optional) a title for the file (80 characters max).
- history = (optional) the first line of history (1024 characters max).
- with_etsf_header = (optional) if true, will create a header as defined in the ETSF specifications (default is .true.). When value is .false., arguments title, history and version are ignored.
- overwrite = (optional) if true, an existing file with the same name as @filename would be overwritten. Default is .false., which means that an IO error is raised if a file already exists.

OUTPUT

- ncid = the NetCDF handler, opened with write access (define mode).
- lstat = .true. if operation succeed.
- error_data <type(etsf_io_low_error)> = (optional) location to store error data.

SOURCE

      subroutine etsf_io_low_open_create(ncid, filename, version, lstat, &
                                       & title, history, error_data, with_etsf_header, &
                                       & overwrite)
        integer, intent(out)                           :: ncid
        character(len = *), intent(in)                 :: filename
        real, intent(in)                               :: version
        logical, intent(out)                           :: lstat
        character(len = *), intent(in), optional       :: title
        character(len = *), intent(in), optional       :: history
        type(etsf_io_low_error), intent(out), optional :: error_data
        logical, intent(in), optional                  :: with_etsf_header
        logical, intent(in), optional                  :: overwrite

        !Local
        character(len = *), parameter :: me = "etsf_io_low_open_create"
        character(len = 256) :: err
        integer :: s, cmode
        logical :: stat

        lstat = .false.
        ! Checking that @version argument is valid.
        if (version < 1.0) then
          if (present(error_data)) then
            write(err, "(A,I0,A)") "Wrong version argument (given: ", version, " ; awaited >= 1.0)"
            call etsf_io_low_error_set(error_data, ERROR_MODE_SPEC, ERROR_TYPE_ATT, me, &
                         & tgtname = "file_format_version", errmess = err)
          end if
          return
        end if
        ! Open file for writing
        cmode = NF90_NOCLOBBER
        if (present(overwrite)) then
          if (overwrite) then
            cmode = NF90_CLOBBER
          end if
        end if
        ! We don't use the 64bits flag since the specifications advice
        ! to split huge quantities of data into several smaller files.
        s = nf90_create(path = filename, cmode = cmode, ncid = ncid)
        if (s /= nf90_noerr) then
          if (present(error_data)) then
            call etsf_io_low_error_set(error_data, ERROR_MODE_IO, ERROR_TYPE_OWR, &
                 & me, tgtname = filename, errid = s, errmess = nf90_strerror(s))
          end if
          return
        end if
        ! From now on the file is open. If an error occur,
        ! we should close it.

        ! We create the header if required.
        if (present(with_etsf_header)) then
          if (.not. with_etsf_header) then
            lstat = .true.
            return
          end if
        end if
        ! The file format
        s = nf90_put_att(ncid, NF90_GLOBAL, "file_format", etsf_io_low_file_format)
        if (s /= nf90_noerr) then
          if (present(error_data)) then
            call etsf_io_low_error_set(error_data, ERROR_MODE_PUT, ERROR_TYPE_ATT, &
                 & me, tgtname = "file_format", errid = s, errmess = nf90_strerror(s))
          end if
          call etsf_io_low_close(ncid, stat)
          return
        end if
        ! The version
        s = nf90_put_att(ncid, NF90_GLOBAL, "file_format_version", version)
        if (s /= nf90_noerr) then
          if (present(error_data)) then
            call etsf_io_low_error_set(error_data, ERROR_MODE_PUT, ERROR_TYPE_ATT, me, &
                 & tgtname = "file_format_version", errid = s, errmess = nf90_strerror(s))
          end if
          call etsf_io_low_close(ncid, stat)
          return
        end if
        ! The conventions
        s = nf90_put_att(ncid, NF90_GLOBAL, "Conventions", etsf_io_low_conventions)
        if (s /= nf90_noerr) then
          if (present(error_data)) then
            call etsf_io_low_error_set(error_data, ERROR_MODE_PUT, ERROR_TYPE_ATT, me, &
                 & tgtname = "Conventions", errid = s, errmess = nf90_strerror(s))
          end if
          call etsf_io_low_close(ncid, stat)
          return
        end if
        ! The title if present
        if (present(title)) then
          s = nf90_put_att(ncid, NF90_GLOBAL, "title", title(1:min(80, len(title))))
          if (s /= nf90_noerr) then
            if (present(error_data)) then
              call etsf_io_low_error_set(error_data, ERROR_MODE_PUT, ERROR_TYPE_ATT, &
                   & me, tgtname = "title", errid = s, errmess = nf90_strerror(s))
            end if
            call etsf_io_low_close(ncid, stat)
            return
          end if
        end if
        ! The history if present
        if (present(history)) then
          s = nf90_put_att(ncid, NF90_GLOBAL, "history", history(1:min(1024, len(history))))
          if (s /= nf90_noerr) then
            if (present(error_data)) then
              call etsf_io_low_error_set(error_data, ERROR_MODE_PUT, ERROR_TYPE_ATT, &
                   & me, tgtname = "history", errid = s, errmess = nf90_strerror(s))
            end if
            call etsf_io_low_close(ncid, stat)
            return
          end if
        end if

        lstat = .true.
      end subroutine etsf_io_low_open_create

## etsf_io_low_open_modify

[ Top ] [ etsf_io_low_file_group ] [ Methods ]

NAME

etsf_io_low_open_modify

FUNCTION

This method is used to open a NetCDF file for modifications. The file should already exist and have a valid ETSF header (if @with_etsf_header is not set to .false.).

When finished, the file handled by @ncid, is in define mode, which means that dimensions (see etsf_io_low_write_dim()), variables (see etsf_io_low_def_var()) and attributes (see etsf_io_low_write_att()) can be defined. To use etsf_io_low_write_var(), the file should be switched to data mode using etsf_io_low_set_write_mode().

If title or history are given and are too long, they will be truncated. Moreover the given history is appended to the already existing history (if enough place exists).

If one wants to create a new file, one should use etsf_io_low_open_create() instead.

INPUTS

- filename = the path to the file to open.
- title = (optional) a title for the file (80 characters max).
- history = (optional) the first line of history (1024 characters max).
- version = (optional) the number of version to be changed (>= 1.0).

OUTPUT

- ncid = the NetCDF handler, opened with write access (define mode).
- lstat = .true. if operation succeed.
- error_data <type(etsf_io_low_error)> = (optional) location to store error data.
- with_etsf_header = (optional) if true, will check that there is a header as defined in the ETSF specifications (default is .true.).

SOURCE

      subroutine etsf_io_low_open_modify(ncid, filename, lstat, &
                                       & title, history, version, error_data, with_etsf_header)
        integer, intent(out)                           :: ncid
        character(len = *), intent(in)                 :: filename
        logical, intent(out)                           :: lstat
        character(len = *), intent(in), optional       :: title
        character(len = *), intent(in), optional       :: history
        real, intent(in), optional                     :: version
        type(etsf_io_low_error), intent(out), optional :: error_data
        logical, intent(in), optional                  :: with_etsf_header

        !Local
        character(len = *), parameter :: me = "etsf_io_low_open_modify"
        character(len = 256) :: err
        character(len = 1024) :: current_history
        integer :: s
        logical :: stat
        logical :: my_with_etsf_header

        lstat = .false.
        ! Checking that @version argument is valid.
        if (present(version)) then
          if (version < 1.0) then
            if (present(error_data)) then
              write(err, "(A,I0,A)") "Wrong version argument (given: ", version, " ; awaited >= 1.0)"
              call etsf_io_low_error_set(error_data, ERROR_MODE_SPEC, ERROR_TYPE_ATT, &
                   & me, tgtname = "file_format_version", errmess = err)
            end if
            return
          end if
        end if
        ! Open file for writing
        s = nf90_open(path = filename, mode = NF90_WRITE, ncid = ncid)
        if (s /= nf90_noerr) then
          if (present(error_data)) then
            call etsf_io_low_error_set(error_data, ERROR_MODE_IO, ERROR_TYPE_OWR, &
                 & me, tgtname = filename, errid = s, errmess = nf90_strerror(s))
          end if
          return
        end if
        ! From now on the file is open. If an error occur,
        ! we should close it.

        ! Before according access to modifications, we check
        ! that the header is valid.
        if (present(with_etsf_header)) then
          my_with_etsf_header = with_etsf_header
        else
          my_with_etsf_header = .true.
        end if
        if (my_with_etsf_header) then
          if (present(error_data)) then
            call etsf_io_low_check_header(ncid, stat, error_data = error_data)
            if (.not. stat) call etsf_io_low_error_update(error_data, me)
          else
            call etsf_io_low_check_header(ncid, stat)
          end if
          if (.not. stat) then
            call etsf_io_low_close(ncid, stat)
            return
          end if
        end if

        ! We switch to define mode to set attributes.
        if (present(error_data)) then
          call etsf_io_low_set_define_mode(ncid, stat, error_data = error_data)
          if (.not. stat) call etsf_io_low_error_update(error_data, me)
        else
          call etsf_io_low_set_define_mode(ncid, stat)
        end if
        if (.not. stat) then
          call etsf_io_low_close(ncid, stat)
          return
        end if
        if (.not. my_with_etsf_header) then
          lstat = .true.
          return
        end if

        ! If a title is given, we change it.
        if (present(title)) then
          s = nf90_put_att(ncid, NF90_GLOBAL, "title", title(1:min(80, len(title))))
          if (s /= nf90_noerr) then
            if (present(error_data)) then
              call etsf_io_low_error_set(error_data, ERROR_MODE_PUT, &
                                       & ERROR_TYPE_ATT, me, tgtname = "title", &
                                       & errid = s, errmess = nf90_strerror(s))
            end if
            call etsf_io_low_close(ncid, stat)
            return
          end if
        end if
        ! If a new version is given, we change it.
        if (present(version)) then
          s = nf90_put_att(ncid, NF90_GLOBAL, "file_format_version", version)
          if (s /= nf90_noerr) then
            if (present(error_data)) then
              call etsf_io_low_error_set(error_data, ERROR_MODE_PUT, ERROR_TYPE_ATT, me, &
                           & tgtname = "file_format_version", &
                           & errid = s, errmess = nf90_strerror(s))
            end if
            call etsf_io_low_close(ncid, stat)
            return
          end if
        end if
        ! If an history value is given, we append it.
        if (present(history)) then
          call etsf_io_low_read_att(ncid, NF90_GLOBAL, "history", 1024, &
               & current_history, stat)
          if (stat) then
            ! appending mode
            if (len(trim(current_history)) + len(history) < 1024) then
              current_history = trim(current_history) // char(10) // history
            end if
          else
            ! overwriting mode
            current_history = history
          end if
          s = nf90_put_att(ncid, NF90_GLOBAL, "history", current_history)
          if (s /= nf90_noerr) then
            if (present(error_data)) then
              call etsf_io_low_error_set(error_data, ERROR_MODE_PUT, ERROR_TYPE_ATT, me, &
                           & tgtname = "history", &
                           & errid = s, errmess = nf90_strerror(s))
            end if
            call etsf_io_low_close(ncid, stat)
            return
          end if
        end if

        lstat = .true.
      end subroutine etsf_io_low_open_modify

## etsf_io_low_write_dim

[ Top ] [ etsf_io_low_write_group ] [ Methods ]

NAME

etsf_io_low_write_dim

FUNCTION

This method is a wraper add a dimension to a NetCDF file. As in pure NetCDF calls, overwriting a value is not permitted. Nevertheless, the method returns .true. in @lstat, if the dimension already exists and has the same value.

INPUTS

- ncid = a NetCDF handler, opened with write access (define mode).
- dimname = a string identifying a dimension.
- dimvalue = a positive integer which is the length of the dimension.

OUTPUT

- lstat = .true. if operation succeed.
- ncdimid = (optional) the id used by NetCDF to identify the written dimension.
- error_data <type(etsf_io_low_error)> = (optional) location to store error data.

SOURCE

      subroutine etsf_io_low_write_dim(ncid, dimname, dimvalue, lstat, ncdimid, error_data)
        integer, intent(in)                            :: ncid
        character(len = *), intent(in)                 :: dimname
        integer, intent(in)                            :: dimvalue
        logical, intent(out)                           :: lstat
        integer, intent(out), optional                 :: ncdimid
        type(etsf_io_low_error), intent(out), optional :: error_data

        ! Local
        character(len = *), parameter :: me = "etsf_io_low_write_dim"
        character(len = 500) :: message
        integer :: s, dimid, readvalue

        ! Check if dimension already exists.
        call etsf_io_low_read_dim(ncid, dimname, readvalue, lstat)
        if (lstat) then
          ! Dimension already exists.
          if (readvalue /= dimvalue) then
            ! Dimension differs, raise error.
            if (present(error_data)) then
              write(message, "(2A,I0,A,I0,A)") "dimension already exists with a different", &
                                             & " value (read = ", readvalue, " ; write = ", &
                                             & dimvalue, ")."
              call etsf_io_low_error_set(error_data, ERROR_MODE_DEF, ERROR_TYPE_DIM, me, &
                                       & tgtname = dimname, errmess = message)
            end if
            lstat = .false.
            return
          else
            ! Dimension matches, return.
            return
          end if
        end if
        ! Define dimension since it don't already exist.
        lstat = .false.
        s = nf90_def_dim(ncid, dimname, dimvalue, dimid)
        if (s /= nf90_noerr) then
          if (present(error_data)) then
            call etsf_io_low_error_set(error_data, ERROR_MODE_DEF, ERROR_TYPE_DIM, me, &
                                     & tgtname = dimname, errid = s, errmess = nf90_strerror(s))
          end if
          return
        end if
        if (present(ncdimid)) then
          ncdimid = dimid
        end if
        lstat = .true.
      end subroutine etsf_io_low_write_dim