1 !***********************************************************************
2 !* GNU Lesser General Public License
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
6 !* FMS is free software: you can redistribute it and/or modify it under
7 !* the terms of the GNU Lesser General Public License as published by
8 !* the Free Software Foundation, either version 3 of the License, or (at
9 !* your option) any later version.
11 !* FMS is distributed in the hope that it will be useful, but WITHOUT
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 !* You should have received a copy of the GNU Lesser General Public
17 !* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18 !***********************************************************************
19 !> @defgroup drifters_input_mod drifters_input_mod
21 !> @brief Imports initial drifter positions from a netCDF file
23 !> @addtogroup drifters_input_mod
25 module drifters_input_mod
29 public :: drifters_input_type, drifters_input_new, drifters_input_del, drifters_input_save, assignment(=)
32 integer, parameter, private :: MAX_STR_LEN = 128
33 ! Include variable "version" to be written to log file.
34 #include<file_version.h>
35 character, parameter, private :: SEPARATOR = ' '
38 !> @brief Input data type for drifters.
40 !> @note Be sure to update drifters_input_new, drifters_input_del and drifters_input_copy_new
41 !! when adding members
42 !> @ingroup drifters_input_mod
43 type drifters_input_type
44 ! Be sure to update drifters_input_new, drifters_input_del and drifters_input_copy_new
46 character(len=MAX_STR_LEN), allocatable :: position_names(:)
47 character(len=MAX_STR_LEN), allocatable :: position_units(:)
48 character(len=MAX_STR_LEN), allocatable :: field_names(:)
49 character(len=MAX_STR_LEN), allocatable :: field_units(:)
50 character(len=MAX_STR_LEN), allocatable :: velocity_names(:)
51 real , allocatable :: positions(:,:)
52 integer , allocatable :: ids(:)
53 character(len=MAX_STR_LEN) :: time_units
54 character(len=MAX_STR_LEN) :: title
55 character(len=MAX_STR_LEN) :: version
56 end type drifters_input_type
58 !> @brief Assignment override for @ref drifters_input_type
59 !> @ingroup drifters_input_mod
60 interface assignment(=)
61 module procedure drifters_input_copy_new
64 !> @addtogroup drifters_input_mod
69 !===============================================================================
71 subroutine drifters_input_new(self, filename, ermesg)
74 use netcdf_nf_interfaces
75 type(drifters_input_type) :: self
76 character(len=*), intent(in) :: filename
77 character(len=*), intent(out):: ermesg
80 integer :: ier, ncid, nd, nf, np, ipos, j, id, i, isz
81 character(len=MAX_STR_LEN) :: attribute
85 ier = nf_open(filename, NF_NOWRITE, ncid)
86 if(ier/=NF_NOERR) then
87 ermesg = 'drifters_input: ERROR could not open netcdf file '//filename
92 ier = NF_PUT_ATT_TEXT(NCID, NF_GLOBAL, 'version', len(version), version)
94 ier = NF_INQ_DIMID(NCID, 'nd', id)
95 if(ier/=NF_NOERR) then
96 ermesg = 'drifters_input: ERROR could not find "nd" (number of dimensions)'
100 ier = NF_INQ_DIMLEN(NCID, id, nd)
102 ! determine number of fields (nf)
104 ier = nf_get_att_text(ncid, NF_GLOBAL, 'field_names', attribute)
105 isz = min(len(attribute), len(trim(attribute))+1)
106 attribute(isz:isz) = ' '
110 if(attribute(i:i)==SEPARATOR) then
115 ier = NF_INQ_DIMID(NCID, 'np', id)
116 if(ier/=NF_NOERR) then
117 ermesg = 'drifters_input: ERROR could not find "np" (number of particles)'
121 ier = NF_INQ_DIMLEN(NCID, id, np)
123 allocate(self%position_names(nd))
124 allocate(self%position_units(nd))
125 allocate(self%field_names(nf))
126 allocate(self%field_units(nf))
127 allocate(self%velocity_names(nd))
128 allocate(self%ids(np))
129 allocate(self%positions(nd, np))
131 ier = NF_INQ_VARID(NCID, 'ids', id)
132 if(ier/=NF_NOERR) then
133 ermesg = 'drifters_input: ERROR could not find "ids"'
137 ier = NF_GET_VAR_INT(NCID, id, self%ids)
139 ier = NF_INQ_VARID(NCID, 'positions', id)
140 if(ier/=NF_NOERR) then
141 ermesg = 'drifters_input: ERROR could not find "positions"'
145 ier = NF90_GET_VAR(NCID, id, self%positions)
148 ier = nf_get_att_text(ncid, NF_GLOBAL, 'version', attribute)
149 self%version = trim(attribute)
152 ier = nf_get_att_text(ncid, NF_GLOBAL, 'time_units', attribute)
153 self%time_units = trim(attribute)
156 ier = nf_get_att_text(ncid, NF_GLOBAL, 'title', attribute)
157 self%title = trim(attribute)
160 ier = nf_get_att_text(ncid, id, 'names', attribute)
161 isz = min(len(attribute), len(trim(attribute))+1)
162 attribute(isz:isz) = ' '
166 if(attribute(i:i)==SEPARATOR) then
167 self%position_names(j) = trim(adjustl(attribute(ipos:i-1)))
175 ier = nf_get_att_text(ncid, id, 'units', attribute)
176 isz = min(len(attribute), len(trim(attribute))+1)
177 attribute(isz:isz) = ' '
181 if(attribute(i:i)==SEPARATOR) then
182 self%position_units(j) = trim(adjustl(attribute(ipos:i-1)))
190 ier = nf_get_att_text(ncid, NF_GLOBAL, 'field_names', attribute)
191 isz = min(len(attribute), len(trim(attribute))+1)
192 attribute(isz:isz) = ' '
196 if(attribute(i:i)==SEPARATOR) then
197 self%field_names(j) = trim(adjustl(attribute(ipos:i-1)))
205 ier = nf_get_att_text(ncid, NF_GLOBAL, 'field_units', attribute)
206 isz = min(len(attribute), len(trim(attribute))+1)
207 attribute(isz:isz) = ' '
211 if(attribute(i:i)==SEPARATOR) then
212 self%field_units(j) = trim(adjustl(attribute(ipos:i-1)))
220 ier = nf_get_att_text(ncid, NF_GLOBAL, 'velocity_names', attribute)
221 isz = min(len(attribute), len(trim(attribute))+1)
222 attribute(isz:isz) = ' '
226 if(attribute(i:i)==SEPARATOR) then
227 self%velocity_names(j) = trim(adjustl(attribute(ipos:i-1)))
234 end subroutine drifters_input_new
236 !===============================================================================
237 subroutine drifters_input_del(self, ermesg)
238 type(drifters_input_type) :: self
239 character(len=*), intent(out):: ermesg
245 deallocate(self%position_names, stat=iflag)
246 deallocate(self%position_units, stat=iflag)
247 deallocate(self%field_names, stat=iflag)
248 deallocate(self%field_units, stat=iflag)
249 deallocate(self%velocity_names, stat=iflag)
250 deallocate(self%ids, stat=iflag)
251 deallocate(self%positions, stat=iflag)
253 end subroutine drifters_input_del
255 !===============================================================================
256 subroutine drifters_input_copy_new(new_instance, old_instance)
258 type(drifters_input_type), intent(inout) :: new_instance
259 type(drifters_input_type), intent(in) :: old_instance
261 allocate(new_instance%position_names( size(old_instance%position_names) ))
262 allocate(new_instance%position_units( size(old_instance%position_units) ))
263 allocate(new_instance%field_names( size(old_instance%field_names) ))
264 allocate(new_instance%field_units( size(old_instance%field_units) ))
265 allocate(new_instance%velocity_names( size(old_instance%velocity_names) ))
266 new_instance%position_names = old_instance%position_names
267 new_instance%position_units = old_instance%position_units
268 new_instance%field_names = old_instance%field_names
269 new_instance%field_units = old_instance%field_units
270 new_instance%velocity_names = old_instance%velocity_names
271 new_instance%time_units = old_instance%time_units
272 new_instance%title = old_instance%title
273 new_instance%version = old_instance%version
274 allocate(new_instance%positions( size(old_instance%positions,1),size(old_instance%positions,2) ))
275 new_instance%positions = old_instance%positions
276 allocate(new_instance%ids(size(old_instance%ids)))
277 new_instance%ids = old_instance%ids
279 end subroutine drifters_input_copy_new
281 !===============================================================================
282 !> @brief save state in netcdf file. can be used as restart file.
283 subroutine drifters_input_save(self, filename, geolon, geolat, ermesg)
284 ! save state in netcdf file. can be used as restart file.
287 use netcdf_nf_interfaces
288 type(drifters_input_type) :: self
289 character(len=*), intent(in ):: filename
290 real, intent(in), optional :: geolon(:), geolat(:)
291 character(len=*), intent(out):: ermesg
294 integer ncid, nc_nd, nc_np, ier, nd, np, nf, nc_pos, nc_ids, i, j, n
295 integer nc_lon, nc_lat
296 character(len=MAX_STR_LEN) :: att
301 ier = nf_create(filename, NF_CLOBBER, ncid)
302 if(ier/=NF_NOERR) then
303 ermesg = 'drifters_input: ERROR cannot create '//filename
307 nd = size(self%positions, 1)
308 np = size(self%positions, 2)
309 nf = size(self%field_names)
312 ier = nf_def_dim(ncid, 'nd', nd, nc_nd)
313 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR creating dim "nd" '//nf_strerror(ier)
315 ier = nf_def_dim(ncid, 'np', np, nc_np)
316 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR creating dim "np" '//nf_strerror(ier)
319 ier = nf_put_att_text(ncid, NF_GLOBAL, 'title', len_trim(self%title), self%title)
320 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR setting global att "title" ' &
323 ier = nf_put_att_text(ncid, NF_GLOBAL, 'time_units', len_trim(self%time_units), self%time_units)
324 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR setting global att "time_units" ' &
330 n = len_trim(self%field_units(i))
331 att(j:j+n+1) = trim(self%field_units(i)) // ' '
334 ier = nf_put_att_text(ncid, NF_GLOBAL, 'field_units', len_trim(att), &
336 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR setting global att "field_units" ' &
342 n = len_trim(self%field_names(i))
343 att(j:j+n+1) = trim(self%field_names(i)) // ' '
346 ier = nf_put_att_text(ncid, NF_GLOBAL, 'field_names', len_trim(att), &
348 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR setting global att "field_names" ' &
354 n = len_trim(self%velocity_names(i))
355 att(j:j+n+1) = trim(self%velocity_names(i)) // ' '
358 ier = nf_put_att_text(ncid, NF_GLOBAL, 'velocity_names', len_trim(att), &
360 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR setting global att "velocity_names" ' &
364 ier = nf_def_var(ncid, 'positions', NF_DOUBLE, 2, (/nc_nd, nc_np/), nc_pos)
365 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR creating var "positions" '//nf_strerror(ier)
367 ier = nf_def_var(ncid, 'ids', NF_INT, 1, (/nc_np/), nc_ids)
368 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR creating var "ids" '//nf_strerror(ier)
370 ! optional: longitudes/latitudes in deg
371 if(present(geolon)) then
372 ier = nf_def_var(ncid, 'longitude', NF_DOUBLE, 1, (/nc_np/), nc_lon)
373 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR creating var "longitude" ' &
376 ier = nf_put_att_text(ncid, nc_lon, 'units', len(trim(att)), trim(att))
377 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR setting att "units" to "longitude" ' &
380 if(present(geolat)) then
381 ier = nf_def_var(ncid, 'latitude', NF_DOUBLE, 1, (/nc_np/), nc_lat)
382 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR creating var "latitude" ' &
384 att = 'degrees_north'
385 ier = nf_put_att_text(ncid, nc_lat, 'units', len(trim(att)), trim(att))
386 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR setting att "units" to "latitude" ' &
390 ! variable attributes
395 n = len_trim(self%position_units(i))
396 att(j:j+n+1) = trim(self%position_units(i)) // ' '
399 ier = nf_put_att_text(ncid, nc_pos, 'units', len_trim(att), &
401 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR setting att "units" to "positions" ' &
407 n = len_trim(self%position_names(i))
408 att(j:j+n+1) = trim(self%position_names(i)) // ' '
411 ier = nf_put_att_text(ncid, nc_pos, 'names', len_trim(att), &
413 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR setting att "names" to "positions" ' &
417 ier = nf_enddef(ncid)
418 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR could not end define mode ' &
422 ier = nf90_put_var(ncid, nc_pos, self%positions)
423 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR could not write "positions" ' &
426 ier = nf90_put_var(ncid, nc_ids, self%ids)
427 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR could not write "ids" ' &
430 if(present(geolon)) then
431 ier = nf90_put_var(ncid, nc_lon, geolon)
432 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR could not write "geolon" ' &
435 if(present(geolat)) then
436 ier = nf90_put_var(ncid, nc_lat, geolat)
437 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR could not write "geolat" ' &
443 if(ier/=NF_NOERR) ermesg = 'drifters_input_save: ERROR could not close file ' &
446 end subroutine drifters_input_save
448 end module drifters_input_mod
450 ! close documentation grouping