FV3 Bundle
ncdf_path_m.f90
Go to the documentation of this file.
1 ! Copyright (c) 2012 Joseph A. Levin
2 !
3 ! Permission is hereby granted, free of charge, to any person obtaining a copy of this
4 ! software and associated documentation files (the "Software"), to deal in the Software
5 ! without restriction, including without limitation the rights to use, copy, modify, merge,
6 ! publish, distribute, sublicense, and/or sell copies of the Software, and to permit
7 ! persons to whom the Software is furnished to do so, subject to the following conditions:
8 !
9 ! The above copyright notice and this permission notice shall be included in all copies or
10 ! substantial portions of the Software.
11 !
12 ! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13 ! INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 ! PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
15 ! LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
16 ! OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17 ! DEALINGS IN THE SOFTWARE.
18 
19 !
20 ! File: ncdf_path_m.f95
21 ! Author: Joseph A. Levin
22 !
23 ! Created on March 10, 2012, 11:01 PM
24 !
25 
27 
28  use ncdf_value_m
29  use ncdf_string_m
30 
31  private
32 
33  public :: ncdf_path_get
34 
35  interface ncdf_path_get
36  module procedure ncdf_get_by_path
37  module procedure ncdf_get_integer
38  module procedure ncdf_get_real
39  module procedure ncdf_get_double
40  module procedure ncdf_get_logical
41  module procedure ncdf_get_chars
42  module procedure ncdf_get_array_1d_integer
43  module procedure ncdf_get_array_2d_integer
44  module procedure ncdf_get_array_1d_real
45  module procedure ncdf_get_array_2d_real
46  module procedure ncdf_get_array_1d_double
47  module procedure ncdf_get_array_2d_double
48  module procedure ncdf_get_array_1d_logical
49  module procedure ncdf_get_array_2d_logical
50  end interface ncdf_path_get
51 
52  abstract interface
53 
54  subroutine ncdf_array_callback_1d(element, i, count)
56  implicit none
57  type(ncdf_value), pointer,intent(in) :: element
58  integer, intent(in) :: i ! index
59  integer, intent(in) :: count ! size of array
60  end subroutine ncdf_array_callback_1d
61 
62  subroutine ncdf_array_callback_2d(element, i1, i2, count1, count2)
64  implicit none
65  type(ncdf_value), pointer,intent(in) :: element
66  integer, intent(in) :: i1, i2
67  integer, intent(in) :: count1, count2
68  end subroutine ncdf_array_callback_2d
69 
70  end interface
71 
72 contains
73  !
74  ! GET BY PATH
75  !
76  ! $ = root
77  ! @ = this
78  ! . = child object member
79  ! [] = child array element
80  !
81  recursive subroutine ncdf_get_by_path(this, path, p)
82  type(ncdf_value), pointer :: this, p
83  character(len=*) :: path
84  integer :: i, length, child_i
85  character :: c
86  logical :: array
87 
88  ! default to assuming relative to this
89  p => this
90 
91  child_i = 1
92 
93  array = .false.
94 
95  length = len_trim(path)
96 
97  do i=1, length
98  c = path(i:i)
99  select case (c)
100  case ("$")
101  ! root
102  do while (associated (p % parent))
103  p => p % parent
104  end do
105  child_i = i + 1
106  case ("@")
107  ! this
108  p => this
109  child_i = i + 1
110  case (".", "[")
111  ! get child member from p
112  if (child_i < i) then
113  p => ncdf_value_get(p, path(child_i:i-1))
114  else
115  child_i = i + 1
116  cycle
117  end if
118 
119  if(.not.associated(p)) then
120  return
121  end if
122 
123  child_i = i+1
124 
125  ! check if this is an array
126  ! if so set the array flag
127  if (c == "[") then
128  ! start looking for the array element index
129  array = .true.
130  end if
131  case ("]")
132  if (.not.array) then
133  print *, "ERROR: Unexpected ], not missing preceding ["
134  call exit(1)
135  end if
136  array = .false.
137  child_i = parse_integer(path(child_i:i-1))
138  p => ncdf_value_get(p, child_i)
139 
140  child_i= i + 1
141  end select
142  end do
143 
144  ! grab the last child if present in the path
145  if (child_i <= length) then
146  p => ncdf_value_get(p, path(child_i:i-1))
147  if(.not.associated(p)) then
148  return
149  else
150  end if
151  end if
152 
153 
154  end subroutine ncdf_get_by_path
155 
156  !
157  ! PARSE INTEGER
158  !
159  integer function parse_integer(chars) result(integral)
160  character(len=*) :: chars
161  character :: c
162  integer :: tmp, i
163 
164  integral = 0
165  do i=1, len_trim(chars)
166  c = chars(i:i)
167  select case(c)
168  case ("0":"9")
169  ! digit
170  read (c, '(i1)') tmp
171 
172  ! shift
173  if(i > 1) then
174  integral = integral * 10
175  end if
176  ! add
177  integral = integral + tmp
178 
179  case default
180  return
181  end select
182  end do
183 
184  end function parse_integer
185 
186  !
187  ! GET INTEGER
188  !
189  subroutine ncdf_get_integer(this, path, value)
190  type(ncdf_value), pointer :: this, p
191  character(len=*), optional :: path
192  integer :: value
193 
194 
195  nullify(p)
196  if(present(path)) then
197  call ncdf_get_by_path(this=this, path=path, p=p)
198  else
199  p => this
200  end if
201 
202  if(.not.associated(p)) then
203  print *, "Unable to resolve path: ", path
204  return
205  end if
206 
207 
208  if(p % value_type == type_integer) then
209  value = p % value_integer
210  else if (p % value_type == type_real) then
211  value = p % value_real
212  else if (p % value_type == type_logical) then
213  if (p % value_logical) then
214  value = 1
215  else
216  value = 0
217  end if
218  else
219  print *, "Unable to resolve value to integer: ", path
220  call exit(1)
221  end if
222 
223  end subroutine ncdf_get_integer
224 
225  !
226  ! GET REAL
227  !
228  subroutine ncdf_get_real(this, path, value)
229  type(ncdf_value), pointer :: this, p
230  character(len=*), optional :: path
231  real :: value
232 
233 
234  nullify(p)
235 
236  if(present(path)) then
237  call ncdf_get_by_path(this=this, path=path, p=p)
238  else
239  p => this
240  end if
241 
242  if(.not.associated(p)) then
243  print *, "Unable to resolve path: ", path
244  return
245  end if
246 
247 
248  if(p % value_type == type_integer) then
249  value = p % value_integer
250  else if (p % value_type == type_real) then
251  value = p % value_real
252  else if (p % value_type == type_logical) then
253  if (p % value_logical) then
254  value = 1
255  else
256  value = 0
257  end if
258  else
259  print *, "Unable to resolve value to real: ", path
260  call exit(1)
261  end if
262 
263  end subroutine ncdf_get_real
264 
265  !
266  ! GET DOUBLE
267  !
268  subroutine ncdf_get_double(this, path, value)
269  type(ncdf_value), pointer :: this, p
270  character(len=*), optional :: path
271  double precision :: value
272 
273 
274  nullify(p)
275 
276  if(present(path)) then
277  call ncdf_get_by_path(this=this, path=path, p=p)
278  else
279  p => this
280  end if
281 
282  if(.not.associated(p)) then
283  print *, "Unable to resolve path: ", path
284  return
285  end if
286 
287 
288  if(p % value_type == type_integer) then
289  value = p % value_integer
290  else if (p % value_type == type_real) then
291  value = p % value_double
292  else if (p % value_type == type_logical) then
293  if (p % value_logical) then
294  value = 1
295  else
296  value = 0
297  end if
298  else
299  print *, "Unable to resolve value to double: ", path
300  call exit(1)
301  end if
302 
303  end subroutine ncdf_get_double
304 
305 
306  !
307  ! GET LOGICAL
308  !
309  subroutine ncdf_get_logical(this, path, value)
310  type(ncdf_value), pointer :: this, p
311  character(len=*), optional :: path
312  logical :: value
313 
314 
315  nullify(p)
316 
317  if(present(path)) then
318  call ncdf_get_by_path(this=this, path=path, p=p)
319  else
320  p => this
321  end if
322 
323  if(.not.associated(p)) then
324  print *, "Unable to resolve path: ", path
325  return
326  end if
327 
328 
329  if(p % value_type == type_integer) then
330  value = (p % value_integer > 0)
331  else if (p % value_type == type_logical) then
332  value = p % value_logical
333  else
334  print *, "Unable to resolve value to real: ", path
335  call exit(1)
336  end if
337 
338  end subroutine ncdf_get_logical
339 
340  !
341  ! GET CHARS
342  !
343  subroutine ncdf_get_chars(this, path, value)
344  type(ncdf_value), pointer :: this, p
345  character(len=*), optional :: path
346  character(len=*) :: value
347 
348  nullify(p)
349 
350  if(present(path)) then
351  call ncdf_get_by_path(this=this, path=path, p=p)
352  else
353  p => this
354  end if
355 
356  if(.not.associated(p)) then
357  print *, "Unable to resolve path: ", path
358  return
359  end if
360 
361 
362  if(p % value_type == type_string) then
363  call ncdf_string_copy(p % value_string, value)
364  else
365  print *, "Unable to resolve value to characters: ", path
366  call exit(1)
367  end if
368 
369  end subroutine ncdf_get_chars
370 
371  !
372  ! GET ARRAY 1D
373  !
374 
375  subroutine ncdf_get_array_1d(this, path, array_callback)
376  type(ncdf_value), pointer :: this
377  character(len = *), optional :: path
378  procedure(ncdf_array_callback_1d) :: array_callback
379 
380  type(ncdf_value), pointer :: p, element
381  integer :: index, count
382 
383  nullify(p)
384 
385  ! resolve the path to the value
386  if(present(path)) then
387  call ncdf_get_by_path(this=this, path=path, p=p)
388  else
389  p => this
390  end if
391 
392  if(.not.associated(p)) then
393  print *, "Unable to resolve path: ", path
394  return
395  end if
396 
397  if(p % value_type == type_array) then
398  count = ncdf_value_count(p)
399  element => p % children
400  do index = 1, count
401  call array_callback(element, index, count)
402  element => element % next
403  end do
404  else
405  print *, "Resolved value is not an array. ", path
406  call exit(1)
407  end if
408 
409  if (associated(p)) nullify(p)
410 
411  end subroutine ncdf_get_array_1d
412 
413 !
414 ! GET ARRAY INTEGER 1D
415 !
416  subroutine ncdf_get_array_1d_integer(this, path, arr)
418  implicit none
419  type(ncdf_value), pointer, intent(in) :: this
420  character(len=*), intent(in), optional :: path
421  integer, allocatable, intent(out) :: arr(:)
422 
423  if (allocated(arr)) deallocate(arr)
425 
426  contains
427 
428  subroutine ncdf_array_callback_1d_integer(element, i, count)
429  implicit none
430  type(ncdf_value), pointer, intent(in) :: element
431  integer, intent(in) :: i, count
432  if (.not. allocated(arr)) allocate(arr(count))
433  call ncdf_path_get(element, "", arr(i))
434  end subroutine ncdf_array_callback_1d_integer
435 
436  end subroutine ncdf_get_array_1d_integer
437 
438 !
439 ! GET ARRAY REAL 1D
440 !
441  subroutine ncdf_get_array_1d_real(this, path, arr)
443  implicit none
444  type(ncdf_value), pointer, intent(in) :: this
445  character(len=*), intent(in), optional :: path
446  real, allocatable, intent(out) :: arr(:)
447 
448  if (allocated(arr)) deallocate(arr)
450 
451  contains
452 
453  subroutine ncdf_array_callback_1d_real(element, i, count)
454  implicit none
455  type(ncdf_value), pointer, intent(in) :: element
456  integer, intent(in) :: i, count
457  if (.not. allocated(arr)) allocate(arr(count))
458  call ncdf_path_get(element, "", arr(i))
459  end subroutine ncdf_array_callback_1d_real
460 
461  end subroutine ncdf_get_array_1d_real
462 
463 !
464 ! GET ARRAY DOUBLE 1D
465 !
466  subroutine ncdf_get_array_1d_double(this, path, arr)
468  implicit none
469  type(ncdf_value), pointer, intent(in) :: this
470  character(len=*), intent(in), optional :: path
471  double precision, allocatable, intent(out) :: arr(:)
472 
473  if (allocated(arr)) deallocate(arr)
475 
476  contains
477 
478  subroutine ncdf_array_callback_1d_double(element, i, count)
479  implicit none
480  type(ncdf_value), pointer, intent(in) :: element
481  integer, intent(in) :: i, count
482  if (.not. allocated(arr)) allocate(arr(count))
483  call ncdf_path_get(element, "", arr(i))
484  end subroutine ncdf_array_callback_1d_double
485 
486  end subroutine ncdf_get_array_1d_double
487 
488 !
489 ! GET ARRAY LOGICAL 1D
490 !
491  subroutine ncdf_get_array_1d_logical(this, path, arr)
493  implicit none
494  type(ncdf_value), pointer, intent(in) :: this
495  character(len=*), intent(in), optional :: path
496  logical, allocatable, intent(out) :: arr(:)
497 
498  if (allocated(arr)) deallocate(arr)
500 
501  contains
502 
503  subroutine ncdf_array_callback_1d_logical(element, i, count)
504  implicit none
505  type(ncdf_value), pointer, intent(in) :: element
506  integer, intent(in) :: i, count
507  if (.not. allocated(arr)) allocate(arr(count))
508  call ncdf_path_get(element, "", arr(i))
509  end subroutine ncdf_array_callback_1d_logical
510 
511  end subroutine ncdf_get_array_1d_logical
512 
513  !
514  ! GET ARRAY 2D
515  !
516 
517  subroutine ncdf_get_array_2d(this, path, array_callback)
518  type(ncdf_value), pointer :: this
519  character(len = *), optional :: path
520  procedure(ncdf_array_callback_2d) :: array_callback
521 
522  type(ncdf_value), pointer :: p, element, item
523  integer :: i1, i2, count1, count2, c
524 
525  nullify(p)
526 
527  ! resolve the path to the value
528  if(present(path)) then
529  call ncdf_get_by_path(this=this, path=path, p=p)
530  else
531  p => this
532  end if
533 
534  if(.not.associated(p)) then
535  print *, "Unable to resolve path: ", path
536  return
537  end if
538 
539  if(p % value_type == type_array) then
540  count1 = ncdf_value_count(p)
541  element => p % children
542  do i1 = 1, count1
543  if (element % value_type == type_array) then
544  c = ncdf_value_count(element)
545  if (i1 == 1) then
546  count2 = c
547  else if (c /= count2) then
548  print *, "Resolved value has the wrong number of elements. ", &
549  path, "[", i1, "]"
550  call exit(1)
551  end if
552  item => element % children
553  do i2 = 1, count2
554  call array_callback(item, i1, i2, count1, count2)
555  item => item % next
556  end do
557  element => element % next
558  else
559  print *, "Resolved value is not an array. ", path, "[", i1, "]"
560  call exit(1)
561  end if
562  end do
563  else
564  print *, "Resolved value is not an array. ", path
565  call exit(1)
566  end if
567 
568  if (associated(p)) nullify(p)
569 
570  end subroutine ncdf_get_array_2d
571 
572 !
573 ! GET ARRAY INTEGER 2D
574 !
575  subroutine ncdf_get_array_2d_integer(this, path, arr)
577  implicit none
578  type(ncdf_value), pointer, intent(in) :: this
579  character(len=*), intent(in), optional :: path
580  integer, allocatable, intent(out) :: arr(:, :)
581 
582  if (allocated(arr)) deallocate(arr)
584 
585  contains
586 
587  subroutine ncdf_array_callback_2d_integer(element, i1, i2, count1, count2)
588  implicit none
589  type(ncdf_value), pointer, intent(in) :: element
590  integer, intent(in) :: i1, i2, count1, count2
591  if (.not. allocated(arr)) allocate(arr(count1, count2))
592  call ncdf_path_get(element, "", arr(i1, i2))
593  end subroutine ncdf_array_callback_2d_integer
594 
595  end subroutine ncdf_get_array_2d_integer
596 
597 !
598 ! GET ARRAY REAL 2D
599 !
600  subroutine ncdf_get_array_2d_real(this, path, arr)
602  implicit none
603  type(ncdf_value), pointer, intent(in) :: this
604  character(len=*), intent(in), optional :: path
605  real, allocatable, intent(out) :: arr(:, :)
606 
607  if (allocated(arr)) deallocate(arr)
609 
610  contains
611 
612  subroutine ncdf_array_callback_2d_real(element, i1, i2, count1, count2)
613  implicit none
614  type(ncdf_value), pointer, intent(in) :: element
615  integer, intent(in) :: i1, i2, count1, count2
616  if (.not. allocated(arr)) allocate(arr(count1, count2))
617  call ncdf_path_get(element, "", arr(i1, i2))
618  end subroutine ncdf_array_callback_2d_real
619 
620  end subroutine ncdf_get_array_2d_real
621 
622 !
623 ! GET ARRAY DOUBLE 2D
624 !
625  subroutine ncdf_get_array_2d_double(this, path, arr)
627  implicit none
628  type(ncdf_value), pointer, intent(in) :: this
629  character(len=*), intent(in), optional :: path
630  double precision, allocatable, intent(out) :: arr(:, :)
631 
632  if (allocated(arr)) deallocate(arr)
634 
635  contains
636 
637  subroutine ncdf_array_callback_2d_double(element, i1, i2, count1, count2)
638  implicit none
639  type(ncdf_value), pointer, intent(in) :: element
640  integer, intent(in) :: i1, i2, count1, count2
641  if (.not. allocated(arr)) allocate(arr(count1, count2))
642  call ncdf_path_get(element, "", arr(i1, i2))
643  end subroutine ncdf_array_callback_2d_double
644 
645  end subroutine ncdf_get_array_2d_double
646 
647 !
648 ! GET ARRAY LOGICAL 2D
649 !
650  subroutine ncdf_get_array_2d_logical(this, path, arr)
652  implicit none
653  type(ncdf_value), pointer, intent(in) :: this
654  character(len=*), intent(in), optional :: path
655  logical, allocatable, intent(out) :: arr(:, :)
656 
657  if (allocated(arr)) deallocate(arr)
659 
660  contains
661 
662  subroutine ncdf_array_callback_2d_logical(element, i1, i2, count1, count2)
663  implicit none
664  type(ncdf_value), pointer, intent(in) :: element
665  integer, intent(in) :: i1, i2, count1, count2
666  if (.not. allocated(arr)) allocate(arr(count1, count2))
667  call ncdf_path_get(element, "", arr(i1, i2))
668  end subroutine ncdf_array_callback_2d_logical
669 
670  end subroutine ncdf_get_array_2d_logical
671 
672 
673 end module ncdf_path_m
subroutine ncdf_array_callback_2d_real(element, i1, i2, count1, count2)
subroutine ncdf_get_double(this, path, value)
integer, parameter, public type_real
subroutine ncdf_array_callback_2d_double(element, i1, i2, count1, count2)
subroutine ncdf_get_array_2d_logical(this, path, arr)
subroutine ncdf_array_callback_1d_double(element, i, count)
integer, parameter, public type_logical
subroutine ncdf_get_array_1d_double(this, path, arr)
subroutine ncdf_get_array_2d(this, path, array_callback)
integer, parameter, public type_integer
integer, parameter, public type_array
integer, parameter, public type_string
subroutine ncdf_get_integer(this, path, value)
subroutine ncdf_get_array_2d_double(this, path, arr)
subroutine ncdf_get_array_1d_logical(this, path, arr)
subroutine ncdf_array_callback_2d_logical(element, i1, i2, count1, count2)
subroutine ncdf_get_array_2d_real(this, path, arr)
subroutine ncdf_array_callback_1d_real(element, i, count)
subroutine ncdf_get_array_1d(this, path, array_callback)
subroutine ncdf_array_callback_1d_integer(element, i, count)
integer function parse_integer(chars)
subroutine ncdf_get_array_2d_integer(this, path, arr)
subroutine ncdf_get_real(this, path, value)
recursive subroutine ncdf_get_by_path(this, path, p)
Definition: ncdf_path_m.f90:82
subroutine ncdf_array_callback_2d_integer(element, i1, i2, count1, count2)
subroutine ncdf_get_logical(this, path, value)
subroutine ncdf_get_array_1d_real(this, path, arr)
subroutine ncdf_array_callback_1d_logical(element, i, count)
subroutine ncdf_get_chars(this, path, value)
subroutine ncdf_get_array_1d_integer(this, path, arr)
integer function, public ncdf_value_count(this)