FV3 Bundle
field_manager.F90
Go to the documentation of this file.
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 
21 #ifndef MAXFIELDS_
22 #define MAXFIELDS_ 250
23 #endif
24 
25 #ifndef MAXFIELDMETHODS_
26 #define MAXFIELDMETHODS_ 250
27 #endif
28 
29 !
30 ! <CONTACT EMAIL="William.Cooke@noaa.gov"> William Cooke
31 ! </CONTACT>
32 !
33 ! <REVIEWER EMAIL="Richard.Slater@noaa.gov"> Richard D. Slater
34 ! </REVIEWER>
35 !
36 ! <REVIEWER EMAIL="Matthew.Harrison@noaa.gov"> Matthew Harrison
37 ! </REVIEWER>
38 !
39 ! <REVIEWER EMAIL="John.Dunne@noaa.gov"> John P. Dunne
40 ! </REVIEWER>
41 !
42 ! <HISTORY
43 ! SRC="http://www.gfdl.noaa.gov/fms-cgi-bin/cvsweb.cgi/FMS/shared/field_manager/field_manager.F90"/>
44 
45 ! <OVERVIEW>
46 
47 ! The field manager reads entries from a field table and stores this
48 ! information along with the type of field it belongs to. This allows
49 ! the component models to query the field manager to see if non-default
50 ! methods of operation are desired. In essence the field table is a
51 ! powerful type of namelist. Default values can be provided for all the
52 ! fields through a namelist, individual fields can be modified through
53 ! the field table however.
54 
55 !</OVERVIEW>
56 
57 ! <DESCRIPTION>
58 !
59 ! An example of field table entries could be
60 ! <PRE>
61 !"tracer","atmos_mod","sphum"/
62 !
63 !"tracer","atmos_mod","sf6"
64 !"longname","sulf_hex"
65 !"advection_scheme_horiz","2nd_order"
66 !"Profile_type","Fixed","surface_value = 0.0E+00"/
67 !
68 !"prog_tracers","ocean_mod","age_global"
69 !horizontal-advection-scheme = mdfl_sweby
70 !vertical-advection-scheme = mdfl_sweby
71 !restart_file = ocean_age.res.nc
72 ! </PRE>
73 !
74 ! The field table consists of entries in the following format.
75 !
76 ! The first line of an entry should consist of three quoted strings.
77 !
78 ! The first quoted string will tell the field manager what type of
79 ! field it is.
80 !
81 ! The second quoted string will tell the field manager which model the
82 ! field is being applied to.
83 ! The supported types at present are
84 !<PRE>
85 ! "coupler_mod" for the coupler,
86 ! "atmos_mod" for the atmosphere model,
87 ! "ocean_mod" for the ocean model,
88 ! "land_mod" for the land model, and,
89 ! "ice_mod" for the ice model.
90 !</PRE>
91 ! The third quoted string should be a unique name that can be used as a
92 ! query.
93 !
94 ! The second and following lines of each entry are called methods in
95 ! this context. Methods can be developed within any module and these
96 ! modules can query the field manager to find any methods that are
97 ! supplied in the field table.
98 !
99 ! These lines can be coded quite flexibly.
100 !
101 ! The line can consist of two or three quoted strings or a simple unquoted
102 ! string.
103 !
104 ! If the line consists two or three quoted strings, then the first string will
105 ! be an identifier that the querying module will ask for.
106 !
107 ! The second string will be a name that the querying module can use to
108 ! set up values for the module.
109 !
110 ! The third string, if present, can supply parameters to the calling module that can be
111 ! parsed and used to further modify values.
112 !
113 ! If the line consists of a simple unquoted string then quotes are not allowed
114 ! in any part of the line.
115 !
116 ! An entry is ended with a backslash (/) as the final character in a
117 ! row.
118 !
119 ! Comments can be inserted in the field table by having a # as the
120 ! first character in the line.
121 !
122 ! In the example above we have three field entries.
123 !
124 ! The first is a simple declaration of a tracer called "sphum".
125 !
126 ! The second is for a tracer called "sf6". In this case a field named
127 ! "longname" will be given the value "sulf_hex". A field named
128 ! "advection_scheme_horiz" will be given the value "2nd_order". Finally a field
129 ! name "Profile_type" will be given a child field called "Fixed", and that field
130 ! will be given a field called "surface_value" with a real value of 0.0E+00.
131 !
132 ! The third entry is an example of a oceanic age tracer. Note that the
133 ! method lines are formatted differently here. This is the flexibility mentioned
134 ! above.
135 !
136 ! With these formats, a number of restrictions are required.
137 !
138 ! The following formats are equally valid.
139 !<PRE>
140 ! "longname","sulf_hex"
141 ! "longname = sulf_hex"
142 ! longname = sulf_hex
143 !</PRE>
144 ! However the following is not valid.
145 !<PRE>
146 ! longname = "sulf_hex"
147 !</PRE>
148 !
149 ! In the SF6 example above the last line of the entry could be written in the
150 ! following ways.
151 !<PRE>
152 ! "Profile_type","Fixed","surface_value = 0.0E+00"/
153 ! Profile_type/Fixed/surface_value = 0.0E+00/
154 !</PRE>
155 !
156 ! Values supplied with fields are converted to the various types with the
157 ! following assumptions.
158 !<PRE>
159 ! Real values : These values contain a decimal point or are in exponential format.
160 ! These values only support e or E format for exponentials.
161 ! e.g. 10.0, 1e10 and 1E10 are considered to be real numbers.
162 !
163 ! Integer values : These values only contain numbers.
164 ! e.g 10 is an integer. 10.0 and 1e10 are not.
165 !
166 ! Logical values : These values are supplied as one of the following formats.
167 ! T, .T., TRUE, .TRUE.
168 ! t, .t., true, .true.
169 ! F, .F., FALSE, .FALSE.
170 ! f, .f., false, .false.
171 ! These will be converted to T or F in a dump of the field.
172 !
173 ! Character strings : These values are assumed to be strings if a character
174 ! other than an e (or E) is in the value. Numbers can be suppled in the value.
175 ! If the value does not meet the criteria for a real, integer or logical type,
176 ! it is assumed to be a character type.
177 !</PRE>
178 ! The entries within the field table can be designed by the individual
179 ! authors of code to allow modification of their routines.
180 !
181 ! </DESCRIPTION>
182 
183 use mpp_mod, only : mpp_error, &
184  fatal, &
185  note, &
186  warning, &
187  mpp_pe, &
188  mpp_root_pe, &
189  stdlog, &
190  stdout
191 use mpp_io_mod, only : mpp_io_init, &
192  mpp_open, &
193  mpp_close, &
194  mpp_ascii, &
195  mpp_rdonly
196 use fms_mod, only : lowercase, &
197  file_exist, &
198  write_version_number
199 
200 implicit none
201 private
202 
203 ! Include variable "version" to be written to log file.
204 #include<file_version.h>
205 logical :: module_is_initialized = .false.
206 
207 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
208 ! Public routines
209 ! Interface definitions (optional arguments are in [brackets]):
210 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
211 public :: field_manager_init ! (nfields, [table_name]) returns number of fields
212 public :: field_manager_end ! ()
213 public :: find_field_index ! (model, field_name) or (list_path)
214 public :: find_field_index_old ! (model, field_name) returns index of field_name in
215 public :: find_field_index_new ! (list_path) returns index of field_name in
216  ! component model model
217 public :: get_field_info ! (n,fld_type,fld_name,model,num_methods)
218  ! Returns parameters relating to field n.
219 public :: get_field_method ! (n, m, method) Returns the m-th method of field n
220 public :: get_field_methods ! (n, methods) Returns the methods related to field n
221 public :: parse ! (text, label, values) Overloaded function to parse integer,
222  ! real or character. Parse returns the number of values
223  ! decoded (> 1 => an array of values)
224 public :: fm_change_list ! (list) return success
225 public :: fm_change_root ! (list) return success
226 public :: fm_dump_list ! (list [, recursive]) return success
227 public :: fm_exists ! (field) return success
228 public :: fm_get_index ! (field) return index
229 public :: fm_get_current_list ! () return path
230 public :: fm_get_length ! (list) return length
231 public :: fm_get_type ! (field) return string
232 public :: fm_get_value ! (entry, value [, index]) return success !! generic
233 public :: fm_get_value_integer ! as above (overloaded function)
234 public :: fm_get_value_logical ! as above (overloaded function)
235 public :: fm_get_value_real ! as above (overloaded function)
236 public :: fm_get_value_string ! as above (overloaded function)
237 public :: fm_intersection ! (lists, num_lists) return fm_array_list pointer
238 public :: fm_init_loop ! (list, iter)
239 public :: fm_loop_over_list ! (list, name, type, index) return success
240  ! (iter, name, type, index) return success
241 public :: fm_new_list ! (list [, create] [, keep]) return index
242 public :: fm_new_value ! (entry, value [, create] [, index]) return index !! generic
243 public :: fm_new_value_integer ! as above (overloaded function)
244 public :: fm_new_value_logical ! as above (overloaded function)
245 public :: fm_new_value_real ! as above (overloaded function)
246 public :: fm_new_value_string ! as above (overloaded function)
247 public :: fm_reset_loop ! ()
248 public :: fm_return_root ! () return success
249 public :: fm_modify_name ! (oldname, newname) return success
250 public :: fm_query_method ! (name, method_name, method_control) return success and
251  ! name and control strings
252 public :: fm_find_methods ! (list, methods, control) return success and name and
253  ! control strings.
254 public :: fm_copy_list ! (list, suffix, [create]) return index
255 public :: fm_set_verbosity ! ([verbosity])
256 
257 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
258 ! Private routines
259 ! Interface definitions (optional arguments are in [brackets]):
260 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
261 
262 private :: create_field ! (list_p, name) return field pointer
263 private :: dump_list ! (list_p, recursive, depth) return success
264 private :: find_base ! (field, path, base)
265 private :: find_field ! (field, list_p) return field pointer
266 private :: find_head ! (field, head, rest)
267 private :: find_list ! (list, list_p, create) return field pointer
268 private :: get_field ! (field, list_p) return field pointer
269 private :: initialize ! ()
270 private :: make_list ! (list_p, name) return field pointer
271 
272 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
273 ! Public parameters
274 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
275 integer, parameter, public :: fm_field_name_len = 48
276 ! <DATA NAME="fm_field_name_len" TYPE="integer, parameter" DEFAULT="48">
277 ! The length of a character string representing the field name.
278 ! </DATA>
279 integer, parameter, public :: fm_path_name_len = 512
280 ! <DATA NAME="fm_path_name_len" TYPE="integer, parameter" DEFAULT="512">
281 ! The length of a character string representing the field path.
282 ! </DATA>
283 integer, parameter, public :: fm_string_len = 128
284 ! <DATA NAME="fm_string_len" TYPE="integer, parameter" DEFAULT="128">
285 ! The length of a character string representing character values for the field.
286 ! </DATA>
287 integer, parameter, public :: fm_type_name_len = 8
288 ! <DATA NAME="fm_type_name_len" TYPE="integer, parameter" DEFAULT="8">
289 ! The length of a character string representing the various types that the values of the field can take.
290 ! </DATA>
291 integer, parameter, public :: num_models = 5
292 ! <DATA NAME="NUM_MODELS" TYPE="integer, parameter" DEFAULT="5">
293 ! Number of models (ATMOS, OCEAN, LAND, ICE, COUPLER).
294 ! </DATA>
295 integer, parameter, public :: no_field = -1
296 ! <DATA NAME="NO_FIELD" TYPE="integer, parameter" DEFAULT="-1">
297 ! The value returned if a field is not defined.
298 ! </DATA>!
299 integer, parameter, public :: model_atmos = 1
300 ! <DATA NAME="MODEL_ATMOS" TYPE="integer, parameter" DEFAULT="1">
301 ! Atmospheric model.
302 ! </DATA>!
303 integer, parameter, public :: model_ocean = 2
304 ! <DATA NAME="MODEL_OCEAN" TYPE="integer, parameter" DEFAULT="2">
305 ! Ocean model.
306 ! </DATA>
307 integer, parameter, public :: model_land = 3
308 ! <DATA NAME="MODEL_LAND" TYPE="integer, parameter" DEFAULT="3">
309 ! Land model.
310 ! </DATA>
311 integer, parameter, public :: model_ice = 4
312 ! <DATA NAME="MODEL_ICE" TYPE="integer, parameter" DEFAULT="4">
313 ! Ice model.
314 ! </DATA>
315 integer, parameter, public :: model_coupler = 5
316 ! <DATA NAME="MODEL_COUPLER" TYPE="integer, parameter" DEFAULT="5">
317 ! Ice model.
318 ! </DATA>
319 character(len=11), parameter, public, dimension(NUM_MODELS) :: &
320  model_names=(/'atmospheric','oceanic ','land ','ice ','coupler '/)
321 ! <DATA NAME="MODEL_NAMES" TYPE="character(len=11), parameter">
322 ! Model names, e.g. MODEL_NAMES(MODEL_OCEAN) is 'oceanic'
323 ! </DATA>
324 
325 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
326 ! Public type definitions
327 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
328 
329 type, public :: fm_array_list_def !{
330  character (len=fm_field_name_len), dimension(:), pointer :: names => null()
331  integer :: length
332 end type fm_array_list_def !}
333 
334 !
335 ! <TYPE NAME="method_type">
336 ! <DESCRIPTION>
337 
338 ! This method_type is a way to allow a component module to alter the parameters it needs
339 ! for various tracers. In essence this is a way to modify a namelist. A namelist can supply
340 ! default parameters for all tracers. This method will allow the user to modify these
341 ! default parameters for an individual tracer. An example could be that the user wishes to
342 ! use second order advection on a tracer and also use fourth order advection on a second
343 ! tracer within the same model run. The default advection could be second order and the
344 ! field table would then indicate that the second tracer requires fourth order advection.
345 ! This would be parsed by the advection routine.
346 
347 !
348 ! </DESCRIPTION>
349 type, public :: method_type
350 
351  ! <DATA NAME="method_type :: method_type" TYPE="character" DIM="(128)">
352  !
353  ! This string represents a tag that a module using this method can
354  ! key on. Typically this should contain some reference to the module
355  ! that is calling it.
356  ! </DATA>
357  !
358  ! <DATA NAME="method_type :: method_name" TYPE="character" DIM="(128)">
359  ! This is the name of a method which the module can parse and use
360  ! to assign different default values to a field method.
361  ! </DATA>
362  !
363  ! <DATA NAME="method_type :: method_control" TYPE="character" DIM="(256)">
364  ! This is the string containing parameters that the module can use
365  ! as values for a field method. These should override default
366  ! values within the module.
367  ! </DATA>
368  character(len=fm_string_len) :: method_type
369  character(len=fm_string_len) :: method_name
370  character(len=fm_string_len) :: method_control
371 end type
372 ! </TYPE> NAME="method_type"
373 
374 ! <TYPE NAME="method_type_short">
375 ! <DESCRIPTION>
376 ! This method_type is the same as method_type except that the
377 ! method_control string is not present. This is used when you wish to
378 ! change to a scheme within a module but do not need to pass
379 ! parameters.
380 ! </DESCRIPTION>
381 type, public :: method_type_short
382  ! <DATA NAME="method_type_short :: method_type" TYPE="character" DIM="(128)">
383  ! see method_type :: method_type above.
384  ! </DATA>
385  !
386  ! <DATA NAME="method_type_short :: method_name" TYPE="character" DIM="(128)">
387  ! see method_type :: method_name above.
388  ! </DATA>
389  character(len=fm_string_len) :: method_type
390  character(len=fm_string_len) :: method_name
391 end type
392 ! </TYPE> NAME="method_type_short"
393 
394 ! <TYPE NAME="method_type_very_short">
395 ! <DESCRIPTION>
396 ! This method_type is the same as method_type except that the
397 ! method_control and method_name strings are not present. This is used
398 ! when you wish to change to a scheme within a module but do not need
399 ! to pass parameters.
400 ! </DESCRIPTION>
401 type, public :: method_type_very_short
402  ! <DATA NAME="method_type_short :: method_type" TYPE="character" DIM="(128)">
403  ! see method_type :: method_type above.
404  ! </DATA>
405  character(len=fm_string_len) :: method_type
406 end type
407 ! </TYPE> NAME="method_type_very_short"
408 
409 ! iterator over the field manager list
410 type, public :: fm_list_iter_type
411  type(field_def), pointer :: ptr => null() ! pointer to the current field
412 end type fm_list_iter_type
413 
414 
415 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
416 ! Public types
417 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
418 
419 type(method_type), public :: default_method
420 
421 
422 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
423 ! Public variables
424 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
425 
426 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
427 ! Interface definitions for overloaded routines
428 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
429 
431  module procedure find_field_index_old
432  module procedure find_field_index_new
433 end interface
434 
435 interface parse
436  module procedure parse_real
437  module procedure parse_reals
438  module procedure parse_integer
439  module procedure parse_integers
440  module procedure parse_string
441  module procedure parse_strings
442 end interface
443 
444 interface fm_new_value !{
445  module procedure fm_new_value_integer
446  module procedure fm_new_value_logical
447  module procedure fm_new_value_real
448  module procedure fm_new_value_string
449 end interface !}
450 
451 interface fm_get_value !{
452  module procedure fm_get_value_integer
453  module procedure fm_get_value_logical
454  module procedure fm_get_value_real
455  module procedure fm_get_value_string
456 end interface !}
457 
459  module procedure fm_loop_over_list_new
460  module procedure fm_loop_over_list_old
461 end interface
462 
463 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
464 ! Private parameters
465 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
466 
467 character(len=17), parameter :: module_name = 'field_manager_mod'
468 character(len=1), parameter :: bracket_left = '['
469 character(len=1), parameter :: bracket_right = ']'
470 character(len=1), parameter :: comma = ","
471 character(len=1), parameter :: comment = '#'
472 character(len=1), parameter :: dquote = '"'
473 character(len=1), parameter :: equal = '='
474 character(len=1), parameter :: list_sep = '/'
475 character(len=1), parameter :: space = ' '
476 character(len=1), parameter :: squote = "'"
477 character(len=1), parameter :: tab = char(9) ! ASCII
478 
479 integer, parameter :: null_type = 0
480 integer, parameter :: integer_type = 1
481 integer, parameter :: list_type = 2
482 integer, parameter :: logical_type = 3
483 integer, parameter :: real_type = 4
484 integer, parameter :: string_type = 5
485 integer, parameter :: num_types = 5
486 integer, parameter :: line_len = 256
487 integer, parameter :: array_increment = 10
488 integer, parameter :: max_fields = maxfields_
489 integer, parameter :: max_field_methods = maxfieldmethods_
490 
491 
492 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
493 ! Private type definitions
494 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
495 
496 type, private :: field_mgr_type !{
497  character(len=fm_field_name_len) :: field_type
498  character(len=fm_string_len) :: field_name
499  integer :: model, num_methods
500  type(method_type) :: methods(max_field_methods)
501 end type field_mgr_type !}
502 
503 type, private :: field_names_type !{
504  character(len=fm_field_name_len) :: fld_type
505  character(len=fm_field_name_len) :: mod_name
506  character(len=fm_string_len) :: fld_name
507 end type field_names_type !}
508 
509 type, private :: field_names_type_short !{
510  character(len=fm_field_name_len) :: fld_type
511  character(len=fm_field_name_len) :: mod_name
512 end type field_names_type_short !}
513 
514 type, private :: field_def !{
515  character (len=fm_field_name_len) :: name
516  integer :: index
517  type(field_def), pointer :: parent => null()
518  integer :: field_type
519  integer :: length
520  integer :: array_dim
521  integer :: max_index
522  type(field_def), pointer :: first_field => null()
523  type(field_def), pointer :: last_field => null()
524  integer, pointer, dimension(:) :: i_value => null()
525  logical, pointer, dimension(:) :: l_value => null()
526  real, pointer, dimension(:) :: r_value => null()
527  character(len=fm_string_len), pointer, dimension(:) :: s_value => null()
528  type(field_def), pointer :: next => null()
529  type(field_def), pointer :: prev => null()
530 end type field_def !}
531 
532 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
533 ! Private types
534 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
535 
536 type(field_mgr_type), private :: fields(max_fields)
537 
538 
539 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
540 ! Private variables
541 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
542 
543 character(len=fm_path_name_len) :: loop_list
544 character(len=fm_type_name_len) :: field_type_name(num_types)
545 character(len=fm_field_name_len) :: save_root_name
546 ! The string set is the set of characters.
547 character(len=52) :: set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
548 ! If a character in the string being parsed matches a character within
549 ! the string set_nonexp then the string being parsed cannot be a number.
550 character(len=50) :: set_nonexp = "ABCDFGHIJKLMNOPQRSTUVWXYZabcdfghijklmnopqrstuvwxyz"
551 ! If a character in the string being parsed matches a character within
552 ! the string setnum then the string may be a number.
553 character(len=13) :: setnum = "0123456789+-."
554 integer :: num_fields = 0
555 integer :: verb = 0
556 integer :: verb_level_warn = 0
557 integer :: verb_level_note = 0
558 integer :: default_verbosity = 0
559 integer :: max_verbosity = 1
560 type(field_def), pointer :: loop_list_p => null()
561 type(field_def), pointer :: current_list_p => null()
562 type(field_def), pointer :: root_p => null()
563 type(field_def), pointer :: save_root_parent_p => null()
564 type(field_def), target, save :: root
565 
566 
567 contains
568 
569 ! <SUBROUTINE NAME="field_manager_init">
570 ! <OVERVIEW>
571 ! Routine to initialize the field manager.
572 ! </OVERVIEW>
573 ! <DESCRIPTION>
574 ! This routine reads from a file containing formatted strings.
575 ! These formatted strings contain information on which schemes are
576 ! needed within various modules. The field manager does not
577 ! initialize any of those schemes however. It simply holds the
578 ! information and is queried by the appropriate module.
579 ! </DESCRIPTION>
580 ! <TEMPLATE>
581 ! call field_manager_init(nfields, table_name)
582 ! </TEMPLATE>
583 
584 subroutine field_manager_init(nfields, table_name)
586 ! <OUT NAME="nfields" TYPE="integer">
587 ! The number of fields.
588 ! </OUT>
589 
590 integer, intent(out), optional :: nfields
591 
592 ! <IN NAME="table_name" TYPE="character, optional"
593 ! DIM="(len=128)" DEFAULT="field_table">
594 ! The name of the field table. The default name is field_table.
595 ! </IN>
596 
597 character(len=fm_string_len), intent(in), optional :: table_name
598 
599 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
600 ! local parameters
601 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
602 character(len=18), parameter :: sub_name = 'field_manager_init'
603 character(len=64), parameter :: error_header = '==>Error from ' // trim(module_name) // &
604  '(' // trim(sub_name) // '): '
605 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
606  '(' // trim(sub_name) // '): '
607 character(len=64), parameter :: note_header = '==>Note from ' // trim(module_name) // &
608  '(' // trim(sub_name) // '): '
609 
610 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
611 ! local variables
612 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
613 character(len=1024) :: record
614 character(len=fm_path_name_len) :: control_str
615 character(len=fm_path_name_len) :: list_name
616 character(len=fm_path_name_len) :: method_name
617 character(len=fm_path_name_len) :: name_str
618 character(len=fm_path_name_len) :: type_str
619 character(len=fm_path_name_len) :: val_name
620 character(len=fm_string_len) :: tbl_name
621 integer :: control_array(max_fields,3)
622 integer :: endcont
623 integer :: icount
624 integer :: index_list_name
625 integer :: iunit
626 integer :: l
627 integer :: log_unit
628 integer :: ltrec
629 integer :: m
630 integer :: midcont
631 integer :: model
632 integer :: startcont
633 logical :: flag_method
634 logical :: fm_success
635 type(field_names_type_short) :: text_names_short
636 type(field_names_type) :: text_names
637 type(method_type_short) :: text_method_short
638 type(method_type) :: text_method
639 type(method_type_very_short) :: text_method_very_short
640 
641 
642 
643 if (module_is_initialized) then
644  if(present(nfields)) nfields = num_fields
645  return
646 endif
647 
648 #ifdef PRESERVE_UNIT_CASE
649 ! <ERROR MSG="Preserving the unit's case is experimental." STATUS="NOTE">
650 ! The case of the units in the field_table is preserved. This option is
651 ! still experimental. It is possible other model components expect the units
652 ! to be lowercase. Please notify the developers if any issues are discovered.
653 ! </ERROR>
654 call mpp_error(note,trim(note_header)//"Preserving the unit's case is experimental.")
655 #endif
656 
657 num_fields = 0
658 call initialize
659 
660 call mpp_io_init()
661 
662 if (.not.PRESENT(table_name)) then
663  tbl_name = 'field_table'
664 else
665  tbl_name = trim(table_name)
666 endif
667 
668 if (.not. file_exist(trim(tbl_name))) then
669 ! <ERROR MSG="No field table available, so no fields are being registered." STATUS="NOTE">
670 ! The field table does not exist.
671 ! </ERROR>
672 if (mpp_pe() == mpp_root_pe()) then
673  if (verb .gt. verb_level_warn) then
674  call mpp_error(note, trim(warn_header)// &
675  'No field table ('//trim(tbl_name)//') available, so no fields are being registered.')
676  endif
677 endif
678 if(present(nfields)) nfields = 0
679 return
680 endif
681 
682 
683 call mpp_open(iunit,file=trim(tbl_name), form=mpp_ascii, action=mpp_rdonly)
684 !write_version_number should precede all writes to stdlog from field_manager
685 call write_version_number("FIELD_MANAGER_MOD", version)
686 log_unit = stdlog()
687 do while (.true.)
688  read(iunit,'(a)',end=89,err=99) record
689  write( log_unit,'(a)' )record
690  if (record(1:1) == "#" ) cycle
691  ltrec = len_trim(record)
692  if (ltrec .le. 0 ) cycle ! Blank line
693 
694 
695  icount = 0
696  do l= 1, ltrec
697  if (record(l:l) == '"' ) then
698  icount = icount + 1
699  endif
700  enddo
701 ! <ERROR MSG="Too many fields in field table header entry." STATUS="FATAL">
702 ! There are more that 3 fields in the field table header entry.
703 ! The entry should look like <BR/>
704 ! "Field_Type","Model_Type","Field_Name" <BR/>
705 ! or<BR/>
706 ! "Field_Type","Model_Type"
707 ! </ERROR>
708  if (icount > 6 ) then
709  call mpp_error(fatal,trim(error_header)//'Too many fields in field table header entry.'//trim(record))
710  endif
711 
712  select case (icount)
713  case (6)
714  read(record,*,end=79,err=79) text_names
715  text_names%fld_type = lowercase(trim(text_names%fld_type))
716  text_names%mod_name = lowercase(trim(text_names%mod_name))
717  text_names%fld_name = lowercase(trim(text_names%fld_name))
718  case(4)
719 ! If there is no control string then the last string can be omitted and there are only 4 '"' in the record.
720  read(record,*,end=79,err=79) text_names_short
721  text_names%fld_type = lowercase(trim(text_names_short%fld_type))
722  text_names%mod_name = lowercase(trim(text_names_short%mod_name))
723  text_names%fld_name = lowercase(trim(text_names_short%mod_name))
724  case(2)
725 ! If there is only the method_type string then the last 2 strings need to be blank and there are only 2 '"' in the record.
726  read(record,*,end=79,err=79) text_names_short
727  text_names%fld_type = lowercase(trim(text_names_short%fld_type))
728  text_names%mod_name = lowercase(trim(text_names_short%mod_name))
729  text_names%fld_name = lowercase(trim(text_names_short%mod_name))
730  case default
731 ! <ERROR MSG="Unterminated field in field table header entry." STATUS="FATAL">
732 ! There is an unterminated or unquoted string in the field table entry.
733  text_names%fld_type = " "
734  text_names%mod_name = lowercase(trim(record))
735  text_names%fld_name = " "
736 ! call mpp_error(FATAL,trim(error_header)//'Unterminated field in field_table header entry.'//trim(record))
737 ! </ERROR>
738  end select
739 
740 ! Create a list with Rick Slaters field manager code
741 
742  list_name = list_sep//trim(text_names%mod_name)//list_sep//trim(text_names%fld_type)//&
743  list_sep//trim(text_names%fld_name)
744  if (mpp_pe() == mpp_root_pe() ) then
745  if (verb .gt. verb_level_note) then
746 ! <ERROR MSG="Creating list name = list_name." STATUS="NOTE">
747 ! A field is being created called list_name.
748 ! </ERROR>
749  call mpp_error(note, trim(note_header)//'Creating list name = '//trim(list_name))
750  endif
751  endif
752 
753  index_list_name = fm_new_list(list_name, create = .true.)
754 ! <ERROR MSG="Could not set field list for list_name." STATUS="FATAL">
755 ! A field called list_name could not be created.
756 ! </ERROR>
757  if ( index_list_name == no_field ) &
758  call mpp_error(fatal, trim(error_header)//'Could not set field list for '//trim(list_name))
759 
760  fm_success = fm_change_list(list_name)
761  select case (text_names%mod_name)
762  case ('coupler_mod')
763  model = model_coupler
764  case ('atmos_mod')
765  model = model_atmos
766  case ('ocean_mod')
767  model = model_ocean
768  case ('land_mod')
769  model = model_land
770  case ('ice_mod')
771  model = model_ice
772  case default
773 ! <ERROR MSG="The model name is unrecognised : model_name" STATUS="FATAL">
774 ! The model name being supplied in the field entry is unrecognised.
775 ! This should be the second string in the first line of the field entry.
776 ! Recognised names are atmos_mod, ice_mod, land_mod and ocean_mod.
777 ! </ERROR>
778  call mpp_error(fatal, trim(error_header)//'The model name is unrecognised : '//trim(text_names%mod_name))
779  end select
780  if (find_field_index(list_name) > 0) then
781  num_fields = num_fields + 1
782 
783 
784 ! <ERROR MSG="max fields exceeded" STATUS="FATAL">
785 ! Maximum number of fields for this module has been exceeded.
786 ! </ERROR>
787  if (num_fields > max_fields) call mpp_error(fatal,trim(error_header)//'max fields exceeded')
788  fields(num_fields)%model = model
789  fields(num_fields)%field_name = lowercase(trim(text_names%fld_name))
790  fields(num_fields)%field_type = lowercase(trim(text_names%fld_type))
791  fields(num_fields)%num_methods = 0
793 
794 ! Check to see that the first line is not the only line
795  if ( record(len_trim(record):len_trim(record)) == list_sep) cycle
796 
797  flag_method = .true.
798  m = 1
799  do while (flag_method)
800  read(iunit,'(a)',end=99,err=99) record
801 ! If the line is blank then fetch the next line.
802  if (len_trim(record) .le. 0) cycle
803 ! If the last character in the line is / then this is the end of the field methods
804  if ( record(len_trim(record):len_trim(record)) == list_sep) then
805  flag_method = .false.
806  if (len_trim(record) == 1) cycle
807  record = record(:len_trim(record)-1) ! Remove the end of field method marker
808  endif
809 ! If the line is now blank, after removing the field separator marker, then fetch the next line.
810  if (len_trim(record) .le. 0) cycle
811 ! If the first character in the line is # then it is treated as a comment
812  if (record(1:1) == comment ) cycle
813 
814  icount = 0
815  do l= 1, len_trim(record)
816  if (record(l:l) == dquote ) then
817  icount = icount + 1
818  endif
819  enddo
820 ! <ERROR MSG="Too many fields in field entry." STATUS="FATAL">
821 ! There are more that 3 fields in the tracer entry. This is probably due
822 ! to separating the parameters entry into multiple strings.
823 ! The entry should look like <BR/>
824 ! "Type","Name","Control1=XXX,Control2=YYY" <BR/>
825 ! and not like<BR/>
826 ! "Type","Name","Control1=XXX","Control2=YYY"
827 ! </ERROR>
828  if (icount > 6 ) call mpp_error(fatal,trim(error_header)//'Too many fields in field entry.'//trim(record))
829 
830  if (.not. fm_change_list( list_name)) &
831  call mpp_error(fatal, trim(error_header)//'Could not change to '//trim(list_name)//' list')
832 
833  select case (icount)
834  case (6)
835  read(record,*,end=99,err=99) text_method
836  fields(num_fields)%methods(m)%method_type = lowercase(trim(text_method%method_type))
837  fields(num_fields)%methods(m)%method_name = lowercase(trim(text_method%method_name))
838  fields(num_fields)%methods(m)%method_control = lowercase(trim(text_method%method_control))
839 
840  type_str = text_method%method_type
841  name_str = text_method%method_name
842  control_str = text_method%method_control
843 
844  case(4)
845 ! If there is no control string then the last string can be omitted and there are only 4 '"' in the record.
846  read(record,*,end=99,err=99) text_method_short
847  fields(num_fields)%methods(m)%method_type =&
848  & lowercase(trim(text_method_short%method_type))
849 #ifdef PRESERVE_UNIT_CASE
850 
851  if ( trim(fields(num_fields)%methods(m)%method_type) == 'units' ) then
852  ! Do not lowercase if units
853  fields(num_fields)%methods(m)%method_name =&
854  & trim(text_method_short%method_name)
855  else
856  fields(num_fields)%methods(m)%method_name =&
857  & lowercase(trim(text_method_short%method_name))
858  end if
859 #else
860  fields(num_fields)%methods(m)%method_name =&
861  & lowercase(trim(text_method_short%method_name))
862 #endif
863  fields(num_fields)%methods(m)%method_control = " "
864 
865  type_str = text_method_short%method_type
866  name_str = ""
867  control_str = text_method_short%method_name
868 
869  case(2)
870 ! If there is only the method_type string then the last 2 strings need to be blank and there are only 2 '"' in the record.
871  read(record,*,end=99,err=99) text_method_very_short
872  fields(num_fields)%methods(m)%method_type = lowercase(trim(text_method_very_short%method_type))
873  fields(num_fields)%methods(m)%method_name = " "
874  fields(num_fields)%methods(m)%method_control = " "
875 
876  type_str = ""
877  name_str = ""
878  control_str = text_method_very_short%method_type
879 
880  case(0)
881  read(record,'(A)',end=99,err=99) control_str
882  type_str = ""
883  name_str = ""
884 
885  case default
886 ! <ERROR MSG="Unterminated field in field entry." STATUS="FATAL">
887 ! There is an unterminated or unquoted string in the field table entry.
888  call mpp_error(fatal,trim(error_header)//'Unterminated field in field entry.'//trim(record))
889 ! </ERROR>
890  end select
891 
892 ! This section of code breaks the control string into separate strings.
893 ! The array control_array contains the following parameters.
894 ! control_array(:,1) = index within control_str of the first character of the name.
895 ! control_array(:,2) = index within control_str of the equal sign
896 ! control_array(:,3) = index within control_str of the last character of the value.
897 !
898 ! control_array(:,1) -> control_array(:,2) -1 = name of the parameter.
899 ! control_array(:,2)+1 -> control_array(:,3) = value of the parameter.
900 
901  ltrec= len_trim(control_str)
902  control_array(:,1) = 1
903  control_array(:,2:3) = ltrec
904  icount = 0
905  do l= 1, ltrec
906  if (control_str(l:l) == equal ) then
907  icount = icount + 1
908  control_array(icount,2) = l ! Middle of string
909  elseif (control_str(l:l) == comma ) then
910  if (icount .eq. 0) then
911 
912 ! <ERROR MSG="Unterminated field in field entry." STATUS="FATAL">
913 ! Bad format for field entry (comma without equals sign)
914  call mpp_error(fatal,trim(error_header) // &
915  ' Bad format for field entry (comma without equals sign): ''' // &
916  trim(control_str) // '''')
917 ! </ERROR>
918 
919  elseif (icount .gt. max_fields) then
920 
921 ! <ERROR MSG="Unterminated field in field entry." STATUS="FATAL">
922 ! Too many fields in field entry
923  call mpp_error(fatal,trim(error_header) // &
924  ' Too many fields in field entry: ''' // &
925  trim(control_str) // '''')
926 ! </ERROR>
927 
928  else
929 
930  control_array(icount,3) = l-1 !End of previous string
931  control_array(min(max_fields,icount+1),1) = l+1 !Start of next string
932 
933  endif
934  endif
935  enddo
936 
937  ! Make sure that we point to the end of the string (minus any trailing comma)
938  ! for the last set of values. This fixes the case where the last set of values
939  ! is a comma separated list
940 
941  if (control_str(ltrec:ltrec) .ne. comma) then
942  control_array(max(1,icount),3) = ltrec
943  endif
944 
945 
946  if ( icount == 0 ) then
947  method_name = type_str
948  if (len_trim(method_name) > 0 ) then
949  method_name = trim(method_name)//list_sep// trim(name_str)
950  else
951  method_name = trim(name_str)
952  endif
953  val_name = control_str
954 
955  call new_name(list_name, method_name, val_name )
956 
957  else
958 
959  do l = 1,icount
960  startcont = control_array(l,1)
961  midcont = control_array(l,2)
962  endcont = control_array(l,3)
963 
964  method_name = trim(type_str)
965  if (len_trim(method_name) > 0 ) then
966  method_name = trim(method_name)//list_sep// trim(name_str)
967  else
968  method_name = trim(name_str)
969  endif
970 
971  if (len_trim(method_name) > 0 ) then
972  method_name = trim(method_name)//list_sep//&
973  trim(control_str(startcont:midcont-1))
974  else
975  method_name = trim(control_str(startcont:midcont-1))
976  endif
977  val_name = trim(control_str(midcont+1:endcont))
978 
979  call new_name(list_name, method_name, val_name )
980  enddo
981 
982  endif
983 
984  fields(num_fields)%num_methods = fields(num_fields)%num_methods + 1
985 ! <ERROR MSG="Maximum number of methods for field exceeded" STATUS="FATAL">
986 ! Maximum number of methods allowed for entries in the field table has been exceeded.
987 ! </ERROR>
988  if (fields(num_fields)%num_methods > max_field_methods) &
989  call mpp_error(fatal,trim(error_header)//'Maximum number of methods for field exceeded')
990  m = m + 1
991  enddo
992  else
993 
994 ! <ERROR MSG="Field with identical name and model name duplicate found, skipping" STATUS="NOTE">
995 ! The name of the field and the model name are identical. Skipping that field.
996 ! </ERROR>
997  if (mpp_pe() == 0) then
998  if (verb .gt. verb_level_warn) then
999  call mpp_error(warning, trim(warn_header)// &
1000  'Field with identical name and model name duplicate found, skipping')
1001  endif
1002  endif
1003  flag_method = .true.
1004  do while (flag_method)
1005  read(iunit,'(A)',end=99,err=99) record
1006  if ( record(len_trim(record):len_trim(record)) == list_sep) then
1007  flag_method = .false.
1008  endif
1009  enddo
1010  endif
1011 79 continue
1012 enddo
1013 
1014 89 continue
1015 close(iunit)
1016 
1017 if(present(nfields)) nfields = num_fields
1018 if (verb .gt. verb_level_warn) &
1019  fm_success= fm_dump_list("/", .true.)
1020 
1021 default_method%method_type = 'none'
1022 default_method%method_name = 'none'
1023 default_method%method_control = 'none'
1024 return
1025 
1026 99 continue
1027 
1028 ! <ERROR MSG="error reading field table" STATUS="FATAL">
1029 ! There is an error in reading the field table.
1030 ! </ERROR>
1031 call mpp_error(fatal,trim(error_header)//' Error reading field table. Record = '//trim(record))
1032 
1033 end subroutine field_manager_init
1034 ! </SUBROUTINE>
1035 
1036 subroutine check_for_name_duplication
1037 integer :: i
1038 
1039 ! Check that name is unique amoung fields of the same field_type and model.
1040 do i=1,num_fields-1
1041  if ( fields(i)%field_type == fields(num_fields)%field_type .and. &
1042  fields(i)%model == fields(num_fields)%model .and. &
1043  fields(i)%field_name == fields(num_fields)%field_name ) then
1044  if (mpp_pe() .eq. mpp_root_pe()) then
1045  call mpp_error(warning,'Error in field_manager_mod. Duplicate field name: Field type='//trim(fields(i)%field_type)// &
1046  ', Model='//trim(model_names(fields(i)%model))// &
1047  ', Duplicated name='//trim(fields(i)%field_name))
1048  endif
1049  endif
1050 enddo
1051 
1052 end subroutine check_for_name_duplication
1053 
1054 !#######################################################################
1055 !#######################################################################
1056 
1057 ! <PRIVATE><SUBROUTINE NAME="new_name">
1058 ! <OVERVIEW>
1059 ! Subroutine to add new values to list parameters.
1060 ! </OVERVIEW>
1061 ! <DESCRIPTION>
1062 ! This subroutine uses input strings list_name, method_name
1063 ! and val_name_in to add new values to the list. Given
1064 ! list_name a new list item is created that is named
1065 ! method_name and is given the value or values in
1066 ! val_name_in. If there is more than 1 value in
1067 ! val_name_in, these values should be comma-separated.
1068 ! </DESCRIPTION>
1069 ! <TEMPLATE>
1070 ! call new_name ( list_name, method_name , val_name_in)
1071 ! </TEMPLATE>
1072 subroutine new_name ( list_name, method_name_in , val_name_in)
1073 ! <IN NAME="list_name" TYPE="character(len=*)">
1074 ! The name of the field that is of interest here.
1075 ! </IN>
1076 ! <IN NAME="method_name" TYPE="character(len=*)">
1077 ! The name of the method that values are being supplied for.
1078 ! </IN>
1079 character(len=*), intent(in) :: list_name
1080 character(len=*), intent(in) :: method_name_in
1081 ! <INOUT NAME="val_name_in" TYPE="character(len=*)">
1082 ! The value or values that will be parsed and used as the value when
1083 ! creating a new field or fields.
1084 ! </INOUT>
1085 character(len=*), intent(inout) :: val_name_in
1086 
1087 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1088 ! local parameters
1089 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1090 character(len=8), parameter :: sub_name = 'new_name'
1091 character(len=64), parameter :: error_header = '==>Error from ' // trim(module_name) // &
1092  '(' // trim(sub_name) // '): '
1093 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
1094  '(' // trim(sub_name) // '): '
1095 character(len=64), parameter :: note_header = '==>Note from ' // trim(module_name) // &
1096  '(' // trim(sub_name) // '): '
1097 
1098 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1099 ! local variables
1100 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1101 character(len=fm_string_len) :: method_name
1102 character(len=fm_string_len) :: val_list
1103 character(len=fm_string_len) :: val_name
1104 integer, dimension(MAX_FIELDS) :: end_val
1105 integer, dimension(MAX_FIELDS) :: start_val
1106 integer :: i
1107 integer :: index_t
1108 integer :: left_br
1109 integer :: num_elem
1110 integer :: out_unit
1111 integer :: right_br
1112 integer :: val_int
1113 integer :: val_type
1114 logical :: append_new
1115 logical :: val_logic
1116 real :: val_real
1117 integer :: length
1118 
1119 call strip_front_blanks(val_name_in)
1120 method_name = trim(method_name_in)
1121 call strip_front_blanks(method_name)
1122 
1123 index_t = 1
1124 num_elem = 1
1125 append_new = .false.
1126 start_val(1) = 1
1127 end_val(:) = len_trim(val_name_in)
1128 
1129 ! If the array of values being passed in is a comma delimited list then count
1130 ! the number of elements.
1131 
1132 do i = 1, len_trim(val_name_in)
1133  if ( val_name_in(i:i) == comma ) then
1134  end_val(num_elem) = i-1
1135  start_val(num_elem+1) = i+1
1136  num_elem = num_elem + 1
1137  endif
1138 enddo
1139 
1140 ! Check to see if this is an array element of form array[x] = value
1141 left_br = scan(method_name,'[')
1142 right_br = scan(method_name,']')
1143 if ( num_elem .eq. 1 ) then
1144 ! <ERROR MSG="Left bracket present without right bracket in method_name" STATUS="FATAL">
1145 ! When using an array element an unpaired bracket was found.
1146 ! </ERROR>
1147  if ( left_br > 0 .and. right_br == 0 ) &
1148  call mpp_error(fatal, trim(error_header)//"Left bracket present without right bracket in "//trim(method_name))
1149 ! <ERROR MSG="Right bracket present without left bracket in method_name" STATUS="FATAL">
1150 ! When using an array element an unpaired bracket was found.
1151 ! </ERROR>
1152  if ( left_br== 0 .and. right_br > 0 ) &
1153  call mpp_error(fatal, trim(error_header)//"Right bracket present without left bracket in "//trim(method_name))
1154 
1155 
1156  if ( left_br > 0 .and. right_br > 0 ) then
1157 ! <ERROR MSG="Using a non-numeric value for index in method_name" STATUS="FATAL">
1158 ! An array assignment was requested but a non-numeric value was found. i.e. array[a] = 1
1159 ! </ERROR>
1160  if ( scan( method_name(left_br+1:right_br -1), set ) > 0 ) &
1161  call mpp_error(fatal, trim(error_header)//"Using a non-numeric value for index in "//trim(method_name))
1162  read(method_name(left_br+1:right_br -1), *) index_t
1163  method_name = method_name(:left_br -1)
1164  endif
1165 else
1166 ! If there are multiple values then there cannot be a bracket in method_name.
1167 ! <ERROR MSG="Using a comma delimited list with an indexed array element in method_name" STATUS="FATAL">
1168 ! When supplying multiple values an index was found. i.e array[3] = 4,5,6 is invalid.
1169 ! </ERROR>
1170  if ( left_br > 0 .or. right_br > 0 ) &
1171  call mpp_error(fatal, &
1172  trim(error_header)//"Using a comma delimited list with an indexed array element in "//trim(method_name))
1173 
1174 endif
1175 
1176 do i = 1, num_elem
1177 
1178  if ( i .gt. 1 .or. index_t .eq. 0 ) then
1179  append_new = .true.
1180  index_t = 0 ! If append is true then index must be <= 0
1181  endif
1182  val_type = string_type ! Assume it is a string
1183  val_name = val_name_in(start_val(i):end_val(i))
1184  call strip_front_blanks(val_name)
1185 
1186 
1187 !
1188 ! if the string starts and ends with matching single quotes, then this is a string
1189 ! if there are quotes which do not match, then this is an error
1190 !
1191 
1192  length = len_trim(val_name)
1193  if (val_name(1:1) .eq. squote) then !{
1194 
1195  if (val_name(length:length) .eq. squote) then
1196  val_name = val_name(2:length-1)
1197  val_type = string_type
1198  elseif (val_name(length:length) .eq. dquote) then
1199  call mpp_error(fatal, trim(error_header) // ' Quotes do not match in ' // trim(val_name) // &
1200  ' for ' // trim(method_name) // ' of ' // trim(list_name))
1201  else
1202  call mpp_error(fatal, trim(error_header) // ' No trailing quote in ' // trim(val_name) // &
1203  ' for ' // trim(method_name) // ' of ' // trim(list_name))
1204  endif
1205 
1206  elseif (val_name(1:1) .eq. dquote .or. val_name(length:length) .eq. dquote) then !}{
1207 
1208  call mpp_error(fatal, trim(error_header) // ' Double quotes not allowed in ' // trim(val_name) // &
1209  ' for ' // trim(method_name) // ' of ' // trim(list_name))
1210 
1211  elseif (val_name(length:length) .eq. squote) then !}{
1212 
1213  call mpp_error(fatal, trim(error_header) // ' No leading quote in ' // trim(val_name) // &
1214  ' for ' // trim(method_name) // ' of ' // trim(list_name))
1215 
1216  else !}{
1217 ! If the string to be parsed is a real then all the characters must be numeric,
1218 ! be a plus/minus, be a decimal point or, for exponentials, be e or E.
1219 
1220 ! If a string is an integer, then all the characters must be numeric.
1221 
1222  if ( scan(val_name(1:1), setnum ) > 0 ) then
1223 
1224 ! If there is a letter in the name it may only be e or E
1225 
1226  if ( scan(val_name, set_nonexp ) > 0 ) then
1227  if (verb .gt. verb_level_warn) then
1228 ! <ERROR MSG="First character of value is numerical but the value does not appear to be numerical." STATUS="WARNING">
1229 ! The value may not be numerical. This is a warning as the user may wish to use a value of 2nd_order.
1230 ! </ERROR>
1231  call mpp_error(warning, trim(warn_header)// &
1232  'First character of value is numerical but the value does not appear to be numerical.')
1233  call mpp_error(warning, 'Name = '// trim(list_name)// list_sep// &
1234  trim(method_name)// ' Value = '// trim(val_name))
1235  endif
1236 
1237  else
1238 ! It is real if there is a . in the name or the value appears exponential
1239  if ( scan(val_name, '.') > 0 .or. scan(val_name, 'e') > 0 .or. scan(val_name, 'E') > 0) then
1240  read(val_name, *) val_real
1241  val_type = real_type
1242  else
1243  read(val_name, *) val_int
1244  val_type = integer_type
1245  endif
1246  endif
1247 
1248  endif
1249 
1250 ! If val_name is t/T or f/F then this is a logical flag.
1251  if ( len_trim(val_name) == 1 .or. len_trim(val_name) == 3) then
1252  if ( val_name == 't' .or. val_name == 'T' .or. val_name == '.t.' .or. val_name == '.T.' ) then
1253  val_logic = .true.
1254  val_type = logical_type
1255  endif
1256  if ( val_name == 'f' .or. val_name == 'F' .or. val_name == '.f.' .or. val_name == '.F.' ) then
1257  val_logic = .false.
1258  val_type = logical_type
1259  endif
1260  endif
1261  if ( trim(lowercase(val_name)) == 'true' .or. trim(lowercase(val_name)) == '.true.' ) then
1262  val_logic = .true.
1263  val_type = logical_type
1264  endif
1265  if ( trim(lowercase(val_name)) == 'false' .or. trim(lowercase(val_name)) == '.false.' ) then
1266  val_logic = .false.
1267  val_type = logical_type
1268  endif
1269  endif !}
1270 
1271  select case(val_type)
1272 
1273  case (integer_type)
1274  if ( fm_new_value( method_name, val_int, create = .true., index = index_t, append = append_new ) < 0 ) &
1275  call mpp_error(fatal, trim(error_header)//'Could not set "' // trim(val_name) // '" for '//trim(method_name)//&
1276  ' (I) for '//trim(list_name))
1277 
1278  case (logical_type)
1279  if ( fm_new_value( method_name, val_logic, create = .true., index = index_t, append = append_new) < 0 ) &
1280  call mpp_error(fatal, trim(error_header)//'Could not set "' // trim(val_name) // '" for '//trim(method_name)//&
1281  ' (L) for '//trim(list_name))
1282 
1283  case (real_type)
1284  if ( fm_new_value( method_name, val_real, create = .true., index = index_t, append = append_new) < 0 ) &
1285  call mpp_error(fatal, trim(error_header)//'Could not set "' // trim(val_name) // '" for '//trim(method_name)//&
1286  ' (R) for '//trim(list_name))
1287 
1288  case (string_type)
1289  if ( fm_new_value( method_name, val_name, create = .true., index = index_t, append = append_new) < 0 ) &
1290  call mpp_error(fatal, trim(error_header)//'Could not set "' // trim(val_name) // '" for '//trim(method_name)//&
1291  ' (S) for '//trim(list_name))
1292  case default
1293  call mpp_error(fatal, trim(error_header)//'Could not find a valid type to set the '//trim(method_name)//&
1294  ' for '//trim(list_name))
1295 
1296  end select
1297 
1298  if (mpp_pe() == mpp_root_pe() ) then
1299  if (verb .gt. verb_level_note) then
1300  out_unit = stdout()
1301  write (out_unit,*) trim(note_header), 'Creating new value = ', trim(method_name), ' ', trim(val_name)
1302  endif
1303  endif
1304 
1305 enddo
1306 
1307 end subroutine new_name
1308 !</SUBROUTINE>
1309 !</PRIVATE>
1310 !#######################################################################
1311 !#######################################################################
1312 
1313 ! <SUBROUTINE NAME="field_manager_end">
1314 ! <OVERVIEW>
1315 ! Destructor for field manager.
1316 ! </OVERVIEW>
1317 ! <DESCRIPTION>
1318 ! This subroutine writes to the logfile that the user is exiting field_manager and
1319 ! changes the initialized flag to false.
1320 ! </DESCRIPTION>
1321 ! <TEMPLATE>
1322 ! call field_manager_end
1323 ! </TEMPLATE>
1324 subroutine field_manager_end
1326 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1327 ! local parameters
1328 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1329 character(len=17), parameter :: sub_name = 'field_manager_end'
1330 character(len=64), parameter :: note_header = '==>Note from ' // trim(module_name) // &
1331  '(' // trim(sub_name) // '): '
1332 
1333 integer :: unit
1334 
1335 call write_version_number("FIELD_MANAGER_MOD", version)
1336 if ( mpp_pe() == mpp_root_pe() ) then
1337  unit = stdlog()
1338  write (unit,'(/,(a))') trim(note_header), 'Exiting field_manager, have a nice day ...'
1339  unit = stdout()
1340  write (unit,'(/,(a))') trim(note_header), 'Exiting field_manager, have a nice day ...'
1341 endif
1342 
1343 module_is_initialized = .false.
1344 
1345 end subroutine field_manager_end
1346 ! </SUBROUTINE>
1347 
1348 !#######################################################################
1349 !#######################################################################
1350 
1351 ! <SUBROUTINE NAME="strip_front_blanks">
1352 ! <OVERVIEW>
1353 ! A routine to strip whitespace from the start of character strings.
1354 ! </OVERVIEW>
1355 ! <DESCRIPTION>
1356 ! This subroutine removes spaces and tabs from the start of a character string.
1357 ! </DESCRIPTION>
1358 ! <TEMPLATE>
1359 ! call strip_front_blanks(name)
1360 ! </TEMPLATE>
1361 subroutine strip_front_blanks(name)
1363 character(len=*), intent(inout) :: name
1364 
1365 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1366 ! local parameters
1367 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1368 
1369 integer :: i, j
1370 
1371 j = 1
1372 do i = 1,len_trim(name) !{
1373  if ( .not. (name(i:i) .eq. space .or. &
1374  name(i:i) .eq. tab)) then !{
1375  j = i
1376  exit
1377  endif !}
1378 enddo !}
1379 name = name(j:)
1380 end subroutine strip_front_blanks
1381 !</SUBROUTINE>
1382 
1383 !#######################################################################
1384 !#######################################################################
1385 
1386 ! <FUNCTION NAME="find_field_index">
1387 ! <OVERVIEW>
1388 ! Function to return the index of the field.
1389 ! </OVERVIEW>
1390 ! <DESCRIPTION>
1391 ! This function when passed a model number and a field name will
1392 ! return the index of the field within the field manager. This index
1393 ! can be used to access other information from the field manager.
1394 ! </DESCRIPTION>
1395 ! <TEMPLATE>
1396 ! value=find_field_index( model, field_name )
1397 ! value=find_field_index( field_name )
1398 ! </TEMPLATE>
1399 
1400 function find_field_index_old(model, field_name)
1401 !
1402 ! <IN NAME="model" TYPE="integer">
1403 ! The number indicating which model is used.
1404 ! </IN>
1405 ! <IN NAME="field_name" TYPE="character">
1406 ! The name of the field that an index is being requested for.
1407 ! </IN>
1408 ! <OUT NAME="find_field_index" TYPE="integer">
1409 ! The index of the field corresponding to field_name.
1410 ! </OUT>
1411 
1412 integer :: find_field_index_old
1413 integer, intent(in) :: model
1414 character(len=*), intent(in) :: field_name
1415 
1416 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1417 ! local parameters
1418 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1419 integer :: i
1420 
1422 
1423 do i=1,num_fields
1424  if (fields(i)%model == model .and. fields(i)%field_name == lowercase(field_name)) then
1426  return
1427  endif
1428 enddo
1429 
1430 end function find_field_index_old
1431 
1432 function find_field_index_new(field_name)
1433 !
1434 ! <IN NAME="field_name" TYPE="character">
1435 ! The path to the name of the field that an index is being requested for.
1436 ! </IN>
1437 ! <OUT NAME="find_field_index" TYPE="integer">
1438 ! The index of the field corresponding to field_name.
1439 ! </OUT>
1440 
1441 integer :: find_field_index_new
1442 character(len=*), intent(in) :: field_name
1443 
1444 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1445 ! local parameters
1446 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1447 integer :: i
1448 
1450 
1451 find_field_index_new = fm_get_index(field_name)
1452 
1453 end function find_field_index_new
1454 ! </FUNCTION>
1455 
1456 !#######################################################################
1457 !#######################################################################
1458 
1459 ! <SUBROUTINE NAME="get_field_info">
1460 ! <OVERVIEW>
1461 ! This routine allows access to field information given an index.
1462 ! </OVERVIEW>
1463 ! <DESCRIPTION>
1464 ! When passed an index, this routine will return the type of field,
1465 ! the name of the field, the model which the field is associated and
1466 ! the number of methods associated with the field.
1467 ! </DESCRIPTION>
1468 ! <TEMPLATE>
1469 ! call get_field_info( n,fld_type,fld_name,model,num_methods )
1470 ! </TEMPLATE>
1471 subroutine get_field_info(n,fld_type,fld_name,model,num_methods)
1473 ! <IN NAME="n" TYPE="integer">
1474 ! The field index.
1475 ! </IN>
1476 integer, intent(in) :: n
1477 
1478 ! <OUT NAME="fld_type" TYPE="character" DIM="(*)">
1479 ! The field type.
1480 ! </OUT>
1481 
1482 ! <OUT NAME="fld_name" TYPE="character" DIM="(*)">
1483 ! The name of the field.
1484 ! </OUT>
1485 
1486 ! <OUT NAME="model" TYPE="integer">
1487 ! The number indicating which model is used.
1488 ! </OUT>
1489 
1490 ! <OUT NAME="num_methods" TYPE="integer">
1491 ! The number of methods.
1492 ! </OUT>
1493 character (len=*),intent(out) :: fld_type, fld_name
1494 integer, intent(out) :: model, num_methods
1495 
1496 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1497 ! local parameters
1498 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1499 character(len=14), parameter :: sub_name = 'get_field_info'
1500 character(len=64), parameter :: error_header = '==>Error from ' // trim(module_name) // &
1501  '(' // trim(sub_name) // '): '
1502 
1503 ! <ERROR MSG="invalid field index" STATUS="FATAL">
1504 ! The field index is invalid because it is less than 1 or greater than the
1505 ! number of fields.
1506 ! </ERROR>
1507 if (n < 1 .or. n > num_fields) call mpp_error(fatal,trim(error_header)//'Invalid field index')
1508 
1509 fld_type = fields(n)%field_type
1510 fld_name = fields(n)%field_name
1511 model = fields(n)%model
1512 num_methods = fields(n)%num_methods
1513 
1514 end subroutine get_field_info
1515 ! </SUBROUTINE>
1516 
1517 !#######################################################################
1518 !#######################################################################
1519 
1520 ! <SUBROUTINE NAME="get_field_method">
1521 ! <OVERVIEW>
1522 ! A routine to get a specified method.
1523 ! </OVERVIEW>
1524 ! <DESCRIPTION>
1525 ! This routine, when passed a field index and a method index will
1526 ! return the method text associated with the field(n) method(m).
1527 ! </DESCRIPTION>
1528 ! <TEMPLATE>
1529 ! call get_field_method( n,m,method )
1530 ! </TEMPLATE>
1531 subroutine get_field_method(n,m,method)
1533 ! <IN NAME="n" TYPE="integer">
1534 ! The field index.
1535 ! </IN>
1536 ! <IN NAME="m" TYPE="integer">
1537 ! The method index.
1538 ! </IN>
1539 ! <OUT NAME="method" TYPE="type(method_type)">
1540 ! The m-th method of field with index n.
1541 ! </OUT>
1542 integer, intent(in) :: n
1543 integer, intent(in) :: m
1544 type(method_type) ,intent(inout) :: method
1545 
1546 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1547 ! local parameters
1548 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1549 character(len=16), parameter :: sub_name = 'get_field_method'
1550 character(len=64), parameter :: error_header = '==>Error from ' // trim(module_name) // &
1551  '(' // trim(sub_name) // '): '
1552 
1553 ! <ERROR MSG="invalid field index" STATUS="FATAL">
1554 ! The field index is invalid because it is less than 1 or greater than the
1555 ! number of fields.
1556 ! </ERROR>
1557 if (n < 1 .or. n > num_fields) call mpp_error(fatal,trim(error_header)//'Invalid field index')
1558 
1559 ! <ERROR MSG="invalid method index" STATUS="FATAL">
1560 ! The method index is invalid because it is less than 1 or greater than
1561 ! the number of methods.
1562 ! </ERROR>
1563 if (m < 1 .or. m > fields(n)%num_methods) call mpp_error(fatal,trim(error_header)//'Invalid method index')
1564 
1565  method = fields(n)%methods(m)
1566 
1567 end subroutine get_field_method
1568 ! </SUBROUTINE>
1569 
1570 !#######################################################################
1571 !#######################################################################
1572 
1573 ! <SUBROUTINE NAME="get_field_methods">
1574 ! <OVERVIEW>
1575 ! A routine to obtain all the methods associated with a field.
1576 ! </OVERVIEW>
1577 ! <DESCRIPTION>
1578 ! When passed a field index, this routine will return the text
1579 ! associated with all the methods attached to the field.
1580 ! </DESCRIPTION>
1581 ! <TEMPLATE>
1582 ! call get_field_methods( n,methods )
1583 ! </TEMPLATE>
1584 subroutine get_field_methods(n,methods)
1586 ! <IN NAME="n" TYPE="integer">
1587 ! The field index.
1588 ! </IN>
1589 ! <OUT NAME="method" TYPE="type(method_type)" DIM="(:)">
1590 ! An array of methods for field with index n.
1591 ! </OUT>
1592 integer, intent(in) :: n
1593 
1594 type(method_type),intent(inout) :: methods(:)
1595 
1596 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1597 ! local parameters
1598 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1599 character(len=17), parameter :: sub_name = 'get_field_methods'
1600 character(len=64), parameter :: error_header = '==>Error from ' // trim(module_name) // &
1601  '(' // trim(sub_name) // '): '
1602 
1603 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1604 ! local variables
1605 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1606 character(len=fm_path_name_len), dimension(size(methods(:))) :: control
1607 character(len=fm_path_name_len), dimension(size(methods(:))) :: method
1608 logical :: found_methods
1609 ! <ERROR MSG="invalid field index" STATUS="FATAL">
1610 ! The field index is invalid because it is less than 1 or greater than the
1611 ! number of fields.
1612 ! </ERROR>
1613  if (n < 1 .or. n > num_fields) &
1614  call mpp_error(fatal,trim(error_header)//'Invalid field index')
1615 
1616 ! <ERROR MSG="method array too small" STATUS="FATAL">
1617 ! The method array is smaller than the number of methods.
1618 ! </ERROR>
1619  if (size(methods(:)) < fields(n)%num_methods) &
1620  call mpp_error(fatal,trim(error_header)//'Method array too small')
1621 
1622  methods = default_method
1623  methods(1:fields(n)%num_methods) = fields(n)%methods(1:fields(n)%num_methods)
1624 
1625 end subroutine get_field_methods
1626 ! </SUBROUTINE>
1627 
1628 !#######################################################################
1629 !#######################################################################
1630 
1631 ! <FUNCTION NAME="parse">
1632 ! <OVERVIEW>
1633 ! A function to parse an integer or an array of integers,
1634 ! a real or an array of reals, a string or an array of strings.
1635 ! </OVERVIEW>
1636 ! <DESCRIPTION>
1637 ! Parse is an integer function that decodes values from a text string.
1638 ! The text string has the form: "label=list" where "label" is an
1639 ! arbitrary user defined label describing the values being decoded,
1640 ! and "list" is a list of one or more values separated by commas.
1641 ! The values may be integer, real, or character.
1642 ! Parse returns the number of values decoded.
1643 ! </DESCRIPTION>
1644 ! <TEMPLATE>
1645 ! number = parse(text, label, value)
1646 ! </TEMPLATE>
1647 
1648 
1649 function parse_reals ( text, label, values ) result (parse)
1651 ! <IN NAME="text" TYPE="character(len=*)">
1652 ! The text string from which the values will be parsed.
1653 ! </IN>
1654 ! <IN NAME="label" TYPE="character(len=*)">
1655 ! A label which describes the values being decoded.
1656 ! </IN>
1657 ! <OUT NAME="value" TYPE="integer, real, character(len=*)">
1658 ! The value or values that have been decoded.
1659 ! </OUT>
1660 ! <OUT NAME="parse" TYPE="integer">
1661 ! The number of values that have been decoded. This allows
1662 ! a user to define a large array and fill it partially with
1663 ! values from a list. This should be the size of the value array.
1664 ! </OUT>
1665 character(len=*), intent(in) :: text, label
1666 real, intent(out) :: values(:)
1667 
1668 include 'parse.inc'
1669 end function parse_reals
1670 ! </FUNCTION>
1671 
1672 !#######################################################################
1673 !#######################################################################
1674 
1675 function parse_integers ( text, label, values ) result (parse)
1676 character(len=*), intent(in) :: text, label
1677 integer, intent(out) :: values(:)
1678 
1679 include 'parse.inc'
1680 end function parse_integers
1681 
1682 !#######################################################################
1683 !#######################################################################
1684 
1685 function parse_strings ( text, label, values ) result (parse)
1686 character(len=*), intent(in) :: text, label
1687 character(len=*), intent(out) :: values(:)
1688 
1689 include 'parse.inc'
1690 end function parse_strings
1691 
1692 !#######################################################################
1693 !#######################################################################
1694 
1695 !---- scalar overloads -----
1696 
1697 function parse_real ( text, label, value ) result (parse)
1698 character(len=*), intent(in) :: text, label
1699 real, intent(out) :: value
1700 integer :: parse
1701 
1702 real :: values(1)
1703 
1704  parse = parse_reals( text, label, values )
1705  if (parse > 0) value = values(1)
1706 end function parse_real
1707 
1708 !#######################################################################
1709 !#######################################################################
1710 
1711 function parse_integer ( text, label, value ) result (parse)
1712 character(len=*), intent(in) :: text, label
1713 integer, intent(out) :: value
1714 integer :: parse
1715 
1716 integer :: values(1)
1717 
1718  parse = parse_integers( text, label, values )
1719  if (parse > 0) value = values(1)
1720 end function parse_integer
1721 
1722 !#######################################################################
1723 !#######################################################################
1724 
1725 function parse_string ( text, label, value ) result (parse)
1726 character(len=*), intent(in) :: text, label
1727 character(len=*), intent(out) :: value
1728 integer :: parse
1729 
1730 character(len=len(value)) :: values(1)
1731 
1732  parse = parse_strings( text, label, values )
1733  if (parse > 0) value = values(1)
1734 end function parse_string
1735 
1736 !#######################################################################
1737 !#######################################################################
1738 
1739 ! <PRIVATE><FUNCTION NAME="create_field">
1740 !
1741 ! <OVERVIEW>
1742 ! A function to create a field as a child of parent_p. This will return
1743 ! a pointer to a field_def type.
1744 ! </OVERVIEW>
1745 ! <DESCRIPTION>
1746 ! Allocate and initialize a new field in parent_p list.
1747 ! Return a pointer to the field on success, or a null pointer
1748 ! on failure.
1749 ! </DESCRIPTION>
1750 ! <TEMPLATE>
1751 ! list_p => create_field(parent_p, name)
1752 ! </TEMPLATE>
1753 !
1754 !
1755 function create_field(parent_p, name) &
1756  result(list_p) !{
1758 ! <IN NAME="parent_p" TYPE="type(field_def), pointer">
1759 ! A pointer to the parent of the field that is to be created.
1760 ! </IN>
1761 ! <IN NAME="name" TYPE="character">
1762 ! The name of the field that is to be created.
1763 ! </IN>
1764 ! <OUT NAME="list_p" TYPE="type(field_def), pointer">
1765 ! A pointer to the field that has been created.
1766 ! </OUT>
1767 !
1768 ! Function definition
1769 !
1770 type(field_def), pointer :: list_p
1771 !
1772 ! arguments
1773 !
1774 type(field_def), pointer :: parent_p
1775 character(len=*), intent(in) :: name
1776 
1777 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1778 ! local parameters
1779 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1780 character(len=12), parameter :: sub_name = 'create_field'
1781 character(len=64), parameter :: error_header = '==>Error from ' // trim(module_name) // &
1782  '(' // trim(sub_name) // '): '
1783 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
1784  '(' // trim(sub_name) // '): '
1785 integer :: ier
1786 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1787 ! local variables
1788 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1789 integer :: error, out_unit
1790 !
1791 ! Check for fatal errors which should never arise
1792 !
1793 out_unit = stdout()
1794 if (.not. associated(parent_p)) then !{
1795 
1796  if (verb .gt. verb_level_warn) then !{
1797  write (out_unit,*) trim(warn_header), 'Unnassociated pointer' &
1798  , ' for ', trim(name)
1799  endif !}
1800  nullify(list_p)
1801  return
1802 endif !}
1803 
1804 if (name .eq. ' ') then !{
1805  if (verb .gt. verb_level_warn) then !{
1806  write (out_unit,*) trim(warn_header), 'Empty name for ' &
1807  , trim(name)
1808  endif !}
1809  nullify(list_p)
1810  return
1811 endif !}
1812 !
1813 ! Allocate space for the new list
1814 !
1815 allocate(list_p, stat = error)
1816 if (error .ne. 0) then !{
1817  write (out_unit,*) trim(error_header), 'Error ', error, &
1818  ' allocating memory for list ', trim(name)
1819  nullify(list_p)
1820  return
1821 endif !}
1822 !
1823 ! Initialize the new field
1824 !
1825 list_p%name = name
1826 
1827 nullify(list_p%next)
1828 list_p%prev => parent_p%last_field
1829 nullify(list_p%first_field)
1830 nullify(list_p%last_field)
1831 list_p%length = 0
1832 list_p%field_type = null_type
1833 list_p%max_index = 0
1834 list_p%array_dim = 0
1835 if (associated(list_p%i_value)) deallocate(list_p%i_value)
1836 if (associated(list_p%l_value)) deallocate(list_p%l_value)
1837 if (associated(list_p%r_value)) deallocate(list_p%r_value)
1838 if (associated(list_p%s_value)) deallocate(list_p%s_value)
1839 !
1840 ! If this is the first field in the parent, then set the pointer
1841 ! to it, otherwise, update the "next" pointer for the last list
1842 !
1843 if (parent_p%length .le. 0) then !{
1844  parent_p%first_field => list_p
1845 else !}{
1846  parent_p%last_field%next => list_p
1847 endif !}
1848 !
1849 ! Update the pointer for the last list in the parent
1850 !
1851 parent_p%last_field => list_p
1852 !
1853 ! Update the length for the parent
1854 !
1855 parent_p%length = parent_p%length + 1
1856 !
1857 ! Set the new index as the return value
1858 !
1859 list_p%index = parent_p%length
1860 !
1861 ! set the pointer to the parent list
1862 !
1863 list_p%parent => parent_p
1864 
1865 end function create_field !}
1866 ! </FUNCTION> NAME="create_field"
1867 !</PRIVATE>
1868 !#######################################################################
1869 !#######################################################################
1870 
1871 ! <PRIVATE><FUNCTION NAME="dump_list">
1872 !
1873 ! <OVERVIEW>
1874 ! This is a function that lists the parameters of a field.
1875 ! </OVERVIEW>
1876 ! <DESCRIPTION>
1877 ! Given a pointer to a list, this function prints out the fields, and
1878 ! subfields, if recursive is true, associated with the list.
1879 !
1880 ! This is most likely to be used through fm_dump_list.
1881 ! </DESCRIPTION>
1882 ! <TEMPLATE>
1883 ! success = dump_list(list_p, recursive= .true., depth=0)
1884 ! </TEMPLATE>
1885 !
1886 logical recursive function dump_list(list_p, recursive, depth, out_unit) result(success)
1888 ! <IN NAME="list_p" TYPE="type(field_def), pointer">
1889 ! A pointer to the field, the contents of which will be printed out.
1890 ! </IN>
1891 ! <IN NAME="recursive" TYPE="logical">
1892 ! A flag to make the function recursively print all the sub-fields
1893 ! of the field pointed to by list_p.
1894 ! </IN>
1895 ! <IN NAME="depth" TYPE="integer">
1896 ! The listing will be padded so that 'depth' spaces appear before
1897 ! the field being printed.
1898 ! </IN>
1899 ! <OUT NAME="success" TYPE="logical">
1900 ! A flag to indicate whether the function operated with (FALSE) or
1901 ! without (TRUE) errors.
1902 ! </OUT>
1903  type(field_def), pointer :: list_p
1904  logical, intent(in) :: recursive
1905  integer, intent(in) :: depth
1906  integer, intent(in) :: out_unit
1907 
1908  ! ---- local constants
1909  character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // '(dump_list): '
1910  ! ---- local variables
1911  integer :: depthp1
1912  integer :: j
1913  character(len=fm_field_name_len) :: num, scratch
1914  type(field_def), pointer :: this_field_p
1915  character(len=depth+fm_field_name_len) :: blank
1916 
1917  blank = ' ' ! initialize blank string
1918 
1919  ! Check for a valid list
1920  success = .false.
1921  if (.not. associated(list_p)) then
1922  if (verb > verb_level_warn) write (out_unit,*) trim(warn_header), 'Invalid list pointer'
1923  return
1924  elseif (list_p%field_type .ne. list_type) then
1925  if (verb > verb_level_warn) write (out_unit,*) trim(warn_header), trim(list_p%name), ' is not a list'
1926  return
1927  endif
1928 
1929  ! set the default return value
1930  success = .true.
1931 
1932  ! Print the name of this list
1933  write (out_unit,'(a,a,a)') blank(1:depth), trim(list_p%name), list_sep
1934 
1935  ! Increment the indentation depth
1936  ! The following max function is to work around an error in the IBM compiler for len_trim
1937  ! depthp1 = depth + max(len_trim(list_p%name),0) + len_trim(list_sep)
1938  depthp1 = depth + 6
1939 
1940  this_field_p => list_p%first_field
1941 
1942  do while (associated(this_field_p))
1943 
1944  select case(this_field_p%field_type)
1945  case(list_type)
1946  ! If this is a list, then call dump_list
1947  if (recursive) then
1948  ! If recursive is true, then this routine will find and dump sub-fields.
1949  success = dump_list(this_field_p, .true., depthp1, out_unit)
1950  if (.not.success) exit ! quit immediately in case of error
1951  else ! Otherwise it will print out the name of this field.
1952  write (out_unit,'(a,a,a)') blank(1:depthp1), trim(this_field_p%name), list_sep
1953  endif
1954 
1955  case(integer_type)
1956  if (this_field_p%max_index .eq. 0) then
1957  write (out_unit,'(a,a,a)') blank(1:depthp1), trim(this_field_p%name), ' = NULL'
1958  elseif (this_field_p%max_index .eq. 1) then
1959  write (scratch,*) this_field_p%i_value(1)
1960  write (out_unit,'(a,a,a,a)') blank(1:depthp1), trim(this_field_p%name), ' = ', &
1961  trim(adjustl(scratch))
1962  else ! Write out the array of values for this field.
1963  do j = 1, this_field_p%max_index
1964  write (scratch,*) this_field_p%i_value(j)
1965  write (num,*) j
1966  write (out_unit,'(a,a,a,a,a,a)') blank(1:depthp1), trim(this_field_p%name), &
1967  '[', trim(adjustl(num)), '] = ', trim(adjustl(scratch))
1968  enddo
1969  endif
1970 
1971  case(logical_type)
1972  if (this_field_p%max_index .eq. 0) then
1973  write (out_unit,'(a,a,a)') blank(1:depthp1), trim(this_field_p%name), ' = NULL'
1974  elseif (this_field_p%max_index .eq. 1) then
1975  write (scratch,'(l1)') this_field_p%l_value(1)
1976  write (out_unit,'(a,a,a,a)') blank(1:depthp1), trim(this_field_p%name), ' = ', &
1977  trim(adjustl(scratch))
1978  else ! Write out the array of values for this field.
1979  do j = 1, this_field_p%max_index
1980  write (scratch,'(l1)') this_field_p%l_value(j)
1981  write (num,*) j
1982  write (out_unit,'(a,a,a,a,a,a)') blank(1:depthp1), trim(this_field_p%name), &
1983  '[', trim(adjustl(num)), '] = ', trim(adjustl(scratch))
1984  enddo
1985  endif
1986 
1987  case(real_type)
1988  if (this_field_p%max_index .eq. 0) then
1989  write (out_unit,'(a,a,a)') blank(1:depthp1), trim(this_field_p%name), ' = NULL'
1990  elseif (this_field_p%max_index .eq. 1) then
1991  write (scratch,*) this_field_p%r_value(1)
1992  write (out_unit,'(a,a,a,a)') blank(1:depthp1), trim(this_field_p%name), ' = ', &
1993  trim(adjustl(scratch))
1994  else ! Write out the array of values for this field.
1995  do j = 1, this_field_p%max_index
1996  write (scratch,*) this_field_p%r_value(j)
1997  write (num,*) j
1998  write (out_unit,'(a,a,a,a,a,a)') blank(1:depthp1), trim(this_field_p%name), &
1999  '[', trim(adjustl(num)), '] = ', trim(adjustl(scratch))
2000  enddo
2001  endif
2002 
2003  case(string_type)
2004  if (this_field_p%max_index .eq. 0) then
2005  write (out_unit,'(a,a,a)') blank(1:depthp1), trim(this_field_p%name), ' = NULL'
2006  elseif (this_field_p%max_index .eq. 1) then
2007  write (out_unit,'(a,a,a,a)') blank(1:depthp1), trim(this_field_p%name), ' = ', &
2008  ''''//trim(this_field_p%s_value(1))//''''
2009  else ! Write out the array of values for this field.
2010  do j = 1, this_field_p%max_index
2011  write (num,*) j
2012  write (out_unit,'(a,a,a,a,a,a)') blank(1:depthp1), trim(this_field_p%name), &
2013  '[', trim(adjustl(num)), '] = ', ''''//trim(this_field_p%s_value(j))//''''
2014  enddo
2015  endif
2016 
2017  case default
2018  if (verb .gt. verb_level_warn) then
2019  write (out_unit,*) trim(warn_header), 'Undefined type for ', trim(this_field_p%name)
2020  endif
2021  success = .false.
2022  exit
2023 
2024  end select
2025 
2026  this_field_p => this_field_p%next
2027  enddo
2028 
2029 end function dump_list
2030 ! </FUNCTION> NAME="dump_list"
2031 !</PRIVATE>
2032 
2033 !#######################################################################
2034 !#######################################################################
2035 
2036 ! <PRIVATE><SUBROUTINE NAME="find_base">
2037 !
2038 ! <OVERVIEW>
2039 ! A subroutine that splits a listname into a path and a base.
2040 ! </OVERVIEW>
2041 ! <DESCRIPTION>
2042 ! Find the base name for a list by splitting the list name into
2043 ! a path and base. The base is the last field within name, while the
2044 ! path is the preceding section of name. The base string can then be
2045 ! used to query for values associated with name.
2046 ! </DESCRIPTION>
2047 ! <TEMPLATE>
2048 ! call find_base(name, path, base)
2049 ! </TEMPLATE>
2050 !
2051 subroutine find_base(name, path, base) !{
2053 ! <IN NAME="name" TYPE="character(len=*)">
2054 ! </IN>
2055 ! <OUT NAME="path" TYPE="character(len=*)">
2056 ! A string containing the path of the base field.
2057 ! </OUT>
2058 ! <OUT NAME="base" TYPE="character(len=*)">
2059 ! A string which can be used to query for values associated with name.
2060 ! </OUT>
2061 !
2062 ! arguments
2063 !
2064 character(len=*), intent(in) :: name
2065 character(len=*), intent(out) :: path
2066 character(len=*), intent(out) :: base
2067 
2068 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2069 ! local variables
2070 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2071 
2072 integer :: i
2073 integer :: length
2074 
2075 !
2076 ! Check for the last occurrence of the list separator in name
2077 !
2078 ! The following max function is to work around an error in the IBM compiler for len_trim
2079 length = max(len_trim(name),0)
2080 
2081 if (length .eq. 0) then !{
2082 
2083  !
2084  ! Empty name, so return empty path and base
2085  !
2086  path = ' '
2087  base = ' '
2088 else !}{
2089  !
2090  ! Remove trailing list separators
2091  !
2092  do while (name(length:length) .eq. list_sep) !{
2093  length = length - 1
2094  if (length .eq. 0) then !{
2095  exit
2096  endif !}
2097  enddo !}
2098  if (length .eq. 0) then !{
2099 
2100  !
2101  ! Name only list separators, so return empty path and base
2102  !
2103  path = ' '
2104  base = ' '
2105  else !}{
2106  !
2107  ! Check for the last occurrence of the list separator in name
2108  !
2109  i = index(name(1:length), list_sep, back = .true.)
2110  if (i .eq. 0) then !{
2111  !
2112  ! no list separators in the path, so return an empty path
2113  ! and name as the base
2114  !
2115  path = ' '
2116  base = name(1:length)
2117  else !}{
2118  !
2119  ! Found a list separator, so return the part up to the last
2120  ! list separator in path, and the remainder in base
2121  !
2122  path = name(1:i)
2123  base = name(i+1:length)
2124  endif !}
2125  endif !}
2126 endif !}
2127 
2128 end subroutine find_base !}
2129 ! </SUBROUTINE> NAME="find_base"
2130 !</PRIVATE>
2131 !#######################################################################
2132 !#######################################################################
2133 
2134 ! <PRIVATE><FUNCTION NAME="find_field">
2135 !
2136 ! <OVERVIEW>
2137 ! Find and return a pointer to the field in the specified
2138 ! list. Return a null pointer on error.
2139 ! </OVERVIEW>
2140 ! <DESCRIPTION>
2141 ! Find and return a pointer to the field in the specified
2142 ! list. Return a null pointer on error. Given a pointer to a field,
2143 ! this function searchs for "name" as a sub field.
2144 ! </DESCRIPTION>
2145 ! <TEMPLATE>
2146 ! field_p => find_field(name, this_list_p)
2147 ! </TEMPLATE>
2148 !
2149 function find_field(name, this_list_p) &
2150  result(field_p) !{
2151 ! <OUT NAME="field_p" TYPE="type(field_def), pointer">
2152 ! A pointer to the field corresponding to "name" or an unassociated
2153 ! pointer if the field name does not exist.
2154 ! </OUT>
2155 ! <IN NAME="name" TYPE="character(len=*)">
2156 ! The name of a field that the user wishes to find.
2157 ! </IN>
2158 ! <IN NAME="this_list_p" TYPE="type(field_def), pointer">
2159 ! A pointer to a list which the user wishes to search for a field "name".
2160 ! </IN>
2161 !
2162 ! Function definition
2163 !
2164 type(field_def), pointer :: field_p
2165 !
2166 ! arguments
2167 !
2168 character(len=*), intent(in) :: name
2169 type(field_def), pointer :: this_list_p
2170 
2171 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2172 ! local variables
2173 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2174 type(field_def), pointer, save :: temp_p
2175 
2176 
2177 nullify (field_p)
2178 
2179 if (name .eq. '.') then !{
2180 
2181 !
2182 ! If the field is '.' then return this list
2183 !
2184  field_p => this_list_p
2185 elseif (name .eq. '..') then !}{
2186 !
2187 ! If the field is '..' then return the parent list
2188 !
2189  field_p => this_list_p%parent
2190 else !}{
2191 !
2192 ! Loop over each field in this list
2193 !
2194  temp_p => this_list_p%first_field
2195 
2196  do while (associated(temp_p)) !{
2197 !
2198 ! If the name matches, then set the return pointer and exit
2199 ! the loop
2200 !
2201  if (temp_p%name .eq. name) then !{
2202  field_p => temp_p
2203  exit
2204  endif !}
2205 
2206  temp_p => temp_p%next
2207 
2208  enddo !}
2209 endif !}
2210 
2211 end function find_field !}
2212 ! </FUNCTION> NAME="find_field"
2213 !</PRIVATE>
2214 
2215 !#######################################################################
2216 !#######################################################################
2217 
2218 ! <PRIVATE><SUBROUTINE NAME="find_head">
2219 !
2220 ! <OVERVIEW>
2221 ! Find the first list for a name by splitting the name into
2222 ! a head and the rest.
2223 ! </OVERVIEW>
2224 ! <DESCRIPTION>
2225 ! Find the first list for a name by splitting the name into a head and the
2226 ! rest. The head is the first field within name, while rest is the remaining
2227 ! section of name. The head string can then be used to find other fields that
2228 ! may be associated with name.
2229 ! </DESCRIPTION>
2230 ! <TEMPLATE>
2231 ! call find_head(name, head, rest)
2232 ! </TEMPLATE>
2233 !
2234 subroutine find_head(name, head, rest) !{
2236 ! <IN NAME="name" TYPE="character(len=*)">
2237 ! The name of a field of interest.
2238 ! </IN>
2239 ! <OUT NAME="head" TYPE="character(len=*)">
2240 ! head is the first field within name.
2241 ! </OUT>
2242 ! <OUT NAME="rest" TYPE="character(len=*)">
2243 ! rest is the remaining section of name.
2244 ! </OUT>
2245 !
2246 ! arguments
2247 !
2248 character(len=*), intent(in) :: name
2249 character(len=*), intent(out) :: head
2250 character(len=*), intent(out) :: rest
2251 
2252 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2253 ! local variables
2254 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2255 integer :: i
2256 !
2257 ! Check for the first occurrence of the list separator in name
2258 !
2259 i = index(name, list_sep)
2260 !
2261 ! Check for additional consecutive list separators and return
2262 ! those also
2263 !
2264 do while (i .le. len(name)) !{
2265  if (name(i+1:i+1) .eq. list_sep) then !{
2266  i = i + 1
2267  else !}{
2268  exit
2269  endif !}
2270 enddo !}
2271 
2272 if (i .eq. 0) then !{
2273 !
2274 ! no list separators in the path, so return an empty head and
2275 ! name as the rest
2276 !
2277  head = ' '
2278  rest = name
2279 elseif (i .eq. len(name)) then !}{
2280 !
2281 ! The last character in name is a list separator, so return name
2282 ! as head and an empty rest
2283 !
2284  head = name
2285  rest = ' '
2286 else !}{
2287 !
2288 ! Found a list separator, so return the part up to the list
2289 ! separator in head, and the remainder in rest
2290 !
2291  head = name(1:i)
2292  rest = name(i+1:)
2293 endif !}
2294 
2295 end subroutine find_head !}
2296 ! </SUBROUTINE> NAME="find_head"
2297 !</PRIVATE>
2298 
2299 !#######################################################################
2300 !#######################################################################
2301 
2302 ! <PRIVATE><FUNCTION NAME="find_list">
2303 !
2304 ! <OVERVIEW>
2305 ! Find and return a pointer to the specified list, relative to
2306 ! relative_p. Return a null pointer on error.
2307 ! </OVERVIEW>
2308 ! <DESCRIPTION>
2309 ! This function, when supplied a pointer to a field and a name of a second
2310 ! field relative to that pointer, will find a list and return the pointer to
2311 ! the second field. If create is .true. and the second field does not exist,
2312 ! it will be created.
2313 ! </DESCRIPTION>
2314 ! <TEMPLATE>
2315 ! list_p => find_list(path, relative_p, create)
2316 ! </TEMPLATE>
2317 !
2318 function find_list(path, relative_p, create) &
2319  result(list_p) !{
2321 ! <OUT NAME="list_p" TYPE="type(field_def), pointer">
2322 ! A pointer to the list to be returned.
2323 ! </OUT>
2324 ! <IN NAME="path" TYPE="character(len=*)">
2325 ! A path to the list of interest.
2326 ! </IN>
2327 ! <IN NAME="list_p" TYPE="type(field_def), pointer">
2328 ! A pointer to the list to which "path" is relative to.
2329 ! </IN>
2330 ! <IN NAME="create" TYPE="logical">
2331 ! If the list does not exist, having create = .true. will create it.
2332 ! </IN>
2333 !
2334 ! Function definition
2335 !
2336 type(field_def), pointer :: list_p
2337 !
2338 ! arguments
2339 !
2340 character(len=*), intent(in) :: path
2341 type(field_def), pointer :: relative_p
2342 logical, intent(in) :: create
2343 
2344 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2345 ! local parameters
2346 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2347 character(len=9), parameter :: sub_name = 'find_list'
2348 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
2349  '(' // trim(sub_name) // '): '
2350 character(len=64), parameter :: note_header = '==>Note from ' // trim(module_name) // &
2351  '(' // trim(sub_name) // '): '
2352 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2353 ! local variables
2354 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2355 character(len=fm_path_name_len) :: working_path
2356 character(len=fm_path_name_len) :: rest
2357 character(len=fm_field_name_len) :: this_list
2358 integer :: i, out_unit
2359 type(field_def), pointer, save :: working_path_p
2360 type(field_def), pointer, save :: this_list_p
2361 
2362 
2363 out_unit = stdout()
2364 nullify(list_p)
2365 !
2366 ! If the path is empty, then return the relative list
2367 !
2368 if (path .eq. ' ') then !{
2369 
2370  list_p => relative_p
2371 
2372 else !}{
2373 !
2374 ! If a fully qualified path is given (i.e., starts with the
2375 ! list separator) then do everything relative to root,
2376 ! otherwise, do everything relative to relative list.
2377 !
2378  if (path(1:1) .eq. list_sep) then !{
2379  working_path_p => root_p
2380  working_path = path(2:)
2381  else !}{
2382  working_path_p => relative_p
2383  working_path = path
2384  endif !}
2385 !
2386 ! Loop over each field in the path
2387 !
2388  do while (working_path .ne. ' ') !{
2389 !
2390 ! Get the first list in the working path
2391 !
2392  call find_head(working_path, this_list, rest)
2393 !
2394 ! If the first list is empty, then the 'rest' should hold the
2395 ! final field in the path
2396 !
2397  if (this_list .eq. ' ') then !{
2398  this_list = rest
2399  rest = ' '
2400  endif !}
2401 !
2402 ! Strip off trailing list separators
2403 !
2404  i = len_trim(this_list)
2405  do while (i .gt. 0 .and. this_list(i:i) .eq. list_sep) !{
2406  this_list(i:i) = ' '
2407  i = i - 1
2408  enddo !}
2409 !
2410 ! Find a pointer to this field in the working list
2411 !
2412  this_list_p => find_field(this_list, working_path_p)
2413 
2414  if (.not. associated(this_list_p)) then !{
2415  if (create) then !{
2416 !
2417 ! Create the list if so requested
2418 !
2419  this_list_p => make_list(working_path_p, this_list)
2420  if (.not. associated(this_list_p)) then !{
2421  if (verb .gt. verb_level_warn) then !{
2422  write (out_unit,*) trim(warn_header), 'List "', &
2423  trim(this_list), '" could not be created in ', &
2424  trim(path)
2425  endif !}
2426  nullify(list_p)
2427  return
2428  endif !}
2429  else !}{
2430 !
2431 ! Otherwise, return an error
2432 !
2433 
2434  if (verb .gt. verb_level_note) then !{
2435  write (out_unit,*) trim(note_header), 'List "', &
2436  trim(this_list), '" does not exist in ', trim(path)
2437  endif !}
2438  nullify(list_p)
2439  return
2440  endif !}
2441  endif !}
2442 !
2443 ! Make sure that the field found is a list, and if so, proceed to
2444 ! the next field in the path, otherwise, return an error
2445 !
2446  if (this_list_p%field_type .eq. list_type) then !{
2447  working_path_p => this_list_p
2448  working_path = rest
2449  else !}{
2450  if (verb .gt. verb_level_warn) then !{
2451  write (out_unit,*) trim(warn_header), '"', &
2452  trim(this_list), '" is not a list in ', trim(path)
2453  endif !}
2454  nullify(list_p)
2455  return
2456  endif !}
2457  enddo !}
2458  list_p => working_path_p
2459 endif !}
2460 
2461 end function find_list !}
2462 ! </FUNCTION> NAME="find_list"
2463 !</PRIVATE>
2464 
2465 !#######################################################################
2466 !#######################################################################
2467 
2468 ! <FUNCTION NAME="fm_change_list">
2469 !
2470 ! <OVERVIEW>
2471 ! Change the current list. Return true on success,
2472 ! false otherwise
2473 ! </OVERVIEW>
2474 ! <DESCRIPTION>
2475 ! This function changes the currect list to correspond to the list named name.
2476 ! If the first character of name is the list separator (/) then the list will
2477 ! search for "name" starting from the root of the field tree. Otherwise it
2478 ! will search for name starting from the current list.
2479 ! </DESCRIPTION>
2480 ! <TEMPLATE>
2481 ! success = fm_change_list(name)
2482 ! </TEMPLATE>
2483 !
2484 function fm_change_list(name) &
2485  result(success) !{
2486 ! <OUT NAME="success" TYPE="logical">
2487 ! A flag to indicate whether the function operated with (FALSE) or
2488 ! without (TRUE) errors.
2489 ! </OUT>
2490 ! <IN NAME="name" TYPE="character(len=*)">
2491 ! The name of a list that the user wishes to change to.
2492 ! </IN>
2493 !
2494 ! Function definition
2495 !
2496 logical :: success
2497 !
2498 ! arguments
2499 !
2500 character(len=*), intent(in) :: name
2501 
2502 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2503 ! local variables
2504 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2505 type(field_def), pointer, save :: temp_p
2506 !
2507 ! Initialize the field manager if needed
2508 !
2509 if (.not. module_is_initialized) then !{
2510  call initialize
2511 endif !}
2512 !
2513 ! Find the list if path is not empty
2514 !
2515 temp_p => find_list(name, current_list_p, .false.)
2516 
2517 if (associated(temp_p)) then !{
2518  current_list_p => temp_p
2519  success = .true.
2520 else !}{
2521  success = .false.
2522 endif !}
2523 
2524 end function fm_change_list !}
2525 ! </FUNCTION> NAME="fm_change_list"
2526 
2527 !#######################################################################
2528 !#######################################################################
2529 
2530 ! <FUNCTION NAME="fm_change_root">
2531 !
2532 ! <OVERVIEW>
2533 ! Change the root list
2534 ! </OVERVIEW>
2535 ! <DESCRIPTION>
2536 ! This function changes the root of the field tree to correspond to the
2537 ! field named name. An example of a use of this would be if code is
2538 ! interested in a subset of fields with a common base. This common base
2539 ! could be set using fm_change_root and fields could be referenced using
2540 ! this root.
2541 !
2542 ! This function should be used in conjunction with fm_return_root.
2543 !
2544 ! </DESCRIPTION>
2545 ! <TEMPLATE>
2546 ! success = fm_change_root(name)
2547 ! </TEMPLATE>
2548 !
2549 function fm_change_root(name) &
2550  result(success) !{
2552 ! <OUT NAME="success" TYPE="logical">
2553 ! A flag to indicate whether the function operated with (FALSE) or
2554 ! without (TRUE) errors.
2555 ! </OUT>
2556 ! <IN NAME="name" TYPE="character(len=*)">
2557 ! The name of the field which the user wishes to become the root.
2558 ! </IN>
2559 !
2560 ! Function definition
2561 !
2562 logical :: success
2563 !
2564 ! arguments
2565 !
2566 character(len=*), intent(in) :: name
2567 
2568 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2569 ! local parameters
2570 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2571 character(len=14), parameter :: sub_name = 'fm_change_root'
2572 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
2573  '(' // trim(sub_name) // '): '
2574 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2575 ! local variables
2576 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2577 type(field_def), pointer, save :: temp_list_p
2578 integer :: out_unit
2579 !
2580 ! Initialize the field manager if needed
2581 !
2582 if (.not. module_is_initialized) then !{
2583  call initialize
2584 endif !}
2585 out_unit = stdout()
2586 !
2587 ! Must supply a field field name
2588 !
2589 if (name .eq. ' ') then !{
2590  if (verb .gt. verb_level_warn) then !{
2591  write (out_unit,*) trim(warn_header), 'Must supply a field name'
2592  endif !}
2593  success = .false.
2594  return
2595 endif !}
2596 !
2597 ! Get a pointer to the list
2598 !
2599 temp_list_p => find_list(name, current_list_p, .false.)
2600 
2601 if (associated(temp_list_p)) then !{
2602 !
2603 ! restore the saved root values if we've already changed root
2604 !
2605  if (save_root_name .ne. ' ') then !{
2606  root_p%name = save_root_name
2607  root_p%parent => save_root_parent_p
2608  endif !}
2609 !
2610 ! set the pointer for the new root field
2611 !
2612  root_p => temp_list_p
2613 !
2614 ! save the new root field's name and parent
2615 !
2616  save_root_name = root_p%name
2617  save_root_parent_p => root_p%parent
2618 !
2619 ! set the new root name and parent fields to appropriate values
2620 !
2621  root_p%name = ' '
2622  nullify(root_p%parent)
2623 !
2624 ! set the current list to the new root as it likely is not
2625 ! going to be meaningful anymore
2626 !
2628  success = .true.
2629 else !}{
2630 !
2631 ! Couldn't find the list
2632 !
2633 
2634  if (verb .gt. verb_level_warn) then !{
2635  write (out_unit,*) trim(warn_header), &
2636  'Could not find list ', trim(name)
2637  endif !}
2638  success = .false.
2639 endif !}
2640 
2641 end function fm_change_root !}
2642 ! </FUNCTION> NAME="fm_change_root"
2643 
2644 !#######################################################################
2645 !#######################################################################
2646 
2647 ! <FUNCTION NAME="fm_dump_list">
2648 !
2649 ! <OVERVIEW>
2650 ! A function to list properties associated with a field.
2651 ! </OVERVIEW>
2652 ! <DESCRIPTION>
2653 ! This function writes the contents of the field named "name" to stdout.
2654 ! If recursive is present and .true., then this function writes out the
2655 ! contents of any subfields associated with the field named "name".
2656 ! </DESCRIPTION>
2657 ! <TEMPLATE>
2658 ! success = fm_dump_list(name, recursive = .true.)
2659 ! </TEMPLATE>
2660 !
2661 logical function fm_dump_list(name, recursive, unit) result (success)
2662  character(len=*), intent(in) :: name
2663  logical, intent(in), optional :: recursive
2664  integer, intent(in), optional :: unit ! file to print to
2665 ! <OUT NAME="success" TYPE="logical">
2666 ! A flag to indicate whether the function operated with (FALSE) or
2667 ! without (TRUE) errors.
2668 ! </OUT>
2669 ! <IN NAME="name" TYPE="character(len=*)">
2670 ! The name of the field for which output is requested.
2671 ! </IN>
2672 ! <IN NAME="recursive" TYPE="logical, optional">
2673 ! If present and .true., then a recursive listing of fields will be
2674 ! performed.
2675 ! </IN>
2676 
2677  ! ---- local parameters
2678  character(len=12), parameter :: sub_name = 'fm_dump_list'
2679  character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
2680  '(' // trim(sub_name) // '): '
2681  ! ---- local variables
2682  logical :: recursive_t
2683  type(field_def), pointer, save :: temp_list_p
2684  integer :: out_unit
2685 
2686  if (present(unit)) then
2687  out_unit = unit
2688  else
2689  out_unit = stdout()
2690  endif
2691 
2692  recursive_t = .false.
2693  if (present(recursive)) recursive_t = recursive
2694  if (.not. module_is_initialized) call initialize()
2695 
2696  if (name .eq. ' ') then
2697  ! If list is empty, then dump the current list
2698  temp_list_p => current_list_p
2699  success = .true.
2700  else
2701  ! Get a pointer to the list
2702  temp_list_p => find_list(name, current_list_p, .false.)
2703  if (associated(temp_list_p)) then
2704  success = .true.
2705  else
2706  ! Error following the path
2707  if (verb .gt. verb_level_warn) then
2708  write (out_unit,*) trim(warn_header), 'Could not follow path for ', trim(name)
2709  endif
2710  success = .false.
2711  endif
2712  endif
2713  ! Dump the list
2714  if (success) then
2715  success = dump_list(temp_list_p, recursive_t, 0, out_unit)
2716  endif
2717 end function fm_dump_list
2718 ! </FUNCTION> NAME="fm_dump_list"
2719 
2720 !#######################################################################
2721 !#######################################################################
2722 
2723 ! <FUNCTION NAME="fm_exists">
2724 !
2725 ! <OVERVIEW>
2726 ! A function to test whether a named field exists.
2727 ! </OVERVIEW>
2728 ! <DESCRIPTION>
2729 ! This function determines is a field exists, relative to the current list,
2730 ! and returns true if the list exists, false otherwise.
2731 ! </DESCRIPTION>
2732 ! <TEMPLATE>
2733 ! success = fm_exists(name)
2734 ! </TEMPLATE>
2735 !
2736 function fm_exists(name) &
2737  result(success) !{
2739 ! <IN NAME="name" TYPE="character(len=*)">
2740 ! The name of the field that is being queried.
2741 ! </IN>
2742 ! <OUT NAME="success" TYPE="logical">
2743 ! A flag to indicate whether the function operated with (FALSE) or
2744 ! without (TRUE) errors.
2745 ! </OUT>
2746 !
2747 ! Function definition
2748 !
2749 logical :: success
2750 !
2751 ! arguments
2752 !
2753 character(len=*), intent(in) :: name
2754 
2755 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2756 ! local variables
2757 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2758 type(field_def), pointer, save :: dummy_p
2759 !
2760 ! Initialize the field manager if needed
2761 !
2762 if (.not. module_is_initialized) then !{
2763  call initialize
2764 endif !}
2765 !
2766 ! Determine whether the field exists
2767 !
2768 dummy_p => get_field(name, current_list_p)
2769 success = associated(dummy_p)
2770 
2771 end function fm_exists !}
2772 ! </FUNCTION> NAME="fm_exists"
2773 
2774 !#######################################################################
2775 !#######################################################################
2776 
2777 ! <FUNCTION NAME="fm_get_index">
2778 !
2779 ! <OVERVIEW>
2780 ! A function to return the index of a named field.
2781 ! </OVERVIEW>
2782 ! <DESCRIPTION>
2783 ! Returns the index for name, returns the parameter NO_FIELD if it does not
2784 ! exist. If the first character of the named field is the list peparator,
2785 ! then the named field will be relative to the root of the field tree.
2786 ! Otherwise the named field will be relative to the current list.
2787 ! </DESCRIPTION>
2788 ! <TEMPLATE>
2789 ! index = fm_get_index(name)
2790 ! </TEMPLATE>
2791 !
2792 function fm_get_index(name) &
2793  result(index) !{
2794 ! <OUT NAME="index" TYPE="index">
2795 ! The index of the named field if it exists.
2796 ! Otherwise the parameter NO_FIELD.
2797 ! </OUT>
2798 ! <IN NAME="name" TYPE="character(len=*)">
2799 ! The name of a field that the user wishes to get an index for.
2800 ! </IN>
2801 !
2802 ! Function definition
2803 !
2804 integer :: index
2805 !
2806 ! arguments
2807 !
2808 character(len=*), intent(in) :: name
2809 
2810 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2811 ! local parameters
2812 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2813 character(len=12), parameter :: sub_name = 'fm_get_index'
2814 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
2815  '(' // trim(sub_name) // '): '
2816 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2817 ! local variables
2818 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2819 type(field_def), pointer, save :: temp_field_p
2820 integer :: out_unit
2821 
2822 out_unit = stdout()
2823 !
2824 ! Initialize the field manager if needed
2825 !
2826 if (.not. module_is_initialized) then !{
2827  call initialize
2828 endif !}
2829 !
2830 ! Must supply a field field name
2831 !
2832 if (name .eq. ' ') then !{
2833  if (verb .gt. verb_level_warn) then !{
2834  write (out_unit,*) trim(warn_header), 'Must supply a field name'
2835  endif !}
2836  index = no_field
2837  return
2838 endif !}
2839 !
2840 ! Get a pointer to the field
2841 !
2842 temp_field_p => get_field(name, current_list_p)
2843 if (associated(temp_field_p)) then !{
2844 !
2845 ! Set the index
2846 !
2847  index = temp_field_p%index
2848 else !}{
2849 !
2850 ! Error following the path
2851 !
2852  if (verb .gt. verb_level_warn) then !{
2853  write (out_unit,*) trim(warn_header), 'Could not follow path for ', trim(name)
2854  endif !}
2855  index = no_field
2856 endif !}
2857 
2858 end function fm_get_index !}
2859 ! </FUNCTION> NAME="fm_get_index"
2860 
2861 !#######################################################################
2862 !#######################################################################
2863 
2864 ! <FUNCTION NAME="fm_get_current_list">
2865 !
2866 ! <OVERVIEW>
2867 ! A function to return the full path of the current list.
2868 ! </OVERVIEW>
2869 ! <DESCRIPTION>
2870 ! This function returns the full path for the current list. A blank
2871 ! path indicates an error condition has occurred.
2872 ! </DESCRIPTION>
2873 ! <TEMPLATE>
2874 ! path = fm_get_current_list()
2875 ! </TEMPLATE>
2876 !
2877 function fm_get_current_list() &
2878  result(path) !{
2880 ! <OUT NAME="path" TYPE="character(len=fm_path_name_len)">
2881 ! The path corresponding to the current list.
2882 ! </OUT>
2883 !
2884 ! Function definition
2885 !
2886 character(len=fm_path_name_len) :: path
2887 !
2888 ! arguments
2889 !
2890 
2891 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2892 ! local variables
2893 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2894 type(field_def), pointer, save :: temp_list_p
2895 !
2896 ! Initialize the field manager if needed
2897 !
2898 if (.not. module_is_initialized) then !{
2899  call initialize
2900 endif !}
2901 !
2902 ! Set a pointer to the current list and proceed
2903 ! up the tree, filling in the name as we go
2904 !
2905 temp_list_p => current_list_p
2906 path = ' '
2907 
2908 do while (associated(temp_list_p)) !{
2909 !
2910 ! Check whether we are at the root field--it is the
2911 ! only field with a blank name
2912 !
2913  if (temp_list_p%name .eq. ' ') then !{
2914  exit
2915  endif !}
2916 !
2917 ! Append the name to the path
2918 !
2919  path = list_sep // trim(temp_list_p%name) // path
2920 !
2921 ! Point to the next field
2922 !
2923  temp_list_p => temp_list_p%parent
2924 enddo !}
2925 
2926 if (.not. associated(temp_list_p)) then !{
2927 !
2928 ! The pointer is not associated, indicating an error has
2929 ! occurred, so set the path accordingly
2930 !
2931  path = ' '
2932 elseif (path .eq. ' ') then !}{
2933 !
2934 ! If path is empty, then the current list must be root,
2935 ! so set path accordingly
2936 !
2937  path = list_sep
2938 endif !}
2939 
2940 end function fm_get_current_list !}
2941 ! </FUNCTION> NAME="fm_get_current_list"
2942 
2943 !#######################################################################
2944 !#######################################################################
2945 
2946 ! <FUNCTION NAME="fm_get_length">
2947 !
2948 ! <OVERVIEW>
2949 ! A function to return how many elements are contained within the named
2950 ! list or entry.
2951 ! </OVERVIEW>
2952 ! <DESCRIPTION>
2953 ! This function returns the list or entry length for the named list or entry.
2954 ! If the named field or entry does not exist, a value of 0 is returned.
2955 ! </DESCRIPTION>
2956 ! <TEMPLATE>
2957 ! length = fm_get_length(name)
2958 ! </TEMPLATE>
2959 !
2960 function fm_get_length(name) &
2961  result(length) !{
2963 ! <OUT NAME="length" TYPE="integer">
2964 ! The number of elements that the field name has.
2965 ! </OUT>
2966 ! <IN NAME="name" TYPE="character(len=*)">
2967 ! The name of a list or entry that the user wishes to get the length of.
2968 ! </IN>
2969 !
2970 ! Function definition
2971 !
2972 integer :: length
2973 !
2974 ! arguments
2975 !
2976 character(len=*), intent(in) :: name
2977 
2978 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2979 ! local parameters
2980 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2981 character(len=13), parameter :: sub_name = 'fm_get_length'
2982 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
2983  '(' // trim(sub_name) // '): '
2984 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2985 ! local variables
2986 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2987 type(field_def), pointer, save :: temp_field_p
2988 integer :: out_unit
2989 
2990 out_unit = stdout()
2991 !
2992 ! Initialize the field manager if needed
2993 !
2994 if (.not. module_is_initialized) then !{
2995  call initialize
2996 endif !}
2997 !
2998 ! Must supply a field name
2999 !
3000 if (name .eq. ' ') then !{
3001  if (verb .gt. verb_level_warn) then !{
3002  write (out_unit,*) trim(warn_header), 'Must supply a field name'
3003  endif !}
3004  length = 0
3005  return
3006 endif !}
3007 !
3008 ! Get a pointer to the field
3009 !
3010 temp_field_p => get_field(name, current_list_p)
3011 
3012 if (associated(temp_field_p)) then !{
3013 !
3014 ! Set the field length
3015 !
3016  if (temp_field_p%field_type .eq. list_type) then !{
3017  length = temp_field_p%length
3018  else !}{
3019  length = temp_field_p%max_index
3020  endif !}
3021 else !}{
3022 !
3023 ! Error following the path
3024 !
3025 
3026  if (verb .gt. verb_level_warn) then !{
3027  write (out_unit,*) trim(warn_header), &
3028  'Could not follow path for ', trim(name)
3029  endif !}
3030  length = 0
3031 endif !}
3032 
3033 end function fm_get_length !}
3034 ! </FUNCTION> NAME="fm_get_length"
3035 
3036 !#######################################################################
3037 !#######################################################################
3038 
3039 ! <FUNCTION NAME="fm_get_type">
3040 !
3041 ! <OVERVIEW>
3042 ! A function to return the type of the named field.
3043 ! </OVERVIEW>
3044 ! <DESCRIPTION>
3045 ! This function returns the type of the field for name.
3046 ! This indicates whether the named field is a "list" (has children fields),
3047 ! or has values of type "integer", "real", "logical" or "string".
3048 ! If it does not exist it returns a blank string.
3049 ! </DESCRIPTION>
3050 ! <TEMPLATE>
3051 ! name_field_type = fm_get_type(name)
3052 ! </TEMPLATE>
3053 !
3054 function fm_get_type(name) &
3055  result(name_field_type) !{
3056 ! <OUT NAME="name_field_type" TYPE="character(len=8)">
3057 ! A string containing the type of the named field.
3058 ! </OUT>
3059 ! <IN NAME="name" TYPE="character(len=*)">
3060 ! The name of a field that the user wishes to find the type of.
3061 ! </IN>
3062 !
3063 ! Function definition
3064 !
3065 character(len=8) :: name_field_type
3066 !
3067 ! arguments
3068 !
3069 character(len=*), intent(in) :: name
3070 
3071 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3072 ! local parameters
3073 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3074 character(len=11), parameter :: sub_name = 'fm_get_type'
3075 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
3076  '(' // trim(sub_name) // '): '
3077 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3078 ! local variables
3079 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3080 type(field_def), pointer, save :: temp_field_p
3081 integer :: out_unit
3082 
3083 out_unit = stdout()
3084 !
3085 ! Initialize the field manager if needed
3086 !
3087 if (.not. module_is_initialized) then !{
3088  call initialize
3089 endif !}
3090 !
3091 ! Must supply a field name
3092 !
3093 if (name .eq. ' ') then !{
3094  if (verb .gt. verb_level_warn) then !{
3095  write (out_unit,*) trim(warn_header), 'Must supply a field name'
3096  endif !}
3097  name_field_type = ' '
3098  return
3099 endif !}
3100 !
3101 ! Get a pointer to the field
3102 !
3103 temp_field_p => get_field(name, current_list_p)
3104 
3105 if (associated(temp_field_p)) then !{
3106 !
3107 ! Set the field type
3108 !
3109  name_field_type = field_type_name(temp_field_p%field_type)
3110 else !}{
3111 !
3112 ! Error following the path
3113 !
3114 
3115  if (verb .gt. verb_level_warn) then !{
3116  write (out_unit,*) trim(warn_header), &
3117  'Could not follow path for ', trim(name)
3118  endif !}
3119  name_field_type = ' '
3120 endif !}
3121 
3122 end function fm_get_type !}
3123 ! </FUNCTION> NAME="fm_get_type"
3124 
3125 !#######################################################################
3126 !#######################################################################
3127 
3128 ! <FUNCTION NAME="fm_get_value">
3129 !
3130 ! <OVERVIEW>
3131 ! An overloaded function to find and extract a value for a named field.
3132 ! </OVERVIEW>
3133 ! <DESCRIPTION>
3134 ! Find and extract the value for name. The value may be of type real,
3135 ! integer, logical or character. If a single value from an array of values
3136 ! is required, an optional index can be supplied.
3137 ! Return true for success and false for failure
3138 ! </DESCRIPTION>
3139 ! <TEMPLATE>
3140 ! success = fm_get_value(name, value, index)
3141 ! </TEMPLATE>
3142 !
3143 function fm_get_value_integer(name, value, index) &
3144  result(success) !{
3145 ! <OUT NAME="success" TYPE="logical">
3146 ! A flag to indicate whether the function operated with (FALSE) or
3147 ! without (TRUE) errors.
3148 ! </OUT>
3149 ! <IN NAME="name" TYPE="character(len=*)">
3150 ! The name of a field that the user wishes to get a value for.
3151 ! </IN>
3152 ! <OUT NAME="value" TYPE="integer, real, logical or character">
3153 ! The value associated with the named field.
3154 ! </OUT>
3155 ! <IN NAME="index" TYPE="integer, optional">
3156 ! An optional index to retrieve a single value from an array.
3157 ! </IN>
3158 !
3159 ! Function definition
3160 !
3161 logical :: success
3162 !
3163 ! arguments
3164 !
3165 character(len=*), intent(in) :: name
3166 integer, intent(out) :: value
3167 integer, intent(in), optional :: index
3168 
3169 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3170 ! local parameters
3171 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3172 character(len=20), parameter :: sub_name = 'fm_get_value_integer'
3173 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
3174  '(' // trim(sub_name) // '): '
3175 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3176 ! local variables
3177 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3178 integer :: index_t
3179 type(field_def), pointer, save :: temp_field_p
3180 integer :: out_unit
3181 
3182 out_unit = stdout()
3183 !
3184 ! Initialize the field manager if needed
3185 !
3186 if (.not. module_is_initialized) then !{
3187  call initialize
3188 endif !}
3189 !
3190 ! Must supply a field field name
3191 !
3192 if (name .eq. ' ') then !{
3193  if (verb .gt. verb_level_warn) then !{
3194  write (out_unit,*) trim(warn_header), 'Must supply a field name'
3195  endif !}
3196  value = 0
3197  success = .false.
3198  return
3199 endif !}
3200 !
3201 ! Set index to retrieve
3202 !
3203 if (present(index)) then !{
3204  index_t = index
3205 else !}{
3206  index_t = 1
3207 endif !}
3208 !
3209 ! Get a pointer to the field
3210 !
3211 temp_field_p => get_field(name, current_list_p)
3212 
3213 if (associated(temp_field_p)) then !{
3214 !
3215 ! check that the field is the correct type
3216 !
3217  if (temp_field_p%field_type .eq. integer_type) then !{
3218  if (index_t .lt. 1) then !{
3219 !
3220 ! Index is not positive
3221 !
3222 
3223  if (verb .gt. verb_level_warn) then !{
3224  write (out_unit,*) trim(warn_header), &
3225  'Optional index for ', trim(name), &
3226  ' not positive: ', index_t
3227  endif !}
3228  value = 0
3229  success = .false.
3230  elseif (index_t .gt. temp_field_p%max_index) then !}{
3231 !
3232 ! Index is too large
3233 !
3234 
3235  if (verb .gt. verb_level_warn) then !{
3236  write (out_unit,*) trim(warn_header), &
3237  'Optional index for ', trim(name), &
3238  ' too large: ', index_t, ' > ', temp_field_p%max_index
3239  endif !}
3240  value = 0
3241  success = .false.
3242  else !}{
3243 !
3244 ! extract the value
3245 !
3246  value = temp_field_p%i_value(index_t)
3247  success = .true.
3248  endif !}
3249  else !}{
3250 !
3251 ! Field not corrcet type
3252 !
3253 
3254  if (verb .gt. verb_level_warn) then !{
3255  write (out_unit,*) trim(warn_header), &
3256  'Field not type integer ', trim(name)
3257  endif !}
3258  value = 0
3259  success = .false.
3260  endif !}
3261 else !}{
3262 !
3263 ! Error following the path
3264 !
3265 
3266  if (verb .gt. verb_level_warn) then !{
3267  write (out_unit,*) trim(warn_header), &
3268  'Could not follow path for ', trim(name)
3269  endif !}
3270  value = 0
3271  success = .false.
3272 endif !}
3273 
3274 end function fm_get_value_integer !}
3275 
3276 !#######################################################################
3277 !#######################################################################
3278 
3279 function fm_get_value_logical(name, value, index) &
3280  result(success) !{
3282 ! Function definition
3283 !
3284 logical :: success
3285 !
3286 ! arguments
3287 !
3288 character(len=*), intent(in) :: name
3289 logical, intent(out) :: value
3290 integer, intent(in), optional :: index
3291 
3292 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3293 ! local parameters
3294 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3295 character(len=20), parameter :: sub_name = 'fm_get_value_logical'
3296 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
3297  '(' // trim(sub_name) // '): '
3298 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3299 ! local variables
3300 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3301 integer :: index_t
3302 type(field_def), pointer, save :: temp_field_p
3303 integer :: out_unit
3304 
3305 out_unit = stdout()
3306 !
3307 ! Initialize the field manager if needed
3308 !
3309 if (.not. module_is_initialized) then !{
3310  call initialize
3311 endif !}
3312 !
3313 ! Must supply a field field name
3314 !
3315 if (name .eq. ' ') then !{
3316  if (verb .gt. verb_level_warn) then !{
3317  write (out_unit,*) trim(warn_header), 'Must supply a field name'
3318  endif !}
3319  value = .false.
3320  success = .false.
3321  return
3322 endif !}
3323 !
3324 ! Set index to retrieve
3325 !
3326 if (present(index)) then !{
3327  index_t = index
3328 else !}{
3329  index_t = 1
3330 endif !}
3331 !
3332 ! Get a pointer to the field
3333 !
3334 temp_field_p => get_field(name, current_list_p)
3335 
3336 if (associated(temp_field_p)) then !{
3337 !
3338 ! check that the field is the correct type
3339 !
3340  if (temp_field_p%field_type .eq. logical_type) then !{
3341 
3342  if (index_t .lt. 1) then !{
3343 !
3344 ! Index is not positive
3345 !
3346 
3347  if (verb .gt. verb_level_warn) then !{
3348  write (out_unit,*) trim(warn_header), &
3349  'Optional index for ', trim(name), &
3350  ' not positive: ', index_t
3351  endif !}
3352  value = .false.
3353  success = .false.
3354 
3355  elseif (index_t .gt. temp_field_p%max_index) then !}{
3356 !
3357 ! Index is too large
3358 !
3359 
3360  if (verb .gt. verb_level_warn) then !{
3361  write (out_unit,*) trim(warn_header), &
3362  'Optional index for ', trim(name), &
3363  ' too large: ', index_t, ' > ', temp_field_p%max_index
3364  endif !}
3365  value = .false.
3366  success = .false.
3367 
3368  else !}{
3369 !
3370 ! extract the value
3371 !
3372  value = temp_field_p%l_value(index_t)
3373  success = .true.
3374  endif !}
3375  else !}{
3376 !
3377 ! Field not correct type
3378 !
3379 
3380  if (verb .gt. verb_level_warn) then !{
3381  write (out_unit,*) trim(warn_header), &
3382  'Field not type logical ', trim(name)
3383  endif !}
3384  value = .false.
3385  success = .false.
3386  endif !}
3387 else !}{
3388 !
3389 ! Error following the path
3390 !
3391 
3392  if (verb .gt. verb_level_warn) then !{
3393  write (out_unit,*) trim(warn_header), &
3394  'Could not follow path for ', trim(name)
3395  endif !}
3396  value = .false.
3397  success = .false.
3398 endif !}
3399 
3400 end function fm_get_value_logical !}
3401 
3402 !#######################################################################
3403 !#######################################################################
3404 
3405 function fm_get_value_real(name, value, index) &
3406  result(success) !{
3408 ! Function definition
3409 !
3410 logical :: success
3411 !
3412 ! arguments
3413 !
3414 character(len=*), intent(in) :: name
3415 real, intent(out) :: value
3416 integer, intent(in), optional :: index
3417 
3418 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3419 ! local parameters
3420 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3421 character(len=17), parameter :: sub_name = 'fm_get_value_real'
3422 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
3423  '(' // trim(sub_name) // '): '
3424 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3425 ! local variables
3426 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3427 integer :: index_t
3428 type(field_def), pointer, save :: temp_field_p
3429 integer :: out_unit
3430 
3431 out_unit = stdout()
3432 !
3433 ! Initialize the field manager if needed
3434 !
3435 if (.not. module_is_initialized) then !{
3436  call initialize
3437 endif !}
3438 !
3439 ! Must supply a field field name
3440 !
3441 if (name .eq. ' ') then !{
3442  if (verb .gt. verb_level_warn) then !{
3443  write (out_unit,*) trim(warn_header), 'Must supply a field name'
3444  endif !}
3445  value = 0.0
3446  success = .false.
3447  return
3448 endif !}
3449 !
3450 ! Set index to retrieve
3451 !
3452 if (present(index)) then !{
3453  index_t = index
3454 else !}{
3455  index_t = 1
3456 endif !}
3457 !
3458 ! Get a pointer to the field
3459 !
3460 temp_field_p => get_field(name, current_list_p)
3461 
3462 if (associated(temp_field_p)) then !{
3463 !
3464 ! check that the field is the correct type
3465 !
3466  if (temp_field_p%field_type .eq. real_type) then !{
3467 
3468  if (index_t .lt. 1) then !{
3469 
3470 !
3471 ! Index is not positive
3472 !
3473 
3474  if (verb .gt. verb_level_warn) then !{
3475  write (out_unit,*) trim(warn_header), &
3476  'Optional index for ', trim(name), &
3477  ' not positive: ', index_t
3478  endif !}
3479  value = 0.0
3480  success = .false.
3481 
3482  elseif (index_t .gt. temp_field_p%max_index) then !}{
3483 
3484 !
3485 ! Index is too large
3486 !
3487 
3488  if (verb .gt. verb_level_warn) then !{
3489  write (out_unit,*) trim(warn_header), &
3490  'Optional index for ', trim(name), &
3491  ' too large: ', index_t, ' > ', temp_field_p%max_index
3492  endif !}
3493  value = 0.0
3494  success = .false.
3495 
3496  else !}{
3497 
3498 !
3499 ! extract the value
3500 !
3501  value = temp_field_p%r_value(index_t)
3502  success = .true.
3503  endif !}
3504  else !}{
3505 !
3506 ! Field not correct type
3507 !
3508 
3509  if (verb .gt. verb_level_warn) then !{
3510  write (out_unit,*) trim(warn_header), &
3511  'Field not type real ', trim(name)
3512  endif !}
3513  value = 0.0
3514  success = .false.
3515  endif !}
3516 else !}{
3517 !
3518 ! Error following the path
3519 !
3520 
3521  if (verb .gt. verb_level_warn) then !{
3522  write (out_unit,*) trim(warn_header), &
3523  'Could not follow path for ', trim(name)
3524  endif !}
3525  value = 0.0
3526  success = .false.
3527 endif !}
3528 
3529 end function fm_get_value_real !}
3530 
3531 !#######################################################################
3532 !#######################################################################
3533 
3534 function fm_get_value_string(name, value, index) &
3535  result(success) !{
3537 ! Function definition
3538 !
3539 logical :: success
3540 !
3541 ! arguments
3542 !
3543 character(len=*), intent(in) :: name
3544 character(len=*), intent(out) :: value
3545 integer, intent(in), optional :: index
3546 
3547 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3548 ! local parameters
3549 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3550 character(len=19), parameter :: sub_name = 'fm_get_value_string'
3551 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
3552  '(' // trim(sub_name) // '): '
3553 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3554 ! local variables
3555 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3556 integer :: index_t
3557 type(field_def), pointer, save :: temp_field_p
3558 integer :: out_unit
3559 
3560 out_unit = stdout()
3561 !
3562 ! Initialize the field manager if needed
3563 !
3564 if (.not. module_is_initialized) then !{
3565  call initialize
3566 endif !}
3567 !
3568 ! Must supply a field field name
3569 !
3570 if (name .eq. ' ') then !{
3571  if (verb .gt. verb_level_warn) then !{
3572  write (out_unit,*) trim(warn_header), 'Must supply a field name'
3573  endif !}
3574  value = ''
3575  success = .false.
3576  return
3577 endif !}
3578 !
3579 ! Set index to retrieve
3580 !
3581 if (present(index)) then !{
3582  index_t = index
3583 else !}{
3584  index_t = 1
3585 endif !}
3586 !
3587 ! Get a pointer to the field
3588 !
3589 temp_field_p => get_field(name, current_list_p)
3590 
3591 if (associated(temp_field_p)) then !{
3592 !
3593 ! check that the field is the correct type
3594 !
3595  if (temp_field_p%field_type .eq. string_type) then !{
3596  if (index_t .lt. 1) then !{
3597 !
3598 ! Index is not positive
3599 !
3600 
3601  if (verb .gt. verb_level_warn) then !{
3602  write (out_unit,*) trim(warn_header), &
3603  'Optional index for ', trim(name), &
3604  ' not positive: ', index_t
3605  endif !}
3606  value = ''
3607  success = .false.
3608 
3609  elseif (index_t .gt. temp_field_p%max_index) then !}{
3610 !
3611 ! Index is too large
3612 !
3613 
3614  if (verb .gt. verb_level_warn) then !{
3615  write (out_unit,*) trim(warn_header), &
3616  'Optional index for ', trim(name), &
3617  ' too large: ', index_t, ' > ', temp_field_p%max_index
3618  endif !}
3619  value = ''
3620  success = .false.
3621  else !}{
3622 !
3623 ! extract the value
3624 !
3625  value = temp_field_p%s_value(index_t)
3626  !if (trim(value) == '') then
3627  !success = .false.
3628  !else
3629  success = .true.
3630  !endif
3631  endif !}
3632  else !}{
3633 !
3634 ! Field not correct type
3635 !
3636 
3637  if (verb .gt. verb_level_warn) then !{
3638  write (out_unit,*) trim(warn_header), &
3639  'Field not type string ', trim(name)
3640  endif !}
3641  value = ''
3642  success = .false.
3643  endif !}
3644 else !}{
3645 !
3646 ! Error following the path
3647 !
3648 
3649  if (verb .gt. verb_level_warn) then !{
3650  write (out_unit,*) trim(warn_header), &
3651  'Could not follow path for ', trim(name)
3652  endif !}
3653  value = ''
3654  success = .false.
3655 endif !}
3656 
3657 end function fm_get_value_string !}
3658 ! </FUNCTION> NAME="fm_get_value"
3659 
3660 !#######################################################################
3661 !#######################################################################
3662 
3663 ! <FUNCTION NAME="fm_intersection">
3664 !
3665 ! <OVERVIEW>
3666 ! A function to find the common names of the sub-fields in a list
3667 ! of fields.
3668 ! </OVERVIEW>
3669 ! <DESCRIPTION>
3670 ! Return a pointer to an fm_array_list of the intersection
3671 ! of an array of lists, ignoring the contents of the values,
3672 ! but just returning the names.
3673 ! Return false on the end of the intersection.
3674 ! </DESCRIPTION>
3675 ! <TEMPLATE>
3676 ! return_p => fm_intersection(lists,dim)
3677 ! </TEMPLATE>
3678 !
3679 function fm_intersection(lists, dim) &
3680  result(return_p) !{
3681 ! <OUT NAME="return_p" TYPE="type (fm_array_list_def), pointer">
3682 ! A pointer to a list of names that are common to the fields provided in
3683 ! lists.
3684 ! </OUT>
3685 ! <IN NAME="dim" TYPE="dim">
3686 ! The dimension of lists.
3687 ! </IN>
3688 ! <IN NAME="lists" TYPE="character(len=*)" DIM="(dim)">
3689 ! A list of fields that the user wishes to find the common fields of.
3690 ! </IN>
3691 !
3692 ! Function definition
3693 !
3694 type(fm_array_list_def), pointer :: return_p
3695 !
3696 ! arguments
3697 !
3698 integer, intent(in) :: dim
3699 character(len=*), intent(in) :: lists(dim)
3700 
3701 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3702 ! local parameters
3703 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3704 character(len=15), parameter :: sub_name = 'fm_intersection'
3705 character(len=64), parameter :: error_header = '==>Error from ' // trim(module_name) // &
3706  '(' // trim(sub_name) // '): '
3707 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
3708  '(' // trim(sub_name) // '): '
3709 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3710 ! local variables
3711 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3712 character (len=fm_field_name_len) :: name
3713 character (len=fm_field_name_len), &
3714  dimension(:), allocatable :: names
3715 character (len=fm_type_name_len) :: field_type
3716 integer :: count
3717 integer :: error
3718 integer :: index
3719 integer :: n, ier
3720 integer :: shortest
3721 logical :: found
3722 type(field_def), pointer, save :: temp_p
3723 integer :: out_unit
3724 
3725 out_unit = stdout()
3726 
3727 nullify(return_p)
3728 !
3729 ! Initialize the field manager if needed
3730 !
3731 if (.not. module_is_initialized) then !{
3732  call initialize
3733 endif !}
3734 !
3735 ! return error if dimension if bad
3736 !
3737 if (dim .le. 0) then !{
3738  if (verb .gt. verb_level_warn) then !{
3739  write (out_unit,*) trim(warn_header), 'Non-positive dimension: ', dim
3740  endif !}
3741  nullify(return_p)
3742  return
3743 endif !}
3744 !
3745 ! make sure that the lists exist, and find the shortest list
3746 ! and its length
3747 !
3748 count = -1
3749 shortest = 0
3750 do n = 1, dim !{
3751  temp_p => find_list(lists(n), current_list_p, .false.)
3752  if (associated(temp_p)) then !{
3753  if (count .eq. -1) then !{
3754  count = temp_p%length
3755  shortest = n
3756  else !}{
3757  if (count .gt. temp_p%length) then !{
3758  count = temp_p%length
3759  shortest = n
3760  endif !}
3761  endif !}
3762  else !}{
3763  if (verb .gt. verb_level_warn) then !{
3764  write (out_unit,*) trim(warn_header), &
3765  'List does not exist: "', trim(lists(n)), '"'
3766  endif !}
3767  nullify(return_p)
3768  return
3769  endif !}
3770 enddo !} n
3771 !
3772 ! allocate return pointer
3773 !
3774 allocate( return_p, stat = error)
3775 if (error .ne. 0) then !{
3776  write (out_unit,*) trim(error_header), 'Error ', error &
3777  , ' allocating memory for return_p '
3778  nullify(return_p)
3779  return
3780 endif !}
3781 if ( associated(return_p%names)) deallocate(return_p%names)
3782 !
3783 ! return if any list is empty
3784 !
3785 if (count .eq. 0) then !{
3786  return_p%length = 0
3787  return
3788 endif !}
3789 !
3790 ! If there is only one list, then return its names
3791 !
3792 if (dim .eq. 1) then !{
3793 !
3794 ! allocate space for names in return pointer
3795 !
3796  allocate( return_p%names(count), stat = error)
3797  if (error .ne. 0) then !{
3798  write (out_unit,*) trim(error_header), 'Error ', error &
3799  , ' allocating memory for names in return_p '
3800  nullify(return_p)
3801  return
3802  endif !}
3803  count = 0
3804  do while (fm_loop_over_list(lists(1), name, field_type, index)) !{
3805  count = count + 1
3806  return_p%names(count) = name
3807  enddo !}
3808  return
3809 endif !}
3810 !
3811 ! allocate space for names
3812 !
3813 allocate( names(count), stat = error)
3814 if (error .ne. 0) then !{
3815  write (out_unit,*) trim(error_header), 'Error ', error &
3816  , ' allocating memory for names '
3817  nullify(return_p)
3818  return
3819 endif !}
3820 !
3821 ! Loop over the shortest list, checking whether its names
3822 ! occur in all of the other lists. If so, then save the name
3823 !
3824 count = 0
3825 do while (fm_loop_over_list(lists(shortest), name, field_type, index)) !{
3826  found = .true.
3827  do n = 1, dim !{
3828  if (n .ne. shortest) then !{
3829  temp_p => find_list(trim(lists(n)) // list_sep // name, &
3830  current_list_p, .false.)
3831  if (.not. associated(temp_p)) then !{
3832  found = .false.
3833  exit
3834  endif !}
3835  endif !}
3836  enddo !}
3837  if (found) then !{
3838  count = count + 1
3839  names(count) = name
3840  endif !}
3841 enddo !}
3842 !
3843 ! allocate space for names in return pointer
3844 !
3845 allocate( return_p%names(count), stat = error)
3846 if (error .ne. 0) then !{
3847  write (out_unit,*) trim(error_header), 'Error ', error &
3848  , ' allocating memory for names in return_p '
3849  deallocate(names)
3850  nullify(return_p)
3851  return
3852 endif !}
3853 !
3854 ! copy the names to the return pointer and clean up
3855 !
3856 do n = 1, count !{
3857  return_p%names(n) = names(n)
3858 enddo !} n
3859 return_p%length = count
3860 deallocate(names)
3861 
3862 end function fm_intersection !}
3863 ! </FUNCTION> NAME="fm_intersection"
3864 
3865 !#######################################################################
3866 !#######################################################################
3867 
3868 ! <FUNCTION NAME="fm_loop_over_list">
3869 !
3870 ! <OVERVIEW>
3871 ! A function for looping over a list.
3872 ! </OVERVIEW>
3873 ! <DESCRIPTION>
3874 ! Loop over the list, setting the name, type and index
3875 ! of the next field. Return false at the end of the loop.
3876 ! </DESCRIPTION>
3877 ! <TEMPLATE>
3878 ! success = fm_loop_over_list(list, name, field_type, index)
3879 ! </TEMPLATE>
3880 !
3881 function fm_loop_over_list_old(list, name, field_type, index) &
3882  result(success) !{
3883 ! <OUT NAME="success" TYPE="logical">
3884 ! A flag to indicate whether the function operated with (FALSE) or
3885 ! without (TRUE) errors.
3886 ! </OUT>
3887 ! <IN NAME="list" TYPE="character(len=*)">
3888 ! The name of a list to loop over.
3889 ! </IN>
3890 ! <OUT NAME="name" TYPE="character(len=*)">
3891 ! The name of a field from list.
3892 ! </OUT>
3893 ! <OUT NAME="field_type" TYPE="character(len=fm_type_name_len)">
3894 ! The type of a list entry.
3895 ! </OUT>
3896 ! <OUT NAME="index" TYPE="integer">
3897 ! The index of tje field within the list.
3898 ! </OUT>
3899 !
3900 ! Function definition
3901 !
3902 logical :: success
3903 !
3904 ! arguments
3905 !
3906 character(len=*), intent(in) :: list
3907 character(len=*), intent(out) :: name
3908 character(len=fm_type_name_len), intent(out) :: field_type
3909 integer, intent(out) :: index
3910 
3911 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3912 ! local parameters
3913 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3914 character(len=17), parameter :: sub_name = 'fm_loop_over_list'
3915 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
3916  '(' // trim(sub_name) // '): '
3917 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3918 ! local variables
3919 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3920 type(field_def), pointer, save :: temp_list_p
3921 integer :: out_unit
3922 
3923 out_unit = stdout()
3924 !
3925 ! Initialize the field manager if needed
3926 !
3927 if (.not. module_is_initialized) then !{
3928  call initialize
3929 endif !}
3930 
3931 if (list .eq. loop_list .and. associated(loop_list_p)) then !{
3932 !
3933 ! We've already started this loop, so continue on
3934 !
3935  loop_list_p => loop_list_p%next
3936  success = set_list_stuff()
3937 elseif (list .eq. ' ') then !{
3938 !
3939 ! If list is empty, then loop over the current list
3940 !
3941  loop_list = ' '
3942  loop_list_p => current_list_p%first_field
3943  success = set_list_stuff()
3944 else !}{
3945 !
3946 ! Get a pointer to the list
3947 !
3948  loop_list = list
3950  if (associated(loop_list_p)) then !{
3951  loop_list_p => loop_list_p%first_field
3952  success = set_list_stuff()
3953  else !}{
3954 !
3955 ! Error following the path
3956 !
3957 
3958  if (verb .gt. verb_level_warn) then !{
3959  write (out_unit,*) trim(warn_header), &
3960  'Could not follow path for ', trim(list)
3961  endif !}
3962  success = .false.
3963  endif !}
3964 endif !}
3965 
3966 return
3967 
3968 contains
3969 
3970 !#######################################################################
3971 !#######################################################################
3972 
3973 ! <FUNCTION NAME="set_list_stuff">
3974 !
3975 ! <DESCRIPTION>
3976 ! If the the pointer matches to the right list,
3977 ! extract the field information. Used in fm_loop_over_list
3978 ! </DESCRIPTION>
3979 function set_list_stuff() &
3980  result(success) !{
3982 ! Function definition
3983 !
3984  logical :: success
3985 !
3986 ! arguments
3987 !
3988  if (associated(loop_list_p)) then !{
3989  name = loop_list_p%name
3990  field_type = field_type_name(loop_list_p%field_type)
3991  index = loop_list_p%index
3992  success = .true.
3993  else !}{
3994  name = ' '
3995  field_type = ' '
3996  index = 0
3997  success = .false.
3998  loop_list = ' '
3999  endif !}
4000 
4001 end function set_list_stuff !}
4002 ! </FUNCTION> NAME="set_list_stuff"
4003 
4004 end function fm_loop_over_list_old
4005 ! </FUNCTION> NAME="fm_loop_over_list"
4006 
4007 !#######################################################################
4008 ! given a name of the list, prepares an iterator over the list content.
4009 ! If the name of the given list is blank, then the current list is used
4010 subroutine fm_init_loop(loop_list, iter)
4011  character(len=*) , intent(in) :: loop_list ! name of the list to iterate over
4012  type(fm_list_iter_type), intent(out) :: iter ! loop iterator
4013 
4014  if (.not.module_is_initialized) call initialize
4015 
4016  if (loop_list==' ') then ! looping over current list
4017  iter%ptr => current_list_p%first_field
4018  else
4019  iter%ptr => find_list(loop_list,current_list_p,.false.)
4020  if (associated(iter%ptr)) iter%ptr => iter%ptr%first_field
4021  endif
4022 end subroutine fm_init_loop
4023 
4024 !#######################################################################
4025 ! given a list iterator, returns information about curren list element
4026 ! and advances the iterator to the next list element. At the end of the
4027 ! list, returns FALSE
4028 function fm_loop_over_list_new(iter, name, field_type, index) &
4029  result(success) ; logical success
4030  type(fm_list_iter_type), intent(inout) :: iter ! list iterator
4031  character(len=*), intent(out) :: name ! name of the current list item
4032  character(len=*), intent(out) :: field_type ! type of the field
4033  integer , intent(out) :: index ! index in the list
4034 
4035  if (.not.module_is_initialized) call initialize
4036  if (associated(iter%ptr)) then
4037  name = iter%ptr%name
4038  field_type = field_type_name(iter%ptr%field_type)
4039  index = iter%ptr%index
4040  success = .true.
4041  iter%ptr => iter%ptr%next
4042  else
4043  name = ' '
4044  field_type = ' '
4045  index = 0
4046  success = .false.
4047  endif
4048 end function fm_loop_over_list_new
4049 
4050 !#######################################################################
4051 !#######################################################################
4052 
4053 ! <FUNCTION NAME="fm_new_list">
4054 !
4055 ! <OVERVIEW>
4056 ! A function to create a new list.
4057 ! </OVERVIEW>
4058 ! <DESCRIPTION>
4059 ! Allocate and initialize a new list and return the index of the list.
4060 ! If an error occurs return the parameter NO_FIELD.
4061 ! </DESCRIPTION>
4062 ! <TEMPLATE>
4063 ! index = fm_new_list(name, create, keep)
4064 ! </TEMPLATE>
4065 !
4066 function fm_new_list(name, create, keep) &
4067  result(index) !{
4068 ! <OUT NAME="index" TYPE="integer">
4069 ! The index of the newly created list.
4070 ! </OUT>
4071 ! <IN NAME="name" TYPE="character(len=*)">
4072 ! The name of a list that the user wishes to create.
4073 ! </IN>
4074 ! <IN NAME="create" TYPE="logical, optional">
4075 ! If present and .true., create the list if it does not exist.
4076 ! </IN>
4077 ! <IN NAME="keep" TYPE="logical, optional">
4078 ! If present and .true., make this list the current list.
4079 ! </IN>
4080 !
4081 ! Function definition
4082 !
4083 integer :: index
4084 !
4085 ! arguments
4086 !
4087 character(len=*), intent(in) :: name
4088 logical, intent(in), optional :: create
4089 logical, intent(in), optional :: keep
4090 
4091 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4092 ! local parameters
4093 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4094 character(len=11), parameter :: sub_name = 'fm_new_list'
4095 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
4096  '(' // trim(sub_name) // '): '
4097 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4098 ! local variables
4099 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4100 logical :: create_t
4101 logical :: keep_t
4102 character(len=fm_path_name_len) :: path
4103 character(len=fm_field_name_len) :: base
4104 type(field_def), pointer, save :: temp_list_p
4105 integer :: out_unit
4106 
4107 out_unit = stdout()
4108 !
4109 ! Initialize the field manager if needed
4110 !
4111 if (.not. module_is_initialized) then !{
4112  call initialize
4113 endif !}
4114 !
4115 ! Must supply a field list name
4116 !
4117 if (name .eq. ' ') then !{
4118  if (verb .gt. verb_level_warn) then !{
4119  write (out_unit,*) trim(warn_header), 'Must supply a list name'
4120  endif !}
4121  index = no_field
4122  return
4123 endif !}
4124 !
4125 ! Check for optional arguments
4126 !
4127 if (present(create)) then !{
4128  create_t = create
4129 else !}{
4130  create_t = .false.
4131 endif !}
4132 
4133 if (present(keep)) then !{
4134  keep_t = keep
4135 else !}{
4136  keep_t = .false.
4137 endif !}
4138 !
4139 ! Get a pointer to the parent list
4140 !
4141 call find_base(name, path, base)
4142 
4143 temp_list_p => find_list(path, current_list_p, create_t)
4144 
4145 if (associated(temp_list_p)) then !{
4146 !
4147 ! Create the list
4148 !
4149  temp_list_p => make_list(temp_list_p, base)
4150  if (associated(temp_list_p)) then !{
4151 !
4152 ! Make this list the current list, if requested
4153 !
4154  if (keep_t) then !{
4155  current_list_p => temp_list_p
4156  endif !}
4157  index = temp_list_p%index
4158  else !}{
4159 !
4160 ! Error in making the list
4161 !
4162 
4163  if (verb .gt. verb_level_warn) then !{
4164  write (out_unit,*) trim(warn_header), &
4165  'Could not create list ', trim(name)
4166  endif !}
4167  index = no_field
4168 
4169  endif !}
4170 else !}{
4171 !
4172 ! Error following the path
4173 !
4174 
4175  if (verb .gt. verb_level_warn) then !{
4176  write (out_unit,*) trim(warn_header), &
4177  'Could not follow path for ', trim(name)
4178  endif !}
4179  index = no_field
4180 
4181 endif !}
4182 
4183 end function fm_new_list !}
4184 ! </FUNCTION> NAME="fm_new_list"
4185 
4186 !#######################################################################
4187 !#######################################################################
4188 
4189 ! <FUNCTION NAME="fm_new_value">
4190 !
4191 ! <OVERVIEW>
4192 ! An overloaded function to assign a value to a field.
4193 ! </OVERVIEW>
4194 ! <DESCRIPTION>
4195 ! Allocate and initialize a new value and return the index.
4196 ! If an error condition occurs the parameter NO_FIELD is returned.
4197 !
4198 ! If the type of the field is changing (e.g. real values being transformed to
4199 ! integers), then any previous values for the field are removed and replaced
4200 ! by the value passed in the present call to this function.
4201 !
4202 ! If append is present and .true., then index cannot be greater than 0 if
4203 ! it is present.
4204 ! </DESCRIPTION>
4205 ! <TEMPLATE>
4206 ! field_index = fm_new_value(name, value, [create], [index], [append])
4207 ! </TEMPLATE>
4208 !
4209 function fm_new_value_integer(name, value, create, index, append) &
4210  result(field_index) !{
4211 ! <OUT NAME="field_index" TYPE="integer">
4212 ! An index for the named field.
4213 ! </OUT>
4214 ! <IN NAME="name" TYPE="character(len=*)">
4215 ! The name of a field that the user wishes to create a value for.
4216 ! </IN>
4217 ! <IN NAME="value" TYPE="integer, real, logical, or character(len=*)">
4218 ! The value that the user wishes to apply to the named field.
4219 ! </IN>
4220 ! <IN NAME="create" TYPE="logical, optional">
4221 ! If present and .true., then a value for this field will be created.
4222 ! </IN>
4223 ! <IN NAME="index" TYPE="integer, optional">
4224 ! The index to an array of values that the user wishes to apply a new value.
4225 ! </IN>
4226 ! <IN NAME="append" TYPE="logical, optional">
4227 ! If present and .true., then append the value to an array of the present
4228 ! values. If present and .true., then index cannot be greater than 0.
4229 ! </IN>
4230 !
4231 ! Function definition
4232 !
4233 integer :: field_index
4234 !
4235 ! arguments
4236 !
4237 character(len=*), intent(in) :: name
4238 integer, intent(in) :: value
4239 logical, intent(in), optional :: create
4240 integer, intent(in), optional :: index
4241 logical, intent(in), optional :: append
4242 
4243 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4244 ! local parameters
4245 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4246 character(len=20), parameter :: sub_name = 'fm_new_value_integer'
4247 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
4248  '(' // trim(sub_name) // '): '
4249 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4250 ! local variables
4251 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4252 logical :: create_t
4253 integer :: i, ier
4254 integer :: index_t
4255 integer, pointer, dimension(:) :: temp_i_value
4256 character(len=fm_path_name_len) :: path
4257 character(len=fm_field_name_len) :: base
4258 type(field_def), pointer, save :: temp_list_p
4259 type(field_def), pointer, save :: temp_field_p
4260 integer :: out_unit
4261 
4262 out_unit = stdout()
4263 !
4264 ! Initialize the field manager if needed
4265 !
4266 if (.not. module_is_initialized) then !{
4267  call initialize
4268 endif !}
4269 !
4270 ! Must supply a field name
4271 !
4272 if (name .eq. ' ') then !{
4273  if (verb .gt. verb_level_warn) then !{
4274  write (out_unit,*) trim(warn_header), 'Must supply a field name'
4275  endif !}
4276  field_index = no_field
4277  return
4278 endif !}
4279 !
4280 ! Check for optional arguments
4281 !
4282 if (present(create)) then !{
4283  create_t = create
4284 else !}{
4285  create_t = .false.
4286 endif !}
4287 !
4288 ! Check that append is not true and index non-positive
4289 !
4290 
4291 if (present(index) .and. present(append)) then !{
4292  if (append .and. index .gt. 0) then !{
4293  if (verb .gt. verb_level_warn) then !{
4294  write (out_unit,*) trim(warn_header), &
4295  'Index and Append both set for ', trim(name)
4296  endif !}
4297  field_index = no_field
4298  return
4299  endif !}
4300 endif !}
4301 !
4302 ! Set index to define
4303 !
4304 if (present(index)) then !{
4305  index_t = index
4306  if (index_t .lt. 0) then !{
4307 !
4308 ! Index is negative
4309 !
4310 
4311  if (verb .gt. verb_level_warn) then !{
4312  write (out_unit,*) trim(warn_header), &
4313  'Optional index for ', trim(name), &
4314  ' negative: ', index_t
4315  endif !}
4316  field_index = no_field
4317  return
4318  endif !}
4319 else !}{
4320  index_t = 1
4321 endif !}
4322 !
4323 ! Get a pointer to the parent list
4324 !
4325 call find_base(name, path, base)
4326 temp_list_p => find_list(path, current_list_p, create_t)
4327 
4328 if (associated(temp_list_p)) then !{
4329  temp_field_p => find_field(base, temp_list_p)
4330  if (.not. associated(temp_field_p)) then !{
4331 !
4332 ! Create the field if it doesn't exist
4333 !
4334  temp_field_p => create_field(temp_list_p, base)
4335  endif !}
4336  if (associated(temp_field_p)) then !{
4337 !
4338 ! Check if the field_type is the same as previously
4339 ! If not then reset max_index to 0
4340 !
4341  if (temp_field_p%field_type == real_type ) then
4342  ! promote integer input to real
4343  field_index = fm_new_value_real(name, real(value), create, index, append)
4344  return
4345  else if (temp_field_p%field_type /= integer_type ) then
4346  ! slm: why would we reset index? Is it not an error to have a "list" defined
4347  ! with different types in more than one place?
4348  temp_field_p%max_index = 0
4349  if (temp_field_p%field_type /= null_type ) then !{
4350  if (verb .gt. verb_level_warn) then !{
4351  write (out_unit,*) trim(warn_header), &
4352  'Changing type of ', trim(name), ' from ', &
4353  trim(field_type_name(temp_field_p%field_type)), &
4354  ' to ', trim(field_type_name(integer_type))
4355  endif !}
4356  endif !}
4357  endif
4358 !
4359 ! Assign the type
4360 !
4361  temp_field_p%field_type = integer_type
4362 !
4363 ! Set the index if appending
4364 !
4365 
4366  if (present(append)) then !{
4367  if (append) then !{
4368  index_t = temp_field_p%max_index + 1
4369  endif !}
4370  endif !}
4371 
4372  if (index_t .gt. temp_field_p%max_index + 1) then !{
4373 
4374 !
4375 ! Index too large
4376 !
4377 
4378  if (verb .gt. verb_level_warn) then !{
4379  write (out_unit,*) trim(warn_header), &
4380  'Index too large for ', trim(name), ': ', index_t
4381  endif !}
4382  field_index = no_field
4383  return
4384 
4385  elseif (index_t .eq. 0 .and. &
4386  temp_field_p%max_index .gt. 0) then !}{
4387 !
4388 ! Can't set non-null field to null
4389 !
4390 
4391  if (verb .gt. verb_level_warn) then !{
4392  write (out_unit,*) trim(warn_header), &
4393  'Trying to nullify a non-null field: ', &
4394  trim(name)
4395  endif !}
4396  field_index = no_field
4397  return
4398 
4399  elseif (.not. associated(temp_field_p%i_value) .and. &
4400  index_t .gt. 0) then !}{
4401 !
4402 ! Array undefined, so allocate the array
4403 !
4404  allocate(temp_field_p%i_value(1))
4405  temp_field_p%max_index = 1
4406  temp_field_p%array_dim = 1
4407  elseif (index_t .gt. temp_field_p%array_dim) then !}{
4408 !
4409 ! Array is too small, so allocate new array and copy over
4410 ! old values
4411 !
4412  temp_field_p%array_dim = temp_field_p%array_dim + array_increment
4413  allocate (temp_i_value(temp_field_p%array_dim))
4414  do i = 1, temp_field_p%max_index !{
4415  temp_i_value(i) = temp_field_p%i_value(i)
4416  enddo !} i
4417  if (associated (temp_field_p%i_value)) deallocate(temp_field_p%i_value)
4418  temp_field_p%i_value => temp_i_value
4419  temp_field_p%max_index = index_t
4420  endif !}
4421 !
4422 ! Assign the value and set the field_index for return
4423 ! for non-null fields (index_t > 0)
4424 !
4425  if (index_t .gt. 0) then !{
4426  temp_field_p%i_value(index_t) = value
4427  if (index_t .gt. temp_field_p%max_index) then !{
4428  temp_field_p%max_index = index_t
4429  endif !}
4430  endif !}
4431  field_index = temp_field_p%index
4432 
4433  else !}{
4434 !
4435 ! Error in making the field
4436 !
4437 
4438  if (verb .gt. verb_level_warn) then !{
4439  write (out_unit,*) trim(warn_header), &
4440  'Could not create integer value field ', &
4441  trim(name)
4442  endif !}
4443  field_index = no_field
4444  endif !}
4445 else !}{
4446 !
4447 ! Error following the path
4448 !
4449 
4450  if (verb .gt. verb_level_warn) then !{
4451  write (out_unit,*) trim(warn_header), &
4452  'Could not follow path for ', &
4453  trim(name)
4454  endif !}
4455  field_index = no_field
4456 endif !}
4457 
4458 end function fm_new_value_integer !}
4459 
4460 !#######################################################################
4461 !#######################################################################
4462 
4463 function fm_new_value_logical(name, value, create, index, append) &
4464  result(field_index) !{
4466 ! Function definition
4467 !
4468 integer :: field_index
4469 !
4470 ! arguments
4471 !
4472 character(len=*), intent(in) :: name
4473 logical, intent(in) :: value
4474 logical, intent(in), optional :: create
4475 integer, intent(in), optional :: index
4476 logical, intent(in), optional :: append
4477 
4478 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4479 ! local parameters
4480 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4481 character(len=20), parameter :: sub_name = 'fm_new_value_logical'
4482 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
4483  '(' // trim(sub_name) // '): '
4484 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4485 ! local variables
4486 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4487 character(len=fm_path_name_len) :: path
4488 character(len=fm_field_name_len) :: base
4489 integer :: i, ier
4490 integer :: index_t
4491 logical :: create_t
4492 logical, dimension(:), pointer :: temp_l_value
4493 type(field_def), pointer, save :: temp_list_p
4494 type(field_def), pointer, save :: temp_field_p
4495 integer :: out_unit
4496 
4497 out_unit = stdout()
4498 !
4499 ! Initialize the field manager if needed
4500 !
4501 if (.not. module_is_initialized) then !{
4502  call initialize
4503 endif !}
4504 !
4505 ! Must supply a field name
4506 !
4507 if (name .eq. ' ') then !{
4508  if (verb .gt. verb_level_warn) then !{
4509  write (out_unit,*) trim(warn_header), 'Must supply a field name'
4510  endif !}
4511  field_index = no_field
4512  return
4513 endif !}
4514 !
4515 ! Check for optional arguments
4516 !
4517 if (present(create)) then !{
4518  create_t = create
4519 else !}{
4520  create_t = .false.
4521 endif !}
4522 !
4523 ! Check that append is not true and index greater than 0
4524 !
4525 if (present(index) .and. present(append)) then !{
4526  if (append .and. index .gt. 0) then !{
4527  if (verb .gt. verb_level_warn) then !{
4528  write (out_unit,*) trim(warn_header), &
4529  'Index and Append both set for ', trim(name)
4530  endif !}
4531  field_index = no_field
4532  return
4533  endif !}
4534 endif !}
4535 !
4536 ! Set index to define
4537 !
4538 
4539 if (present(index)) then !{
4540  index_t = index
4541  if (index_t .lt. 0) then !{
4542 !
4543 ! Index is negative
4544 !
4545 
4546  if (verb .gt. verb_level_warn) then !{
4547  write (out_unit,*) trim(warn_header), &
4548  'Optional index for ', trim(name), &
4549  ' negative: ', index_t
4550  endif !}
4551  field_index = no_field
4552  return
4553  endif !}
4554 else !}{
4555  index_t = 1
4556 endif !}
4557 !
4558 ! Get a pointer to the parent list
4559 !
4560 call find_base(name, path, base)
4561 temp_list_p => find_list(path, current_list_p, create_t)
4562 
4563 if (associated(temp_list_p)) then !{
4564  temp_field_p => find_field(base, temp_list_p)
4565  if (.not. associated(temp_field_p)) then !{
4566 !
4567 ! Create the field if it doesn't exist
4568 !
4569  temp_field_p => create_field(temp_list_p, base)
4570  endif !}
4571  if (associated(temp_field_p)) then !{
4572 !
4573 ! Check if the field_type is the same as previously
4574 ! If not then reset max_index to 0
4575 !
4576  if (temp_field_p%field_type /= logical_type ) then
4577  temp_field_p%max_index = 0
4578  if (temp_field_p%field_type /= null_type ) then !{
4579  if (verb .gt. verb_level_warn) then !{
4580  write (out_unit,*) trim(warn_header), &
4581  'Changing type of ', trim(name), ' from ', &
4582  trim(field_type_name(temp_field_p%field_type)), &
4583  ' to ', trim(field_type_name(logical_type))
4584  endif !}
4585  endif !}
4586  endif
4587 !
4588 ! Assign the type
4589 !
4590  temp_field_p%field_type = logical_type
4591 !
4592 ! Set the index if appending
4593 !
4594 
4595  if (present(append)) then !{
4596  if (append) then !{
4597  index_t = temp_field_p%max_index + 1
4598  endif !}
4599  endif !}
4600 
4601  if (index_t .gt. temp_field_p%max_index + 1) then !{
4602 
4603 !
4604 ! Index too large
4605 !
4606 
4607  if (verb .gt. verb_level_warn) then !{
4608  write (out_unit,*) trim(warn_header), &
4609  'Index too large for ', trim(name), ': ', index_t
4610  endif !}
4611  field_index = no_field
4612  return
4613 
4614  elseif (index_t .eq. 0 .and. &
4615  temp_field_p%max_index .gt. 0) then !}{
4616 
4617 !
4618 ! Can't set non-null field to null
4619 !
4620 
4621  if (verb .gt. verb_level_warn) then !{
4622  write (out_unit,*) trim(warn_header), &
4623  'Trying to nullify a non-null field: ', trim(name)
4624  endif !}
4625  field_index = no_field
4626  return
4627 
4628  elseif (.not. associated(temp_field_p%l_value) .and. &
4629  index_t .gt. 0) then !}{
4630 
4631 !
4632 ! Array undefined, so allocate the array
4633 !
4634 
4635  allocate(temp_field_p%l_value(1))
4636  temp_field_p%max_index = 1
4637  temp_field_p%array_dim = 1
4638 
4639  elseif (index_t .gt. temp_field_p%array_dim) then !}{
4640 
4641 !
4642 ! Array is too small, so allocate new array and copy over
4643 ! old values
4644 !
4645  temp_field_p%array_dim = temp_field_p%array_dim + array_increment
4646  allocate (temp_l_value(temp_field_p%array_dim))
4647  do i = 1, temp_field_p%max_index !{
4648  temp_l_value(i) = temp_field_p%l_value(i)
4649  enddo !} i
4650  if (associated(temp_field_p%l_value)) deallocate(temp_field_p%l_value)
4651  temp_field_p%l_value => temp_l_value
4652  temp_field_p%max_index = index_t
4653 
4654  endif !}
4655 
4656 !
4657 ! Assign the value and set the field_index for return
4658 ! for non-null fields (index_t > 0)
4659 !
4660 
4661  if (index_t .gt. 0) then !{
4662  temp_field_p%l_value(index_t) = value
4663  if (index_t .gt. temp_field_p%max_index) then !{
4664  temp_field_p%max_index = index_t
4665  endif !}
4666  endif !}
4667  field_index = temp_field_p%index
4668  else !}{
4669 !
4670 ! Error in making the field
4671 !
4672 
4673  if (verb .gt. verb_level_warn) then !{
4674  write (out_unit,*) trim(warn_header), &
4675  'Could not create logical value field ', &
4676  trim(name)
4677  endif !}
4678  field_index = no_field
4679  endif !}
4680 else !}{
4681 !
4682 ! Error following the path
4683 !
4684 
4685  if (verb .gt. verb_level_warn) then !{
4686  write (out_unit,*) trim(warn_header), &
4687  'Could not follow path for ', &
4688  trim(name)
4689  endif !}
4690  field_index = no_field
4691 endif !}
4692 
4693 end function fm_new_value_logical !}
4694 
4695 !#######################################################################
4696 !#######################################################################
4697 
4698 function fm_new_value_real(name, value, create, index, append) &
4699  result(field_index) !{
4701 ! Function definition
4702 !
4703 integer :: field_index
4704 !
4705 ! arguments
4706 !
4707 character(len=*), intent(in) :: name
4708 real, intent(in) :: value
4709 logical, intent(in), optional :: create
4710 integer, intent(in), optional :: index
4711 logical, intent(in), optional :: append
4712 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4713 ! local parameters
4714 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4715 
4716 character(len=17), parameter :: sub_name = 'fm_new_value_real'
4717 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
4718  '(' // trim(sub_name) // '): '
4719 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4720 ! local variables
4721 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4722 
4723 logical :: create_t
4724 integer :: i, ier
4725 integer :: index_t
4726 real, pointer, dimension(:) :: temp_r_value
4727 character(len=fm_path_name_len) :: path
4728 character(len=fm_field_name_len) :: base
4729 type(field_def), pointer, save :: temp_list_p
4730 type(field_def), pointer, save :: temp_field_p
4731 integer :: out_unit
4732 
4733 out_unit = stdout()
4734 !
4735 ! Initialize the field manager if needed
4736 !
4737 if (.not. module_is_initialized) then !{
4738  call initialize
4739 endif !}
4740 !
4741 ! Must supply a field name
4742 !
4743 if (name .eq. ' ') then !{
4744  if (verb .gt. verb_level_warn) then !{
4745  write (out_unit,*) trim(warn_header), 'Must supply a field name'
4746  endif !}
4747  field_index = no_field
4748  return
4749 endif !}
4750 !
4751 ! Check for optional arguments
4752 !
4753 if (present(create)) then !{
4754  create_t = create
4755 else !}{
4756  create_t = .false.
4757 endif !}
4758 !
4759 ! Check that append is not true and index greater than 0
4760 !
4761 if (present(index) .and. present(append)) then !{
4762  if (append .and. index .gt. 0) then !{
4763  if (verb .gt. verb_level_warn) then !{
4764  write (out_unit,*) trim(warn_header), &
4765  'Index and Append both set for ', trim(name)
4766  endif !}
4767  field_index = no_field
4768  return
4769  endif !}
4770 endif !}
4771 !
4772 ! Set index to define
4773 !
4774 
4775 if (present(index)) then !{
4776  index_t = index
4777  if (index_t .lt. 0) then !{
4778 !
4779 ! Index is negative
4780 !
4781 
4782  if (verb .gt. verb_level_warn) then !{
4783  write (out_unit,*) trim(warn_header), &
4784  'Optional index for ', trim(name), &
4785  ' negative: ', index_t
4786  endif !}
4787  field_index = no_field
4788  return
4789  endif !}
4790 else !}{
4791  index_t = 1
4792 endif !}
4793 
4794 !
4795 ! Get a pointer to the parent list
4796 !
4797 call find_base(name, path, base)
4798 temp_list_p => find_list(path, current_list_p, create_t)
4799 
4800 if (associated(temp_list_p)) then !{
4801  temp_field_p => find_field(base, temp_list_p)
4802  if (.not. associated(temp_field_p)) then !{
4803 !
4804 ! Create the field if it doesn't exist
4805 !
4806  temp_field_p => create_field(temp_list_p, base)
4807  endif !}
4808  if (associated(temp_field_p)) then !{
4809 !
4810 ! Check if the field_type is the same as previously
4811 ! If not then reset max_index to 0
4812 !
4813  if (temp_field_p%field_type == integer_type) then
4814  ! promote integer field to real
4815  allocate(temp_field_p%r_value(size(temp_field_p%i_value)))
4816  do i = 1, size(temp_field_p%i_value)
4817  temp_field_p%r_value(i) = temp_field_p%i_value(i)
4818  enddo
4819  temp_field_p%field_type = real_type
4820  deallocate(temp_field_p%i_value)
4821  else if (temp_field_p%field_type /= real_type ) then
4822  ! slm: why reset index to 0? does it make any sense? It sounds like this is the
4823  ! case where the values in the array have different types, so is it not an error?
4824  ! Or, alternatively, if string follows a real value, should not be the entire
4825  ! array converted to string type?
4826  temp_field_p%max_index = 0
4827  if (temp_field_p%field_type /= null_type ) then !{
4828  if (verb .gt. verb_level_warn) then !{
4829  write (out_unit,*) trim(warn_header), &
4830  'Changing type of ', trim(name), ' from ', &
4831  trim(field_type_name(temp_field_p%field_type)), &
4832  ' to ', trim(field_type_name(real_type))
4833  endif !}
4834  endif !}
4835  endif
4836 !
4837 ! Assign the type
4838 !
4839  temp_field_p%field_type = real_type
4840 !
4841 ! Set the index if appending
4842 !
4843  if (present(append)) then !{
4844  if (append) then !{
4845  index_t = temp_field_p%max_index + 1
4846  endif !}
4847  endif !}
4848  if (index_t .gt. temp_field_p%max_index + 1) then !{
4849 !
4850 ! Index too large
4851 !
4852 
4853  if (verb .gt. verb_level_warn) then !{
4854  write (out_unit,*) trim(warn_header), &
4855  'Index too large for ', trim(name), ': ', index_t
4856  endif !}
4857  field_index = no_field
4858  return
4859  elseif (index_t .eq. 0 .and. &
4860  temp_field_p%max_index .gt. 0) then !}{
4861 !
4862 ! Can't set non-null field to null
4863 !
4864 
4865  if (verb .gt. verb_level_warn) then !{
4866  write (out_unit,*) trim(warn_header), &
4867  'Trying to nullify a non-null field: ', &
4868  trim(name)
4869  endif !}
4870  field_index = no_field
4871  return
4872  elseif (.not. associated(temp_field_p%r_value) .and. &
4873  index_t .gt. 0) then !}{
4874 !
4875 ! Array undefined, so allocate the array
4876 !
4877  allocate(temp_field_p%r_value(1))
4878  temp_field_p%max_index = 1
4879  temp_field_p%array_dim = 1
4880  elseif (index_t .gt. temp_field_p%array_dim) then !}{
4881 !
4882 ! Array is too small, so allocate new array and copy over
4883 ! old values
4884 !
4885  temp_field_p%array_dim = temp_field_p%array_dim + array_increment
4886  allocate (temp_r_value(temp_field_p%array_dim))
4887  do i = 1, temp_field_p%max_index !{
4888  temp_r_value(i) = temp_field_p%r_value(i)
4889  enddo !} i
4890  if (associated(temp_field_p%r_value)) deallocate(temp_field_p%r_value)
4891  temp_field_p%r_value => temp_r_value
4892  temp_field_p%max_index = index_t
4893  endif !}
4894 !
4895 ! Assign the value and set the field_index for return
4896 ! for non-null fields (index_t > 0)
4897 !
4898  if (index_t .gt. 0) then !{
4899  temp_field_p%r_value(index_t) = value
4900  if (index_t .gt. temp_field_p%max_index) then !{
4901  temp_field_p%max_index = index_t
4902  endif !}
4903  endif !}
4904  field_index = temp_field_p%index
4905  else !}{
4906 !
4907 ! Error in making the field
4908 !
4909 
4910  if (verb .gt. verb_level_warn) then !{
4911  write (out_unit,*) trim(warn_header), &
4912  'Could not create real value field ', trim(name)
4913  endif !}
4914  field_index = no_field
4915  endif !}
4916 else !}{
4917 !
4918 ! Error following the path
4919 !
4920 
4921  if (verb .gt. verb_level_warn) then !{
4922  write (out_unit,*) trim(warn_header), &
4923  'Could not follow path for ', trim(name)
4924  endif !}
4925  field_index = no_field
4926 endif !}
4927 
4928 end function fm_new_value_real !}
4929 
4930 !#######################################################################
4931 !#######################################################################
4932 
4933 function fm_new_value_string(name, value, create, index, append) &
4934  result(field_index) !{
4936 ! Function definition
4937 !
4938 integer :: field_index
4939 !
4940 ! arguments
4941 !
4942 character(len=*), intent(in) :: name
4943 character(len=*), intent(in) :: value
4944 logical, intent(in), optional :: create
4945 integer, intent(in), optional :: index
4946 logical, intent(in), optional :: append
4947 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4948 ! local parameters
4949 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4950 
4951 character(len=19), parameter :: sub_name = 'fm_new_value_string'
4952 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
4953  '(' // trim(sub_name) // '): '
4954 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4955 ! local variables
4956 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4957 
4958 character(len=fm_string_len), dimension(:), pointer :: temp_s_value
4959 character(len=fm_path_name_len) :: path
4960 character(len=fm_field_name_len) :: base
4961 integer :: i, ier
4962 integer :: index_t
4963 logical :: create_t
4964 type(field_def), save, pointer :: temp_list_p
4965 type(field_def), save, pointer :: temp_field_p
4966 integer :: out_unit
4967 
4968 out_unit = stdout()
4969 !
4970 ! Initialize the field manager if needed
4971 !
4972 if (.not. module_is_initialized) then !{
4973  call initialize
4974 endif !}
4975 !
4976 ! Must supply a field name
4977 !
4978 if (name .eq. ' ') then !{
4979  if (verb .gt. verb_level_warn) then !{
4980  write (out_unit,*) trim(warn_header), 'Must supply a field name'
4981  endif !}
4982  field_index = no_field
4983  return
4984 endif !}
4985 !
4986 ! Check for optional arguments
4987 !
4988 if (present(create)) then !{
4989  create_t = create
4990 else !}{
4991  create_t = .false.
4992 endif !}
4993 !
4994 ! Check that append is not true and index greater than 0
4995 !
4996 
4997 if (present(index) .and. present(append)) then !{
4998  if (append .and. index .gt. 0) then !{
4999  if (verb .gt. verb_level_warn) then !{
5000  write (out_unit,*) trim(warn_header), &
5001  'Index and Append both set for ', trim(name)
5002  endif !}
5003  field_index = no_field
5004  return
5005  endif !}
5006 endif !}
5007 !
5008 ! Set index to define
5009 !
5010 if (present(index)) then !{
5011  index_t = index
5012  if (index_t .lt. 0) then !{
5013 !
5014 ! Index is negative
5015 !
5016 
5017  if (verb .gt. verb_level_warn) then !{
5018  write (out_unit,*) trim(warn_header), &
5019  'Optional index for ', trim(name), &
5020  ' negative: ', index_t
5021  endif !}
5022  field_index = no_field
5023  return
5024  endif !}
5025 else !}{
5026  index_t = 1
5027 endif !}
5028 
5029 !
5030 ! Get a pointer to the parent list
5031 !
5032 call find_base(name, path, base)
5033 temp_list_p => find_list(path, current_list_p, create_t)
5034 
5035 if (associated(temp_list_p)) then !{
5036  temp_field_p => find_field(base, temp_list_p)
5037  if (.not. associated(temp_field_p)) then !{
5038 !
5039 ! Create the field if it doesn't exist
5040 !
5041  temp_field_p => create_field(temp_list_p, base)
5042  endif !}
5043  if (associated(temp_field_p)) then !{
5044 !
5045 ! Check if the field_type is the same as previously
5046 ! If not then reset max_index to 0
5047 !
5048  if (temp_field_p%field_type /= string_type ) then
5049  temp_field_p%max_index = 0
5050  if (temp_field_p%field_type /= null_type ) then !{
5051  if (verb .gt. verb_level_warn) then !{
5052  write (out_unit,*) trim(warn_header), &
5053  'Changing type of ', trim(name), ' from ', &
5054  trim(field_type_name(temp_field_p%field_type)), &
5055  ' to ', trim(field_type_name(string_type))
5056  endif !}
5057  endif !}
5058  endif
5059 !
5060 ! Assign the type
5061 !
5062  temp_field_p%field_type = string_type
5063 !
5064 ! Set the index if appending
5065 !
5066 
5067  if (present(append)) then !{
5068  if (append) then !{
5069  index_t = temp_field_p%max_index + 1
5070  endif !}
5071  endif !}
5072 
5073  if (index_t .gt. temp_field_p%max_index + 1) then !{
5074 
5075 !
5076 ! Index too large
5077 !
5078 
5079  if (verb .gt. verb_level_warn) then !{
5080  write (out_unit,*) trim(warn_header), &
5081  'Index too large for ', trim(name), ': ', index_t
5082  endif !}
5083  field_index = no_field
5084  return
5085 
5086  elseif (index_t .eq. 0 .and. &
5087  temp_field_p%max_index .gt. 0) then !}{
5088 
5089 !
5090 ! Can't set non-null field to null
5091 !
5092 
5093  if (verb .gt. verb_level_warn) then !{
5094  write (out_unit,*) trim(warn_header), &
5095  'Trying to nullify a non-null field: ', &
5096  trim(name)
5097  endif !}
5098  field_index = no_field
5099  return
5100 
5101  elseif (.not. associated(temp_field_p%s_value) .and. &
5102  index_t .gt. 0) then !}{
5103 
5104 !
5105 ! Array undefined, so allocate the array
5106 !
5107 
5108  allocate(temp_field_p%s_value(1))
5109  temp_field_p%max_index = 1
5110  temp_field_p%array_dim = 1
5111 
5112  elseif (index_t .gt. temp_field_p%array_dim) then !}{
5113 
5114 !
5115 ! Array is too small, so allocate new array and copy over
5116 ! old values
5117 !
5118  temp_field_p%array_dim = temp_field_p%array_dim + array_increment
5119  allocate (temp_s_value(temp_field_p%array_dim))
5120  do i = 1, temp_field_p%max_index !{
5121  temp_s_value(i) = temp_field_p%s_value(i)
5122  enddo !} i
5123  if (associated(temp_field_p%s_value)) deallocate(temp_field_p%s_value)
5124  temp_field_p%s_value => temp_s_value
5125  temp_field_p%max_index = index_t
5126 
5127  endif !}
5128 
5129 !
5130 ! Assign the value and set the field_index for return
5131 ! for non-null fields (index_t > 0)
5132 !
5133 
5134  if (index_t .gt. 0) then !{
5135  temp_field_p%s_value(index_t) = value
5136  if (index_t .gt. temp_field_p%max_index) then !{
5137  temp_field_p%max_index = index_t
5138  endif !}
5139  endif !}
5140  field_index = temp_field_p%index
5141  else !}{
5142 !
5143 ! Error in making the field
5144 !
5145 
5146  if (verb .gt. verb_level_warn) then !{
5147  write (out_unit,*) trim(warn_header), &
5148  'Could not create string value field ', &
5149  trim(name)
5150  endif !}
5151  field_index = no_field
5152  endif !}
5153 else !}{
5154 !
5155 ! Error following the path
5156 !
5157 
5158  if (verb .gt. verb_level_warn) then !{
5159  write (out_unit,*) trim(warn_header), &
5160  'Could not follow path for ', trim(name)
5161  endif !}
5162  field_index = no_field
5163 endif !}
5164 
5165 end function fm_new_value_string !}
5166 ! </FUNCTION> NAME="fm_new_value"
5167 
5168 
5169 !#######################################################################
5170 !#######################################################################
5171 
5172 ! <FUNCTION NAME="fm_reset_loop">
5173 !
5174 ! <OVERVIEW>
5175 ! Resets the loop variable. For use in conjunction with fm_loop_over_list.
5176 ! </OVERVIEW>
5177 ! <DESCRIPTION>
5178 ! Resets the loop variable. For use in conjunction with fm_loop_over_list.
5179 ! </DESCRIPTION>
5180 ! <TEMPLATE>
5181 ! call fm_reset_loop
5182 ! </TEMPLATE>
5183 !
5184 subroutine fm_reset_loop
5186 ! arguments
5187 !
5188 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5189 ! local variables
5190 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5191 
5192 !
5193 ! Initialize the field manager if needed
5194 !
5195 if (.not. module_is_initialized) then !{
5196  call initialize
5197 endif !}
5198 !
5199 ! Reset the variables
5200 !
5201 loop_list = ' '
5202 nullify(loop_list_p)
5203 
5204 end subroutine fm_reset_loop !}
5205 ! </FUNCTION> NAME="fm_reset_loop"
5206 
5207 !#######################################################################
5208 !#######################################################################
5209 
5210 ! <FUNCTION NAME="fm_return_root">
5211 !
5212 ! <OVERVIEW>
5213 ! Return the root list to the value at initialization
5214 ! </OVERVIEW>
5215 ! <DESCRIPTION>
5216 ! Return the root list to the value at initialization.
5217 ! For use in conjunction with fm_change_root.
5218 !
5219 ! Users should use this routine before leaving their routine if they
5220 ! previously used fm_change_root.
5221 ! </DESCRIPTION>
5222 ! <TEMPLATE>
5223 ! call fm_return_root
5224 ! </TEMPLATE>
5225 !
5226 subroutine fm_return_root !{
5228 ! arguments
5229 !
5230 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5231 ! local variables
5232 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5233 !
5234 ! Initialize the field manager if needed
5235 !
5236 if (.not. module_is_initialized) then !{
5237  call initialize
5238 endif !}
5239 !
5240 ! restore the saved values to the current root
5241 !
5242 root_p%name = save_root_name
5243 root_p%parent => save_root_parent_p
5244 !
5245 ! set the pointer to the original root field
5246 !
5247 root_p => root
5248 !
5249 ! reset the save root name and parent variables
5250 !
5251 save_root_name = ' '
5252 nullify(save_root_parent_p)
5253 
5254 end subroutine fm_return_root !}
5255 ! </FUNCTION> NAME="fm_return_root"
5256 
5257 !#######################################################################
5258 !#######################################################################
5259 
5260 ! <PRIVATE><FUNCTION NAME="get_field">
5261 !
5262 ! <OVERVIEW>
5263 ! Return a pointer to the field if it exists relative to this_list_p,
5264 ! null otherwise
5265 ! </OVERVIEW>
5266 ! <DESCRIPTION>
5267 ! Return a pointer to the field if it exists relative to this_list_p,
5268 ! null otherwise
5269 ! </DESCRIPTION>
5270 ! <TEMPLATE>
5271 ! list_p => get_field(name, this_list_p)
5272 ! </TEMPLATE>
5273 !
5274 function get_field(name, this_list_p) &
5275  result(list_p) !{
5276 ! <OUT NAME="list_p" TYPE="type (field_def)">
5277 ! A pointer to the field name.
5278 ! </OUT>
5279 ! <IN NAME="name" TYPE="character(len=*)">
5280 ! The name of a list that the user wishes to get information for.
5281 ! </IN>
5282 ! <IN NAME="this_list_p" TYPE="type (field_def)">
5283 ! A pointer to a list that serves as the base point for searching for name.
5284 ! </IN>
5285 !
5286 ! Function definition
5287 !
5288 type(field_def), pointer :: list_p
5289 !
5290 ! arguments
5291 !
5292 character(len=*), intent(in) :: name
5293 type(field_def), pointer :: this_list_p
5294 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5295 ! local variables
5296 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5297 character(len=fm_path_name_len) :: path
5298 character(len=fm_field_name_len) :: base
5299 type(field_def), pointer, save :: temp_p
5300 
5301 nullify(list_p)
5302 !
5303 ! Get the path and base for name
5304 !
5305 call find_base(name, path, base)
5306 !
5307 ! Find the list if path is not empty
5308 !
5309 if (path .ne. ' ') then !{
5310  temp_p => find_list(path, this_list_p, .false.)
5311  if (associated(temp_p)) then !{
5312  list_p => find_field(base, temp_p)
5313  else !}{
5314  nullify(list_p)
5315  endif !}
5316 else !}{
5317  list_p => find_field(base, this_list_p)
5318 endif !}
5319 
5320 end function get_field !}
5321 ! </FUNCTION> NAME="get_field"
5322 !</PRIVATE>
5323 
5324 
5325 !#######################################################################
5326 !#######################################################################
5327 
5328 ! <FUNCTION NAME="fm_modify_name">
5329 !
5330 ! <OVERVIEW>
5331 ! This function allows a user to rename a field without modifying the
5332 ! contents of the field.
5333 ! </OVERVIEW>
5334 ! <DESCRIPTION>
5335 ! Function to modify the name of a field.
5336 ! Should be used with caution.
5337 ! </DESCRIPTION>
5338 ! <TEMPLATE>
5339 ! success = fm_modify_name(oldname, newname)
5340 ! </TEMPLATE>
5341 !
5342 function fm_modify_name(oldname, newname) &
5343  result(success) !{
5344 ! <OUT NAME="success" TYPE="logical">
5345 ! A flag to indicate whether the function operated with (FALSE) or
5346 ! without (TRUE) errors.
5347 ! </OUT>
5348 ! <IN NAME="oldname" TYPE="character(len=*)">
5349 ! The name of a field that the user wishes to change the name of.
5350 ! </IN>
5351 ! <IN NAME="newname" TYPE="character(len=*)">
5352 ! The name that the user wishes to change the name of the field to.
5353 ! </IN>
5354 !
5355 ! Function definition
5356 !
5357 logical :: success
5358 !
5359 ! arguments
5360 !
5361 character(len=*), intent(in) :: oldname
5362 character(len=*), intent(in) :: newname
5363 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5364 ! local variables
5365 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5366 character(len=fm_path_name_len) :: path
5367 character(len=fm_field_name_len) :: base
5368 type(field_def), pointer, save :: list_p
5369 type(field_def), pointer, save :: temp_p
5370 !
5371 ! Get the path and base for name
5372 !
5373 call find_base(oldname, path, base)
5374 !
5375 ! Find the list if path is not empty
5376 !
5377 success = .false.
5378 if (path .ne. ' ') then !{
5379  temp_p => find_list(path, current_list_p, .false.)
5380  if (associated(temp_p)) then !{
5381  list_p => find_field(base, temp_p)
5382  if (associated(list_p)) then !{
5383  list_p%name = newname
5384  success = .true.
5385  endif!}
5386  else !}{
5387  nullify(list_p)
5388  endif !}
5389 else !}{
5390  list_p => find_field(base, current_list_p)
5391  if (associated(list_p)) then !{
5392  list_p%name = newname
5393  success = .true.
5394  endif !}
5395 endif !}
5396 
5397 end function fm_modify_name !}
5398 ! </FUNCTION> NAME="fm_modify_name"
5399 
5400 
5401 !#######################################################################
5402 !#######################################################################
5403 
5404 ! <PRIVATE><FUNCTION NAME="initialize">
5405 !
5406 ! <OVERVIEW>
5407 ! A function to initialize the values of the pointers. This will remove
5408 ! all fields and reset the field tree to only the root field.
5409 ! </OVERVIEW>
5410 ! <DESCRIPTION>
5411 ! A function to initialize the values of the pointers. This will remove
5412 ! all fields and reset the field tree to only the root field.
5413 ! </DESCRIPTION>
5414 ! <TEMPLATE>
5415 ! call initialize
5416 ! </TEMPLATE>
5417 !
5418 subroutine initialize !{
5420 ! arguments
5421 !
5422 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5423 ! local variables
5424 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5425 integer :: ier
5426 !
5427 ! Initialize the root field
5428 !
5429 if (.not. module_is_initialized) then !{
5430  root_p => root
5431 
5432  field_type_name(integer_type) = 'integer'
5433  field_type_name(list_type) = 'list'
5434  field_type_name(logical_type) = 'logical'
5435  field_type_name(real_type) = 'real'
5436  field_type_name(string_type) = 'string'
5437 
5438  root%name = ' '
5439  root%index = 1
5440  root%parent => root_p
5441 
5442  root%field_type = list_type
5443 
5444  root%length = 0
5445  nullify(root%first_field)
5446  nullify(root%last_field)
5447  root%max_index = 0
5448  root%array_dim = 0
5449  if (associated(root%i_value)) deallocate(root%i_value)
5450  if (associated(root%l_value)) deallocate(root%l_value)
5451  if (associated(root%r_value)) deallocate(root%r_value)
5452  if (associated(root%s_value)) deallocate(root%s_value)
5453 
5454  nullify(root%next)
5455  nullify(root%prev)
5456 
5457  current_list_p => root
5458 
5459  nullify(loop_list_p)
5460  loop_list = ' '
5461 
5462  nullify(save_root_parent_p)
5463  save_root_name = ' '
5464 
5465  module_is_initialized = .true.
5466 
5467 endif !}
5468 
5469 end subroutine initialize !}
5470 ! </FUNCTION> NAME="initialize"
5471 !</PRIVATE>
5472 
5473 !#######################################################################
5474 !#######################################################################
5475 
5476 ! <PRIVATE><FUNCTION NAME="make_list">
5477 !
5478 ! <OVERVIEW>
5479 ! This function creates a new field and returns a pointer to that field.
5480 ! </OVERVIEW>
5481 ! <DESCRIPTION>
5482 ! Allocate and initialize a new list in this_list_p list.
5483 ! Return a pointer to the list on success, or a null pointer
5484 ! on failure
5485 ! </DESCRIPTION>
5486 ! <TEMPLATE>
5487 ! list_p => make_list(this_list_p, name)
5488 ! </TEMPLATE>
5489 !
5490 function make_list(this_list_p, name) &
5491  result(list_p) !{
5492 ! <OUT NAME="list_p" TYPE="type (field_def), pointer">
5493 ! A pointer to the list that has been created.
5494 ! </OUT>
5495 ! <IN NAME="this_list_p" TYPE="type (field_def), pointer">
5496 ! The base of a list that the user wishes to add a list to.
5497 ! </IN>
5498 ! <IN NAME="name" TYPE="character(len=*)">
5499 ! The name of a list that the user wishes to create.
5500 ! </IN>
5501 !
5502 ! Function definition
5503 !
5504 type(field_def), pointer :: list_p
5505 !
5506 ! arguments
5507 !
5508 type(field_def), pointer :: this_list_p
5509 character(len=*), intent(in) :: name
5510 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5511 ! local parameters
5512 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5513 character(len=9), parameter :: sub_name = 'make_list'
5514 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
5515  '(' // trim(sub_name) // '): '
5516 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5517 ! local variables
5518 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5519 integer :: ier
5520 type(field_def), pointer, save :: dummy_p
5521 integer :: out_unit
5522 
5523 out_unit = stdout()
5524 !
5525 ! Check to see whether there is already a list with
5526 ! this name, and if so, return an error as list names
5527 ! must be unique
5528 !
5529 dummy_p => find_field(name, this_list_p )
5530 if (associated(dummy_p)) then !{
5531 !
5532 ! This list is already specified, return an error
5533 !
5534  if (verb .gt. verb_level_warn) then !{
5535  write (out_unit,*) trim(warn_header), 'List ', &
5536  trim(name), ' already exists'
5537  endif !}
5538 ! nullify(list_p)
5539  list_p => dummy_p
5540  return
5541 endif !}
5542 !
5543 ! Create a field for the new list
5544 !
5545 nullify(list_p)
5546 list_p => create_field(this_list_p, name)
5547 if (.not. associated(list_p)) then !{
5548  if (verb .gt. verb_level_warn) then !{
5549  write (out_unit,*) trim(warn_header), &
5550  'Could not create field ', trim(name)
5551  endif !}
5552  nullify(list_p)
5553  return
5554 endif !}
5555 !
5556 ! Initialize the new list
5557 !
5558 list_p%length = 0
5559 list_p%field_type = list_type
5560 if (associated(list_p%i_value)) deallocate(list_p%i_value)
5561 if (associated(list_p%l_value)) deallocate(list_p%l_value)
5562 if (associated(list_p%r_value)) deallocate(list_p%r_value)
5563 if (associated(list_p%s_value)) deallocate(list_p%s_value)
5564 
5565 end function make_list !}
5566 ! </FUNCTION> NAME="make_list"
5567 !</PRIVATE>
5568 
5569 
5570 !#######################################################################
5571 !#######################################################################
5572 
5573 ! <FUNCTION NAME="fm_query_method">
5574 !
5575 ! <OVERVIEW>
5576 ! This is a function that provides the capability to return parameters
5577 ! associated with a field in a pair of strings.
5578 ! </OVERVIEW>
5579 ! <DESCRIPTION>
5580 ! Given a name return a list of method names and control strings.
5581 ! This function should return strings similar to those in the field
5582 ! table if a comma delimited format is being used.
5583 ! </DESCRIPTION>
5584 ! <TEMPLATE>
5585 ! success = fm_query_method(name, method_name, method_control)
5586 ! </TEMPLATE>
5587 !
5588 function fm_query_method(name, method_name, method_control) &
5589  result(success) !{
5590 ! <OUT NAME="success" TYPE="logical">
5591 ! A flag to indicate whether the function operated with (FALSE) or
5592 ! without (TRUE) errors.
5593 ! </OUT>
5594 ! <IN NAME="name" TYPE="character(len=*)">
5595 ! The name of a list that the user wishes to change to.
5596 ! </IN>
5597 ! <OUT NAME="method_name" TYPE="character(len=*)">
5598 ! The name of a parameter associated with the named field.
5599 ! </OUT>
5600 ! <OUT NAME="method_control" TYPE="character(len=*)">
5601 ! The value of parameters associated with the named field.
5602 ! </OUT>
5603 !
5604 ! Function definition
5605 !
5606 logical :: success
5607 !
5608 ! arguments
5609 !
5610 character(len=*), intent(in) :: name
5611 character(len=*), intent(out) :: method_name
5612 character(len=*), intent(out) :: method_control
5613 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5614 ! local parameters
5615 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5616 character(len=15), parameter :: sub_name = 'fm_query_method'
5617 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
5618  '(' // trim(sub_name) // '): '
5619 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5620 ! local variables
5621 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5622 character(len=fm_path_name_len) :: path
5623 character(len=fm_path_name_len) :: base
5624 character(len=fm_path_name_len) :: name_loc
5625 logical :: recursive_t
5626 type(field_def), pointer, save :: temp_list_p
5627 type(field_def), pointer, save :: temp_value_p
5628 type(field_def), pointer, save :: this_field_p
5629 integer :: out_unit
5630 
5631  out_unit = stdout()
5632  success = .false.
5633  recursive_t = .true.
5634  method_name = " "
5635  method_control = " "
5636 !
5637 ! Initialize the field manager if needed
5638 !
5639 if (.not. module_is_initialized) call initialize
5640 name_loc = lowercase(name)
5641 call find_base(name_loc, path, base)
5642 
5643  temp_list_p => find_list(name_loc, current_list_p, .false.)
5644 
5645 if (associated(temp_list_p)) then
5646 ! Find the entry values for the list.
5647  success = query_method(temp_list_p, recursive_t, base, method_name, method_control)
5648 else !}{
5649 ! This is not a list but it may be a parameter with a value
5650 ! If so put the parameter value in method_name.
5651 
5652  temp_value_p => find_list(path, current_list_p, .false.)
5653  if (associated(temp_value_p)) then !{
5654 ! Find the entry values for this item.
5655  this_field_p => temp_value_p%first_field
5656 
5657  do while (associated(this_field_p)) !{
5658  if ( this_field_p%name == base ) then !{
5659  method_name = this_field_p%s_value(1)
5660  method_control = ""
5661  success = .true.
5662  exit
5663  else !}{
5664  success = .false.
5665  endif !}
5666  this_field_p => this_field_p%next
5667  enddo
5668 
5669  else !}{
5670 !
5671 ! Error following the path
5672 !
5673  if (verb .gt. verb_level_warn) then
5674  write (out_unit,*) trim(warn_header), 'Could not follow path for ', trim(path)
5675  endif
5676  success = .false.
5677  endif !}
5678 endif !}
5679 
5680 end function fm_query_method !}
5681 ! </FUNCTION> NAME="fm_query_method"
5682 
5683 !#######################################################################
5684 !#######################################################################
5685 
5686 ! <PRIVATE><FUNCTION NAME="query_method">
5687 !
5688 ! <OVERVIEW>
5689 ! A private function that can recursively recover values for parameters
5690 ! associated with a field.
5691 ! </OVERVIEW>
5692 ! <DESCRIPTION>
5693 ! A private function that can recursively recover values for parameters
5694 ! associated with a field.
5695 ! </DESCRIPTION>
5696 ! <TEMPLATE>
5697 ! success = query_method(list_p, recursive, name, method_name, method_control)
5698 ! </TEMPLATE>
5699 !
5700 recursive function query_method(list_p, recursive, name, method_name, method_control) &
5701  result(success)
5702 logical :: success
5703 ! <OUT NAME="success" TYPE="logical">
5704 ! A flag to indicate whether the function operated with (FALSE) or
5705 ! without (TRUE) errors.
5706 ! </OUT>
5707 ! <IN NAME="list_p" TYPE="type (field_def), pointer">
5708 ! A pointer to the field that is of interest.
5709 ! </IN>
5710 ! <IN NAME="name" TYPE="character(len=*)">
5711 ! The name of a list that the user wishes to change to.
5712 ! </IN>
5713 ! <OUT NAME="method_name" TYPE="character(len=*)">
5714 ! The name of a parameter associated with the named field.
5715 ! </OUT>
5716 ! <OUT NAME="method_control" TYPE="character(len=*)">
5717 ! The value of parameters associated with the named field.
5718 ! </OUT>
5719 !
5720 ! Function definition
5721 !
5722 !
5723 ! arguments
5724 !
5725 type(field_def), pointer :: list_p
5726 logical, intent(in) :: recursive
5727 character(len=*), intent(in) :: name
5728 character(len=*), intent(out) :: method_name, method_control
5729 
5730 ! local parameters
5731 character(len=12), parameter :: sub_name = 'query_method'
5732 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
5733  '(' // trim(sub_name) // '): '
5734 ! local variables
5735 integer :: i
5736 character(len=64) :: scratch
5737 type(field_def), pointer :: this_field_p
5738 integer :: out_unit
5739 
5740 out_unit = stdout()
5741 
5742 ! Check for a valid list
5743 if (.not. associated(list_p)) then
5744  if (verb .gt. verb_level_warn) then
5745  write (out_unit,*) trim(warn_header), 'Invalid list pointer'
5746  endif
5747  success = .false.
5748 elseif (list_p%field_type .ne. list_type) then
5749  if (verb .gt. verb_level_warn) then
5750  write (out_unit,*) trim(warn_header), trim(list_p%name)//' is not a list'
5751  endif
5752  success = .false.
5753 else
5754 
5755  ! set the default return value
5756  success = .true.
5757 
5758  this_field_p => list_p%first_field
5759 
5760  do while (associated(this_field_p))
5761  select case(this_field_p%field_type)
5762  case(list_type)
5763  ! If this is a list, then this is the method name
5764  if (recursive) then
5765  if (.not. query_method(this_field_p, .true., this_field_p%name, method_name, method_control)) then
5766  success = .false.
5767  exit
5768  else
5769  method_name = trim(method_name)//trim(this_field_p%name)
5770  ! TODO: check length
5771  endif
5772  endif
5773 
5774  case(integer_type)
5775  write (scratch,*) this_field_p%i_value
5776  call concat_strings(method_control, comma//trim(this_field_p%name)//' = '//trim(adjustl(scratch)))
5777 
5778  case(logical_type)
5779  write (scratch,'(l1)')this_field_p%l_value
5780  call concat_strings(method_control, comma//trim(this_field_p%name)//' = '//trim(adjustl(scratch)))
5781 
5782  case(real_type)
5783  write (scratch,*) this_field_p%r_value
5784  call concat_strings(method_control, comma//trim(this_field_p%name)//' = '//trim(adjustl(scratch)))
5785 
5786  case(string_type)
5787  call concat_strings(method_control, comma//trim(this_field_p%name)//' = '//trim(this_field_p%s_value(1)))
5788  do i = 2, this_field_p%max_index
5789  call concat_strings(method_control, comma//trim(this_field_p%s_value(i)))
5790  enddo
5791 
5792  case default
5793  if (verb .gt. verb_level_warn) then
5794  write (out_unit,*) trim(warn_header), 'Undefined type for ', trim(this_field_p%name)
5795  endif
5796  success = .false.
5797  exit
5798 
5799  end select
5800  this_field_p => this_field_p%next
5801  enddo
5802 endif
5803 
5804 end function query_method
5805 
5806 !#######################################################################
5807 ! private function: appends str2 to the end of str1, with length check
5808 subroutine concat_strings(str1,str2)
5809  character(*), intent(inout) :: str1
5810  character(*), intent(in) :: str2
5811 
5812  character(64) :: n1,n2 ! for error reporting
5813 
5814  if (len_trim(str1)+len_trim(str2)>len(str1)) then
5815  write(n1,*)len(str1)
5816  write(n2,*)len_trim(str1)+len_trim(str2)
5817  call mpp_error(fatal,'length of output string ('//trim(adjustl(n1))&
5818  //') is not enough for the result of concatenation (len='&
5819  //trim(adjustl(n2))//')')
5820  endif
5821  str1 = trim(str1)//trim(str2)
5822 end subroutine concat_strings
5823 
5824 ! </FUNCTION> NAME="query_method"
5825 !</PRIVATE>
5826 
5827 !#######################################################################
5828 !#######################################################################
5829 
5830 ! <FUNCTION NAME = "fm_copy_list" >
5831 ! <OVERVIEW>
5832 ! A function that allows the user to copy a field and add a suffix to
5833 ! the name of the new field.
5834 ! </OVERVIEW>
5835 ! <DESCRIPTION>
5836 ! Given the name of a pre-existing field and a suffix, this function
5837 ! will create a new field. The name of the new field will be that of
5838 ! the old field with a suffix supplied by the user.
5839 ! </DESCRIPTION>
5840 ! <TEMPLATE>
5841 ! index = fm_copy_list(list_name, suffix, create)
5842 ! </TEMPLATE>
5843 !
5844 function fm_copy_list(list_name, suffix, create ) &
5845  result(index) !{
5846 ! <OUT NAME="index" TYPE="integer">
5847 ! The index of the field that has been created by the copy.
5848 ! </OUT>
5849 ! <IN NAME="list_name" TYPE="character(len=*)">
5850 ! The name of a field that the user wishes to copy..
5851 ! </IN>
5852 ! <IN NAME="suffix" TYPE="character(len=*)">
5853 ! The suffix that will be added to list_name when the field is copied.
5854 ! </IN>
5855 !
5856 ! Function definition
5857 !
5858 integer :: index
5859 !
5860 ! arguments
5861 !
5862 character(len=*), intent(in) :: list_name
5863 character(len=*), intent(in) :: suffix
5864 logical, intent(in), optional :: create
5865 
5866 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5867 ! local parameters
5868 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5869 character(len=12), parameter :: sub_name = 'fm_copy_list'
5870 character(len=64), parameter :: error_header = '==>Error from ' // trim(module_name) // &
5871  '(' // trim(sub_name) // '): '
5872 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
5873  '(' // trim(sub_name) // '): '
5874 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5875 ! local variables
5876 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5877 character(len=fm_string_len), dimension(MAX_FIELD_METHODS) :: control
5878 character(len=fm_string_len), dimension(MAX_FIELD_METHODS) :: method
5879 character(len=fm_string_len) :: head
5880 character(len=fm_string_len) :: list_name_new
5881 character(len=fm_string_len) :: tail
5882 character(len=fm_string_len) :: val_str
5883 integer :: n
5884 integer :: num_meth
5885 integer :: val_int
5886 logical :: found_methods
5887 logical :: got_value
5888 logical :: recursive_t
5889 logical :: success
5890 logical :: val_logical
5891 real :: val_real
5892 type(field_def), pointer, save :: temp_field_p
5893 type(field_def), pointer, save :: temp_list_p
5894 integer :: out_unit
5895 
5896 out_unit = stdout()
5897 
5898 
5899 num_meth= 1
5900 list_name_new = trim(list_name)//trim(suffix)
5901 !
5902  recursive_t = .true.
5903 !
5904 ! Initialize the field manager if needed
5905 !
5906 if (.not. module_is_initialized) then !{
5907  call initialize
5908 endif !}
5909 
5910 if (list_name .eq. ' ') then !{
5911 !
5912 ! If list is empty, then dump the current list
5913 !
5914  temp_list_p => current_list_p
5915  success = .true.
5916 else !}{
5917 !
5918 ! Get a pointer to the list
5919 !
5920  temp_list_p => find_list(list_name, current_list_p, .false.)
5921  if (associated(temp_list_p)) then !{
5922  success = .true.
5923  else !}{
5924 !
5925 ! Error following the path
5926 !
5927  if (verb .gt. verb_level_warn) then
5928  write (out_unit,*) trim(warn_header), 'Could not follow path for ', trim(list_name)
5929  endif
5930  success = .false.
5931  endif !}
5932 endif !}
5933 
5934 !
5935 ! Find the list
5936 !
5937 if (success) then !{
5938  method(:) = ' '
5939  control(:) = ' '
5940  found_methods = fm_find_methods(trim(list_name), method, control)
5941  do n = 1, max_field_methods
5942  if (len_trim(method(n)) > 0 ) then
5943  index = fm_new_list(trim(list_name_new)//list_sep//method(n), create = create)
5944  call find_base(method(n), head, tail)
5945  temp_field_p => find_list(trim(list_name)//list_sep//head,temp_list_p, .false.)
5946  temp_field_p => find_field(tail,temp_field_p)
5947  select case (temp_field_p%field_type)
5948  case (integer_type)
5949  got_value = fm_get_value( trim(list_name)//list_sep//method(n), val_int)
5950  if ( fm_new_value( trim(list_name_new)//list_sep//method(n), val_int, &
5951  create = create, append = .true.) < 0 ) &
5952  call mpp_error(fatal, trim(error_header)//'Could not set the '//trim(method(n))//&
5953  ' for '//trim(list_name)//trim(suffix))
5954 
5955  case (logical_type)
5956  got_value = fm_get_value( trim(list_name)//list_sep//method(n), val_logical)
5957  if ( fm_new_value( trim(list_name_new)//list_sep//method(n), val_logical, &
5958  create = create, append = .true.) < 0 ) &
5959  call mpp_error(fatal, trim(error_header)//'Could not set the '//trim(method(n))//&
5960  ' for '//trim(list_name)//trim(suffix))
5961 
5962  case (real_type)
5963  got_value = fm_get_value( trim(list_name)//list_sep//method(n), val_real)
5964  if ( fm_new_value( trim(list_name_new)//list_sep//method(n), val_real, &
5965  create = create, append = .true.) < 0 ) &
5966  call mpp_error(fatal, trim(error_header)//'Could not set the '//trim(method(n))//&
5967  ' for '//trim(list_name)//trim(suffix))
5968 
5969  case (string_type)
5970  got_value = fm_get_value( trim(list_name)//list_sep//method(n), val_str)
5971  if ( fm_new_value( trim(list_name_new)//list_sep//method(n), val_str, &
5972  create = create, append = .true.) < 0 ) &
5973  call mpp_error(fatal, trim(error_header)//'Could not set the '//trim(method(n))//&
5974  ' for '//trim(list_name)//trim(suffix))
5975  case default
5976  end select
5977 
5978  endif
5979  enddo
5980 endif !}
5981 
5982 end function fm_copy_list !}
5983 ! </FUNCTION > NAME = "fm_copy_list"
5984 
5985 !#######################################################################
5986 !#######################################################################
5987 
5988 ! <FUNCTION NAME = "fm_find_methods" >
5989 ! <OVERVIEW>
5990 ! This function retrieves all the methods associated with a field.
5991 ! </OVERVIEW>
5992 ! <DESCRIPTION>
5993 ! This function retrieves all the methods associated with a field.
5994 ! This is different from fm_query_method in that this function gets all
5995 ! the methods associated as opposed to 1 method.
5996 ! </DESCRIPTION>
5997 ! <TEMPLATE>
5998 ! success = fm_find_methods(list_name, methods, control )
5999 ! </TEMPLATE>
6000 !
6001 function fm_find_methods(list_name, methods, control ) &
6002  result(success) !{
6003 ! <OUT NAME="success" TYPE="logical">
6004 ! A flag to indicate whether the function operated with (FALSE) or
6005 ! without (TRUE) errors.
6006 ! </OUT>
6007 ! <IN NAME="list_name" TYPE="character(len=*)">
6008 ! The name of a list that the user wishes to find methods for.
6009 ! </IN>
6010 ! <OUT NAME="methods" TYPE="character(len=*)">
6011 ! An array of the methods associated with list_name.
6012 ! </OUT>
6013 ! <OUT NAME="control" TYPE="character(len=*)">
6014 ! An array of the parameters associated with methods.
6015 ! </OUT>
6016 !
6017 ! Function definition
6018 !
6019 logical :: success
6020 !
6021 ! arguments
6022 !
6023 character(len=*), intent(in) :: list_name
6024 character(len=*), intent(out), dimension(:) :: methods
6025 character(len=*), intent(out), dimension(:) :: control
6026 
6027 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
6028 ! local parameters
6029 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
6030 character(len=15), parameter :: sub_name = 'fm_find_methods'
6031 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
6032  '(' // trim(sub_name) // '): '
6033 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
6034 ! local variables
6035 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
6036 integer :: num_meth
6037 logical :: recursive_t
6038 type(field_def), pointer, save :: temp_list_p
6039 integer :: out_unit
6040 
6041 out_unit = stdout()
6042 num_meth= 1
6043 !
6044 ! Check whether to do things recursively
6045 !
6046  recursive_t = .true.
6047 ! recursive_t = .false.
6048 !
6049 ! Initialize the field manager if needed
6050 !
6051 if (.not. module_is_initialized) then !{
6052  call initialize
6053 endif !}
6054 
6055 if (list_name .eq. ' ') then !{
6056 !
6057 ! If list is empty, then dump the current list
6058 !
6059  temp_list_p => current_list_p
6060  success = .true.
6061 else !}{
6062 !
6063 ! Get a pointer to the list
6064 !
6065  temp_list_p => find_list(list_name, current_list_p, .false.)
6066  if (associated(temp_list_p)) then !{
6067  success = .true.
6068  else !}{
6069 !
6070 ! Error following the path
6071 !
6072  if (verb .gt. verb_level_warn) then
6073  write (out_unit,*) trim(warn_header), 'Could not follow path for ', trim(list_name)
6074  endif
6075  success = .false.
6076  endif !}
6077 endif !}
6078 
6079 !
6080 ! Find the list
6081 !
6082 if (success) then !{
6083  success = find_method(temp_list_p, recursive_t, num_meth, methods, control)
6084 endif !}
6085 
6086 end function fm_find_methods !}
6087 ! </FUNCTION > NAME = "fm_find_methods"
6088 
6089 !#######################################################################
6090 !#######################################################################
6091 
6092 ! <PRIVATE><FUNCTION NAME = "find_method">
6093 !
6094 ! <OVERVIEW>
6095 ! Given a field list pointer this function retrieves methods and
6096 ! associated parameters for the field list.
6097 ! </OVERVIEW>
6098 ! <DESCRIPTION>
6099 ! Given a field list pointer this function retrieves methods and
6100 ! associated parameters for the field list.
6101 ! </DESCRIPTION>
6102 ! <TEMPLATE>
6103 ! success = find_method(list_p, recursive, num_meth, method, control)
6104 ! </TEMPLATE>
6105 !
6106 recursive function find_method(list_p, recursive, num_meth, method, control) &
6107  result(success) !{
6108 ! <OUT NAME="success" TYPE="logical">
6109 ! A flag to indicate whether the function operated with (FALSE) or
6110 ! without (TRUE) errors.
6111 ! </OUT>
6112 ! <IN NAME="list_p" TYPE="type (field_def), pointer">
6113 ! A pointer to the field of interest
6114 ! </IN>
6115 ! <IN NAME="recursive" TYPE="logical">
6116 ! If true, then recursively search for methods.
6117 ! </IN>
6118 ! <INOUT NAME="num_meth" TYPE="integer">
6119 ! The number of methods found.
6120 ! </INOUT>
6121 ! <OUT NAME="method" TYPE="character(len=*)" DIM="(:)">
6122 ! The methods associated with the field pointed to by list_p
6123 ! </OUT>
6124 ! <OUT NAME="control" TYPE="character(len=*)" DIM="(:)">
6125 ! The control parameters for the methods found.
6126 ! </OUT>
6127 !
6128 ! Function definition
6129 !
6130 logical :: success
6131 !
6132 ! arguments
6133 !
6134 type(field_def), pointer :: list_p
6135 logical, intent(in) :: recursive
6136 integer, intent(inout) :: num_meth
6137 character(len=*), intent(out), dimension(:) :: method
6138 character(len=*), intent(out), dimension(:) :: control
6139 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
6140 ! local parameters
6141 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
6142 character(len=11), parameter :: sub_name = 'find_method'
6143 character(len=64), parameter :: warn_header = '==>Warning from ' // trim(module_name) // &
6144  '(' // trim(sub_name) // '): '
6145 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
6146 ! local variables
6147 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
6148 character(len=fm_path_name_len) :: scratch
6149 integer :: depthp1
6150 integer :: first
6151 integer :: i
6152 integer :: last
6153 integer :: n
6154 type(field_def), pointer, save :: this_field_p
6155 integer :: out_unit
6156 
6157 out_unit = stdout()
6158 !
6159 ! Check for a valid list
6160 !
6161 if (.not. associated(list_p)) then !{
6162  if (verb .gt. verb_level_warn) then
6163  write (out_unit,*) trim(warn_header), 'Invalid list pointer'
6164  endif
6165  success = .false.
6166 elseif (list_p%field_type .ne. list_type) then !}{
6167  if (verb .gt. verb_level_warn) then
6168  write (out_unit,*) trim(warn_header), trim(list_p%name), ' is not a list'
6169  endif
6170  success = .false.
6171 else !}{
6172 !
6173 ! set the default return value
6174 !
6175  success = .true.
6176 
6177  this_field_p => list_p%first_field
6178 
6179  do while (associated(this_field_p)) !{
6180  select case(this_field_p%field_type)
6181  case(list_type)
6182 !
6183 ! If this is a list, then this is the method name
6184 !
6185  if ( this_field_p%length > 1) then
6186  do n = num_meth+1, num_meth + this_field_p%length - 1
6187  write (method(n),'(a,a,a,$)') trim(method(num_meth)), &
6188  trim(this_field_p%name), list_sep
6189  enddo
6190  write (method(num_meth),'(a,a,a,$)') trim(method(num_meth)), &
6191  trim(this_field_p%name), list_sep
6192  else
6193  write (method(num_meth),'(a,a,a,$)') trim(method(num_meth)), &
6194  trim(this_field_p%name), list_sep
6195  endif
6196  success = find_method(this_field_p, .true., num_meth, method, control)
6197 
6198  case(integer_type)
6199  write (scratch,*) this_field_p%i_value
6200  call strip_front_blanks(scratch)
6201  write (method(num_meth),'(a,a)') trim(method(num_meth)), &
6202  trim(this_field_p%name)
6203  write (control(num_meth),'(a)') &
6204  trim(scratch)
6205  num_meth = num_meth + 1
6206 
6207 
6208  case(logical_type)
6209 
6210  write (method(num_meth),'(a,a)') trim(method(num_meth)), &
6211  trim(this_field_p%name)
6212  write (control(num_meth),'(l1)') &
6213  this_field_p%l_value
6214  num_meth = num_meth + 1
6215 
6216  case(real_type)
6217 
6218  write (scratch,*) this_field_p%r_value
6219  call strip_front_blanks(scratch)
6220  write (method(num_meth),'(a,a)') trim(method(num_meth)), &
6221  trim(this_field_p%name)
6222  write (control(num_meth),'(a)') &
6223  trim(scratch)
6224  num_meth = num_meth + 1
6225 
6226 
6227  case(string_type)
6228  write (method(num_meth),'(a,a)') trim(method(num_meth)), &
6229  trim(this_field_p%name)
6230  write (control(num_meth),'(a)') &
6231  trim(this_field_p%s_value(1))
6232  do i = 2, this_field_p%max_index
6233  write (control(num_meth),'(a,a,$)') comma//trim(this_field_p%s_value(i))
6234  enddo
6235  num_meth = num_meth + 1
6236 
6237 
6238  case default
6239  if (verb .gt. verb_level_warn) then
6240  write (out_unit,*) trim(warn_header), 'Undefined type for ', trim(this_field_p%name)
6241  endif
6242  success = .false.
6243  exit
6244 
6245  end select
6246 
6247  this_field_p => this_field_p%next
6248  enddo !}
6249 endif !}
6250 
6251 end function find_method !}
6252 ! </FUNCTION > NAME = "find_method"
6253 !</PRIVATE>
6254 
6255 !#######################################################################
6256 ! <SUBROUTINE NAME="fm_set_verbosity">
6257 !
6258 ! <OVERVIEW>
6259 ! A subroutine to set the verbosity of the field manager output.
6260 ! </OVERVIEW>
6261 ! <DESCRIPTION>
6262 ! This subroutine will set the level of verbosity in the module.
6263 ! Currently, verbosity is either on (1) or off (0). However,
6264 ! in the future, "on" may have more granularity. If no argument
6265 ! is given, then, if verbosity is on it will be turned off, and
6266 ! is off, will be turned to the default on level.
6267 ! If verbosity is negative then it is turned off.
6268 ! Values greater than the maximum will be set to the maximum.
6269 ! </DESCRIPTION>
6270 ! <TEMPLATE>
6271 ! call fm_set_verbosity(verbosity)
6272 ! </TEMPLATE>
6273 !
6274 subroutine fm_set_verbosity(verbosity) !{
6275 ! <IN NAME="verbosity" TYPE="integer, optional">
6276 ! The level of verbosity required by the user.
6277 ! </IN>
6278 !
6279 ! arguments
6280 !
6281 
6282 integer, intent(in), optional :: verbosity
6283 
6284 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
6285 ! local parameters
6286 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
6287 
6288 character(len=16), parameter :: sub_name = 'fm_set_verbosity'
6289 character(len=64), parameter :: note_header = '==>Note from ' // trim(module_name) // &
6290  '(' // trim(sub_name) // '): '
6291 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
6292 ! local variables
6293 !+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
6294 integer :: out_unit
6295 
6296 out_unit = stdout()
6297 
6298 !
6299 ! Check whether an argument has been given
6300 !
6301 
6302 if (present(verbosity)) then !{
6303 
6304  if (verbosity .le. 0) then !{
6305  verb = 0
6306  elseif (verbosity .ge. max_verbosity) then !}{
6308  else !}{
6309  verb = verbosity
6310  endif !}
6311 
6312 else !}{
6313 
6314  if (verb .eq. 0) then !{
6316  else !}{
6317  verb = 0
6318  endif !}
6319 
6320 endif !}
6321 
6322 write (out_unit,*)
6323 write (out_unit,*) trim(note_header), &
6324  'Verbosity now at level ', verb
6325 write (out_unit,*)
6326 
6327 end subroutine fm_set_verbosity !}
6328 ! </SUBROUTINE> NAME="fm_set_verbosity"
6329 
6330 end module field_manager_mod
6331 
6332 #ifdef test_field_manager
6333 
6334 program test
6335 
6337 use mpp_mod, only : mpp_exit, mpp_pe, mpp_root_pe, mpp_error, note
6338 
6339 implicit none
6340 !#include "mpif.h"
6341 
6342 
6343 integer :: i, j, nfields, num_methods, model
6344 character(len=fm_string_len) :: field_type, field_name, str, name_field_type, path
6345 character(len=512) :: method_name, method_control
6346 real :: param
6347 integer :: flag, index
6348 logical :: success
6349 type(method_type), dimension(20) :: methods
6350 
6351 call field_manager_init(nfields)
6352 
6353 ! Dump the list of fields produced from reading the field_table
6354 
6355 ! Here are the lists that propagate off the root "/"
6356 ! By calling fm_dump_list with a single argument you only get the
6357 ! lists branching off this argument in the list.
6358 write(*,*) "Here's a baseline listing"
6359 success = fm_dump_list("/")
6360 write(*,*) '+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+'
6361 
6362 ! By adding the optional .true. argument you get a recursive listing of the fields.
6363 write(*,*) "Here's a recursive listing"
6364 success = fm_dump_list("/", .true.)
6365 write(*,*) '+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+'
6366 
6367 ! Using fm_dump_list with a blank first argument returns the last field accessed by field manager.
6368 write(*,*) 'Dumping last field changed to by field_manager using fm_change_list'
6369 success = fm_dump_list("", .true.)
6370 write(*,*) '+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+'
6371 
6372 ! Change list to look at the land model fields
6373 write(*,*) 'Changing list to land_mod'
6374 success = fm_change_list("/land_mod")
6375 write(*,*) 'Dumping last list changed to by field_manager using fm_change_list i.e list of land model fields'
6376 success = fm_dump_list("", .true.)
6377 write(*,*) '+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+'
6378 
6379 ! Now let's modify some of the field entries.
6380 !
6381 !In this example we add a field ( convection = 'off' ) to the radon list
6382 write(*,*) "ADDING convection = off TO RADON LIST"
6383 !if ( fm_change_list('/atmos_mod/tracer/radon')) then
6384 if ( fm_exists('/atmos_mod/tracer/radon')) then
6385  write(*,*) "'/atmos_mod/tracer/radon' exists "
6386  success = fm_change_list('/atmos_mod/tracer/radon')
6387 ! The next line creates a new field branching off radon.
6388  index = fm_new_value('convection','off')
6389 endif
6390 
6391 success = fm_query_method('radon',method_name,method_control)
6392 if (success ) then
6393 call mpp_error(note, "Method names for radon is/are "//trim(method_name))
6394 call mpp_error(note, "Method controls for radon is/are "//trim(method_control))
6395 else
6396 call mpp_error(note, "There is no atmos model radon field defined in the field_table")
6397 endif
6398 ! Dump the listing of the modified tracer
6399 success = fm_dump_list("/atmos_mod/tracer/radon", .true.)
6400 if (.not. success ) call mpp_error(note, "There is no atmos model radon field defined in the field_table")
6401 write(*,*) '+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+'
6402 
6403 
6404 ! Find out what the current path is. Should be '/atmos_mod/tracer/radon' as set in fm_change_list above.
6405 path = fm_get_current_list()
6406 write(*,*) 'Current path is ',trim(path)
6407 write(*,*) '+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+'
6408 
6409 ! Now let's modify the value of the field we just added.
6410 write(*,*) "MODIFYING RADON FIELD CONVECTION ATTRIBUTE TO convection = RAS_off "
6411 index = fm_new_value('convection','RAS_off')
6412 
6413 ! Dump the listing of the modified tracer
6414 success = fm_dump_list("/atmos_mod/tracer/radon", .true.)
6415 write(*,*) '+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+'
6416 
6417 
6418 
6419 
6420 
6421 write(*,*) "ORIGINAL OCEAN MODEL TRACER FIELDS"
6422 
6423 ! Dump the listing of the original ocean model tracers
6424 success = fm_dump_list("/ocean_mod/tracer", .true.)
6425 write(*,*) '+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+'
6426 
6427 
6428 index = fm_get_length("/ocean_mod/tracer")
6429 write(*,*) "The length of the current list '/ocean_mod/tracer' is ",index," i.e."
6430 success = fm_dump_list("/ocean_mod/tracer")
6431 write(*,*) '+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+'
6432 
6433 ! Find out what type of field this is. Possibilities are real, integer, string, logical, and list
6434 name_field_type = fm_get_type('/ocean_mod/tracer/biotic1/diff_horiz/linear/slope')
6435 write(*,*) 'The type for /ocean_mod/tracer/biotic1/diff_horiz/linear/slope is ',name_field_type
6436 
6437 success = fm_get_value('/ocean_mod/tracer/biotic1/diff_horiz/linear/slope',str)
6438 write(*,*) 'The value for /ocean_mod/tracer/biotic1/diff_horiz/linear/slope is (character) ',str
6439 
6440 
6441 write(*,*) '+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+'
6442 
6443 write(*,*) "MODIFYING BIOTIC1 FIELD slope ATTRIBUTE TO slope = 0.95 "
6444 if ( fm_change_list('/ocean_mod/tracer/biotic1/diff_horiz/linear')) &
6445  index = fm_new_value('slope',0.95, index = 1)
6446 
6447 ! Dump the listing of the modified ocean model tracer attribute
6448 success = fm_dump_list("/ocean_mod/tracer/biotic1", .true.)
6449 write(*,*) '+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+'
6450 
6451 name_field_type = fm_get_type('/ocean_mod/tracer/biotic1/diff_horiz/linear/slope')
6452 write(*,*) 'Now the type for /ocean_mod/tracer/biotic1/diff_horiz/linear/slope is ',name_field_type
6453 success = fm_get_value('/ocean_mod/tracer/biotic1/diff_horiz/linear/slope',param)
6454 write(*,*) 'The value for /ocean_mod/tracer/biotic1/diff_horiz/linear/slope is (real) ',param
6455 write(*,*) '+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+'
6456 
6457 write(*,*) 'Changing the name of biotic1 to biotic_control'
6458 success = fm_modify_name('/ocean_mod/tracer/biotic1', 'biotic_control')
6459 
6460 ! Dump the listing of the modified tracer
6461 success = fm_dump_list("/ocean_mod/tracer/biotic_control", .true.)
6462 
6463 ! Double check to show that the tracer has been renamed and the original doesn't exist anymore.
6464 success = fm_dump_list("/ocean_mod/tracer/biotic1", .true.)
6465 if (.not. success ) call mpp_error(note, "Ocean model tracer biotic1 does not exist anymore.")
6466 write(*,*) '+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+'
6467 
6468 
6469 if ( fm_change_list("/ocean_mod/tracer/age_ctl") ) then
6470 success = fm_dump_list("", .true.)
6471 write(*,*) "Now we'll add a new list to this list"
6472 index = fm_new_list("units",create = .true.)
6473 
6474 success = fm_dump_list("", .true.)
6475 
6476 write(*,*) "Now we'll give it a value"
6477 if (success) index = fm_new_value('units','days')
6478 
6479 success = fm_dump_list("", .true.)
6480 
6481 
6482 write(*,*) '+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+'
6483 endif
6484 !errorcode = 121
6485 !CALL MPI_ERROR_STRING(errorcode, string, resultlen, ierror)
6486 !write(*,*) string
6487 call field_manager_end
6488 
6489 call mpp_exit
6490 
6491 end program test
6492 
6493 #endif
Definition: fms.F90:20
character(len=8) function, public fm_get_type(name)
integer, parameter, public model_ice
integer function, public fm_get_index(name)
type(fm_array_list_def) function, pointer, public fm_intersection(lists, dim)
type(field_def) function, pointer, private find_list(path, relative_p, create)
integer, parameter, public fm_path_name_len
function parse_reals(text, label, values)
integer, parameter, public model_atmos
character(len=fm_field_name_len) save_root_name
type(field_def) function, pointer, private get_field(name, this_list_p)
character(len=1), parameter equal
logical function, public fm_get_value_string(name, value, index)
character(len=1), parameter bracket_left
integer function, public fm_new_value_real(name, value, create, index, append)
integer, parameter, public set
logical function, public fm_get_value_real(name, value, index)
recursive logical function find_method(list_p, recursive, num_meth, method, control)
function parse_integers(text, label, values)
integer function, public fm_new_value_logical(name, value, create, index, append)
subroutine, private find_base(name, path, base)
integer, parameter string_type
integer, parameter real_type
integer, parameter, public no_field
subroutine, public field_manager_end
character(len=1), parameter comment
integer function, public fm_new_list(name, create, keep)
subroutine, private find_head(name, head, rest)
integer, parameter, public fm_string_len
subroutine check_for_name_duplication
type(field_def) function, pointer, private make_list(this_list_p, name)
integer, parameter, public model_ocean
integer, parameter list_type
integer function, public find_field_index_new(field_name)
subroutine, public get_field_info(n, fld_type, fld_name, model, num_methods)
type(field_def), pointer current_list_p
logical function, public fm_find_methods(list_name, methods, control)
type(field_mgr_type), dimension(max_fields), private fields
type(field_def) function, pointer, private create_field(parent_p, name)
integer, parameter, public model_land
logical function, public fm_change_list(name)
character(len=1), parameter bracket_right
integer function parse_string(text, label, value)
type(method_type), public default_method
integer, parameter max_fields
type(field_def), pointer save_root_parent_p
Definition: mpp.F90:39
subroutine, public fm_init_loop(loop_list, iter)
integer, parameter null_type
subroutine concat_strings(str1, str2)
l_size ! loop over number of fields ke do je do ie to je n if(.NOT. d_comm%R_do_buf(list)) cycle from_pe
integer, parameter logical_type
integer, parameter, public fm_type_name_len
integer function, public fm_new_value_integer(name, value, create, index, append)
subroutine, private initialize
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! MPP_TRANSMIT !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! subroutine MPP_TRANSMIT_(put_data, put_len, to_pe, get_data, get_len, from_pe, block, tag, recv_request, send_request)!a message-passing routine intended to be reminiscent equally of both MPI and SHMEM!put_data and get_data are contiguous MPP_TYPE_ arrays!at each call, your put_data array is put to to_pe 's get_data! your get_data array is got from from_pe 's put_data!i.e we assume that typically(e.g updating halo regions) each PE performs a put _and_ a get!special PE designations:! NULL_PE:to disable a put or a get(e.g at boundaries)! ANY_PE:if remote PE for the put or get is to be unspecific! ALL_PES:broadcast and collect operations(collect not yet implemented)!ideally we would not pass length, but this f77-style call performs better(arrays passed by address, not descriptor)!further, this permits< length > contiguous words from an array of any rank to be passed(avoiding f90 rank conformance check)!caller is responsible for completion checks(mpp_sync_self) before and after integer, intent(in) ::put_len, to_pe, get_len, from_pe MPP_TYPE_, intent(in) ::put_data(*) MPP_TYPE_, intent(out) ::get_data(*) logical, intent(in), optional ::block integer, intent(in), optional ::tag integer, intent(out), optional ::recv_request, send_request logical ::block_comm integer ::i MPP_TYPE_, allocatable, save ::local_data(:) !local copy used by non-parallel code(no SHMEM or MPI) integer ::comm_tag integer ::rsize if(.NOT.module_is_initialized) call mpp_error(FATAL, 'MPP_TRANSMIT:You must first call mpp_init.') if(to_pe.EQ.NULL_PE .AND. from_pe.EQ.NULL_PE) return block_comm=.true. if(PRESENT(block)) block_comm=block if(debug) then call SYSTEM_CLOCK(tick) write(stdout_unit,'(a, i18, a, i6, a, 2i6, 2i8)')&'T=', tick, ' PE=', pe, ' MPP_TRANSMIT begin:to_pe, from_pe, put_len, get_len=', to_pe, from_pe, put_len, get_len end if comm_tag=DEFAULT_TAG if(present(tag)) comm_tag=tag!do put first and then get if(to_pe.GE.0 .AND. to_pe.LT.npes) then!use non-blocking sends if(debug .and.(current_clock.NE.0)) call SYSTEM_CLOCK(start_tick)!z1l:truly non-blocking send.! if(request(to_pe).NE.MPI_REQUEST_NULL) then !only one message from pe-> to_pe in queue *PE waiting for to_pe ! call error else get_len so only do gets but you cannot have a pure get with MPI call mpp_error(FATAL, 'MPP_TRANSMIT:you cannot transmit to ANY_PE using MPI.') else if(to_pe.NE.NULL_PE) then !no other valid cases except NULL_PE call mpp_error(FATAL
logical function fm_loop_over_list_old(list, name, field_type, index)
type(field_def) function, pointer, private find_field(name, this_list_p)
type(field_def), pointer loop_list_p
character(len=1), parameter comma
character(len=1), parameter dquote
integer function, public fm_new_value_string(name, value, create, index, append)
logical function, public fm_get_value_integer(name, value, index)
recursive logical function query_method(list_p, recursive, name, method_name, method_control)
integer, parameter line_len
subroutine, public fm_set_verbosity(verbosity)
integer, parameter array_increment
character(len=50) set_nonexp
integer function parse_integer(text, label, value)
logical function, public fm_dump_list(name, recursive, unit)
logical module_is_initialized
logical function, public fm_exists(name)
logical recursive function, private dump_list(list_p, recursive, depth, out_unit)
logical function, public fm_query_method(name, method_name, method_control)
subroutine, public get_field_method(n, m, method)
subroutine new_name(list_name, method_name_in, val_name_in)
character(len=11), dimension(num_models), parameter, public model_names
subroutine, public fm_reset_loop
logical function, public fm_modify_name(oldname, newname)
logical function set_list_stuff()
type(field_def), target, save root
integer, parameter, public num_models
integer, parameter num_types
#define max(a, b)
Definition: mosaic_util.h:33
integer, parameter max_field_methods
character(len=1), parameter space
character(len=1), parameter squote
subroutine, public fm_return_root
character(len=13) setnum
integer function, public fm_copy_list(list_name, suffix, create)
integer, parameter, public model_coupler
type(field_def), pointer root_p
character(len=1), parameter tab
character(len=fm_type_name_len), dimension(num_types) field_type_name
logical function fm_loop_over_list_new(iter, name, field_type, index)
integer function parse_real(text, label, value)
#define min(a, b)
Definition: mosaic_util.h:32
character(len=1), parameter list_sep
subroutine strip_front_blanks(name)
function parse_strings(text, label, values)
character(len=fm_path_name_len) loop_list
integer function, public fm_get_length(name)
integer function, public find_field_index_old(model, field_name)
subroutine, public get_field_methods(n, methods)
logical function, public fm_change_root(name)
integer, parameter integer_type
character(len=fm_path_name_len) function, public fm_get_current_list()
integer, parameter, public fm_field_name_len
character(len=17), parameter module_name
logical function, public fm_get_value_logical(name, value, index)
subroutine, public field_manager_init(nfields, table_name)