FV3 Bundle
nc_diag_read_mod.F90
Go to the documentation of this file.
2  use ncd_kinds, only: i_long
9  use ncdr_climsg, only: ncdr_error
11  use netcdf, only: nf90_open, nf90_close, nf90_inquire, &
12  nf90_inq_libvers, nf90_nowrite
13 
14  !------------------------------------------------------------------
15  ! API imports to expose API from this module
16  !------------------------------------------------------------------
17  use ncdr_alloc_assert, only: &
22 
23  use ncdr_attrs, only: &
29 
30  use ncdr_attrs_fetch, only: &
34 
35  use ncdr_dims, only: &
43 
44  use ncdr_global_attrs, only: &
50 
51  use ncdr_global_attrs_fetch, only: &
55 
56  use ncdr_vars, only: &
65 
67 
68  implicit none
69 
70 #define INITIAL_SIZE 1024
71 #define NCDR_MULTI_BASE 1
72 
73  contains
74  ! NCID = NetCDF ID
75  ! NCDR_ID = NetCDF Diag Reader ID (relative indexing)
76 
77  ! NCID = NetCDF ID
78  ! NCDR_ID = NetCDF Diag Reader ID (relative indexing)
79 
80  ! Parses a given file for metadata, dimensions, and variables.
81  !
82  ! Given the NetCDF file name and its NCID, create an entry in
83  ! the internal nc_diag_read file table and populate it with
84  ! file information and variable/dimension structure.
85  !
86  ! This subroutine is meant to be called internally by
87  ! nc_diag_read_id_init, and is NOT meant for calling from
88  ! anywhere else.
89  !
90  ! Args:
91  ! filename (character(len=*): NetCDF file name to store in
92  ! internal file table.
93  ! file_ncid (integer(i_long)): the corresponding NetCDF ID
94  ! (NCID) of the opened NetCDF file to store in the
95  ! internal file table and use for file reading.
96  ! file_ncdr_id (integer(i_long)): internal nc_diag_read ID
97  ! for use in other subroutines and functions. This is
98  ! essentially the index of the internal file table that
99  ! nc_diag_read uses for referencing the specified file.
100  !
101  ! Returns:
102  ! file_ncdr_id (integer(i_long)): internal nc_diag_read ID
103  ! for use in other subroutines and functions. This is
104  ! essentially the index of the internal file table that
105  ! nc_diag_read uses for referencing the specified file.
106  !
107  subroutine nc_diag_read_parse_file(filename, file_ncid, file_ncdr_id)
108  character(len=*),intent(in) :: filename
109  integer(i_long), intent(in) :: file_ncid
110  integer(i_long), intent(out) :: file_ncdr_id
111 
112  integer(i_long) :: input_ndims
113  integer(i_long) :: input_nvars
114  integer(i_long) :: input_nattrs
115 
117 
118  if (allocated(ncdr_files)) then
119  if (ncdr_file_count > ncdr_file_total) then
120  call ncdr_realloc(ncdr_files, ncdr_file_total * ncdr_multi_base)
121  end if
122  else
123  allocate(ncdr_files(ncdr_default_ent))
124  end if
125 
126  ncdr_files(ncdr_file_count)%filename = filename
127  ncdr_files(ncdr_file_count)%ncid = file_ncid
128 
129  ! Get top level info about the file!
130  call ncdr_nc_check(nf90_inquire(file_ncid, ndimensions = input_ndims, &
131  nvariables = input_nvars, nattributes = input_nattrs))
132 
133  call nc_diag_read_parse_file_dims(file_ncid, ncdr_file_count, input_ndims)
134  call nc_diag_read_parse_file_vars(file_ncid, ncdr_file_count, input_nvars)
135 
136  ! Make sure file is now open!
137  ncdr_files(ncdr_file_count)%file_open = .true.
138 
139  ! Update highest record - this will let us keep track and
140  ! help us clear memory when we can!
143  end if
144 
145  ! Set the NCDR ID - relative index!
146  file_ncdr_id = ncdr_file_count
147  end subroutine nc_diag_read_parse_file
148 
149  ! Opens a given file for reading.
150  !
151  ! Given the NetCDF file name, open the file and set everything
152  ! up for reading the file.
153  !
154  ! Args:
155  ! filename (character(len=*): NetCDF file name to store in
156  ! internal file table.
157  !
158  ! Returns:
159  ! file_ncdr_id (integer(i_long)): internal nc_diag_read ID
160  ! for use in other subroutines and functions.
161  !
162  function nc_diag_read_id_init(filename) result(file_ncdr_id)
163  character(len=*),intent(in) :: filename
164  integer(i_long) :: file_ncid
165  integer(i_long) :: file_ncdr_id
166 
167  if (nc_diag_read_get_index_from_filename(filename) /= -1) &
168  call ncdr_error("Can't open the same file more than once! (Opening, closing, and then opening again is allowed.)")
169 
170  call ncdr_nc_check( nf90_open(filename, nf90_nowrite, file_ncid) )
171 
172  call nc_diag_read_parse_file(filename, file_ncid, file_ncdr_id)
173  end function nc_diag_read_id_init
174 
175  subroutine nc_diag_read_init(filename, file_ncdr_id, from_push)
176  character(len=*),intent(in) :: filename
177  integer(i_long), intent(out), optional :: file_ncdr_id
178  logical, intent(in), optional :: from_push
179  integer(i_long) :: f_ncdr_id
180 
181  if (ncdr_id_stack_count > 0) then
182  if (.NOT. (present(from_push) .AND. (from_push))) &
183  call ncdr_error("Can not initialize due to push/pop queue use! If you want to init without the stack, you must use nc_diag_read_id_init or clear the queue first!")
184  end if
185 
186  f_ncdr_id = nc_diag_read_id_init(filename)
187 
188  if (present(file_ncdr_id)) &
189  file_ncdr_id = f_ncdr_id
190 
191  ! Set current ncid
192  current_ncdr_id = f_ncdr_id
193  end subroutine nc_diag_read_init
194 
195  subroutine nc_diag_read_push(filename, file_ncdr_id)
196  character(len=*),intent(in) :: filename
197  integer(i_long), intent(out), optional :: file_ncdr_id
198 
199  if ((ncdr_id_stack_count == 0) .AND. (current_ncdr_id /= -1)) &
200  call ncdr_error("Can not initialize due to normal caching use! If you want to init with the stack, you must close the cached file first, then use nc_diag_read_push()!")
201 
203 
204  if (allocated(ncdr_id_stack)) then
208  end if
209  else
210  allocate(ncdr_id_stack(initial_size))
212  end if
213 
214  if (present(file_ncdr_id)) then
215  call nc_diag_read_init(filename, file_ncdr_id, .true.)
216  else
217  call nc_diag_read_init(filename, from_push = .true.)
218  end if
219 
220  ! Push new NCID to stack
222  end subroutine nc_diag_read_push
223 
224  subroutine nc_diag_read_close(filename, file_ncdr_id, from_pop)
225  character(len=*),intent(in), optional :: filename
226  integer(i_long), intent(in), optional :: file_ncdr_id
227  logical, intent(in), optional :: from_pop
228 
229  integer(i_long) :: f_ncdr_id, f_ncid, i
230  logical :: range_closed
231 
232  f_ncid = -1
233 
234  if (ncdr_file_count == 0) &
235  call ncdr_error("No files are currently open!")
236 
237  if (ncdr_id_stack_count > 0) then
238  if ((any(ncdr_id_stack == file_ncdr_id)) .AND. (.NOT. (present(from_pop) .AND. (from_pop)))) &
239  call ncdr_error("Can not close due to push/pop queue use! If you want to use this without the stack, you must use nc_diag_read_id_init or clear the queue first!")
240  end if
241 
242  if (present(filename)) then
243  f_ncdr_id = nc_diag_read_get_index_from_filename(filename)
244 
245  if (f_ncdr_id == -1) &
246  call ncdr_error("The NetCDF file specified, " // filename // ", is not open and can't be closed.")
247  else if (present(file_ncdr_id)) then
248  ! Do... nothing. Just store the ncid.
249  f_ncdr_id = file_ncdr_id
250  else
251  ! Try to see if current_ncid is defined
252  if (current_ncdr_id == -1) &
253  call ncdr_error("No arguments specified for closing a file! (Also, no current NCIDs were found!)")
254  f_ncdr_id = current_ncdr_id
255  end if
256 
257  ! Sanity check
258  call ncdr_check_ncdr_id(f_ncdr_id)
259 
260  ! Fetch NCID
261  f_ncid = ncdr_files(f_ncdr_id)%ncid
262 
263  ! Sanity check for the NCID...
264  call ncdr_check_ncid(f_ncid)
265 
266  ! Close it!
267  call ncdr_nc_check(nf90_close(f_ncid))
268 
269  ! Deactivate entry...
270  ncdr_files(f_ncdr_id)%file_open = .false.
271 
272  ! Deallocate as much as possible!
273  deallocate(ncdr_files(f_ncdr_id)%dims)
274  deallocate(ncdr_files(f_ncdr_id)%vars)
275 
276  ! Set current_ncid to -1, as necessary:
277  if (current_ncdr_id == f_ncdr_id) then
278  current_ncdr_id = -1
279  end if
280 
281  ! Update highest record - this will let us keep track and
282  ! help us clear memory when we can!
283  range_closed = .true.
284 
285  if (f_ncdr_id < ncdr_file_highest) then
286  do i = f_ncdr_id, ncdr_file_highest
287  if (ncdr_files(i)%file_open) then
288  range_closed = .false.
289  exit
290  end if
291  end do
292 
293  if (range_closed) then
294  ncdr_file_highest = f_ncdr_id
295  ncdr_file_count = f_ncdr_id
296  end if
297  else if (f_ncdr_id == ncdr_file_highest) then
298  ncdr_file_highest = f_ncdr_id - 1
299  ncdr_file_count = f_ncdr_id - 1
300 
301  do i = 1, ncdr_file_highest
302  if (ncdr_files(i)%file_open) then
303  range_closed = .false.
304  exit
305  end if
306  end do
307 
308  if (range_closed) then
310  ncdr_file_count = 0
311  end if
312  end if
313  end subroutine nc_diag_read_close
314 
315  ! Pop - we return the thing we just deleted, and push things up!
316  subroutine nc_diag_read_pop(filename, file_ncdr_id)
317  character(len=*),intent(out), optional :: filename
318  integer(i_long), intent(out), optional :: file_ncdr_id
319 
320  if (ncdr_id_stack_count == 0) &
321  call ncdr_error("No NetCDF files to pop!")
322 
324  call ncdr_error("BUG - current NCID differs from the current queued NCID!")
325 
326  if (present(filename)) then
327  filename = ncdr_files(ncdr_id_stack(ncdr_id_stack_count))%filename
328  end if
329 
330  if (present(file_ncdr_id)) then
331  file_ncdr_id = ncdr_id_stack(ncdr_id_stack_count)
332  end if
333 
334  ! Close the file
335  call nc_diag_read_close(file_ncdr_id = ncdr_id_stack(ncdr_id_stack_count), from_pop = .true.)
336 
337  ! Set the stack spot to -1...
339 
340  ! ...and decrease the count, effectively "popping" it!
342 
343  ! If everything is gone, set current to -1.
344  if (ncdr_id_stack_count /= 0) then
346  else
347  current_ncdr_id = -1
348  end if
349  end subroutine nc_diag_read_pop
350 
351  ! Get current file in queue
352  subroutine nc_diag_read_get_current_queue(filename, file_ncdr_id)
353  character(len=*),intent(out), optional :: filename
354  integer(i_long), intent(out), optional :: file_ncdr_id
355 
356  if (present(filename)) then
357  if (ncdr_id_stack_count > 0) then
358  filename = ncdr_files(ncdr_id_stack(ncdr_id_stack_count))%filename
359  else
360  filename = "(no file in queue at the moment)"
361  end if
362  end if
363 
364  if (present(file_ncdr_id)) then
365  if (ncdr_id_stack_count > 0) then
366  file_ncdr_id = ncdr_id_stack(ncdr_id_stack_count)
367  else
368  file_ncdr_id = -1
369  end if
370  end if
371  end subroutine nc_diag_read_get_current_queue
372 
373  ! Get current file, disregarding queue
374  subroutine nc_diag_read_get_current(filename, file_ncdr_id)
375  character(len=*),intent(out), optional :: filename
376  integer(i_long), intent(out), optional :: file_ncdr_id
377 
378  if (present(filename)) then
379  if (current_ncdr_id /= -1) then
380  filename = ncdr_files(current_ncdr_id)%filename
381  else
382  filename = "(no file open at the moment)"
383  end if
384  end if
385 
386  if (present(file_ncdr_id)) then
387  if (current_ncdr_id /= -1) then
388  file_ncdr_id = current_ncdr_id
389  else
390  file_ncdr_id = -1
391  end if
392  end if
393  end subroutine nc_diag_read_get_current
394 end module nc_diag_read_mod
subroutine nc_diag_read_id_get_attr_1d_string(file_ncdr_id, var_name, attr_name, attr_stor)
character(len=:) function, allocatable nc_diag_read_get_type_str(var_type)
integer(i_long) function nc_diag_read_id_init(filename)
integer, parameter, public i_long
Definition: ncd_kinds.F90:47
subroutine nc_diag_read_parse_file_vars(file_ncid, file_index, num_vars)
Definition: ncdr_vars.f90:52
subroutine ncdr_nc_check(status)
Definition: ncdr_check.f90:85
integer(i_long) current_ncdr_id
Definition: ncdr_state.f90:7
type(ncdr_file), dimension(:), allocatable ncdr_files
Definition: ncdr_state.f90:14
subroutine ncdr_check_ncid(file_ncid)
Definition: ncdr_check.f90:28
subroutine nc_diag_read_noid_get_global_attr_1d_string(attr_name, attr_stor)
subroutine nc_diag_read_parse_file(filename, file_ncid, file_ncdr_id)
integer(i_long) ncdr_file_highest
Definition: ncdr_state.f90:17
integer(i_short), parameter ncdr_default_ent
Definition: ncdr_state.f90:20
subroutine nc_diag_read_push(filename, file_ncdr_id)
subroutine ncdr_check_ncdr_id(file_ncdr_id)
Definition: ncdr_check.f90:12
integer(i_long) ncdr_file_total
Definition: ncdr_state.f90:16
subroutine nc_diag_read_parse_file_dims(file_ncid, file_index, num_dims)
Definition: ncdr_dims.f90:47
integer(i_long) function nc_diag_read_get_index_from_filename(file_name)
Definition: ncdr_check.f90:66
subroutine nc_diag_read_close(filename, file_ncdr_id, from_pop)
integer(i_long) ncdr_file_count
Definition: ncdr_state.f90:15
subroutine nc_diag_read_get_current(filename, file_ncdr_id)
subroutine nc_diag_read_id_get_global_attr_1d_string(file_ncdr_id, attr_name, attr_stor)
subroutine ncdr_error(err)
Definition: ncdr_climsg.F90:13
subroutine nc_diag_read_get_current_queue(filename, file_ncdr_id)
subroutine nc_diag_read_noid_get_attr_1d_string(var_name, attr_name, attr_stor)
integer(i_long), dimension(:), allocatable ncdr_id_stack
Definition: ncdr_state.f90:8
integer(i_long) ncdr_id_stack_count
Definition: ncdr_state.f90:9
subroutine nc_diag_read_init(filename, file_ncdr_id, from_push)
integer(i_long) ncdr_id_stack_size
Definition: ncdr_state.f90:9
subroutine nc_diag_read_pop(filename, file_ncdr_id)