FMS 2025.01-dev
Flexible Modeling System
Loading...
Searching...
No Matches
field_manager.inc
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!> @returns The number of values that have been decoded. This allows
20!! a user to define a large array and fill it partially with
21!! values from a list. This should be the size of the value array.
22function parse_reals_ ( text, label, values ) result (parse)
23character(len=*), intent(in) :: text !< The text string from which the values will be parsed.
24character(len=*), intent(in) :: label !< A label which describes the values being decoded.
25real(FMS_FM_KIND_), intent(out) :: values(:) !< The value or values that have been decoded.
26
27include 'parse.inc'
28end function parse_reals_
29
30function parse_real_ ( text, label, parse_rval ) result (parse)
31character(len=*), intent(in) :: text !< The text string from which the values will be parsed.
32character(len=*), intent(in) :: label !< A label which describes the values being decoded.
33real(FMS_FM_KIND_), intent(out) :: parse_rval !< The value or values that have been decoded.
34integer :: parse
35
36real(FMS_FM_KIND_) :: values(1)
37
38 parse = parse_reals_( text, label, values )
39 if (parse > 0) parse_rval = values(1)
40 end function parse_real_
41
42!> @returns A flag to indicate whether the function operated with (false) or without
43!! (true) errors.
44function fm_get_value_real_(name, get_rval, index) &
45 result(success)
46logical :: success
47character(len=*), intent(in) :: name !< The name of a field that the user wishes to get a value for.
48real(FMS_FM_KIND_), intent(out) :: get_rval !< The value associated with the named field
49integer, intent(in), optional :: index !< An optional index to retrieve a single value from an array.
50
51integer :: index_t
52type (field_def), pointer, save :: temp_field_p
53integer :: out_unit
54
55integer, parameter :: lkind=fms_fm_kind_
56
57out_unit = stdout()
58! Initialize the field manager if needed
59if (.not. module_is_initialized) then
60 call initialize_module_variables
61endif
62! Must supply a field field name
63if (name .eq. ' ') then
64 get_rval = 0.0_lkind
65 success = .false.
66 return
67endif
68! Set index to retrieve
69if (present(index)) then
70 index_t = index
71else
72 index_t = 1
73endif
74! Get a pointer to the field
75temp_field_p => get_field(name, current_list_p)
76
77if (associated(temp_field_p)) then
78! check that the field is the correct type
79 if (temp_field_p%field_type .eq. real_type) then
80 if (index_t .lt. 1 .or. index_t .gt. temp_field_p%max_index) then
81! Index is not positive or is too large
82 get_rval = 0.0_lkind
83 success = .false.
84 else
85! extract the value; the value is stored as r8_kind
86 get_rval = real(temp_field_p%r_value(index_t),lkind)
87 success = .true.
88 endif
89 else
90 get_rval = 0.0_lkind
91 success = .false.
92 endif
93else
94 get_rval = 0.0_lkind
95 success = .false.
96endif
97
98end function fm_get_value_real_
99
100!> @brief Assigns a given value to a given field
101!> @returns An index for the named field
102function fm_new_value_real_(name, new_rval, create, index, append) &
103 result(field_index)
104integer :: field_index
105character(len=*), intent(in) :: name !< The name of a field that the user wishes to create
106 !! a value for.
107real(FMS_FM_KIND_), intent(in) :: new_rval !< The value that the user wishes to apply to the
108 !! named field.
109logical, intent(in), optional :: create !< If present and .true., then a value for this
110 !! field will be created.
111integer, intent(in), optional :: index !< The index to an array of values that the user
112 !! wishes to apply a new value.
113logical, intent(in), optional :: append !< If present and .true., then append the value to
114 !! an array of the present values. If present and .true., then index cannot be greater than 0.
115
116logical :: create_t
117integer :: i
118integer :: index_t
119real(r8_kind), allocatable, dimension(:) :: temp_r_value
120character(len=FMS_PATH_LEN) :: path
121character(len=fm_field_name_len) :: base
122type (field_def), pointer, save :: temp_list_p
123type (field_def), pointer, save :: temp_field_p
124integer :: out_unit
125
126out_unit = stdout()
127! Initialize the field manager if needed
128if (.not. module_is_initialized) then
129 call initialize_module_variables
130endif
131! Must supply a field name
132if (name .eq. ' ') then
133 field_index = no_field
134 return
135endif
136! Check for optional arguments
137if (present(create)) then
138 create_t = create
139else
140 create_t = .false.
141endif
142! Check that append is not true and index greater than 0
143if (present(index) .and. present(append)) then
144 if (append .and. index .gt. 0) then
145 field_index = no_field
146 return
147 endif
148endif
149! Set index to define
150if (present(index)) then
151 index_t = index
152 if (index_t .lt. 0) then
153! Index is negative
154 field_index = no_field
155 return
156 endif
157else
158 index_t = 1
159endif
160
161! Get a pointer to the parent list
162call find_base(name, path, base)
163temp_list_p => find_list(path, current_list_p, create_t)
164
165if (associated(temp_list_p)) then
166 temp_field_p => find_field(base, temp_list_p)
167 if (.not. associated(temp_field_p)) then
168! Create the field if it doesn't exist
169 temp_field_p => create_field(temp_list_p, base)
170 endif
171 if (associated(temp_field_p)) then
172! Check if the field_type is the same as previously
173! If not then reset max_index to 0
174 if (temp_field_p%field_type == integer_type) then
175 ! promote integer field to real
176 allocate(temp_field_p%r_value(size(temp_field_p%i_value)))
177 do i = 1, size(temp_field_p%i_value)
178 ! all real field values are stored as r8_kind
179 temp_field_p%r_value(i) = real(temp_field_p%i_value(i),r8_kind)
180 enddo
181 temp_field_p%field_type = real_type
182 deallocate(temp_field_p%i_value)
183 else if (temp_field_p%field_type /= real_type ) then
184 ! slm: why reset index to 0? does it make any sense? It sounds like this is the
185 ! case where the values in the array have different types, so is it not an error?
186 ! Or, alternatively, if string follows a real value, should not be the entire
187 ! array converted to string type?
188 temp_field_p%max_index = 0
189 endif
190! Assign the type
191 temp_field_p%field_type = real_type
192! Set the index if appending
193 if (present(append)) then
194 if (append) then
195 index_t = temp_field_p%max_index + 1
196 endif
197 endif
198 if (index_t .gt. temp_field_p%max_index + 1) then
199! Index too large
200 field_index = no_field
201 return
202 elseif (index_t .eq. 0 .and. &
203 temp_field_p%max_index .gt. 0) then
204! Can't set non-null field to null
205 field_index = no_field
206 return
207 elseif (.not. allocated(temp_field_p%r_value) .and. &
208 index_t .gt. 0) then
209! Array undefined, so allocate the array
210 allocate(temp_field_p%r_value(1))
211 temp_field_p%max_index = 1
212 temp_field_p%array_dim = 1
213 elseif (index_t .gt. temp_field_p%array_dim) then
214! Array is too small, so allocate new array and copy over
215! old values
216 temp_field_p%array_dim = temp_field_p%array_dim + array_increment
217 allocate (temp_r_value(temp_field_p%array_dim))
218 do i = 1, temp_field_p%max_index
219 temp_r_value(i) = temp_field_p%r_value(i)
220 enddo
221 if (allocated(temp_field_p%r_value)) deallocate(temp_field_p%r_value)
222 temp_field_p%r_value = temp_r_value
223 temp_field_p%max_index = index_t
224 endif
225! Assign the value and set the field_index for return
226! for non-null fields (index_t > 0)
227 if (index_t .gt. 0) then
228 ! all real field values are stored as r8_kind
229 temp_field_p%r_value(index_t) = real(new_rval,r8_kind)
230 if (index_t .gt. temp_field_p%max_index) then
231 temp_field_p%max_index = index_t
232 endif
233 endif
234 field_index = temp_field_p%index
235 else
236! Error in making the field
237 field_index = no_field
238 endif
239else
240! Error following the path
241 field_index = no_field
242endif
243
244end function fm_new_value_real_
245!> @}
246! close documentation grouping