157module field_manager_mod
160#define MAXFIELDS_ 250
164#ifndef MAXFIELDMETHODS_
165#define MAXFIELDMETHODS_ 250
190use fms_mod,
only : lowercase, &
191 write_version_number, &
193use fms2_io_mod,
only: file_exists, get_instance_filename
194use platform_mod,
only: r4_kind, r8_kind, fms_path_len, fms_file_len
202#include<file_version.h>
203logical :: module_is_initialized = .false.
228public :: fm_get_value_real_r4
229public :: fm_get_value_real_r8
238public :: fm_new_value_real_r4
239public :: fm_new_value_real_r8
284character(len=11),
parameter,
public,
dimension(NUM_MODELS) :: &
285 model_names=(/
'atmospheric',
'oceanic ',
'land ',
'ice ',
'coupler '/)
305 character(len=fm_string_len) :: method_name
308 character(len=fm_string_len) :: method_control
319 character(len=fm_string_len) :: method_type
320 character(len=fm_string_len) :: method_name
329 character(len=fm_string_len) :: method_type
370 module procedure parse_real_r4
371 module procedure parse_real_r8
372 module procedure parse_reals_r4
373 module procedure parse_reals_r8
399 module procedure fm_new_value_real_r4
400 module procedure fm_new_value_real_r8
418 module procedure fm_get_value_real_r4
419 module procedure fm_get_value_real_r8
437character(len=17),
parameter :: module_name =
'field_manager_mod'
438character(len=33),
parameter :: error_header =
'==>Error from '//trim(module_name)//
': '
439character(len=35),
parameter :: warn_header =
'==>Warning from '//trim(module_name)//
': '
440character(len=32),
parameter :: note_header =
'==>Note from '//trim(module_name)//
': '
441character(len=1),
parameter :: comma =
","
442character(len=1),
parameter :: list_sep =
'/'
444character(len=1),
parameter :: comment =
'#'
445character(len=1),
parameter :: dquote =
'"'
446character(len=1),
parameter :: equal =
'='
447character(len=1),
parameter :: squote =
"'"
449integer,
parameter :: null_type = 0
450integer,
parameter :: integer_type = 1
451integer,
parameter :: list_type = 2
452integer,
parameter :: logical_type = 3
453integer,
parameter :: real_type = 4
454integer,
parameter :: string_type = 5
455integer,
parameter :: num_types = 5
456integer,
parameter :: array_increment = 10
458integer,
parameter :: MAX_FIELDS = maxfields_
459integer,
parameter :: MAX_FIELD_METHODS = maxfieldmethods_
465 character(len=fm_field_name_len) :: field_type
466 character(len=fm_string_len) :: field_name
467 integer :: model, num_methods
476 character(len=fm_field_name_len) :: fld_type
477 character(len=fm_field_name_len) :: mod_name
478 character(len=fm_string_len) :: fld_name
484 character(len=fm_field_name_len) :: fld_type
485 character(len=fm_field_name_len) :: mod_name
491 character (len=fm_field_name_len) :: name
493 type (field_def),
pointer :: parent => null()
494 integer :: field_type
498 type (field_def),
pointer :: first_field => null()
499 type (field_def),
pointer :: last_field => null()
500 integer,
allocatable,
dimension(:) :: i_value
501 logical,
allocatable,
dimension(:) :: l_value
502 real(r8_kind),
allocatable,
dimension(:) :: r_value
504 character(len=fm_string_len),
allocatable,
dimension(:) :: s_value
505 type (
field_def),
pointer :: next => null()
506 type (
field_def),
pointer :: prev => null()
514character(len=FMS_PATH_LEN) :: loop_list
515character(len=fm_type_name_len) :: field_type_name(num_types)
516character(len=fm_field_name_len) :: save_root_name
518character(len=52) :: set =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
521character(len=50) :: set_nonexp =
"ABCDFGHIJKLMNOPQRSTUVWXYZabcdfghijklmnopqrstuvwxyz"
524character(len=13) :: setnum =
"0123456789+-."
525integer :: num_fields = 0
526type (
field_def),
pointer :: loop_list_p => null()
527type (
field_def),
pointer :: current_list_p => null()
528type (
field_def),
pointer :: root_p => null()
529type (
field_def),
pointer :: save_root_parent_p => null()
557integer,
intent(out),
optional :: nfields
558character(len=fm_string_len),
intent(in),
optional :: table_name
560if (module_is_initialized)
then
561 if(
present(nfields)) nfields = num_fields
571 call mpp_error(fatal,
"You cannot have use_field_table_yaml=.true. without compiling with -Duse_yaml")
573 if (file_exists(
"field_table")) &
574 call mpp_error(fatal,
"You cannot have the legacy field_table if use_field_table_yaml=.true.")
576 call mpp_error(note,
"You are using the yaml version of the field_table")
580 if (file_exists(
"field_table.yaml")) &
581 call mpp_error(fatal,
"You cannot have the yaml field_table if use_field_table_yaml=.false.")
582 call mpp_error(note,
"You are using the legacy version of the field_table")
592integer,
intent(out),
optional :: nfields
593character(len=*),
intent(in),
optional :: table_name
595character(len=FMS_FILE_LEN) :: tbl_name
596character(len=fm_string_len) :: method_control
597integer :: h, i, j, k, l, m
598type (fmTable_t) :: my_table
600character(len=FMS_PATH_LEN) :: list_name
601character(len=fm_string_len) :: subparamvalue
602character(len=fm_string_len) :: fm_yaml_null
603integer :: current_field
604integer :: index_list_name
605integer :: subparamindex
609character(len=FMS_FILE_LEN) :: filename
611if (.not.
PRESENT(table_name))
then
612 tbl_name =
'field_table.yaml'
614 tbl_name = trim(table_name)
617call get_instance_filename(tbl_name, filename)
618if (index(trim(filename),
"ens_") .ne. 0)
then
619 if (file_exists(filename) .and. file_exists(tbl_name)) &
620 call mpp_error(fatal,
"Both "//trim(tbl_name)//
" and "//trim(filename)//
" exists, pick one!")
624 if (.not. file_exists(filename)) filename = tbl_name
627if (.not. file_exists(trim(filename)))
then
628 if(
present(nfields)) nfields = 0
635do h=1,
size(my_table%types)
636 do i=1,
size(my_table%types(h)%models)
637 do j=1,
size(my_table%types(h)%models(i)%variables)
638 num_fields = num_fields + 1
643allocate(
fields(num_fields))
646do h=1,
size(my_table%types)
647 do i=1,
size(my_table%types(h)%models)
648 select case (my_table%types(h)%models(i)%name)
660 call mpp_error(fatal, trim(error_header)//
'The model name is unrecognised : &
661 &'//trim(my_table%types(h)%models(i)%name))
663 do j=1,
size(my_table%types(h)%models(i)%variables)
664 current_field = current_field + 1
665 list_name = list_sep//lowercase(trim(my_table%types(h)%models(i)%name))//list_sep//&
666 lowercase(trim(my_table%types(h)%name))//list_sep//&
667 lowercase(trim(my_table%types(h)%models(i)%variables(j)%name))
668 index_list_name =
fm_new_list(list_name, create = .true.)
669 if ( index_list_name ==
no_field ) &
670 call mpp_error(fatal, trim(error_header)//
'Could not set field list for '//trim(list_name))
672 fields(current_field)%model = model
673 fields(current_field)%field_name = lowercase(trim(my_table%types(h)%models(i)%variables(j)%name))
674 fields(current_field)%field_type = lowercase(trim(my_table%types(h)%name))
675 fields(current_field)%num_methods =
size(my_table%types(h)%models(i)%variables(j)%keys)
676 allocate(
fields(current_field)%methods(
fields(current_field)%num_methods))
677 if(
fields(current_field)%num_methods.gt.0)
then
678 subparams = (
size(my_table%types(h)%models(i)%variables(j)%attributes) .gt. 0)
679 do k=1,
size(my_table%types(h)%models(i)%variables(j)%keys)
680 fields(current_field)%methods(k)%method_type = &
681 lowercase(trim(my_table%types(h)%models(i)%variables(j)%keys(k)))
682 fields(current_field)%methods(k)%method_name = &
683 lowercase(trim(my_table%types(h)%models(i)%variables(j)%values(k)))
684 if (.not.subparams)
then
685 call new_name(list_name, my_table%types(h)%models(i)%variables(j)%keys(k),&
686 my_table%types(h)%models(i)%variables(j)%values(k) )
689 do l=1,
size(my_table%types(h)%models(i)%variables(j)%attributes)
690 if(lowercase(trim(my_table%types(h)%models(i)%variables(j)%attributes(l)%paramname)).eq.&
691 lowercase(trim(
fields(current_field)%methods(k)%method_type)))
then
696 if (subparamindex.eq.-1)
then
697 call new_name(list_name, my_table%types(h)%models(i)%variables(j)%keys(k),&
698 my_table%types(h)%models(i)%variables(j)%values(k) )
700 do m=1,
size(my_table%types(h)%models(i)%variables(j)%attributes(subparamindex)%keys)
703 if (trim(my_table%types(h)%models(i)%variables(j)%values(k)).eq.
'fm_yaml_null')
then
706 fm_yaml_null = trim(my_table%types(h)%models(i)%variables(j)%values(k))//
'/'
708 method_control = trim(my_table%types(h)%models(i)%variables(j)%keys(k))//
"/"//&
709 &trim(fm_yaml_null)//&
710 &trim(my_table%types(h)%models(i)%variables(j)%attributes(subparamindex)%keys(m))
711 subparamvalue = trim(my_table%types(h)%models(i)%variables(j)%attributes(subparamindex)%values(m))
712 call new_name(list_name, method_control, subparamvalue)
722if (
present(nfields)) nfields = num_fields
734character(len=*),
intent(in) :: list_name
735character(len=*),
intent(in) :: method_name_in
737character(len=*),
intent(inout) :: val_name_in
740character(len=fm_string_len) :: method_name
741character(len=fm_string_len) :: val_name
742integer,
dimension(:),
allocatable :: end_val
743integer,
dimension(:),
allocatable :: start_val
751real(r8_kind) :: val_real
755method_name = trim(method_name_in)
765do i = 1, len_trim(val_name_in)
766 if ( val_name_in(i:i) == comma )
then
767 num_elem = num_elem + 1
771allocate(start_val(num_elem))
772allocate(end_val(num_elem))
774end_val(:) = len_trim(val_name_in)
777do i = 1, len_trim(val_name_in)
778 if ( val_name_in(i:i) == comma )
then
779 end_val(num_elem) = i-1
780 start_val(num_elem+1) = i+1
781 num_elem = num_elem + 1
787 if ( i .gt. 1 .or. index_t .eq. 0 )
then
791 val_type = string_type
792 val_name = val_name_in(start_val(i):end_val(i))
795 if ( scan(val_name(1:1), setnum ) > 0 )
then
796 if ( scan(val_name, set_nonexp ) .le. 0 )
then
797 if ( scan(val_name,
'.') > 0 .or. scan(val_name,
'e') > 0 .or. scan(val_name,
'E') > 0)
then
798 read(val_name, *) val_real
801 read(val_name, *) val_int
802 val_type = integer_type
807 if ( len_trim(val_name) == 1 .or. len_trim(val_name) == 3)
then
808 if ( val_name ==
't' .or. val_name ==
'T' .or. val_name ==
'.t.' .or. val_name ==
'.T.' )
then
810 val_type = logical_type
812 if ( val_name ==
'f' .or. val_name ==
'F' .or. val_name ==
'.f.' .or. val_name ==
'.F.' )
then
814 val_type = logical_type
817 if ( trim(lowercase(val_name)) ==
'true' .or. trim(lowercase(val_name)) ==
'.true.' )
then
819 val_type = logical_type
821 if ( trim(lowercase(val_name)) ==
'false' .or. trim(lowercase(val_name)) ==
'.false.' )
then
823 val_type = logical_type
826 select case(val_type)
829 if (
fm_new_value( method_name, val_int, create = .true., index = index_t, append = append_new ) < 0 ) &
830 call mpp_error(fatal, trim(error_header)//
'Could not set "' // trim(val_name) //
'" for '//trim(method_name)//&
831 ' (I) for '//trim(list_name))
834 if (
fm_new_value( method_name, val_logic, create = .true., index = index_t, append = append_new) < 0 ) &
835 call mpp_error(fatal, trim(error_header)//
'Could not set "' // trim(val_name) //
'" for '//trim(method_name)//&
836 ' (L) for '//trim(list_name))
839 if (
fm_new_value( method_name, val_real, create = .true., index = index_t, append = append_new) < 0 ) &
840 call mpp_error(fatal, trim(error_header)//
'Could not set "' // trim(val_name) //
'" for '//trim(method_name)//&
841 ' (R) for '//trim(list_name))
844 if (
fm_new_value( method_name, val_name, create = .true., index = index_t, append = append_new) < 0 ) &
845 call mpp_error(fatal, trim(error_header)//
'Could not set "' // trim(val_name) //
'" for '//trim(method_name)//&
846 ' (S) for '//trim(list_name))
848 call mpp_error(fatal, trim(error_header)//
'Could not find a valid type to set the '//trim(method_name)//&
849 ' for '//trim(list_name))
854 deallocate(start_val)
869integer,
intent(out),
optional :: nfields
870character(len=fm_string_len),
intent(in),
optional :: table_name
873character(len=1024) :: record
874character(len=fm_string_len) :: control_str
875character(len=FMS_PATH_LEN) :: list_name
876character(len=fm_string_len) :: method_name
877character(len=fm_string_len) :: name_str
878character(len=fm_string_len) :: type_str
879character(len=fm_string_len) :: val_name
880character(len=fm_string_len) :: tbl_name
881integer :: control_array(MAX_FIELDS,3)
884integer :: index_list_name
894logical :: flag_method
902if (.not.
PRESENT(table_name))
then
903 tbl_name =
'field_table'
905 tbl_name = trim(table_name)
907if (.not. file_exists(trim(tbl_name)))
then
908 if(
present(nfields)) nfields = 0
912allocate(
fields(max_fields))
914open(newunit=iunit, file=trim(tbl_name), action=
'READ', iostat=io_status)
915if(io_status/=0)
call mpp_error(fatal,
'field_manager_mod: Error in opening file '//trim(tbl_name))
917call write_version_number(
"FIELD_MANAGER_MOD", version)
920 read(iunit,
'(a)',
end=89,err=99) record
921 write( log_unit,
'(a)' )record
922 if (record(1:1) ==
"#" ) cycle
923 ltrec = len_trim(record)
924 if (ltrec .le. 0 ) cycle
929 if (record(l:l) ==
'"' )
then
933 if (icount > 6 )
then
934 call mpp_error(fatal,trim(error_header)//
'Too many fields in field table header entry.'//trim(record))
939 read(record,*,
end=79,err=79) text_names
940 text_names%fld_type = lowercase(trim(text_names%fld_type))
941 text_names%mod_name = lowercase(trim(text_names%mod_name))
942 text_names%fld_name = lowercase(trim(text_names%fld_name))
945 read(record,*,
end=79,err=79) text_names_short
946 text_names%fld_type = lowercase(trim(text_names_short%fld_type))
947 text_names%mod_name = lowercase(trim(text_names_short%mod_name))
948 text_names%fld_name = lowercase(trim(text_names_short%mod_name))
952 read(record,*,
end=79,err=79) text_names_short
953 text_names%fld_type = lowercase(trim(text_names_short%fld_type))
954 text_names%mod_name = lowercase(trim(text_names_short%mod_name))
955 text_names%fld_name = lowercase(trim(text_names_short%mod_name))
958 text_names%fld_type =
" "
959 text_names%mod_name = lowercase(trim(record))
960 text_names%fld_name =
" "
965 list_name = list_sep//trim(text_names%mod_name)//list_sep//trim(text_names%fld_type)//&
966 list_sep//trim(text_names%fld_name)
968 index_list_name =
fm_new_list(list_name, create = .true.)
969 if ( index_list_name ==
no_field ) &
970 call mpp_error(fatal, trim(error_header)//
'Could not set field list for '//trim(list_name))
973 select case (text_names%mod_name)
985 call mpp_error(fatal, trim(error_header)//
'The model name is unrecognised : '//trim(text_names%mod_name))
988 num_fields = num_fields + 1
990 if (num_fields > max_fields)
call mpp_error(fatal,trim(error_header)//
'max fields exceeded')
991 fields(num_fields)%model = model
992 fields(num_fields)%field_name = lowercase(trim(text_names%fld_name))
993 fields(num_fields)%field_type = lowercase(trim(text_names%fld_type))
994 fields(num_fields)%num_methods = 0
995 allocate(
fields(num_fields)%methods(max_field_methods))
996 call check_for_name_duplication
999 if ( record(len_trim(record):len_trim(record)) == list_sep) cycle
1001 flag_method = .true.
1003 do while (flag_method)
1004 read(iunit,
'(a)',
end=99,err=99) record
1006 if (len_trim(record) .le. 0) cycle
1008 if ( record(len_trim(record):len_trim(record)) == list_sep)
then
1009 flag_method = .false.
1010 if (len_trim(record) == 1) cycle
1011 record = record(:len_trim(record)-1)
1014 if (len_trim(record) .le. 0) cycle
1016 if (record(1:1) == comment ) cycle
1019 do l= 1, len_trim(record)
1020 if (record(l:l) == dquote )
then
1024 if (icount > 6 )
call mpp_error(fatal,trim(error_header)//
'Too many fields in field entry.'//trim(record))
1027 call mpp_error(fatal, trim(error_header)//
'Could not change to '//trim(list_name)//
' list')
1029 select case (icount)
1031 read(record,*,
end=99,err=99) text_method
1032 fields(num_fields)%methods(m)%method_type = lowercase(trim(text_method%method_type))
1033 fields(num_fields)%methods(m)%method_name = lowercase(trim(text_method%method_name))
1034 fields(num_fields)%methods(m)%method_control = lowercase(trim(text_method%method_control))
1036 type_str = text_method%method_type
1037 name_str = text_method%method_name
1038 control_str = text_method%method_control
1042 read(record,*,
end=99,err=99) text_method_short
1043 fields(num_fields)%methods(m)%method_type =&
1044 & lowercase(trim(text_method_short%method_type))
1045 fields(num_fields)%methods(m)%method_name =&
1046 & lowercase(trim(text_method_short%method_name))
1047 fields(num_fields)%methods(m)%method_control =
" "
1049 type_str = text_method_short%method_type
1051 control_str = text_method_short%method_name
1056 read(record,*,
end=99,err=99) text_method_very_short
1057 fields(num_fields)%methods(m)%method_type = lowercase(trim(text_method_very_short%method_type))
1058 fields(num_fields)%methods(m)%method_name =
" "
1059 fields(num_fields)%methods(m)%method_control =
" "
1063 control_str = text_method_very_short%method_type
1066 read(record,
'(A)',
end=99,err=99) control_str
1071 call mpp_error(fatal,trim(error_header)//
'Unterminated field in field entry.'//trim(record))
1083 ltrec= len_trim(control_str)
1084 control_array(:,1) = 1
1085 control_array(:,2:3) = ltrec
1088 if (control_str(l:l) == equal )
then
1090 control_array(icount,2) = l
1091 elseif (control_str(l:l) == comma )
then
1092 if (icount .eq. 0)
then
1093 call mpp_error(fatal,trim(error_header) // &
1094 ' Bad format for field entry (comma without equals sign): ''' // &
1095 trim(control_str) //
'''')
1096 elseif (icount .gt. max_fields)
then
1097 call mpp_error(fatal,trim(error_header) // &
1098 ' Too many fields in field entry: ''' // &
1099 trim(control_str) //
'''')
1101 control_array(icount,3) = l-1
1102 control_array(min(max_fields,icount+1),1) = l+1
1111 if (control_str(ltrec:ltrec) .ne. comma)
then
1112 control_array(max(1,icount),3) = ltrec
1115 if ( icount == 0 )
then
1116 method_name = type_str
1117 if (len_trim(method_name) > 0 )
then
1118 method_name = trim(method_name)//list_sep// trim(name_str)
1120 method_name = trim(name_str)
1122 val_name = control_str
1124 call new_name(list_name, method_name, val_name )
1129 startcont = control_array(l,1)
1130 midcont = control_array(l,2)
1131 endcont = control_array(l,3)
1133 method_name = trim(type_str)
1134 if (len_trim(method_name) > 0 )
then
1135 method_name = trim(method_name)//list_sep// trim(name_str)
1137 method_name = trim(name_str)
1140 if (len_trim(method_name) > 0 )
then
1141 method_name = trim(method_name)//list_sep//&
1142 trim(control_str(startcont:midcont-1))
1144 method_name = trim(control_str(startcont:midcont-1))
1146 val_name = trim(control_str(midcont+1:endcont))
1148 call new_name(list_name, method_name, val_name )
1153 fields(num_fields)%num_methods =
fields(num_fields)%num_methods + 1
1154 if (
fields(num_fields)%num_methods > max_field_methods) &
1155 call mpp_error(fatal,trim(error_header)//
'Maximum number of methods for field exceeded')
1159 flag_method = .true.
1160 do while (flag_method)
1161 read(iunit,
'(A)',
end=99,err=99) record
1162 if ( record(len_trim(record):len_trim(record)) == list_sep)
then
1163 flag_method = .false.
1171close(iunit, iostat=io_status)
1172if(io_status/=0)
call mpp_error(fatal,
'field_manager_mod: Error in closing file '//trim(tbl_name))
1175if(
present(nfields)) nfields = num_fields
1177default_method%method_type =
'none'
1178default_method%method_name =
'none'
1179default_method%method_control =
'none'
1184call mpp_error(fatal,trim(error_header)//
' Error reading field table. Record = '//trim(record))
1188subroutine check_for_name_duplication
1193 if (
fields(i)%field_type ==
fields(num_fields)%field_type .and. &
1195 fields(i)%field_name ==
fields(num_fields)%field_name )
then
1196 if (mpp_pe() .eq. mpp_root_pe())
then
1197 call mpp_error(warning,
'Error in field_manager_mod. Duplicate field name: Field type='//&
1198 trim(
fields(i)%field_type)// &
1200 ', Duplicated name='//trim(
fields(i)%field_name))
1205end subroutine check_for_name_duplication
1215subroutine new_name ( list_name, method_name_in , val_name_in)
1216character(len=*),
intent(in) :: list_name
1217character(len=*),
intent(in) :: method_name_in
1219character(len=*),
intent(inout) :: val_name_in
1222character(len=fm_string_len) :: method_name
1223character(len=fm_string_len) :: val_name
1224integer,
dimension(MAX_FIELDS) :: end_val
1225integer,
dimension(MAX_FIELDS) :: start_val
1234logical :: append_new
1236real(r8_kind) :: val_real
1240method_name = trim(method_name_in)
1247end_val(:) = len_trim(val_name_in)
1252do i = 1, len_trim(val_name_in)
1253 if ( val_name_in(i:i) == comma )
then
1254 end_val(num_elem) = i-1
1255 start_val(num_elem+1) = i+1
1256 num_elem = num_elem + 1
1261left_br = scan(method_name,
'[')
1262right_br = scan(method_name,
']')
1263if ( num_elem .eq. 1 )
then
1264 if ( left_br > 0 .and. right_br == 0 ) &
1265 call mpp_error(fatal, trim(error_header)//
"Left bracket present without right bracket in "//trim(method_name))
1266 if ( left_br== 0 .and. right_br > 0 ) &
1267 call mpp_error(fatal, trim(error_header)//
"Right bracket present without left bracket in "//trim(method_name))
1268 if ( left_br > 0 .and. right_br > 0 )
then
1269 if ( scan( method_name(left_br+1:right_br -1), set ) > 0 ) &
1270 call mpp_error(fatal, trim(error_header)//
"Using a non-numeric value for index in "//trim(method_name))
1271 read(method_name(left_br+1:right_br -1), *) index_t
1272 method_name = method_name(:left_br -1)
1276 if ( left_br > 0 .or. right_br > 0 ) &
1277 call mpp_error(fatal, &
1278 trim(error_header)//
"Using a comma delimited list with an indexed array element in "//trim(method_name))
1283 if ( i .gt. 1 .or. index_t .eq. 0 )
then
1287 val_type = string_type
1288 val_name = val_name_in(start_val(i):end_val(i))
1296 length = len_trim(val_name)
1297 if (val_name(1:1) .eq. squote)
then
1299 if (val_name(length:length) .eq. squote)
then
1300 val_name = val_name(2:length-1)//repeat(
" ",len(val_name)-length+2)
1301 val_type = string_type
1302 elseif (val_name(length:length) .eq. dquote)
then
1303 call mpp_error(fatal, trim(error_header) //
' Quotes do not match in ' // trim(val_name) // &
1304 ' for ' // trim(method_name) //
' of ' // trim(list_name))
1306 call mpp_error(fatal, trim(error_header) //
' No trailing quote in ' // trim(val_name) // &
1307 ' for ' // trim(method_name) //
' of ' // trim(list_name))
1310 elseif (val_name(1:1) .eq. dquote .or. val_name(length:length) .eq. dquote)
then
1312 call mpp_error(fatal, trim(error_header) //
' Double quotes not allowed in ' // trim(val_name) // &
1313 ' for ' // trim(method_name) //
' of ' // trim(list_name))
1315 elseif (val_name(length:length) .eq. squote)
then
1317 call mpp_error(fatal, trim(error_header) //
' No leading quote in ' // trim(val_name) // &
1318 ' for ' // trim(method_name) //
' of ' // trim(list_name))
1326 if ( scan(val_name(1:1), setnum ) > 0 )
then
1330 if ( scan(val_name, set_nonexp ) .le. 0 )
then
1332 if ( scan(val_name,
'.') > 0 .or. scan(val_name,
'e') > 0 .or. scan(val_name,
'E') > 0)
then
1333 read(val_name, *) val_real
1334 val_type = real_type
1336 read(val_name, *) val_int
1337 val_type = integer_type
1344 if ( len_trim(val_name) == 1 .or. len_trim(val_name) == 3)
then
1345 if ( val_name ==
't' .or. val_name ==
'T' .or. val_name ==
'.t.' .or. val_name ==
'.T.' )
then
1347 val_type = logical_type
1349 if ( val_name ==
'f' .or. val_name ==
'F' .or. val_name ==
'.f.' .or. val_name ==
'.F.' )
then
1351 val_type = logical_type
1354 if ( trim(lowercase(val_name)) ==
'true' .or. trim(lowercase(val_name)) ==
'.true.' )
then
1356 val_type = logical_type
1358 if ( trim(lowercase(val_name)) ==
'false' .or. trim(lowercase(val_name)) ==
'.false.' )
then
1360 val_type = logical_type
1364 select case(val_type)
1367 if (
fm_new_value( method_name, val_int, create = .true., index = index_t, append = append_new ) < 0 ) &
1368 call mpp_error(fatal, trim(error_header)//
'Could not set "' // trim(val_name) //
'" for '//trim(method_name)//&
1369 ' (I) for '//trim(list_name))
1372 if (
fm_new_value( method_name, val_logic, create = .true., index = index_t, append = append_new) < 0 ) &
1373 call mpp_error(fatal, trim(error_header)//
'Could not set "' // trim(val_name) //
'" for '//trim(method_name)//&
1374 ' (L) for '//trim(list_name))
1377 if (
fm_new_value( method_name, val_real, create = .true., index = index_t, append = append_new) < 0 ) &
1378 call mpp_error(fatal, trim(error_header)//
'Could not set "' // trim(val_name) //
'" for '//trim(method_name)//&
1379 ' (R) for '//trim(list_name))
1382 if (
fm_new_value( method_name, val_name, create = .true., index = index_t, append = append_new) < 0 ) &
1383 call mpp_error(fatal, trim(error_header)//
'Could not set "' // trim(val_name) //
'" for '//trim(method_name)//&
1384 ' (S) for '//trim(list_name))
1386 call mpp_error(fatal, trim(error_header)//
'Could not find a valid type to set the '//trim(method_name)//&
1387 ' for '//trim(list_name))
1402module_is_initialized = .false.
1405 if(
allocated(
fields(j)%methods))
deallocate(
fields(j)%methods)
1416character(len=*),
intent(inout) :: name
1418name = trim(adjustl(name))
1430integer,
intent(in) :: model
1431character(len=*),
intent(in) :: field_name
1438 if (
fields(i)%model == model .and.
fields(i)%field_name == lowercase(field_name))
then
1450character(len=*),
intent(in) :: field_name
1469integer,
intent(in) :: n
1470character (len=*),
intent(out) :: fld_type
1471character (len=*),
intent(out) :: fld_name
1472integer,
intent(out) :: model
1473integer,
intent(out) :: num_methods
1475if (n < 1 .or. n > num_fields)
call mpp_error(fatal,trim(error_header)//
'Invalid field index')
1477fld_type =
fields(n)%field_type
1478fld_name =
fields(n)%field_name
1480num_methods =
fields(n)%num_methods
1490integer,
intent(in) :: n
1491integer,
intent(in) :: m
1494if (n < 1 .or. n > num_fields)
call mpp_error(fatal,trim(error_header)//
'Invalid field index')
1495if (m < 1 .or. m >
fields(n)%num_methods)
call mpp_error(fatal,trim(error_header)//
'Invalid method index')
1497 method =
fields(n)%methods(m)
1507integer,
intent(in) :: n
1510 if (n < 1 .or. n > num_fields) &
1511 call mpp_error(fatal,trim(error_header)//
'Invalid field index')
1513 if (
size(methods(:)) <
fields(n)%num_methods) &
1514 call mpp_error(fatal,trim(error_header)//
'Method array too small')
1516 methods = default_method
1525character(len=*),
intent(in) :: text
1526character(len=*),
intent(in) :: label
1527integer,
intent(out) :: values(:)
1533character(len=*),
intent(in) :: text
1534character(len=*),
intent(in) :: label
1535character(len=*),
intent(out) :: values(:)
1541character(len=*),
intent(in) :: text
1542character(len=*),
intent(in) :: label
1543integer,
intent(out) :: parse_ival
1549 if (
parse > 0) parse_ival = values(1)
1553character(len=*),
intent(in) :: text
1554character(len=*),
intent(in) :: label
1555character(len=*),
intent(out) :: parse_sval
1558character(len=len(parse_sval)) :: values(1)
1561 if (
parse > 0) parse_sval = values(1)
1578character(len=*),
intent(in) :: name
1580integer :: error, out_unit
1583if (.not.
associated(parent_p) .or. name .eq.
' ')
then
1589allocate(list_p, stat = error)
1590if (error .ne. 0)
then
1591 write (out_unit,*) trim(error_header),
'Error ', error, &
1592 ' allocating memory for list ', trim(name)
1600list_p%prev => parent_p%last_field
1601nullify(list_p%first_field)
1602nullify(list_p%last_field)
1604list_p%field_type = null_type
1607if (
allocated(list_p%i_value))
deallocate(list_p%i_value)
1608if (
allocated(list_p%l_value))
deallocate(list_p%l_value)
1609if (
allocated(list_p%r_value))
deallocate(list_p%r_value)
1610if (
allocated(list_p%s_value))
deallocate(list_p%s_value)
1613if (parent_p%length .le. 0)
then
1614 parent_p%first_field => list_p
1616 parent_p%last_field%next => list_p
1619parent_p%last_field => list_p
1621parent_p%length = parent_p%length + 1
1623list_p%index = parent_p%length
1625list_p%parent => parent_p
1639logical recursive function
dump_list(list_p,
recursive, depth, out_unit) result(success)
1642 logical,
intent(in) ::
recursive
1643 integer,
intent(in) :: depth
1645 integer,
intent(in) :: out_unit
1649 character(len=fm_field_name_len) :: num, scratch
1650 type (
field_def),
pointer :: this_field_p
1651 character(len=depth+fm_field_name_len) :: blank
1657 if (.not.
associated(list_p))
then
1659 elseif (list_p%field_type .ne. list_type)
then
1667 write (out_unit,
'(a,a,a)') blank(1:depth), trim(list_p%name), list_sep
1674 this_field_p => list_p%first_field
1676 do while (
associated(this_field_p))
1678 select case(this_field_p%field_type)
1683 success =
dump_list(this_field_p, .true., depthp1, out_unit)
1684 if (.not.success)
exit
1686 write (out_unit,
'(a,a,a)') blank(1:depthp1), trim(this_field_p%name), list_sep
1690 if (this_field_p%max_index .eq. 0)
then
1691 write (out_unit,
'(a,a,a)') blank(1:depthp1), trim(this_field_p%name),
' = NULL'
1692 elseif (this_field_p%max_index .eq. 1)
then
1693 write (scratch,*) this_field_p%i_value(1)
1694 write (out_unit,
'(a,a,a,a)') blank(1:depthp1), trim(this_field_p%name),
' = ', &
1695 trim(adjustl(scratch))
1697 do j = 1, this_field_p%max_index
1698 write (scratch,*) this_field_p%i_value(j)
1700 write (out_unit,
'(a,a,a,a,a,a)') blank(1:depthp1), trim(this_field_p%name), &
1701 '[', trim(adjustl(num)),
'] = ', trim(adjustl(scratch))
1706 if (this_field_p%max_index .eq. 0)
then
1707 write (out_unit,
'(a,a,a)') blank(1:depthp1), trim(this_field_p%name),
' = NULL'
1708 elseif (this_field_p%max_index .eq. 1)
then
1709 write (scratch,
'(l1)') this_field_p%l_value(1)
1710 write (out_unit,
'(a,a,a,a)') blank(1:depthp1), trim(this_field_p%name),
' = ', &
1711 trim(adjustl(scratch))
1713 do j = 1, this_field_p%max_index
1714 write (scratch,
'(l1)') this_field_p%l_value(j)
1716 write (out_unit,
'(a,a,a,a,a,a)') blank(1:depthp1), trim(this_field_p%name), &
1717 '[', trim(adjustl(num)),
'] = ', trim(adjustl(scratch))
1722 if (this_field_p%max_index .eq. 0)
then
1723 write (out_unit,
'(a,a,a)') blank(1:depthp1), trim(this_field_p%name),
' = NULL'
1724 elseif (this_field_p%max_index .eq. 1)
then
1725 write (scratch,*) this_field_p%r_value(1)
1726 write (out_unit,
'(a,a,a,a)') blank(1:depthp1), trim(this_field_p%name),
' = ', &
1727 trim(adjustl(scratch))
1729 do j = 1, this_field_p%max_index
1730 write (scratch,*) this_field_p%r_value(j)
1732 write (out_unit,
'(a,a,a,a,a,a)') blank(1:depthp1), trim(this_field_p%name), &
1733 '[', trim(adjustl(num)),
'] = ', trim(adjustl(scratch))
1738 if (this_field_p%max_index .eq. 0)
then
1739 write (out_unit,
'(a,a,a)') blank(1:depthp1), trim(this_field_p%name),
' = NULL'
1740 elseif (this_field_p%max_index .eq. 1)
then
1741 write (out_unit,
'(a,a,a,a)') blank(1:depthp1), trim(this_field_p%name),
' = ', &
1742 ''''//trim(this_field_p%s_value(1))//
''''
1744 do j = 1, this_field_p%max_index
1746 write (out_unit,
'(a,a,a,a,a,a)') blank(1:depthp1), trim(this_field_p%name), &
1747 '[', trim(adjustl(num)),
'] = ',
''''//trim(this_field_p%s_value(j))//
''''
1757 this_field_p => this_field_p%next
1770character(len=*),
intent(in) :: name
1771character(len=*),
intent(out) :: path
1772character(len=*),
intent(out) :: base
1779length = max(len_trim(name),0)
1780if (length .eq. 0)
then
1787 do while (name(length:length) .eq. list_sep)
1789 if (length .eq. 0)
then
1793 if (length .eq. 0)
then
1800 i = index(name(1:length), list_sep, back = .true.)
1805 base = name(1:length)
1810 base = name(i+1:length)
1828character(len=*),
intent(in) :: name
1832type (
field_def),
pointer,
save :: temp_p
1837if (name .eq.
'.')
then
1840 field_p => this_list_p
1841elseif (name .eq.
'..')
then
1843 field_p => this_list_p%parent
1846 temp_p => this_list_p%first_field
1848 do while (
associated(temp_p))
1851 if (temp_p%name .eq. name)
then
1856 temp_p => temp_p%next
1872character(len=*),
intent(in) :: name
1873character(len=*),
intent(out) :: head
1874character(len=*),
intent(out) :: rest
1878i = index(name, list_sep)
1881do while (i .le. len(name))
1882 if (name(i+1:i+1) .eq. list_sep)
then
1894elseif (i .eq. len(name))
then
1919character(len=*),
intent(in) :: path
1921logical,
intent(in) :: create
1923character(len=FMS_PATH_LEN) :: working_path
1924character(len=FMS_PATH_LEN) :: rest
1925character(len=fm_field_name_len) :: this_list
1926integer :: i, out_unit
1927type (
field_def),
pointer,
save :: working_path_p
1928type (
field_def),
pointer,
save :: this_list_p
1933if (path .eq.
' ')
then
1935 list_p => relative_p
1941 if (path(1:1) .eq. list_sep)
then
1942 working_path_p => root_p
1943 working_path = path(2:)
1945 working_path_p => relative_p
1949 do while (working_path .ne.
' ')
1951 call find_head(working_path, this_list, rest)
1954 if (this_list .eq.
' ')
then
1959 i = len_trim(this_list)
1960 do while (i .gt. 0 .and. this_list(i:i) .eq. list_sep)
1961 this_list(i:i) =
' '
1965 this_list_p =>
find_field(this_list, working_path_p)
1967 if (.not.
associated(this_list_p))
then
1970 this_list_p =>
make_list(working_path_p, this_list)
1971 if (.not.
associated(this_list_p))
then
1984 if (this_list_p%field_type .eq. list_type)
then
1985 working_path_p => this_list_p
1992 list_p => working_path_p
2007character(len=*),
intent(in) :: name
2009type (
field_def),
pointer,
save :: temp_p
2011if (.not. module_is_initialized)
then
2015temp_p =>
find_list(name, current_list_p, .false.)
2017if (
associated(temp_p))
then
2018 current_list_p => temp_p
2039character(len=*),
intent(in) :: name
2041type (
field_def),
pointer,
save :: temp_list_p
2044if (.not. module_is_initialized)
then
2049if (name .eq.
' ')
then
2054temp_list_p =>
find_list(name, current_list_p, .false.)
2056if (
associated(temp_list_p))
then
2058 if (save_root_name .ne.
' ')
then
2059 root_p%name = save_root_name
2060 root_p%parent => save_root_parent_p
2063 root_p => temp_list_p
2065 save_root_name = root_p%name
2066 save_root_parent_p => root_p%parent
2069 nullify(root_p%parent)
2072 current_list_p => root_p
2088 character(len=*),
intent(in) :: name
2089 logical,
intent(in),
optional ::
recursive
2091 integer,
intent(in),
optional :: unit
2093 logical :: recursive_t
2094 type (
field_def),
pointer,
save :: temp_list_p
2097 if (
present(unit))
then
2103 recursive_t = .false.
2104 if (
present(
recursive)) recursive_t =
recursive
2107 if (name .eq.
' ')
then
2109 temp_list_p => current_list_p
2113 temp_list_p =>
find_list(name, current_list_p, .false.)
2114 if (
associated(temp_list_p))
then
2122 success =
dump_list(temp_list_p, recursive_t, 0, out_unit)
2134character(len=*),
intent(in) :: name
2136type (
field_def),
pointer,
save :: dummy_p
2138if (.not. module_is_initialized)
then
2142dummy_p =>
get_field(name, current_list_p)
2143success =
associated(dummy_p)
2157character(len=*),
intent(in) :: name
2159type (
field_def),
pointer,
save :: temp_field_p
2164if (.not. module_is_initialized)
then
2168if (name .eq.
' ')
then
2173temp_field_p =>
get_field(name, current_list_p)
2174if (
associated(temp_field_p))
then
2176 index = temp_field_p%index
2190character(len=FMS_PATH_LEN) :: path
2192type (
field_def),
pointer,
save :: temp_list_p
2194if (.not. module_is_initialized)
then
2199temp_list_p => current_list_p
2202do while (
associated(temp_list_p))
2205 if (temp_list_p%name .eq.
' ')
then
2209 path = list_sep // trim(temp_list_p%name) // path
2211 temp_list_p => temp_list_p%parent
2214if (.not.
associated(temp_list_p))
then
2218elseif (path .eq.
' ')
then
2235character(len=*),
intent(in) :: name
2237type (
field_def),
pointer,
save :: temp_field_p
2242if (.not. module_is_initialized)
then
2246if (name .eq.
' ')
then
2251temp_field_p =>
get_field(name, current_list_p)
2253if (
associated(temp_field_p))
then
2255 if (temp_field_p%field_type .eq. list_type)
then
2256 length = temp_field_p%length
2258 length = temp_field_p%max_index
2274 result(name_field_type)
2275character(len=8) :: name_field_type
2276character(len=*),
intent(in) :: name
2278type (
field_def),
pointer,
save :: temp_field_p
2283if (.not. module_is_initialized)
then
2287if (name .eq.
' ')
then
2288 name_field_type =
' '
2292temp_field_p =>
get_field(name, current_list_p)
2294if (
associated(temp_field_p))
then
2296 name_field_type = field_type_name(temp_field_p%field_type)
2298 name_field_type =
' '
2308character(len=*),
intent(in) :: name
2309integer,
intent(out) :: get_ival
2310integer,
intent(in),
optional :: index
2313type (
field_def),
pointer,
save :: temp_field_p
2318if (.not. module_is_initialized)
then
2322if (name .eq.
' ')
then
2328if (
present(index))
then
2334temp_field_p =>
get_field(name, current_list_p)
2336if (
associated(temp_field_p))
then
2338 if (temp_field_p%field_type .eq. integer_type)
then
2339 if (index_t .lt. 1 .or. index_t .gt. temp_field_p%max_index)
then
2345 get_ival = temp_field_p%i_value(index_t)
2365character(len=*),
intent(in) :: name
2366logical,
intent(out) :: get_lval
2367integer,
intent(in),
optional :: index
2370type (
field_def),
pointer,
save :: temp_field_p
2375if (.not. module_is_initialized)
then
2379if (name .eq.
' ')
then
2385if (
present(index))
then
2391temp_field_p =>
get_field(name, current_list_p)
2393if (
associated(temp_field_p))
then
2395 if (temp_field_p%field_type .eq. logical_type)
then
2397 if (index_t .lt. 1 .or. index_t .gt. temp_field_p%max_index)
then
2403 get_lval = temp_field_p%l_value(index_t)
2423character(len=*),
intent(in) :: name
2424character(len=*),
intent(out) :: get_sval
2425integer,
intent(in),
optional :: index
2428type (
field_def),
pointer,
save :: temp_field_p
2433if (.not. module_is_initialized)
then
2437if (name .eq.
' ')
then
2443if (
present(index))
then
2449temp_field_p =>
get_field(name, current_list_p)
2451if (
associated(temp_field_p))
then
2453 if (temp_field_p%field_type .eq. string_type)
then
2454 if (index_t .lt. 1 .or. index_t .gt. temp_field_p%max_index)
then
2460 get_sval = temp_field_p%s_value(index_t)
2481character(len=*),
intent(in) :: list
2482character(len=*),
intent(out) :: name
2483character(len=fm_type_name_len),
intent(out) :: field_type
2484integer,
intent(out) :: index
2490if (.not. module_is_initialized)
then
2494if (list .eq. loop_list .and.
associated(loop_list_p))
then
2496 loop_list_p => loop_list_p%next
2498elseif (list .eq.
' ')
then
2501 loop_list_p => current_list_p%first_field
2506 loop_list_p =>
find_list(loop_list, current_list_p, .false.)
2507 if (
associated(loop_list_p))
then
2508 loop_list_p => loop_list_p%first_field
2528 if (
associated(loop_list_p))
then
2529 name = loop_list_p%name
2530 field_type = field_type_name(loop_list_p%field_type)
2531 index = loop_list_p%index
2548 character(len=*) ,
intent(in) :: loop_list
2553 if (loop_list==
' ')
then
2554 iter%ptr => current_list_p%first_field
2556 iter%ptr =>
find_list(loop_list,current_list_p,.false.)
2557 if (
associated(iter%ptr)) iter%ptr => iter%ptr%first_field
2565 result(success) ;
logical success
2567 character(len=*),
intent(out) :: name
2568 character(len=*),
intent(out) :: field_type
2569 integer ,
intent(out) :: index
2572 if (
associated(iter%ptr))
then
2573 name = iter%ptr%name
2574 field_type = field_type_name(iter%ptr%field_type)
2575 index = iter%ptr%index
2577 iter%ptr => iter%ptr%next
2594character(len=*),
intent(in) :: name
2595logical,
intent(in),
optional :: create
2596logical,
intent(in),
optional :: keep
2600character(len=FMS_PATH_LEN) :: path
2601character(len=fm_field_name_len) :: base
2602type (
field_def),
pointer,
save :: temp_list_p
2607if (.not. module_is_initialized)
then
2611if (name .eq.
' ')
then
2616if (
present(create))
then
2622if (
present(keep))
then
2630temp_list_p =>
find_list(path, current_list_p, create_t)
2632if (
associated(temp_list_p))
then
2634 temp_list_p =>
make_list(temp_list_p, base)
2635 if (
associated(temp_list_p))
then
2638 current_list_p => temp_list_p
2640 index = temp_list_p%index
2654integer :: field_index
2655character(len=*),
intent(in) :: name
2657integer,
intent(in) :: new_ival
2659logical,
intent(in),
optional :: create
2661integer,
intent(in),
optional :: index
2663logical,
intent(in),
optional :: append
2669integer,
pointer,
dimension(:) :: temp_i_value
2670character(len=FMS_PATH_LEN) :: path
2671character(len=fm_field_name_len) :: base
2672type (
field_def),
pointer,
save :: temp_list_p
2673type (
field_def),
pointer,
save :: temp_field_p
2678if (.not. module_is_initialized)
then
2682if (name .eq.
' ')
then
2687if (
present(create))
then
2693if (
present(index) .and.
present(append))
then
2694 if (append .and. index .gt. 0)
then
2700if (
present(index))
then
2702 if (index_t .lt. 0)
then
2712temp_list_p =>
find_list(path, current_list_p, create_t)
2714if (
associated(temp_list_p))
then
2715 temp_field_p =>
find_field(base, temp_list_p)
2716 if (.not.
associated(temp_field_p))
then
2720 if (
associated(temp_field_p))
then
2723 if (temp_field_p%field_type == real_type )
then
2726 field_index =
fm_new_value(name, real(new_ival,r8_kind), create, index, append)
2728 else if (temp_field_p%field_type /= integer_type )
then
2731 temp_field_p%max_index = 0
2734 temp_field_p%field_type = integer_type
2736 if (
present(append))
then
2738 index_t = temp_field_p%max_index + 1
2742 if (index_t .gt. temp_field_p%max_index + 1)
then
2747 elseif (index_t .eq. 0 .and. &
2748 temp_field_p%max_index .gt. 0)
then
2753 elseif (.not.
allocated(temp_field_p%i_value) .and. &
2754 index_t .gt. 0)
then
2756 allocate(temp_field_p%i_value(1))
2757 temp_field_p%max_index = 1
2758 temp_field_p%array_dim = 1
2759 elseif (index_t .gt. temp_field_p%array_dim)
then
2762 temp_field_p%array_dim = temp_field_p%array_dim + array_increment
2763 allocate (temp_i_value(temp_field_p%array_dim))
2764 do i = 1, temp_field_p%max_index
2765 temp_i_value(i) = temp_field_p%i_value(i)
2767 if (
allocated(temp_field_p%i_value))
deallocate(temp_field_p%i_value)
2768 temp_field_p%i_value = temp_i_value
2769 temp_field_p%max_index = index_t
2773 if (index_t .gt. 0)
then
2774 temp_field_p%i_value(index_t) = new_ival
2775 if (index_t .gt. temp_field_p%max_index)
then
2776 temp_field_p%max_index = index_t
2779 field_index = temp_field_p%index
2794integer :: field_index
2795character(len=*),
intent(in) :: name
2797logical,
intent(in) :: new_lval
2799logical,
intent(in),
optional :: create
2801integer,
intent(in),
optional :: index
2803logical,
intent(in),
optional :: append
2806character(len=FMS_PATH_LEN) :: path
2807character(len=fm_field_name_len) :: base
2811logical,
dimension(:),
pointer :: temp_l_value
2812type (
field_def),
pointer,
save :: temp_list_p
2813type (
field_def),
pointer,
save :: temp_field_p
2818if (.not. module_is_initialized)
then
2822if (name .eq.
' ')
then
2827if (
present(create))
then
2833if (
present(index) .and.
present(append))
then
2834 if (append .and. index .gt. 0)
then
2840if (
present(index))
then
2842 if (index_t .lt. 0)
then
2852temp_list_p =>
find_list(path, current_list_p, create_t)
2854if (
associated(temp_list_p))
then
2855 temp_field_p =>
find_field(base, temp_list_p)
2856 if (.not.
associated(temp_field_p))
then
2860 if (
associated(temp_field_p))
then
2863 if (temp_field_p%field_type /= logical_type )
then
2864 temp_field_p%max_index = 0
2867 temp_field_p%field_type = logical_type
2869 if (
present(append))
then
2871 index_t = temp_field_p%max_index + 1
2875 if (index_t .gt. temp_field_p%max_index + 1)
then
2880 elseif (index_t .eq. 0 .and. &
2881 temp_field_p%max_index .gt. 0)
then
2886 elseif (.not.
allocated(temp_field_p%l_value) .and. &
2887 index_t .gt. 0)
then
2889 allocate(temp_field_p%l_value(1))
2890 temp_field_p%max_index = 1
2891 temp_field_p%array_dim = 1
2893 elseif (index_t .gt. temp_field_p%array_dim)
then
2896 temp_field_p%array_dim = temp_field_p%array_dim + array_increment
2897 allocate (temp_l_value(temp_field_p%array_dim))
2898 do i = 1, temp_field_p%max_index
2899 temp_l_value(i) = temp_field_p%l_value(i)
2901 if (
allocated(temp_field_p%l_value))
deallocate(temp_field_p%l_value)
2902 temp_field_p%l_value = temp_l_value
2903 temp_field_p%max_index = index_t
2908 if (index_t .gt. 0)
then
2909 temp_field_p%l_value(index_t) = new_lval
2910 if (index_t .gt. temp_field_p%max_index)
then
2911 temp_field_p%max_index = index_t
2914 field_index = temp_field_p%index
2928integer :: field_index
2929character(len=*),
intent(in) :: name
2931character(len=*),
intent(in) :: new_sval
2933logical,
intent(in),
optional :: create
2935integer,
intent(in),
optional :: index
2937logical,
intent(in),
optional :: append
2939character(len=fm_string_len),
dimension(:),
pointer :: temp_s_value
2940character(len=FMS_PATH_LEN) :: path
2941character(len=fm_field_name_len) :: base
2945type (
field_def),
save,
pointer :: temp_list_p
2946type (
field_def),
save,
pointer :: temp_field_p
2951if (.not. module_is_initialized)
then
2955if (name .eq.
' ')
then
2960if (
present(create))
then
2966if (
present(index) .and.
present(append))
then
2967 if (append .and. index .gt. 0)
then
2973if (
present(index))
then
2975 if (index_t .lt. 0)
then
2985temp_list_p =>
find_list(path, current_list_p, create_t)
2987if (
associated(temp_list_p))
then
2988 temp_field_p =>
find_field(base, temp_list_p)
2989 if (.not.
associated(temp_field_p))
then
2993 if (
associated(temp_field_p))
then
2996 if (temp_field_p%field_type /= string_type )
then
2997 temp_field_p%max_index = 0
3000 temp_field_p%field_type = string_type
3002 if (
present(append))
then
3004 index_t = temp_field_p%max_index + 1
3008 if (index_t .gt. temp_field_p%max_index + 1)
then
3013 elseif (index_t .eq. 0 .and. &
3014 temp_field_p%max_index .gt. 0)
then
3019 elseif (.not.
allocated(temp_field_p%s_value) .and. &
3020 index_t .gt. 0)
then
3022 allocate(temp_field_p%s_value(1))
3023 temp_field_p%max_index = 1
3024 temp_field_p%array_dim = 1
3026 elseif (index_t .gt. temp_field_p%array_dim)
then
3029 temp_field_p%array_dim = temp_field_p%array_dim + array_increment
3030 allocate (temp_s_value(temp_field_p%array_dim))
3031 do i = 1, temp_field_p%max_index
3032 temp_s_value(i) = temp_field_p%s_value(i)
3034 if (
allocated(temp_field_p%s_value))
deallocate(temp_field_p%s_value)
3035 temp_field_p%s_value = temp_s_value
3036 temp_field_p%max_index = index_t
3041 if (index_t .gt. 0)
then
3042 temp_field_p%s_value(index_t) = new_sval
3043 if (index_t .gt. temp_field_p%max_index)
then
3044 temp_field_p%max_index = index_t
3047 field_index = temp_field_p%index
3063if (.not. module_is_initialized)
then
3080if (.not. module_is_initialized)
then
3084root_p%name = save_root_name
3085root_p%parent => save_root_parent_p
3090nullify(save_root_parent_p)
3100character(len=*),
intent(in) :: name
3104character(len=FMS_PATH_LEN) :: path
3105character(len=fm_field_name_len) :: base
3106type (
field_def),
pointer,
save :: temp_p
3112if (path .ne.
' ')
then
3113 temp_p =>
find_list(path, this_list_p, .false.)
3114 if (
associated(temp_p))
then
3135character(len=*),
intent(in) :: oldname
3137character(len=*),
intent(in) :: newname
3140character(len=FMS_PATH_LEN) :: path
3141character(len=fm_field_name_len) :: base
3142type (
field_def),
pointer,
save :: list_p
3143type (
field_def),
pointer,
save :: temp_p
3148if (path .ne.
' ')
then
3149 temp_p =>
find_list(path, current_list_p, .false.)
3150 if (
associated(temp_p))
then
3152 if (
associated(list_p))
then
3153 list_p%name = newname
3161 if (
associated(list_p))
then
3162 list_p%name = newname
3176 if (.not. module_is_initialized)
then
3178 read (input_nml_file, nml=field_manager_nml, iostat=io)
3179 ierr = check_nml_error(io,
"field_manager_nml")
3182 if (mpp_pe() == mpp_root_pe())
write (logunit, nml=field_manager_nml)
3186 field_type_name(integer_type) =
'integer'
3187 field_type_name(list_type) =
'list'
3188 field_type_name(logical_type) =
'logical'
3189 field_type_name(real_type) =
'real'
3190 field_type_name(string_type) =
'string'
3194 root%parent => root_p
3196 root%field_type = list_type
3199 nullify(root%first_field)
3200 nullify(root%last_field)
3203 if (
allocated(root%i_value))
deallocate(root%i_value)
3204 if (
allocated(root%l_value))
deallocate(root%l_value)
3205 if (
allocated(root%r_value))
deallocate(root%r_value)
3206 if (
allocated(root%s_value))
deallocate(root%s_value)
3211 current_list_p => root
3213 nullify(loop_list_p)
3216 nullify(save_root_parent_p)
3217 save_root_name =
' '
3219 module_is_initialized = .true.
3234character(len=*),
intent(in) :: name
3236type (
field_def),
pointer,
save :: dummy_p
3244if (
associated(dummy_p))
then
3252if (.not.
associated(list_p))
then
3258list_p%field_type = list_type
3259if (
allocated(list_p%i_value))
deallocate(list_p%i_value)
3260if (
allocated(list_p%l_value))
deallocate(list_p%l_value)
3261if (
allocated(list_p%r_value))
deallocate(list_p%r_value)
3262if (
allocated(list_p%s_value))
deallocate(list_p%s_value)
3277character(len=*),
intent(in) :: name
3278character(len=*),
intent(out) :: method_name
3279character(len=*),
intent(out) :: method_control
3281character(len=FMS_PATH_LEN) :: path
3282character(len=FMS_PATH_LEN) :: base
3283character(len=FMS_PATH_LEN) :: name_loc
3284logical :: recursive_t
3285type (
field_def),
pointer,
save :: temp_list_p
3286type (
field_def),
pointer,
save :: temp_value_p
3287type (
field_def),
pointer,
save :: this_field_p
3292 recursive_t = .true.
3294 method_control =
" "
3297name_loc = lowercase(name)
3300 temp_list_p =>
find_list(name_loc, current_list_p, .false.)
3302if (
associated(temp_list_p))
then
3304 success =
query_method(temp_list_p, recursive_t, base, method_name, method_control)
3309 temp_value_p =>
find_list(path, current_list_p, .false.)
3310 if (
associated(temp_value_p))
then
3312 this_field_p => temp_value_p%first_field
3314 do while (
associated(this_field_p))
3315 if ( this_field_p%name == base )
then
3316 method_name = this_field_p%s_value(1)
3323 this_field_p => this_field_p%next
3338recursive function query_method(list_p, recursive, name, method_name, method_control) &
3342logical,
intent(in) ::
recursive
3343character(len=*),
intent(in) :: name
3344character(len=*),
intent(out) :: method_name
3345character(len=*),
intent(out) :: method_control
3348character(len=64) :: scratch
3349type (
field_def),
pointer :: this_field_p
3355if (.not.
associated(list_p) .or. list_p%field_type .ne. list_type)
then
3362 this_field_p => list_p%first_field
3364 do while (
associated(this_field_p))
3365 select case(this_field_p%field_type)
3369 if (.not.
query_method(this_field_p, .true., this_field_p%name, method_name, method_control))
then
3373 method_name = trim(method_name)//trim(this_field_p%name)
3378 write (scratch,*) this_field_p%i_value
3379 call concat_strings(method_control, comma//trim(this_field_p%name)//
' = '//trim(adjustl(scratch)))
3382 write (scratch,
'(l1)')this_field_p%l_value
3383 call concat_strings(method_control, comma//trim(this_field_p%name)//
' = '//trim(adjustl(scratch)))
3386 write (scratch,*) this_field_p%r_value
3387 call concat_strings(method_control, comma//trim(this_field_p%name)//
' = '//trim(adjustl(scratch)))
3390 call concat_strings(method_control, comma//trim(this_field_p%name)//
' = '//trim(this_field_p%s_value(1)))
3391 do i = 2, this_field_p%max_index
3392 call concat_strings(method_control, comma//trim(this_field_p%s_value(i)))
3400 this_field_p => this_field_p%next
3408 character(*),
intent(inout) :: str1
3409 character(*),
intent(in) :: str2
3411 character(64) :: n1,n2
3413 if (len_trim(str1)+len_trim(str2)>len(str1))
then
3414 write(n1,*)len(str1)
3415 write(n2,*)len_trim(str1)+len_trim(str2)
3416 call mpp_error(fatal,
'length of output string ('//trim(adjustl(n1))&
3417 //
') is not enough for the result of concatenation (len='&
3418 //trim(adjustl(n2))//
')')
3420 str1 = trim(str1)//trim(str2)
3433character(len=*),
intent(in) :: list_name
3434character(len=*),
intent(in) :: suffix
3436logical,
intent(in),
optional :: create
3438character(len=fm_string_len),
dimension(:),
allocatable :: control
3439character(len=fm_string_len),
dimension(:),
allocatable :: method
3440character(len=fm_string_len) :: head
3441character(len=fm_string_len) :: list_name_new
3442character(len=fm_string_len) :: tail
3443character(len=fm_string_len) :: val_str
3447logical :: found_methods
3449logical :: recursive_t
3451logical :: val_logical
3452real(r8_kind) :: val_real
3453type (
field_def),
pointer,
save :: temp_field_p
3454type (
field_def),
pointer,
save :: temp_list_p
3461list_name_new = trim(list_name)//trim(suffix)
3462 recursive_t = .true.
3464if (.not. module_is_initialized)
then
3468if (list_name .eq.
' ')
then
3470 temp_list_p => current_list_p
3474 temp_list_p =>
find_list(list_name, current_list_p, .false.)
3475 if (
associated(temp_list_p))
then
3485 do n = 1,
size(method)
3486 if (len_trim(method(n)) > 0 )
then
3487 index =
fm_new_list(trim(list_name_new)//list_sep//method(n), create = create)
3489 temp_field_p =>
find_list(trim(list_name)//list_sep//head,temp_list_p, .false.)
3490 temp_field_p =>
find_field(tail,temp_field_p)
3491 select case (temp_field_p%field_type)
3493 got_value =
fm_get_value( trim(list_name)//list_sep//method(n), val_int)
3494 if (
fm_new_value( trim(list_name_new)//list_sep//method(n), val_int, &
3495 create = create, append = .true.) < 0 ) &
3496 call mpp_error(fatal, trim(error_header)//
'Could not set the '//trim(method(n))//&
3497 ' for '//trim(list_name)//trim(suffix))
3500 got_value =
fm_get_value( trim(list_name)//list_sep//method(n), val_logical)
3501 if (
fm_new_value( trim(list_name_new)//list_sep//method(n), val_logical, &
3502 create = create, append = .true.) < 0 ) &
3503 call mpp_error(fatal, trim(error_header)//
'Could not set the '//trim(method(n))//&
3504 ' for '//trim(list_name)//trim(suffix))
3507 got_value =
fm_get_value( trim(list_name)//list_sep//method(n), val_real)
3508 if (
fm_new_value( trim(list_name_new)//list_sep//method(n), val_real, &
3509 create = create, append = .true.) < 0 ) &
3510 call mpp_error(fatal, trim(error_header)//
'Could not set the '//trim(method(n))//&
3511 ' for '//trim(list_name)//trim(suffix))
3514 got_value =
fm_get_value( trim(list_name)//list_sep//method(n), val_str)
3515 if (
fm_new_value( trim(list_name_new)//list_sep//method(n), val_str, &
3516 create = create, append = .true.) < 0 ) &
3517 call mpp_error(fatal, trim(error_header)//
'Could not set the '//trim(method(n))//&
3518 ' for '//trim(list_name)//trim(suffix))
3537character(len=*),
intent(in) :: list_name
3538character(len=*),
intent(out),
dimension(:) :: methods
3539character(len=*),
intent(out),
dimension(:) :: control
3542logical :: recursive_t
3543type (
field_def),
pointer,
save :: temp_list_p
3549 recursive_t = .true.
3551if (.not. module_is_initialized)
then
3555if (list_name .eq.
' ')
then
3557 temp_list_p => current_list_p
3561 temp_list_p =>
find_list(list_name, current_list_p, .false.)
3562 if (
associated(temp_list_p))
then
3571 success =
find_method(temp_list_p, recursive_t, num_meth, methods, control)
3580recursive function find_method(list_p, recursive, num_meth, method, control) &
3584logical,
intent(in) ::
recursive
3585integer,
intent(inout) :: num_meth
3586character(len=*),
intent(out),
dimension(:) :: method
3587character(len=*),
intent(out),
dimension(:) :: control
3589character(len=FMS_PATH_LEN) :: scratch
3592type (
field_def),
pointer,
save :: this_field_p
3597if (.not.
associated(list_p) .or. list_p%field_type .ne. list_type)
then
3603 this_field_p => list_p%first_field
3605 do while (
associated(this_field_p))
3606 select case(this_field_p%field_type)
3609 if ( this_field_p%length > 1)
then
3610 do n = num_meth+1, num_meth + this_field_p%length - 1
3611 write (method(n),
'(a,a,a,$)') trim(method(num_meth)), &
3612 trim(this_field_p%name), list_sep
3614 write (method(num_meth),
'(a,a,a,$)') trim(method(num_meth)), &
3615 trim(this_field_p%name), list_sep
3617 write (method(num_meth),
'(a,a,a,$)') trim(method(num_meth)), &
3618 trim(this_field_p%name), list_sep
3620 success =
find_method(this_field_p, .true., num_meth, method, control)
3623 write (scratch,*) this_field_p%i_value
3625 write (method(num_meth),
'(a,a)') trim(method(num_meth)), &
3626 trim(this_field_p%name)
3627 write (control(num_meth),
'(a)') &
3629 num_meth = num_meth + 1
3634 write (method(num_meth),
'(a,a)') trim(method(num_meth)), &
3635 trim(this_field_p%name)
3636 write (control(num_meth),
'(l1)') &
3637 this_field_p%l_value
3638 num_meth = num_meth + 1
3642 if(
allocated(this_field_p%r_value))
write (scratch,*) this_field_p%r_value
3644 write (method(num_meth),
'(a,a)') trim(method(num_meth)), &
3645 trim(this_field_p%name)
3646 write (control(num_meth),
'(a)') &
3648 num_meth = num_meth + 1
3652 write (method(num_meth),
'(a,a)') trim(method(num_meth)), &
3653 trim(this_field_p%name)
3654 write (control(num_meth),
'(a)') &
3655 trim(this_field_p%s_value(1))
3656 do i = 2, this_field_p%max_index
3657 write (control(num_meth),
'(a,a,$)') comma//trim(this_field_p%s_value(i))
3659 num_meth = num_meth + 1
3668 this_field_p => this_field_p%next
3674#include "field_manager_r4.fh"
3675#include "field_manager_r8.fh"
3677end module field_manager_mod
character(len=fms_path_len) function, public fm_get_current_list()
A function to return the full path of the current list.
integer function, public fm_get_index(name)
A function to return the index of a named field.
logical function set_list_stuff()
If the the pointer matches to the right list, extract the field information. Used in fm_loop_over_lis...
subroutine, public get_field_info(n, fld_type, fld_name, model, num_methods)
This routine allows access to field information given an index.
subroutine concat_strings(str1, str2)
private function: appends str2 to the end of str1, with length check
integer function, public find_field_index_new(field_name)
character(len=8) function, public fm_get_type(name)
A function to return the type of the named field.
subroutine, private find_head(name, head, rest)
Find the first list for a name by splitting the name into a head and the rest.
type(field_def) function, pointer, private get_field(name, this_list_p)
Return a pointer to the field if it exists relative to this_list_p, null otherwise.
subroutine, public get_field_method(n, m, method)
A routine to get a specified method.
logical function fm_loop_over_list_old(list, name, field_type, index)
Iterates through the given list.
integer, parameter, public fm_string_len
The length of a character string representing character values for the field.
logical function fm_loop_over_list_new(iter, name, field_type, index)
given a list iterator, returns information about curren list element and advances the iterator to the...
subroutine read_field_table_legacy(nfields, table_name)
Routine to read and parse the field table yaml.
logical function, public fm_dump_list(name, recursive, unit)
A function to list properties associated with a field.
subroutine new_name_yaml(list_name, method_name_in, val_name_in)
Subroutine to add new values to list parameters.
subroutine, public fm_return_root
Return the root list to the value at initialization.
logical function, public fm_modify_name(oldname, newname)
This function allows a user to rename a field without modifying the contents of the field.
integer, parameter, public model_land
Land model.
type(field_def) function, pointer, private make_list(this_list_p, name)
This function creates a new field and returns a pointer to that field.
function parse_strings(text, label, values)
function parse_integers(text, label, values)
integer function parse_string(text, label, parse_sval)
type(field_def) function, pointer, private find_list(path, relative_p, create)
Find and return a pointer to the specified list, relative to relative_p. Return a null pointer on err...
logical function, public fm_change_root(name)
Change the root list.
subroutine, public fm_init_loop(loop_list, iter)
given a name of the list, prepares an iterator over the list content. If the name of the given list i...
character(len=11), dimension(num_models), parameter, public model_names
Model names, e.g. MODEL_NAMES(MODEL_OCEAN) is 'oceanic'.
logical function, public fm_change_list(name)
Change the current list. Return true on success, false otherwise.
type(field_mgr_type), dimension(:), allocatable, private fields
fields of field_mgr_type
subroutine, private initialize_module_variables
A function to initialize the values of the pointers. This will remove all fields and reset the field ...
subroutine, public fm_reset_loop
Resets the loop variable. For use in conjunction with fm_loop_over_list.
subroutine, public field_manager_end
Destructor for field manager.
subroutine new_name(list_name, method_name_in, val_name_in)
Subroutine to add new values to list parameters.
integer, parameter, public model_coupler
Ice model.
subroutine, private find_base(name, path, base)
A subroutine that splits a listname into a path and a base.
type(field_def) function, pointer, private create_field(parent_p, name)
A function to create a field as a child of parent_p. This will return a pointer to a field_def type.
integer, parameter, public fm_field_name_len
The length of a character string representing the field name.
logical recursive function, private dump_list(list_p, recursive, depth, out_unit)
This is a function that lists the parameters of a field.
subroutine read_field_table_yaml(nfields, table_name)
Routine to read and parse the field table yaml.
integer, parameter, public fm_type_name_len
The length of a character string representing the various types that the values of the field can take...
logical use_field_table_yaml
.True. if using the field_table.yaml, .false. if using the legacy field_table
subroutine, public get_field_methods(n, methods)
A routine to obtain all the methods associated with a field.
logical function, public fm_get_value_string(name, get_sval, index)
integer, parameter, public model_ocean
Ocean model.
logical function, public fm_get_value_integer(name, get_ival, index)
integer, parameter, public fm_path_name_len
The length of a character string representing the field path.
integer function, public fm_new_list(name, create, keep)
A function to create a new list.
integer, parameter, public no_field
The value returned if a field is not defined.
integer function, public fm_new_value_integer(name, new_ival, create, index, append)
Assigns a given value to a given field.
integer, parameter, public model_ice
Ice model.
logical function, public fm_find_methods(list_name, methods, control)
This function retrieves all the methods associated with a field.
logical function, public fm_query_method(name, method_name, method_control)
This is a function that provides the capability to return parameters associated with a field in a pai...
integer function, public fm_new_value_logical(name, new_lval, create, index, append)
Assigns a given value to a given field.
recursive logical function query_method(list_p, recursive, name, method_name, method_control)
A private function that can recursively recover values for parameters associated with a field.
type(field_def) function, pointer, private find_field(name, this_list_p)
Find and return a pointer to the field in the specified list. Return a null pointer on error.
integer function, public fm_copy_list(list_name, suffix, create)
A function that allows the user to copy a field and add a suffix to the name of the new field.
logical function, public fm_exists(name)
A function to test whether a named field exists.
integer function parse_integer(text, label, parse_ival)
integer, parameter, public model_atmos
Atmospheric model.
logical function, public fm_get_value_logical(name, get_lval, index)
integer, parameter, public num_models
Number of models (ATMOS, OCEAN, LAND, ICE, COUPLER).
subroutine, public field_manager_init(nfields, table_name)
Routine to initialize the field manager.
integer function, public fm_new_value_string(name, new_sval, create, index, append)
Assigns a given value to a given field.
subroutine strip_front_blanks(name)
A routine to strip whitespace from the start of character strings.
integer function, public fm_get_length(name)
A function to return how many elements are contained within the named list or entry.
recursive logical function find_method(list_p, recursive, num_meth, method, control)
Given a field list pointer this function retrieves methods and associated parameters for the field li...
integer function, public find_field_index_old(model, field_name)
Function to return the index of the field.
Returns an index corresponding to the given field name.
An overloaded function to find and extract a value for a named field.
A function for looping over a list.
An overloaded function to assign a value to a field.
A function to parse an integer or an array of integers, a real or an array of reals,...
Private type for internal use.
Private type for internal use.
Private type for internal use.
Private type for internal use.
Iterator over the field manager list.
This method_type is a way to allow a component module to alter the parameters it needs for various tr...
This method_type is the same as method_type except that the method_control string is not present....
This is the same as method_type except that the method_control and method_name strings are not presen...
subroutine, public build_fmtable(fmtable, filename)
Subroutine to populate an fmTable by reading a yaml file, given an optional filename.