!*********************************************************************** !* GNU Lesser General Public License !* !* This file is part of the GFDL Flexible Modeling System (FMS). !* !* FMS is free software: you can redistribute it and/or modify it under !* the terms of the GNU Lesser General Public License as published by !* the Free Software Foundation, either version 3 of the License, or (at !* your option) any later version. !* !* FMS is distributed in the hope that it will be useful, but WITHOUT !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License !* for more details. !* !* You should have received a copy of the GNU Lesser General Public !* License along with FMS. If not, see . !*********************************************************************** !!#include module drifters_io_mod implicit none private public :: drifters_io_type, drifters_io_new, drifters_io_del, drifters_io_set_time_units public :: drifters_io_set_position_names, drifters_io_set_position_units, drifters_io_set_field_names public :: drifters_io_set_field_units, drifters_io_write ! Globals integer, parameter, private :: MAX_STR_LEN = 128 ! Include variable "version" to be written to log file. #include real :: drfts_eps_t = 10.*epsilon(1.) type drifters_io_type real :: time integer :: it ! time index integer :: it_id ! infinite axis index integer :: ncid integer :: nc_positions, nc_fields, nc_ids, nc_time, nc_index_time logical :: enddef end type drifters_io_type contains !############################################################################### subroutine drifters_io_new(self, filename, nd, nf, ermesg) type(drifters_io_type) :: self character(len=*), intent(in) :: filename integer, intent(in) :: nd ! number of dims integer, intent(in) :: nf ! number of fields character(len=*), intent(out) :: ermesg integer ier, nc_it_id, nc_nd, nc_nf integer :: size1(1), size2(2) include 'netcdf.inc' ermesg='' self%enddef = .FALSE. ier = nf_create(filename, NF_CLOBBER, self%ncid) if(ier/=NF_NOERR) ermesg = 'drifters_io_new::nf_create ('//filename//') '//nf_strerror(ier) ! global attributes ier = nf_put_att_text(self%ncid, NF_GLOBAL, 'version', len_trim(version), trim(version)) ! dimensions ier = nf_def_dim(self%ncid, 'np', NF_UNLIMITED, nc_it_id) if(ier/=NF_NOERR) ermesg = 'drifters_io_new::nf_def_dim (it_id) '//nf_strerror(ier) ier = nf_def_dim(self%ncid, 'nf', nf, nc_nf) if(ier/=NF_NOERR) ermesg = 'drifters_io_new::nf_def_dim (nf) '//nf_strerror(ier) ier = nf_def_dim(self%ncid, 'nd', nd, nc_nd) if(ier/=NF_NOERR) ermesg = 'drifters_io_new::nf_def_dim (nd) '//nf_strerror(ier) ! variables size1 = (/nc_it_id/) ier = nf_def_var(self%ncid, 'index_time', NF_INT, 1, size1, self%nc_index_time) if(ier/=NF_NOERR) ermesg = 'drifters_io_new::nf_def_var (index_time)'//nf_strerror(ier) ier = nf_def_var(self%ncid, 'time', NF_DOUBLE, 1, size1, self%nc_time) if(ier/=NF_NOERR) ermesg = 'drifters_io_new::nf_def_var (time)'//nf_strerror(ier) ier = nf_def_var(self%ncid, 'ids', NF_INT, 1, size1, self%nc_ids) if(ier/=NF_NOERR) ermesg = 'drifters_io_new::nf_def_var (ids)'//nf_strerror(ier) size2 = (/nc_nd, nc_it_id/) ier = nf_def_var(self%ncid, 'positions', NF_DOUBLE, 2, size2, self%nc_positions) if(ier/=NF_NOERR) ermesg = 'drifters_io_new::nf_def_var (positions)'//nf_strerror(ier) size2 = (/nc_nf, nc_it_id/) ier = nf_def_var(self%ncid, 'fields', NF_DOUBLE, 2, size2, self%nc_fields) if(ier/=NF_NOERR) ermesg = 'drifters_io_new::nf_def_var (fields)'//nf_strerror(ier) self%time = -huge(1.) self%it = -1 self%it_id = 1 end subroutine drifters_io_new !############################################################################### subroutine drifters_io_del(self, ermesg) type(drifters_io_type) :: self character(len=*), intent(out) :: ermesg integer ier include 'netcdf.inc' ermesg = '' ier = nf_close(self%ncid) if(ier/=NF_NOERR) ermesg = 'drifters_io_del::nf_close '//nf_strerror(ier) end subroutine drifters_io_del !############################################################################### subroutine drifters_io_set_time_units(self, name, ermesg) type(drifters_io_type) :: self character(len=*), intent(in) :: name character(len=*), intent(out) :: ermesg integer ier include 'netcdf.inc' ermesg = '' ier = nf_put_att_text(self%ncid, NF_GLOBAL, & & 'time_units', len_trim(name), trim(name)) if(ier/=NF_NOERR) & & ermesg = 'drifters_io_set_time_units::failed to add time_units attribute ' & & //nf_strerror(ier) end subroutine drifters_io_set_time_units !############################################################################### subroutine drifters_io_set_position_names(self, names, ermesg) type(drifters_io_type) :: self character(len=*), intent(in) :: names(:) character(len=*), intent(out) :: ermesg integer n, ier, i character(len=128) :: attname include 'netcdf.inc' n = size(names) ermesg = '' do i = 1, n write(attname, '(i6)' ) i attname = 'name_'//adjustl(attname) ier = nf_put_att_text(self%ncid, self%nc_positions, & & trim(attname), len_trim(names(i)), trim(names(i))) if(ier/=NF_NOERR) & & ermesg = 'drifters_io_set_position_names::failed to add name attribute to positions '//nf_strerror(ier) enddo end subroutine drifters_io_set_position_names !############################################################################### subroutine drifters_io_set_position_units(self, names, ermesg) type(drifters_io_type) :: self character(len=*), intent(in) :: names(:) character(len=*), intent(out) :: ermesg integer n, ier, i character(len=128) :: attname include 'netcdf.inc' n = size(names) ermesg = '' do i = 1, n write(attname, '(i6)' ) i attname = 'unit_'//adjustl(attname) ier = nf_put_att_text(self%ncid, self%nc_positions, & & trim(attname), len_trim(names(i)), trim(names(i))) if(ier/=NF_NOERR) & & ermesg = 'drifters_io_set_position_names::failed to add unit attribute to positions '//nf_strerror(ier) enddo end subroutine drifters_io_set_position_units !############################################################################### subroutine drifters_io_set_field_names(self, names, ermesg) type(drifters_io_type) :: self character(len=*), intent(in) :: names(:) character(len=*), intent(out) :: ermesg integer n, ier, i character(len=128) :: attname include 'netcdf.inc' n = size(names) ermesg = '' do i = 1, n write(attname, '(i6)' ) i attname = 'name_'//adjustl(attname) ier = nf_put_att_text(self%ncid, self%nc_fields, & & trim(attname), len_trim(names(i)), trim(names(i))) if(ier/=NF_NOERR) & & ermesg = 'drifters_io_set_field_names::failed to add name attribute to fields '//nf_strerror(ier) enddo end subroutine drifters_io_set_field_names !############################################################################### subroutine drifters_io_set_field_units(self, names, ermesg) type(drifters_io_type) :: self character(len=*), intent(in) :: names(:) character(len=*), intent(out) :: ermesg integer n, ier, i character(len=128) :: attname include 'netcdf.inc' n = size(names) ermesg = '' do i = 1, n write(attname, '(i6)' ) i attname = 'unit_'//adjustl(attname) ier = nf_put_att_text(self%ncid, self%nc_fields, & & trim(attname), len_trim(names(i)), trim(names(i))) if(ier/=NF_NOERR) & & ermesg = 'drifters_io_set_field_units::failed to add unit attribute to fields '//nf_strerror(ier) enddo end subroutine drifters_io_set_field_units !############################################################################### subroutine drifters_io_write(self, time, np, nd, nf, ids, positions, fields, ermesg) type(drifters_io_type) :: self real, intent(in) :: time integer, intent(in) :: np ! number of dirfters integer, intent(in) :: nd ! number of dimensions integer, intent(in) :: nf ! number of fields integer, intent(in) :: ids(np) ! of size np real, intent(in) :: positions(nd,np) ! nd times np real, intent(in) :: fields(nf,np) ! nf times np character(len=*), intent(out) :: ermesg integer ier, i integer :: start1(1), len1(1), start2(2), len2(2) integer :: it_indices(np) real :: time_array(np) include 'netcdf.inc' ermesg = '' if(.not. self%enddef) then ier = nf_enddef(self%ncid) if(ier/=NF_NOERR) then ermesg = 'drifters_io_write::nf_enddef failure. No data will be written. '//nf_strerror(ier) return endif self%enddef = .TRUE. endif if(abs(time - self%time) > drfts_eps_t) then self%it = self%it + 1 self%time = time endif start1(1) = self%it_id len1(1) = np it_indices = (/(self%it,i=1,np)/) ier = nf_put_vara_int( self%ncid, self%nc_index_time, start1, len1, it_indices ) if(ier/=NF_NOERR) & & ermesg = 'drifters_io_write::failed to write index_time: ' //nf_strerror(ier) time_array = (/(time,i=1,np)/) ier = nf_put_vara_double( self%ncid, self%nc_time, start1, len1, time_array ) if(ier/=NF_NOERR) & & ermesg = 'drifters_io_write::failed to write time: ' //nf_strerror(ier) ier = nf_put_vara_int(self%ncid, self%nc_ids, start1, len1, ids) if(ier/=NF_NOERR) & & ermesg = 'drifters_io_write::failed to write ids: '//nf_strerror(ier) start2(1) = 1 start2(2) = self%it_id len2(1) = nd len2(2) = np ier = nf_put_vara_double(self%ncid, self%nc_positions, start2, len2, positions) if(ier/=NF_NOERR) & & ermesg = 'drifters_io_write::failed to write positions: '//nf_strerror(ier) len2(1) = nf len2(2) = np ier = nf_put_vara_double(self%ncid, self%nc_fields, start2, len2, fields) if(ier/=NF_NOERR) & & ermesg = 'drifters_io_write::failed to write fields: '//nf_strerror(ier) self%it_id = self%it_id + np end subroutine drifters_io_write end module drifters_io_mod !############################################################################### !###############################################################################