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