FV3 Bundle
read_climate_nudge_data_nlm.F90
Go to the documentation of this file.
1 
3 
4 use fms_mod, only: open_namelist_file, check_nml_error, close_file, &
5  stdlog, mpp_pe, mpp_root_pe, write_version_number, &
6  string, error_mesg, fatal, note, file_exist
7 use mpp_mod, only: input_nml_file
8 use mpp_io_mod, only: mpp_open, mpp_netcdf, mpp_rdonly,mpp_multi, mpp_single
9 use mpp_io_mod, only: axistype, fieldtype, mpp_get_time_axis, mpp_get_atts
10 use mpp_io_mod, only: mpp_get_fields, mpp_get_info, mpp_get_axes, mpp_get_times
11 use mpp_io_mod, only: mpp_get_axis_data, mpp_read, mpp_close, mpp_get_default_calendar
12 use constants_mod, only: pi, grav, rdgas, rvgas
14 
15 implicit none
16 private
17 
20 public :: read_sub_domain_init
21 
23  module procedure read_climate_nudge_data_2d
24  module procedure read_climate_nudge_data_3d
25 end interface
26 
27  real(FVPRC), parameter :: p0 = 1.e5
28  real(FVPRC), parameter :: d608 = rvgas/rdgas - 1.
29 
30  integer, parameter :: num_req_axes = 3
31  integer, parameter :: index_lon = 1, index_lat = 2, index_lev = 3
32  character(len=8), dimension(NUM_REQ_AXES) :: required_axis_names = &
33  (/ 'lon', 'lat', 'lev' /)
34 
35  integer, parameter :: num_req_flds = 9
36  integer, parameter :: index_p0 = 1, index_ak = 2, index_bk = 3, &
37  index_zs = 4, index_ps = 5, &
38  index_t = 6, index_q = 7, &
39  index_u = 8, index_v = 9
40  character(len=8), dimension(NUM_REQ_FLDS) :: required_field_names = &
41  (/ 'P0 ', 'hyai', 'hybi', 'PHI ', 'PS ', 'T ', 'Q ', 'U ', 'V ' /)
42 
43  integer, parameter :: maxfiles = 53
44  character(len=256) :: filenames(maxfiles)
45  character(len=256) :: filename_tails(maxfiles)
46  character(len=256) :: filename_head
47  integer :: read_buffer_size
48  integer :: nfiles = 0
49  logical :: module_is_initialized = .false.
50 
51  namelist /read_climate_nudge_data_nml/ filename_tails, read_buffer_size, &
53 
54 ! dimensions for checking
56  integer, allocatable :: file_index(:)
57 
59  integer :: ncid
60  integer, pointer :: length_axes(:) ! length of all dimensions in file
61  integer :: ndim, nvar, natt, ntim, varid_time
62  integer :: time_offset
63  integer, dimension(NUM_REQ_FLDS) :: field_index ! varid for variables
64  integer, dimension(NUM_REQ_AXES) :: axis_index ! varid for dimensions
65  type(axistype), dimension(NUM_REQ_FLDS) :: axes
66  type(fieldtype), dimension(NUM_REQ_FLDS) :: fields
67 end type
68 
69  type(filedata_type), allocatable :: files(:)
70 
71 CONTAINS
72 
73 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
74 
75 subroutine read_climate_nudge_data_init (nlon, nlat, nlev, ntime)
76 integer, intent(out) :: nlon, nlat, nlev, ntime
77 ! returns dimension lengths of input data set
78 ! nlon, nlat lat/lon grid size
79 ! nlev number of levels
80 ! ntime number of time levels
81 
82  integer :: iunit, ierr, io
83  character(len=128) :: name
84  integer :: istat, i, j, k, n, nd, siz(4), i1, i2
85  type(axistype), allocatable :: axes(:)
86  type(fieldtype), allocatable :: fields(:)
87 
88  if (module_is_initialized) return
89  ! initial file names to blanks
90  do n = 1, maxfiles
91  do i = 1, len(filename_tails(n))
92  filename_tails(n)(i:i) = ' '
93  filenames(n)(i:i) = ' '
94  enddo
95  enddo
96 
97 !----- read namelist -----
98 #ifdef INTERNAL_FILE_NML
99  read (input_nml_file, nml=read_climate_nudge_data_nml, iostat=io)
100  ierr = check_nml_error(io, 'read_climate_nudge_data_nml')
101 #else
102  if (file_exist('input.nml') ) then
103  iunit = open_namelist_file()
104  ierr=1
105  do while (ierr /= 0)
106  read (iunit, nml=read_climate_nudge_data_nml, iostat=io, end=10)
107  ierr = check_nml_error(io, 'read_climate_nudge_data_nml')
108  enddo
109 10 call close_file (iunit)
110  endif
111 #endif
112 
113 !----- write version and namelist to log file -----
114 
115  iunit = stdlog()
116  call write_version_number ( '0.0', 'fv3-jedi-lm' )
117  if (mpp_pe() == mpp_root_pe()) write (iunit, nml=read_climate_nudge_data_nml)
118 
119  ! determine the number of files
120  do n = 1, maxfiles
121  if (filename_tails(n)(1:1) .eq. ' ') exit
122  nfiles = n
123  enddo
124  do n=1,nfiles
125  filenames(n) = trim(filename_head)//trim(filename_tails(n))
126  end do
127 
128  allocate(files(nfiles))
129  numtime = 0
130 
131 ! open input file(s)
132  do n = 1, nfiles
133  call mpp_open(files(n)%ncid, trim(filenames(n)), form=mpp_netcdf,action=mpp_rdonly,threading=mpp_multi, &
134  fileset=mpp_single )
135 ! call error_mesg ('read_climate_nudge_data_nlm_mod', 'Buffer size for reading = '//trim(string(read_buffer_size)), NOTE)
136 
137  call mpp_get_info(files(n)%ncid, files(n)%ndim, files(n)%nvar, files(n)%natt, files(n)%ntim)
138 
139  allocate (files(n)%length_axes(files(n)%ndim))
140  allocate (axes(files(n)%ndim))
141  call mpp_get_axes(files(n)%ncid,axes)
142 
143  ! inquire dimension sizes
144  do i = 1, files(n)%ndim
145  call mpp_get_atts(axes(i), name=name, len=files(n)%length_axes(i))
146  do j = 1, num_req_axes
147  if (trim(name) .eq. trim(required_axis_names(j))) then
148  call check_axis_size (j,files(n)%length_axes(i))
149  files(n)%axes(j) = axes(i)
150  files(n)%axis_index(j) = i
151  exit
152  endif
153  enddo
154  enddo
155  deallocate(axes)
156  ! time axis indexing
157  files(n)%time_offset = numtime
158  numtime = numtime + files(n)%ntim
159 
160  allocate(fields(files(n)%nvar))
161  call mpp_get_fields(files(n)%ncid,fields)
162  files(n)%field_index = 0
163  do i = 1, files(n)%nvar
164  call mpp_get_atts(fields(i), name=name, ndim=nd, siz=siz)
165  do j = 1, num_req_flds
166  if (trim(name) .eq. trim(required_field_names(j))) then
167  files(n)%field_index(j) = i
168  files(n)%fields(j) = fields(i)
169  if (j .gt. 3) then
170  call check_resolution (siz(1:nd))
171  endif
172  exit
173  endif
174  enddo
175 
176  ! special case for surface geopotential (sometimes the name is PHIS)
177  ! z1l: the following is not needed
178 ! ! rab: if not needed, should we remove?
179 ! if (trim(name) .eq. 'PHIS') then
180 ! Files(n)%field_index(INDEX_ZS) = i
181 ! call check_resolution (siz(1:nd))
182 ! endif
183  enddo
184  deallocate(fields)
185 
186  enddo ! "n" files loop
187 
188  ! setup file indexing
189  allocate(file_index(numtime))
190  i2 = 0
191  do n = 1, nfiles
192  i1 = i2+1
193  i2 = i2+files(n)%ntim
194  file_index(i1:i2) = n
195  enddo
196 
198 
199  ! output arguments
203  ntime = numtime
204 
205  module_is_initialized = .true.
206 
207 end subroutine read_climate_nudge_data_init
208 
209 !###############################################################################
210 
211 subroutine read_time ( times, units, calendar )
212 real(FVPRC), intent(out) :: times(:)
213 character(len=*), intent(out) :: units, calendar
214 integer :: istat, i1, i2, n
215 type(axistype), save:: time_axis
216 character(len=32) :: default_calendar
217 
218  if (.not.module_is_initialized) then
219  call error_mesg ('read_climate_nudge_data_nlm_mod/read_time', &
220  'module not initialized', fatal)
221  endif
222 
223  if (size(times(:)) < numtime) then
224  call error_mesg ('read_climate_nudge_data_nlm_mod', 'argument times too small in read_time', fatal)
225  endif
226 
227  ! data
228  i2 = 0
229  do n = 1, nfiles
230  i1 = i2+1
231  i2 = i2+files(n)%ntim
232  if( n == 1) then
233  default_calendar = mpp_get_default_calendar()
234  call mpp_get_time_axis( files(n)%ncid, time_axis)
235  call mpp_get_atts(time_axis, units=units, calendar=calendar)
236  if( trim(calendar) == trim(default_calendar)) calendar = 'gregorian '
237  endif
238  call mpp_get_times(files(n)%ncid, times(i1:i2))
239  enddo
240 
241 ! NOTE: need to do the conversion to time_type in this routine
242 ! this will allow different units and calendars for each file
243 
244 end subroutine read_time
245 
246 !###############################################################################
247 
248 subroutine read_grid ( lon, lat, ak, bk )
249 real(FVPRC), intent(out), dimension(:) :: lon, lat, ak, bk
250 
251  real(FVPRC) :: pref
252  integer :: istat
253 
254  if (.not.module_is_initialized) then
255  call error_mesg ('read_climate_nudge_data_nlm_mod/read_grid', &
256  'module not initialized', fatal)
257  endif
258 
259 
260  ! static fields from first file only
261  call mpp_get_axis_data(files(1)%axes(index_lon), lon)
262  call mpp_get_axis_data(files(1)%axes(index_lat), lat)
263 
264  ! units are assumed to be degrees east and north
265  ! convert to radians
266  lon = lon * pi/180.
267  lat = lat * pi/180.
268 
269  ! vertical coodinate
270  if (files(1)%field_index(index_ak) .gt. 0) then
271  call mpp_read(files(1)%ncid, files(1)%fields(index_ak), ak)
272  if (files(1)%field_index(index_p0) .gt. 0) then
273  call mpp_read(files(1)%ncid, files(1)%fields(index_p0), pref)
274  else
275  pref = p0
276  endif
277  ak = ak*pref
278  else
279  ak = 0.
280  endif
281 
282  call mpp_read(files(1)%ncid, files(1)%fields(index_bk), bk)
283 
284 
285 end subroutine read_grid
286 
287 !###############################################################################
288 
289 subroutine read_sub_domain_init ( ylo, yhi, ydat, js, je )
290  real(FVPRC), intent(in) :: ylo, yhi, ydat(:)
291  integer, intent(out) :: js, je
292  integer :: j
293 
294  if (.not.module_is_initialized) then
295  call error_mesg ('read_climate_nudge_data_nlm_mod/read_sub_domain_init', &
296  'module not initialized', fatal)
297  endif
298  ! increasing data
299  if (ydat(1) < ydat(2)) then
300  js = 1
301  do j = 1, size(ydat(:))-1
302  if (ylo >= ydat(j) .and. ylo <= ydat(j+1)) then
303  js = j
304  exit
305  endif
306  enddo
307 
308  if (ylo < -1.5) then
309  print *, 'ylo=',ylo
310  print *, 'js,ydat=',js,ydat(js)
311  print *, 'ydat=',ydat(:js+2)
312  endif
313 
314  je = size(ydat(:))
315  do j = js, size(ydat(:))-1
316  if (yhi >= ydat(j) .and. yhi <= ydat(j+1)) then
317  je = j+1
318  exit
319  endif
320  enddo
321 
322  if (yhi > 1.5) then
323  print *, 'yhi=',yhi
324  print *, 'je,ydat=',je,ydat(je)
325  print *, 'ydat=',ydat(je-2:)
326  endif
327 
328  ! decreasing data (may not work)
329  else
330  call error_mesg ('read_climate_nudge_data_nlm_mod', 'latitude values for observational data decrease with increasing index', note)
331  je = size(ydat(:))-1
332  do j = 1, size(ydat(:))-1
333  if (ylo >= ydat(j+1) .and. ylo <= ydat(j)) then
334  je = j+1
335  exit
336  endif
337  enddo
338 
339  js = 1
340  do j = 1, je
341  if (yhi >= ydat(j+1) .and. yhi <= ydat(j)) then
342  js = j
343  exit
344  endif
345  enddo
346 
347  endif
348 
349  sub_domain_latitude_size = je-js+1
350 
351  end subroutine read_sub_domain_init
352 
353 !###############################################################################
354 
355 subroutine read_climate_nudge_data_2d (itime, field, dat, is, js)
356 integer, intent(in) :: itime
357 character(len=4), intent(in) :: field
358 real(FVPRC), intent(out), dimension(:,:) :: dat
359 integer, intent(in), optional :: is, js
360 integer :: istat, atime, n, this_index
361 integer :: nread(4), start(4)
362 
363  if (.not.module_is_initialized) then
364  call error_mesg ('read_climate_nudge_data_nlm_mod', &
365  'module not initialized', fatal)
366  endif
367  ! time index check
368  if (itime < 1 .or. itime > numtime) then
369  call error_mesg ('read_climate_nudge_data_nlm_mod', 'itime out of range', fatal)
370  endif
371 
372  ! check dimensions
373  if (present(js)) then
374  if (size(dat,1) .ne. global_axis_size(index_lon) .or. &
375  size(dat,2) .ne. sub_domain_latitude_size) then
376  !write (*,'(a)') 'climate_nudge_data_mod: size dat2d = '//trim(string(size(dat,1)))//' x '//trim(string(size(dat,2)))// &
377  ! ' <-vs-> '//trim(string(global_axis_size(INDEX_LON)))//' x '//trim(string(sub_domain_latitude_size))
378  call error_mesg ('read_climate_nudge_data_nlm_mod', 'incorrect 2d array dimensions', fatal)
379  endif
380  else
381  if (size(dat,1) .ne. global_axis_size(index_lon) .or. &
382  size(dat,2) .ne. global_axis_size(index_lat)) &
383  call error_mesg ('read_climate_nudge_data_nlm_mod', 'incorrect 2d array dimensions', fatal)
384  endif
385 
386  ! check field
387  if (field .eq. 'phis') then
388  this_index = index_zs
389  else if (field .eq. 'psrf') then
390  this_index = index_ps
391  else
392  call error_mesg ('read_climate_nudge_data_nlm_mod', 'incorrect field requested in read_climate_nudge_data_2d', fatal)
393  endif
394 
395  ! file index and actual time index in file
396  n = file_index(itime)
397  atime = itime - files(n)%time_offset
398 
399  start = 1
400  if (present(is)) start(1) = is
401  if (present(js)) start(2) = js
402  start(3) = atime
403 
404  nread = 1
405  nread(1) = size(dat,1)
406  nread(2) = size(dat,2)
407 
408  call mpp_read(files(n)%ncid, files(n)%fields(this_index), dat, start, nread)
409 
410  ! geopotential height (convert to m2/s2 if necessary)
411  if (field .eq. 'phis') then
412  if (maxval(dat) > 1000.*grav) then
413  ! do nothing
414  else
415  dat = dat * grav
416  endif
417  endif
418 
419 end subroutine read_climate_nudge_data_2d
420 
421 !###############################################################################
422 
423 subroutine read_climate_nudge_data_3d (itime, field, dat, is, js)
424 integer, intent(in) :: itime
425 character(len=4), intent(in) :: field
426 real(FVPRC), intent(out), dimension(:,:,:) :: dat
427 integer, intent(in), optional :: is, js
428 integer :: istat, atime, n, this_index, start(4), nread(4)
429 !logical :: convert_virt_temp = .false.
430 
431  if (.not.module_is_initialized) then
432  call error_mesg ('read_climate_nudge_data_nlm_mod', &
433  'module not initialized', fatal)
434  endif
435 
436  ! time index check
437  if (itime < 1 .or. itime > numtime) then
438  call error_mesg ('read_climate_nudge_data_nlm_mod', 'itime out of range', fatal)
439  endif
440 
441  ! check dimensions
442  if (present(js)) then
443  if (size(dat,1) .ne. global_axis_size(index_lon) .or. &
444  size(dat,2) .ne. sub_domain_latitude_size .or. &
445  size(dat,3) .ne. global_axis_size(index_lev)) then
446  !write (*,'(a)') 'climate_nudge_data_mod: size dat3d = '//trim(string(size(dat,1)))//' x '//trim(string(size(dat,2)))// &
447  ! ' x '//trim(string(size(dat,3)))
448  call error_mesg ('read_climate_nudge_data_nlm_mod', 'incorrect 3d array dimensions', fatal)
449  endif
450  else
451  if (size(dat,1) .ne. global_axis_size(index_lon) .or. &
452  size(dat,2) .ne. global_axis_size(index_lat) .or. &
453  size(dat,3) .ne. global_axis_size(index_lev)) &
454  call error_mesg ('read_climate_nudge_mod', 'incorrect 3d array dimensions', fatal)
455  endif
456 
457  ! check field
458  if (field .eq. 'temp') then
459  this_index = index_t
460  else if (field .eq. 'qhum') then
461  this_index = index_q
462  else if (field .eq. 'uwnd') then
463  this_index = index_u
464  else if (field .eq. 'vwnd') then
465  this_index = index_v
466  else
467  call error_mesg ('read_climate_nudge_data_nlm_mod', 'incorrect field requested in read_climate_nudge_data_3d', fatal)
468  endif
469 
470 
471  ! file index and actual time index in file
472  n = file_index(itime)
473  atime = itime - files(n)%time_offset
474 
475  start = 1
476  if (present(is)) start(1) = is
477  if (present(js)) start(2) = js
478  start(4) = atime
479 
480  nread = 1
481  nread(1) = size(dat,1)
482  nread(2) = size(dat,2)
483  nread(3) = size(dat,3)
484 
485  call mpp_read(files(n)%ncid, files(n)%fields(this_index), dat, start, nread)
486 
487  ! convert virtual temp to temp
488  ! necessary for some of the high resol AVN analyses
489  !if (convert_virt_temp) then
490  ! temp = temp/(1.+D608*qhum)
491  !endif
492 
493 end subroutine read_climate_nudge_data_3d
494 
495 !###############################################################################
496 
498 integer :: istat, n
499 
500  if ( .not.module_is_initialized) return
501  do n = 1, nfiles
502  call mpp_close(files(n)%ncid)
503  enddo
504  deallocate (files)
505  module_is_initialized = .false.
506 
507 end subroutine read_climate_nudge_data_end
508 
509 !###############################################################################
510 
511  subroutine check_axis_size (ind,lendim)
512  integer, intent(in) :: ind,lendim
513 
514  ! once the axis size is set all subsuquent axes must be the same
515  if (global_axis_size(ind) .gt. 0) then
516  if (global_axis_size(ind) .ne. lendim) then
517  call error_mesg ('read_climate_nudge_data_nlm_mod', 'incorrect axis size for axis = '//trim(required_axis_names(ind)), fatal)
518  endif
519  else
520  global_axis_size(ind) = lendim
521  endif
522 
523  end subroutine check_axis_size
524 
525 !------------------------------------
526 
527  subroutine check_resolution (axis_len)
528  integer, intent(in) :: axis_len(:)
529 
530  if (size(axis_len(:)) .lt. 2) then
531  call error_mesg ('read_climate_nudge_data_nlm_mod', 'incorrect number of array dimensions', fatal)
532  endif
533  if (axis_len(1) .ne. global_axis_size(index_lon)) then
534  call error_mesg ('read_climate_nudge_data_nlm_mod', 'incorrect array dimension one', fatal)
535  endif
536  if (axis_len(2) .ne. global_axis_size(index_lat)) then
537  call error_mesg ('read_climate_nudge_data_nlm_mod', 'incorrect array dimension two', fatal)
538  endif
539  if (size(axis_len(:)) .gt. 3) then
540  if (axis_len(3) .ne. global_axis_size(index_lev)) then
541  call error_mesg ('read_climate_nudge_data_nlm_mod', 'incorrect array dimension three', fatal)
542  endif
543  endif
544 
545  end subroutine check_resolution
546 
547 !###############################################################################
548 
550 
Definition: fms.F90:20
integer, parameter real8
type(filedata_type), dimension(:), allocatable files
real, parameter, public rdgas
Gas constant for dry air [J/kg/deg].
Definition: constants.F90:77
character(len=256), dimension(maxfiles) filenames
integer, parameter real4
Definition: mpp.F90:39
integer function, public check_nml_error(IOSTAT, NML_NAME)
Definition: fms.F90:658
character(len=256), dimension(maxfiles) filename_tails
character(len=input_str_length), dimension(:), allocatable, target, public input_nml_file
Definition: mpp.F90:1378
subroutine read_climate_nudge_data_2d(itime, field, dat, is, js)
real, parameter, public rvgas
Gas constant for water vapor [J/kg/deg].
Definition: constants.F90:78
subroutine read_climate_nudge_data_3d(itime, field, dat, is, js)
real, parameter, public grav
Acceleration due to gravity [m/s^2].
Definition: constants.F90:76
subroutine, public read_grid(lon, lat, ak, bk)
integer, dimension(num_req_axes) global_axis_size
integer, dimension(:), allocatable file_index
character(len=8), dimension(num_req_flds) required_field_names
subroutine, public read_sub_domain_init(ylo, yhi, ydat, js, je)
subroutine, public read_time(times, units, calendar)
character(len=8), dimension(num_req_axes) required_axis_names
subroutine, public error_mesg(routine, message, level)
Definition: fms.F90:529
integer, parameter fvprc
subroutine, public read_climate_nudge_data_init(nlon, nlat, nlev, ntime)
real(fp), parameter, public pi