FV3 Bundle
ioda_obsvar_mod.F90
Go to the documentation of this file.
1 !
2 ! (C) Copyright 2017 UCAR
3 !
4 ! This software is licensed under the terms of the Apache Licence Version 2.0
5 ! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6 
7 ! IODA observation memory store
8 !
9 ! For now using a linked list. This assumes that we have a small number of
10 ! variables thus searching the list is fast. This implementation is meant to
11 ! be a quick and dirty placeholder until a decision about ODB is made. We will
12 ! then either replace this with ODB, or work on a more appropriate storage
13 ! mechanism.
14 
16 
17 use kinds
18 
19 implicit none
20 
21 integer, parameter :: ioda_obsvar_maxstrlen = 80
22 
23 !> observation variable
24 type :: ioda_obs_var
25  integer :: nobs !< number of observations
26 
27  character(len=IODA_OBSVAR_MAXSTRLEN) :: vname !< variable name
28  real(kind_real), allocatable :: vals(:) !< values (nobs)
29 
30  type(ioda_obs_var), pointer :: next
31 end type ioda_obs_var
32 
34  integer :: n_nodes
35  type(ioda_obs_var), pointer :: head
36 
37 contains
38  procedure :: setup => setup_
39  procedure :: delete => delete_
40  procedure :: add_node => add_node_
41  procedure :: get_node => get_node_
42  procedure :: remove_node => remove_node_
43 end type ioda_obs_variables
44 
45 contains
46 
47 !> Initialize the linked list
48 subroutine setup_(self)
49  implicit none
50  class(ioda_obs_variables) :: self
51 
52  ! Set the count to zero and nullify the head
53  self%n_nodes = 0
54  self%head => null()
55 end subroutine setup_
56 
57 !> Add a node to the linked list
58 subroutine add_node_(self, vname, ptr)
59  implicit none
60 
61  class(ioda_obs_variables) :: self
62  character(len=*) :: vname
63  type(ioda_obs_var), pointer :: ptr
64 
65  type(ioda_obs_var), pointer :: new_node
66 
67  ! Create a new node and insert at beginning of list
68  allocate(new_node)
69  new_node%nobs = 0
70  new_node%vname = trim(vname)
71  new_node%next => self%head
72  self%head => new_node
73 
74  ! Return a pointer to the newly inserted node
75  ptr => new_node
76 
77  ! Keep count of items in the list
78  self%n_nodes = self%n_nodes + 1
79 end subroutine add_node_
80 
81 !> Find a node in the linked list by key
82 subroutine get_node_(self, vname, ptr)
83  implicit none
84 
85  class(ioda_obs_variables) :: self
86  character(len=*) :: vname
87  type(ioda_obs_var), pointer :: ptr
88 
89  type(ioda_obs_var), pointer :: current
90 
91  ! Walk the list and look for matching vname
92  ptr => null()
93  current => self%head
94  do while (associated(current))
95  if (trim(vname) .eq. trim(current%vname)) then
96  ptr => current
97  exit
98  endif
99 
100  ! Move to the next node and check
101  current => current%next
102  enddo
103 end subroutine get_node_
104 
105 !> Remove an element from the linked list
106 subroutine remove_node_(self, vname)
107  implicit none
108 
109  class(ioda_obs_variables) :: self
110  character(len=IODA_OBSVAR_MAXSTRLEN) :: vname
111 
112  type(ioda_obs_var), pointer :: prev
113  type(ioda_obs_var), pointer :: current
114 
115  ! Walk list to find the element matching vname
116  current => self%head
117  prev => null()
118  do while (associated(current))
119  if (trim(vname) .eq. trim(current%vname)) exit
120  prev => current
121  current => current%next
122  enddo
123 
124  ! If found, rewire the list to skip over the node
125  if (associated(current)) then
126  if (associated(current%next)) then
127  ! current is not at the end of the list, so we need to
128  ! move the next pointer of the node pointed to by prev
129  ! to the next pointer of the node pointed to by current
130  if (associated(prev)) then
131  ! We are beyond the head of the list
132  prev%next => current%next
133  else
134  ! We are at the head of the list
135  self%head%next => current%next
136  endif
137  endif
138 
139  ! Get rid of the node and decrement the list count.
140  if (allocated(current%vals)) then
141  deallocate(current%vals)
142  endif
143  deallocate(current)
144 
145  self%n_nodes = self%n_nodes - 1
146  endif
147 end subroutine remove_node_
148 
149 !> Finalize the linked list, deallocate all nodes
150 subroutine delete_(self)
151  implicit none
152 
153  class(ioda_obs_variables) :: self
154 
155  type(ioda_obs_var), pointer :: current
156  type(ioda_obs_var), pointer :: next
157 
158  ! Walk the list and deallocate nodes
159  current => self%head
160  do while (associated(current))
161  ! Grab the pointer to the next node
162  next => current%next
163 
164  ! Delete the current node
165  if (allocated(current%vals)) then
166  deallocate(current%vals)
167  endif
168  deallocate(current)
169  self%n_nodes = self%n_nodes - 1
170 
171  ! Move to the next node
172  current => next
173  enddo
174 
175  self%head => null()
176 end subroutine delete_
177 
178 end module ioda_obsvar_mod
subroutine delete_(self)
Finalize the linked list, deallocate all nodes.
integer, parameter ioda_obsvar_maxstrlen
subroutine remove_node_(self, vname)
Remove an element from the linked list.
subroutine setup_(self)
Initialize the linked list.
subroutine get_node_(self, vname, ptr)
Find a node in the linked list by key.
subroutine add_node_(self, vname, ptr)
Add a node to the linked list.