FMS  2025.03
Flexible Modeling System
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.
22 function parse_reals_ ( text, label, values ) result (parse)
23 character(len=*), intent(in) :: text !< The text string from which the values will be parsed.
24 character(len=*), intent(in) :: label !< A label which describes the values being decoded.
25 real(FMS_FM_KIND_), intent(out) :: values(:) !< The value or values that have been decoded.
26 
27 include 'parse.inc'
28 end function parse_reals_
29 
30 function parse_real_ ( text, label, parse_rval ) result (parse)
31 character(len=*), intent(in) :: text !< The text string from which the values will be parsed.
32 character(len=*), intent(in) :: label !< A label which describes the values being decoded.
33 real(FMS_FM_KIND_), intent(out) :: parse_rval !< The value or values that have been decoded.
34 integer :: parse
35 
36 real(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.
44 function fm_get_value_real_(name, get_rval, index) &
45  result(success)
46 logical :: success
47 character(len=*), intent(in) :: name !< The name of a field that the user wishes to get a value for.
48 real(FMS_FM_KIND_), intent(out) :: get_rval !< The value associated with the named field
49 integer, intent(in), optional :: index !< An optional index to retrieve a single value from an array.
50 
51 integer :: index_t
52 type (field_def), pointer, save :: temp_field_p
53 integer :: out_unit
54 
55 integer, parameter :: lkind=fms_fm_kind_
56 
57 out_unit = stdout()
58 ! Initialize the field manager if needed
59 if (.not. module_is_initialized) then
60  call initialize_module_variables
61 endif
62 ! Must supply a field field name
63 if (name .eq. ' ') then
64  get_rval = 0.0_lkind
65  success = .false.
66  return
67 endif
68 ! Set index to retrieve
69 if (present(index)) then
70  index_t = index
71 else
72  index_t = 1
73 endif
74 ! Get a pointer to the field
75 temp_field_p => get_field(name, current_list_p)
76 
77 if (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
93 else
94  get_rval = 0.0_lkind
95  success = .false.
96 endif
97 
98 end function fm_get_value_real_
99 
100 !> @brief Assigns a given value to a given field
101 !> @returns An index for the named field
102 function fm_new_value_real_(name, new_rval, create, index, append) &
103  result(field_index)
104 integer :: field_index
105 character(len=*), intent(in) :: name !< The name of a field that the user wishes to create
106  !! a value for.
107 real(FMS_FM_KIND_), intent(in) :: new_rval !< The value that the user wishes to apply to the
108  !! named field.
109 logical, intent(in), optional :: create !< If present and .true., then a value for this
110  !! field will be created.
111 integer, intent(in), optional :: index !< The index to an array of values that the user
112  !! wishes to apply a new value.
113 logical, 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 
116 logical :: create_t
117 integer :: i
118 integer :: index_t
119 real(r8_kind), allocatable, dimension(:) :: temp_r_value
120 character(len=FMS_PATH_LEN) :: path
121 character(len=fm_field_name_len) :: base
122 type (field_def), pointer, save :: temp_list_p
123 type (field_def), pointer, save :: temp_field_p
124 integer :: out_unit
125 
126 out_unit = stdout()
127 ! Initialize the field manager if needed
128 if (.not. module_is_initialized) then
129  call initialize_module_variables
130 endif
131 ! Must supply a field name
132 if (name .eq. ' ') then
133  field_index = no_field
134  return
135 endif
136 ! Check for optional arguments
137 if (present(create)) then
138  create_t = create
139 else
140  create_t = .false.
141 endif
142 ! Check that append is not true and index greater than 0
143 if (present(index) .and. present(append)) then
144  if (append .and. index .gt. 0) then
145  field_index = no_field
146  return
147  endif
148 endif
149 ! Set index to define
150 if (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
157 else
158  index_t = 1
159 endif
160 
161 ! Get a pointer to the parent list
162 call find_base(name, path, base)
163 temp_list_p => find_list(path, current_list_p, create_t)
164 
165 if (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
239 else
240 ! Error following the path
241  field_index = no_field
242 endif
243 
244 end function fm_new_value_real_
245 !> @}
246 ! close documentation grouping
integer function stdout()
This function returns the current standard fortran unit numbers for output.
Definition: mpp_util.inc:43