!***********************************************************************
!* 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 .
!***********************************************************************
module drifters_input_mod
#include
implicit none
private
public :: drifters_input_type, drifters_input_new, drifters_input_del, drifters_input_save, assignment(=)
! Globals
integer, parameter, private :: MAX_STR_LEN = 128
! Include variable "version" to be written to log file.
#include
character, parameter, private :: SEPARATOR = ' '
type drifters_input_type
! Be sure to update drifters_input_new, drifters_input_del and drifters_input_copy_new
! when adding members
character(len=MAX_STR_LEN), _ALLOCATABLE :: position_names(:) _NULL
character(len=MAX_STR_LEN), _ALLOCATABLE :: position_units(:) _NULL
character(len=MAX_STR_LEN), _ALLOCATABLE :: field_names(:) _NULL
character(len=MAX_STR_LEN), _ALLOCATABLE :: field_units(:) _NULL
character(len=MAX_STR_LEN), _ALLOCATABLE :: velocity_names(:) _NULL
real , _ALLOCATABLE :: positions(:,:) _NULL
integer , _ALLOCATABLE :: ids(:) _NULL
character(len=MAX_STR_LEN) :: time_units
character(len=MAX_STR_LEN) :: title
character(len=MAX_STR_LEN) :: version
end type drifters_input_type
interface assignment(=)
module procedure drifters_input_copy_new
end interface
contains
!===============================================================================
subroutine drifters_input_new(self, filename, ermesg)
type(drifters_input_type) :: self
character(len=*), intent(in) :: filename
character(len=*), intent(out):: ermesg
! Local
integer :: ier, ncid, nd, nf, np, ipos, j, id, i, isz
character(len=MAX_STR_LEN) :: attribute
include 'netcdf.inc'
ermesg = ''
ier = nf_open(filename, NF_NOWRITE, ncid)
if(ier/=NF_NOERR) then
ermesg = 'drifters_input: ERROR could not open netcdf file '//filename
return
endif
! version
ier = NF_PUT_ATT_TEXT(NCID, NF_GLOBAL, 'version', len(version), version)
ier = NF_INQ_DIMID(NCID, 'nd', id)
if(ier/=NF_NOERR) then
ermesg = 'drifters_input: ERROR could not find "nd" (number of dimensions)'
ier = nf_close(ncid)
return
endif
ier = NF_INQ_DIMLEN(NCID, id, nd)
! determine number of fields (nf)
attribute = ''
ier = nf_get_att_text(ncid, NF_GLOBAL, 'field_names', attribute)
isz = min(len(attribute), len(trim(attribute))+1)
attribute(isz:isz) = ' '
ipos = 1
nf = 0
do i = 1, isz
if(attribute(i:i)==SEPARATOR) then
nf = nf + 1
endif
enddo
ier = NF_INQ_DIMID(NCID, 'np', id)
if(ier/=NF_NOERR) then
ermesg = 'drifters_input: ERROR could not find "np" (number of particles)'
ier = nf_close(ncid)
return
endif
ier = NF_INQ_DIMLEN(NCID, id, np)
allocate(self%position_names(nd))
allocate(self%position_units(nd))
allocate(self%field_names(nf))
allocate(self%field_units(nf))
allocate(self%velocity_names(nd))
allocate(self%ids(np))
allocate(self%positions(nd, np))
ier = NF_INQ_VARID(NCID, 'ids', id)
if(ier/=NF_NOERR) then
ermesg = 'drifters_input: ERROR could not find "ids"'
ier = nf_close(ncid)
return
endif
ier = NF_GET_VAR_INT(NCID, id, self%ids)
ier = NF_INQ_VARID(NCID, 'positions', id)
if(ier/=NF_NOERR) then
ermesg = 'drifters_input: ERROR could not find "positions"'
ier = nf_close(ncid)
return
endif
ier = NF_GET_VAR_DOUBLE(NCID, id, self%positions)
attribute = ''
ier = nf_get_att_text(ncid, NF_GLOBAL, 'version', attribute)
self%version = trim(attribute)
attribute = ''
ier = nf_get_att_text(ncid, NF_GLOBAL, 'time_units', attribute)
self%time_units = trim(attribute)
attribute = ''
ier = nf_get_att_text(ncid, NF_GLOBAL, 'title', attribute)
self%title = trim(attribute)
attribute = ''
ier = nf_get_att_text(ncid, id, 'names', attribute)
isz = min(len(attribute), len(trim(attribute))+1)
attribute(isz:isz) = ' '
ipos = 1
j = 1
do i = 1, isz
if(attribute(i:i)==SEPARATOR) then
self%position_names(j) = trim(adjustl(attribute(ipos:i-1)))
ipos = i+1
j = j + 1
if(j > nd) exit
endif
enddo
attribute = ''
ier = nf_get_att_text(ncid, id, 'units', attribute)
isz = min(len(attribute), len(trim(attribute))+1)
attribute(isz:isz) = ' '
ipos = 1
j = 1
do i = 1, isz
if(attribute(i:i)==SEPARATOR) then
self%position_units(j) = trim(adjustl(attribute(ipos:i-1)))
ipos = i+1
j = j + 1
if(j > nd) exit
endif
enddo
attribute = ''
ier = nf_get_att_text(ncid, NF_GLOBAL, 'field_names', attribute)
isz = min(len(attribute), len(trim(attribute))+1)
attribute(isz:isz) = ' '
ipos = 1
j = 1
do i = 1, isz
if(attribute(i:i)==SEPARATOR) then
self%field_names(j) = trim(adjustl(attribute(ipos:i-1)))
ipos = i+1
j = j + 1
if(j > nf) exit
endif
enddo
attribute = ''
ier = nf_get_att_text(ncid, NF_GLOBAL, 'field_units', attribute)
isz = min(len(attribute), len(trim(attribute))+1)
attribute(isz:isz) = ' '
ipos = 1
j = 1
do i = 1, isz
if(attribute(i:i)==SEPARATOR) then
self%field_units(j) = trim(adjustl(attribute(ipos:i-1)))
ipos = i+1
j = j + 1
if(j > nf) exit
endif
enddo
attribute = ''
ier = nf_get_att_text(ncid, NF_GLOBAL, 'velocity_names', attribute)
isz = min(len(attribute), len(trim(attribute))+1)
attribute(isz:isz) = ' '
ipos = 1
j = 1
do i = 1, isz
if(attribute(i:i)==SEPARATOR) then
self%velocity_names(j) = trim(adjustl(attribute(ipos:i-1)))
ipos = i+1
j = j + 1
if(j > nd) exit
endif
enddo
end subroutine drifters_input_new
!===============================================================================
subroutine drifters_input_del(self, ermesg)
type(drifters_input_type) :: self
character(len=*), intent(out):: ermesg
integer :: iflag
ermesg = ''
deallocate(self%position_names, stat=iflag)
deallocate(self%position_units, stat=iflag)
deallocate(self%field_names, stat=iflag)
deallocate(self%field_units, stat=iflag)
deallocate(self%velocity_names, stat=iflag)
deallocate(self%ids, stat=iflag)
deallocate(self%positions, stat=iflag)
end subroutine drifters_input_del
!===============================================================================
subroutine drifters_input_copy_new(new_instance, old_instance)
type(drifters_input_type), intent(inout) :: new_instance
type(drifters_input_type), intent(in) :: old_instance
allocate(new_instance%position_names( size(old_instance%position_names) ))
allocate(new_instance%position_units( size(old_instance%position_units) ))
allocate(new_instance%field_names( size(old_instance%field_names) ))
allocate(new_instance%field_units( size(old_instance%field_units) ))
allocate(new_instance%velocity_names( size(old_instance%velocity_names) ))
new_instance%position_names = old_instance%position_names
new_instance%position_units = old_instance%position_units
new_instance%field_names = old_instance%field_names
new_instance%field_units = old_instance%field_units
new_instance%velocity_names = old_instance%velocity_names
new_instance%time_units = old_instance%time_units
new_instance%title = old_instance%title
new_instance%version = old_instance%version
allocate(new_instance%positions( size(old_instance%positions,1),size(old_instance%positions,2) ))
new_instance%positions = old_instance%positions
allocate(new_instance%ids(size(old_instance%ids)))
new_instance%ids = old_instance%ids
end subroutine drifters_input_copy_new
!===============================================================================
subroutine drifters_input_save(self, filename, geolon, geolat, ermesg)
! save state in netcdf file. can be used as restart file.
type(drifters_input_type) :: self
character(len=*), intent(in ):: filename
real, intent(in), optional :: geolon(:), geolat(:)
character(len=*), intent(out):: ermesg
integer ncid, nc_nd, nc_np, ier, nd, np, nf, nc_pos, nc_ids, i, j, n
integer nc_lon, nc_lat
character(len=MAX_STR_LEN) :: att
include 'netcdf.inc'
ermesg = ''
ier = nf_create(filename, NF_CLOBBER, ncid)
if(ier/=NF_NOERR) then
ermesg = 'drifters_input: ERROR cannot create '//filename
return
endif
nd = size(self%positions, 1)
np = size(self%positions, 2)
nf = size(self%field_names)
! dimensions
ier = nf_def_dim(ncid, 'nd', nd, nc_nd)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR creating dim "nd" '//nf_strerror(ier)
ier = nf_def_dim(ncid, 'np', np, nc_np)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR creating dim "np" '//nf_strerror(ier)
! global attributes
ier = nf_put_att_text(ncid, NF_GLOBAL, 'title', len_trim(self%title), self%title)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR setting global att "title" ' &
& //nf_strerror(ier)
ier = nf_put_att_text(ncid, NF_GLOBAL, 'time_units', len_trim(self%time_units), self%time_units)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR setting global att "time_units" ' &
& //nf_strerror(ier)
att = ''
j = 1
do i = 1, nf
n = len_trim(self%field_units(i))
att(j:j+n+1) = trim(self%field_units(i)) // ' '
j = j + n + 1
enddo
ier = nf_put_att_text(ncid, NF_GLOBAL, 'field_units', len_trim(att), &
& att)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR setting global att "field_units" ' &
& //nf_strerror(ier)
att = ''
j = 1
do i = 1, nf
n = len_trim(self%field_names(i))
att(j:j+n+1) = trim(self%field_names(i)) // ' '
j = j + n + 1
enddo
ier = nf_put_att_text(ncid, NF_GLOBAL, 'field_names', len_trim(att), &
& att)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR setting global att "field_names" ' &
& //nf_strerror(ier)
att = ''
j = 1
do i = 1, nd
n = len_trim(self%velocity_names(i))
att(j:j+n+1) = trim(self%velocity_names(i)) // ' '
j = j + n + 1
enddo
ier = nf_put_att_text(ncid, NF_GLOBAL, 'velocity_names', len_trim(att), &
& att)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR setting global att "velocity_names" ' &
& //nf_strerror(ier)
! variables
ier = nf_def_var(ncid, 'positions', NF_DOUBLE, 2, (/nc_nd, nc_np/), nc_pos)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR creating var "positions" '//nf_strerror(ier)
ier = nf_def_var(ncid, 'ids', NF_INT, 1, (/nc_np/), nc_ids)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR creating var "ids" '//nf_strerror(ier)
! optional: longitudes/latitudes in deg
if(present(geolon)) then
ier = nf_def_var(ncid, 'longitude', NF_DOUBLE, 1, (/nc_np/), nc_lon)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR creating var "longitude" ' &
& //nf_strerror(ier)
att = 'degrees_east'
ier = nf_put_att_text(ncid, nc_lon, 'units', len(trim(att)), trim(att))
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR setting att "units" to "longitude" ' &
& //nf_strerror(ier)
endif
if(present(geolat)) then
ier = nf_def_var(ncid, 'latitude', NF_DOUBLE, 1, (/nc_np/), nc_lat)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR creating var "latitude" ' &
& //nf_strerror(ier)
att = 'degrees_north'
ier = nf_put_att_text(ncid, nc_lat, 'units', len(trim(att)), trim(att))
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR setting att "units" to "latitude" ' &
& //nf_strerror(ier)
endif
! variable attributes
att = ''
j = 1
do i = 1, nd
n = len_trim(self%position_units(i))
att(j:j+n+1) = trim(self%position_units(i)) // ' '
j = j + n + 1
enddo
ier = nf_put_att_text(ncid, nc_pos, 'units', len_trim(att), &
& att)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR setting att "units" to "positions" ' &
& //nf_strerror(ier)
att = ''
j = 1
do i = 1, nd
n = len_trim(self%position_names(i))
att(j:j+n+1) = trim(self%position_names(i)) // ' '
j = j + n + 1
enddo
ier = nf_put_att_text(ncid, nc_pos, 'names', len_trim(att), &
& att)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR setting att "names" to "positions" ' &
& //nf_strerror(ier)
! end of define mode
ier = nf_enddef(ncid)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR could not end define mode ' &
& //nf_strerror(ier)
! data
ier = nf_put_var_double(ncid, nc_pos, self%positions)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR could not write "positions" ' &
& //nf_strerror(ier)
ier = nf_put_var_int(ncid, nc_ids, self%ids)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR could not write "ids" ' &
& //nf_strerror(ier)
if(present(geolon)) then
ier = nf_put_var_double(ncid, nc_lon, geolon)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR could not write "geolon" ' &
& //nf_strerror(ier)
endif
if(present(geolat)) then
ier = nf_put_var_double(ncid, nc_lat, geolat)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR could not write "geolat" ' &
& //nf_strerror(ier)
endif
ier = nf_close(ncid)
if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR could not close file ' &
& //nf_strerror(ier)
end subroutine drifters_input_save
end module drifters_input_mod
!===============================================================================
!===============================================================================