FV3 Bundle
drifters_input.F90
Go to the documentation of this file.
1 !***********************************************************************
2 !* GNU Lesser General Public License
3 !*
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
5 !*
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.
10 !*
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
14 !* for more details.
15 !*
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 
20 
22 #include <fms_platform.h>
23  implicit none
24  private
25 
27 
28  ! Globals
29  integer, parameter, private :: max_str_len = 128
30  ! Include variable "version" to be written to log file.
31 #include<file_version.h>
32  character, parameter, private :: separator = ' '
33 
35  ! Be sure to update drifters_input_new, drifters_input_del and drifters_input_copy_new
36  ! when adding members
37  character(len=MAX_STR_LEN), _allocatable :: position_names(:) _null
38  character(len=MAX_STR_LEN), _allocatable :: position_units(:) _null
39  character(len=MAX_STR_LEN), _allocatable :: field_names(:) _null
40  character(len=MAX_STR_LEN), _allocatable :: field_units(:) _null
41  character(len=MAX_STR_LEN), _allocatable :: velocity_names(:) _null
42  real , _allocatable :: positions(:,:) _null
43  integer , _allocatable :: ids(:) _null
44  character(len=MAX_STR_LEN) :: time_units
45  character(len=MAX_STR_LEN) :: title
46  character(len=MAX_STR_LEN) :: version
47  end type drifters_input_type
48 
49  interface assignment(=)
50  module procedure drifters_input_copy_new
51  end interface
52 
53 
54  contains
55 
56 !===============================================================================
57 
58  subroutine drifters_input_new(self, filename, ermesg)
59  type(drifters_input_type) :: self
60  character(len=*), intent(in) :: filename
61  character(len=*), intent(out):: ermesg
62 
63  ! Local
64  integer :: ier, ncid, nd, nf, np, ipos, j, id, i, isz
65  character(len=MAX_STR_LEN) :: attribute
66  include 'netcdf.inc'
67 
68  ermesg = ''
69 
70  ier = nf_open(filename, nf_nowrite, ncid)
71  if(ier/=nf_noerr) then
72  ermesg = 'drifters_input: ERROR could not open netcdf file '//filename
73  return
74  endif
75 
76  ! version
77  ier = nf_put_att_text(ncid, nf_global, 'version', len(version), version)
78 
79  ier = nf_inq_dimid(ncid, 'nd', id)
80  if(ier/=nf_noerr) then
81  ermesg = 'drifters_input: ERROR could not find "nd" (number of dimensions)'
82  ier = nf_close(ncid)
83  return
84  endif
85  ier = nf_inq_dimlen(ncid, id, nd)
86 
87  ! determine number of fields (nf)
88  attribute = ''
89  ier = nf_get_att_text(ncid, nf_global, 'field_names', attribute)
90  isz = min(len(attribute), len(trim(attribute))+1)
91  attribute(isz:isz) = ' '
92  ipos = 1
93  nf = 0
94  do i = 1, isz
95  if(attribute(i:i)==separator) then
96  nf = nf + 1
97  endif
98  enddo
99 
100  ier = nf_inq_dimid(ncid, 'np', id)
101  if(ier/=nf_noerr) then
102  ermesg = 'drifters_input: ERROR could not find "np" (number of particles)'
103  ier = nf_close(ncid)
104  return
105  endif
106  ier = nf_inq_dimlen(ncid, id, np)
107 
108  allocate(self%position_names(nd))
109  allocate(self%position_units(nd))
110  allocate(self%field_names(nf))
111  allocate(self%field_units(nf))
112  allocate(self%velocity_names(nd))
113  allocate(self%ids(np))
114  allocate(self%positions(nd, np))
115 
116  ier = nf_inq_varid(ncid, 'ids', id)
117  if(ier/=nf_noerr) then
118  ermesg = 'drifters_input: ERROR could not find "ids"'
119  ier = nf_close(ncid)
120  return
121  endif
122  ier = nf_get_var_int(ncid, id, self%ids)
123 
124  ier = nf_inq_varid(ncid, 'positions', id)
125  if(ier/=nf_noerr) then
126  ermesg = 'drifters_input: ERROR could not find "positions"'
127  ier = nf_close(ncid)
128  return
129  endif
130  ier = nf_get_var_double(ncid, id, self%positions)
131 
132  attribute = ''
133  ier = nf_get_att_text(ncid, nf_global, 'version', attribute)
134  self%version = trim(attribute)
135 
136  attribute = ''
137  ier = nf_get_att_text(ncid, nf_global, 'time_units', attribute)
138  self%time_units = trim(attribute)
139 
140  attribute = ''
141  ier = nf_get_att_text(ncid, nf_global, 'title', attribute)
142  self%title = trim(attribute)
143 
144  attribute = ''
145  ier = nf_get_att_text(ncid, id, 'names', attribute)
146  isz = min(len(attribute), len(trim(attribute))+1)
147  attribute(isz:isz) = ' '
148  ipos = 1
149  j = 1
150  do i = 1, isz
151  if(attribute(i:i)==separator) then
152  self%position_names(j) = trim(adjustl(attribute(ipos:i-1)))
153  ipos = i+1
154  j = j + 1
155  if(j > nd) exit
156  endif
157  enddo
158 
159  attribute = ''
160  ier = nf_get_att_text(ncid, id, 'units', attribute)
161  isz = min(len(attribute), len(trim(attribute))+1)
162  attribute(isz:isz) = ' '
163  ipos = 1
164  j = 1
165  do i = 1, isz
166  if(attribute(i:i)==separator) then
167  self%position_units(j) = trim(adjustl(attribute(ipos:i-1)))
168  ipos = i+1
169  j = j + 1
170  if(j > nd) exit
171  endif
172  enddo
173 
174  attribute = ''
175  ier = nf_get_att_text(ncid, nf_global, 'field_names', attribute)
176  isz = min(len(attribute), len(trim(attribute))+1)
177  attribute(isz:isz) = ' '
178  ipos = 1
179  j = 1
180  do i = 1, isz
181  if(attribute(i:i)==separator) then
182  self%field_names(j) = trim(adjustl(attribute(ipos:i-1)))
183  ipos = i+1
184  j = j + 1
185  if(j > nf) exit
186  endif
187  enddo
188 
189  attribute = ''
190  ier = nf_get_att_text(ncid, nf_global, 'field_units', attribute)
191  isz = min(len(attribute), len(trim(attribute))+1)
192  attribute(isz:isz) = ' '
193  ipos = 1
194  j = 1
195  do i = 1, isz
196  if(attribute(i:i)==separator) then
197  self%field_units(j) = trim(adjustl(attribute(ipos:i-1)))
198  ipos = i+1
199  j = j + 1
200  if(j > nf) exit
201  endif
202  enddo
203 
204  attribute = ''
205  ier = nf_get_att_text(ncid, nf_global, 'velocity_names', attribute)
206  isz = min(len(attribute), len(trim(attribute))+1)
207  attribute(isz:isz) = ' '
208  ipos = 1
209  j = 1
210  do i = 1, isz
211  if(attribute(i:i)==separator) then
212  self%velocity_names(j) = trim(adjustl(attribute(ipos:i-1)))
213  ipos = i+1
214  j = j + 1
215  if(j > nd) exit
216  endif
217  enddo
218 
219  end subroutine drifters_input_new
220 
221 !===============================================================================
222  subroutine drifters_input_del(self, ermesg)
223  type(drifters_input_type) :: self
224  character(len=*), intent(out):: ermesg
225 
226  integer :: iflag
227 
228  ermesg = ''
229 
230  deallocate(self%position_names, stat=iflag)
231  deallocate(self%position_units, stat=iflag)
232  deallocate(self%field_names, stat=iflag)
233  deallocate(self%field_units, stat=iflag)
234  deallocate(self%velocity_names, stat=iflag)
235  deallocate(self%ids, stat=iflag)
236  deallocate(self%positions, stat=iflag)
237 
238  end subroutine drifters_input_del
239 
240 !===============================================================================
241  subroutine drifters_input_copy_new(new_instance, old_instance)
243  type(drifters_input_type), intent(inout) :: new_instance
244  type(drifters_input_type), intent(in) :: old_instance
245 
246  allocate(new_instance%position_names( size(old_instance%position_names) ))
247  allocate(new_instance%position_units( size(old_instance%position_units) ))
248  allocate(new_instance%field_names( size(old_instance%field_names) ))
249  allocate(new_instance%field_units( size(old_instance%field_units) ))
250  allocate(new_instance%velocity_names( size(old_instance%velocity_names) ))
251  new_instance%position_names = old_instance%position_names
252  new_instance%position_units = old_instance%position_units
253  new_instance%field_names = old_instance%field_names
254  new_instance%field_units = old_instance%field_units
255  new_instance%velocity_names = old_instance%velocity_names
256  new_instance%time_units = old_instance%time_units
257  new_instance%title = old_instance%title
258  new_instance%version = old_instance%version
259  allocate(new_instance%positions( size(old_instance%positions,1),size(old_instance%positions,2) ))
260  new_instance%positions = old_instance%positions
261  allocate(new_instance%ids(size(old_instance%ids)))
262  new_instance%ids = old_instance%ids
263 
264  end subroutine drifters_input_copy_new
265 
266 !===============================================================================
267  subroutine drifters_input_save(self, filename, geolon, geolat, ermesg)
268  ! save state in netcdf file. can be used as restart file.
269  type(drifters_input_type) :: self
270  character(len=*), intent(in ):: filename
271  real, intent(in), optional :: geolon(:), geolat(:)
272  character(len=*), intent(out):: ermesg
273 
274  integer ncid, nc_nd, nc_np, ier, nd, np, nf, nc_pos, nc_ids, i, j, n
275  integer nc_lon, nc_lat
276  character(len=MAX_STR_LEN) :: att
277 
278  include 'netcdf.inc'
279 
280  ermesg = ''
281 
282  ier = nf_create(filename, nf_clobber, ncid)
283  if(ier/=nf_noerr) then
284  ermesg = 'drifters_input: ERROR cannot create '//filename
285  return
286  endif
287 
288  nd = size(self%positions, 1)
289  np = size(self%positions, 2)
290  nf = size(self%field_names)
291 
292  ! dimensions
293  ier = nf_def_dim(ncid, 'nd', nd, nc_nd)
294  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR creating dim "nd" '//nf_strerror(ier)
295 
296  ier = nf_def_dim(ncid, 'np', np, nc_np)
297  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR creating dim "np" '//nf_strerror(ier)
298 
299  ! global attributes
300  ier = nf_put_att_text(ncid, nf_global, 'title', len_trim(self%title), self%title)
301  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR setting global att "title" ' &
302  & //nf_strerror(ier)
303 
304  ier = nf_put_att_text(ncid, nf_global, 'time_units', len_trim(self%time_units), self%time_units)
305  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR setting global att "time_units" ' &
306  & //nf_strerror(ier)
307 
308  att = ''
309  j = 1
310  do i = 1, nf
311  n = len_trim(self%field_units(i))
312  att(j:j+n+1) = trim(self%field_units(i)) // ' '
313  j = j + n + 1
314  enddo
315  ier = nf_put_att_text(ncid, nf_global, 'field_units', len_trim(att), &
316  & att)
317  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR setting global att "field_units" ' &
318  & //nf_strerror(ier)
319 
320  att = ''
321  j = 1
322  do i = 1, nf
323  n = len_trim(self%field_names(i))
324  att(j:j+n+1) = trim(self%field_names(i)) // ' '
325  j = j + n + 1
326  enddo
327  ier = nf_put_att_text(ncid, nf_global, 'field_names', len_trim(att), &
328  & att)
329  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR setting global att "field_names" ' &
330  & //nf_strerror(ier)
331 
332  att = ''
333  j = 1
334  do i = 1, nd
335  n = len_trim(self%velocity_names(i))
336  att(j:j+n+1) = trim(self%velocity_names(i)) // ' '
337  j = j + n + 1
338  enddo
339  ier = nf_put_att_text(ncid, nf_global, 'velocity_names', len_trim(att), &
340  & att)
341  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR setting global att "velocity_names" ' &
342  & //nf_strerror(ier)
343 
344  ! variables
345  ier = nf_def_var(ncid, 'positions', nf_double, 2, (/nc_nd, nc_np/), nc_pos)
346  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR creating var "positions" '//nf_strerror(ier)
347 
348  ier = nf_def_var(ncid, 'ids', nf_int, 1, (/nc_np/), nc_ids)
349  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR creating var "ids" '//nf_strerror(ier)
350 
351  ! optional: longitudes/latitudes in deg
352  if(present(geolon)) then
353  ier = nf_def_var(ncid, 'longitude', nf_double, 1, (/nc_np/), nc_lon)
354  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR creating var "longitude" ' &
355  & //nf_strerror(ier)
356  att = 'degrees_east'
357  ier = nf_put_att_text(ncid, nc_lon, 'units', len(trim(att)), trim(att))
358  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR setting att "units" to "longitude" ' &
359  & //nf_strerror(ier)
360  endif
361  if(present(geolat)) then
362  ier = nf_def_var(ncid, 'latitude', nf_double, 1, (/nc_np/), nc_lat)
363  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR creating var "latitude" ' &
364  & //nf_strerror(ier)
365  att = 'degrees_north'
366  ier = nf_put_att_text(ncid, nc_lat, 'units', len(trim(att)), trim(att))
367  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR setting att "units" to "latitude" ' &
368  & //nf_strerror(ier)
369  endif
370 
371  ! variable attributes
372 
373  att = ''
374  j = 1
375  do i = 1, nd
376  n = len_trim(self%position_units(i))
377  att(j:j+n+1) = trim(self%position_units(i)) // ' '
378  j = j + n + 1
379  enddo
380  ier = nf_put_att_text(ncid, nc_pos, 'units', len_trim(att), &
381  & att)
382  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR setting att "units" to "positions" ' &
383  & //nf_strerror(ier)
384 
385  att = ''
386  j = 1
387  do i = 1, nd
388  n = len_trim(self%position_names(i))
389  att(j:j+n+1) = trim(self%position_names(i)) // ' '
390  j = j + n + 1
391  enddo
392  ier = nf_put_att_text(ncid, nc_pos, 'names', len_trim(att), &
393  & att)
394  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR setting att "names" to "positions" ' &
395  & //nf_strerror(ier)
396 
397  ! end of define mode
398  ier = nf_enddef(ncid)
399  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR could not end define mode ' &
400  & //nf_strerror(ier)
401 
402  ! data
403  ier = nf_put_var_double(ncid, nc_pos, self%positions)
404  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR could not write "positions" ' &
405  & //nf_strerror(ier)
406 
407  ier = nf_put_var_int(ncid, nc_ids, self%ids)
408  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR could not write "ids" ' &
409  & //nf_strerror(ier)
410 
411  if(present(geolon)) then
412  ier = nf_put_var_double(ncid, nc_lon, geolon)
413  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR could not write "geolon" ' &
414  & //nf_strerror(ier)
415  endif
416  if(present(geolat)) then
417  ier = nf_put_var_double(ncid, nc_lat, geolat)
418  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR could not write "geolat" ' &
419  & //nf_strerror(ier)
420  endif
421 
422 
423  ier = nf_close(ncid)
424  if(ier/=nf_noerr) ermesg = 'drifters_input_save: ERROR could not close file ' &
425  & //nf_strerror(ier)
426 
427  end subroutine drifters_input_save
428 
429 end module drifters_input_mod
430 
431 !===============================================================================
432 !===============================================================================
433 #ifdef _TEST_DRIFTERS_INPUT
434 program test
436  implicit none
437  character(len=128) :: ermesg
438  integer :: i
439 
440  type(drifters_input_type) :: obj
441 
442  call drifters_input_new(obj, 'input.nc', ermesg)
443  if(ermesg/='') print *,'ERROR: ', ermesg
444 
445  print *,'field_names:'
446  do i = 1, size(obj%field_names)
447  print *,trim(obj%field_names(i))
448  enddo
449 
450  print *,'velocity_names:'
451  do i = 1, size(obj%velocity_names)
452  print *,trim(obj%velocity_names(i))
453  enddo
454 
455  print *,'ids = ', obj%ids
456 
457  print *,'positions: '
458  do i = 1, size(obj%positions, 2)
459  print *,obj%positions(:,i)
460  enddo
461 
462  call drifters_input_del(obj, ermesg)
463 end program test
464 
465 #endif
subroutine, public drifters_input_del(self, ermesg)
integer, parameter, private max_str_len
subroutine drifters_input_copy_new(new_instance, old_instance)
subroutine, public drifters_input_new(self, filename, ermesg)
character, parameter, private separator
#define min(a, b)
Definition: mosaic_util.h:32
subroutine, public drifters_input_save(self, filename, geolon, geolat, ermesg)