156 module field_manager_mod
159 #define MAXFIELDS_ 250
163 #ifndef MAXFIELDMETHODS_
164 #define MAXFIELDMETHODS_ 250
189 use fms_mod,
only : lowercase, &
192 use fms2_io_mod,
only: file_exists, get_instance_filename
193 use platform_mod,
only: r4_kind, r8_kind, fms_path_len, fms_file_len
201 #include<file_version.h>
202 logical :: module_is_initialized = .false.
267 character(len=11),
parameter,
public,
dimension(NUM_MODELS) :: &
268 model_names=(/
'atmospheric',
'oceanic ',
'land ',
'ice ',
'coupler '/)
288 character(len=fm_string_len) :: method_name
291 character(len=fm_string_len) :: method_control
302 character(len=fm_string_len) :: method_type
303 character(len=fm_string_len) :: method_name
312 character(len=fm_string_len) :: method_type
353 module procedure parse_real_r4
354 module procedure parse_real_r8
355 module procedure parse_reals_r4
356 module procedure parse_reals_r8
382 module procedure fm_new_value_real_r4
383 module procedure fm_new_value_real_r8
401 module procedure fm_get_value_real_r4
402 module procedure fm_get_value_real_r8
420 character(len=17),
parameter :: module_name =
'field_manager_mod'
421 character(len=33),
parameter :: error_header =
'==>Error from '//trim(module_name)//
': '
422 character(len=35),
parameter :: warn_header =
'==>Warning from '//trim(module_name)//
': '
423 character(len=32),
parameter :: note_header =
'==>Note from '//trim(module_name)//
': '
424 character(len=1),
parameter :: comma =
","
425 character(len=1),
parameter :: list_sep =
'/'
427 character(len=1),
parameter :: comment =
'#'
428 character(len=1),
parameter :: dquote =
'"'
429 character(len=1),
parameter :: equal =
'='
430 character(len=1),
parameter :: squote =
"'"
432 integer,
parameter :: null_type = 0
433 integer,
parameter :: integer_type = 1
434 integer,
parameter :: list_type = 2
435 integer,
parameter :: logical_type = 3
436 integer,
parameter :: real_type = 4
437 integer,
parameter :: string_type = 5
438 integer,
parameter :: num_types = 5
439 integer,
parameter :: array_increment = 10
441 integer,
parameter :: MAX_FIELDS = maxfields_
442 integer,
parameter :: MAX_FIELD_METHODS = maxfieldmethods_
448 character(len=fm_field_name_len) :: field_type
449 character(len=fm_string_len) :: field_name
450 integer :: model, num_methods
459 character(len=fm_field_name_len) :: fld_type
460 character(len=fm_field_name_len) :: mod_name
461 character(len=fm_string_len) :: fld_name
467 character(len=fm_field_name_len) :: fld_type
468 character(len=fm_field_name_len) :: mod_name
474 character (len=fm_field_name_len) :: name
476 type (field_def),
pointer :: parent => null()
477 integer :: field_type
481 type (field_def),
pointer :: first_field => null()
482 type (field_def),
pointer :: last_field => null()
483 integer,
allocatable,
dimension(:) :: i_value
484 logical,
allocatable,
dimension(:) :: l_value
485 real(r8_kind),
allocatable,
dimension(:) :: r_value
487 character(len=fm_string_len),
allocatable,
dimension(:) :: s_value
488 type (
field_def),
pointer :: next => null()
489 type (
field_def),
pointer :: prev => null()
497 character(len=FMS_PATH_LEN) :: loop_list
498 character(len=fm_type_name_len) :: field_type_name(num_types)
499 character(len=fm_field_name_len) :: save_root_name
501 character(len=52) :: set =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
504 character(len=50) :: set_nonexp =
"ABCDFGHIJKLMNOPQRSTUVWXYZabcdfghijklmnopqrstuvwxyz"
507 character(len=13) :: setnum =
"0123456789+-."
508 integer :: num_fields = 0
509 type (
field_def),
pointer :: loop_list_p => null()
510 type (
field_def),
pointer :: current_list_p => null()
511 type (
field_def),
pointer :: root_p => null()
512 type (
field_def),
pointer :: save_root_parent_p => null()
540 integer,
intent(out),
optional :: nfields
541 character(len=fm_string_len),
intent(in),
optional :: table_name
543 if (module_is_initialized)
then
544 if(
present(nfields)) nfields = num_fields
554 call mpp_error(fatal,
"You cannot have use_field_table_yaml=.true. without compiling with -Duse_yaml")
556 if (file_exists(
"field_table")) &
557 call mpp_error(fatal,
"You cannot have the legacy field_table if use_field_table_yaml=.true.")
559 call mpp_error(note,
"field_manager_init:: You are using the yaml version of the field_table")
561 &
"field_manager_init:: You are using the yaml version of the field_table. &
562 The legacy field_table format will be deprecated in a future release, &
563 please switch to the yaml format.")
567 if (file_exists(
"field_table.yaml")) &
568 call mpp_error(fatal,
"You cannot have the yaml field_table if use_field_table_yaml=.false.")
569 call mpp_error(note,
"field_manager_init:: You are using the legacy version of the field_table")
571 &
"field_manager_init:: You are using the yaml version of the field_table. &
572 The legacy field_table format will be deprecated in a future release, &
573 please switch to the yaml format.")
583 integer,
intent(out),
optional :: nfields
584 character(len=*),
intent(in),
optional :: table_name
586 character(len=FMS_FILE_LEN) :: tbl_name
587 character(len=fm_string_len) :: method_control
588 integer :: h, i, j, k, l, m
589 type (fmTable_t) :: my_table
591 character(len=FMS_PATH_LEN) :: list_name
592 character(len=fm_string_len) :: subparamvalue
593 character(len=fm_string_len) :: fm_yaml_null
594 integer :: current_field
595 integer :: index_list_name
596 integer :: subparamindex
597 logical :: fm_success
600 character(len=FMS_FILE_LEN) :: filename
602 if (.not.
PRESENT(table_name))
then
603 tbl_name =
'field_table.yaml'
605 tbl_name = trim(table_name)
608 call get_instance_filename(tbl_name, filename)
609 if (index(trim(filename),
"ens_") .ne. 0)
then
610 if (file_exists(filename) .and. file_exists(tbl_name)) &
611 call mpp_error(fatal,
"Both "//trim(tbl_name)//
" and "//trim(filename)//
" exists, pick one!")
615 if (.not. file_exists(filename)) filename = tbl_name
618 if (.not. file_exists(trim(filename)))
then
619 if(
present(nfields)) nfields = 0
626 do h=1,
size(my_table%types)
627 do i=1,
size(my_table%types(h)%models)
628 do j=1,
size(my_table%types(h)%models(i)%variables)
629 num_fields = num_fields + 1
634 allocate(
fields(num_fields))
637 do h=1,
size(my_table%types)
638 do i=1,
size(my_table%types(h)%models)
639 select case (my_table%types(h)%models(i)%name)
651 call mpp_error(fatal, trim(error_header)//
'The model name is unrecognised : &
652 &'//trim(my_table%types(h)%models(i)%name))
654 do j=1,
size(my_table%types(h)%models(i)%variables)
655 current_field = current_field + 1
656 list_name = list_sep//lowercase(trim(my_table%types(h)%models(i)%name))//list_sep//&
657 lowercase(trim(my_table%types(h)%name))//list_sep//&
658 lowercase(trim(my_table%types(h)%models(i)%variables(j)%name))
659 index_list_name =
fm_new_list(list_name, create = .true.)
660 if ( index_list_name ==
no_field ) &
661 call mpp_error(fatal, trim(error_header)//
'Could not set field list for '//trim(list_name))
663 fields(current_field)%model = model
664 fields(current_field)%field_name = lowercase(trim(my_table%types(h)%models(i)%variables(j)%name))
665 fields(current_field)%field_type = lowercase(trim(my_table%types(h)%name))
666 fields(current_field)%num_methods =
size(my_table%types(h)%models(i)%variables(j)%keys)
667 allocate(
fields(current_field)%methods(
fields(current_field)%num_methods))
668 if(
fields(current_field)%num_methods.gt.0)
then
669 subparams = (
size(my_table%types(h)%models(i)%variables(j)%attributes) .gt. 0)
670 do k=1,
size(my_table%types(h)%models(i)%variables(j)%keys)
671 fields(current_field)%methods(k)%method_type = &
672 lowercase(trim(my_table%types(h)%models(i)%variables(j)%keys(k)))
673 fields(current_field)%methods(k)%method_name = &
674 lowercase(trim(my_table%types(h)%models(i)%variables(j)%values(k)))
675 if (.not.subparams)
then
676 call new_name(list_name, my_table%types(h)%models(i)%variables(j)%keys(k),&
677 my_table%types(h)%models(i)%variables(j)%values(k) )
680 do l=1,
size(my_table%types(h)%models(i)%variables(j)%attributes)
681 if(lowercase(trim(my_table%types(h)%models(i)%variables(j)%attributes(l)%paramname)).eq.&
682 lowercase(trim(
fields(current_field)%methods(k)%method_type)))
then
687 if (subparamindex.eq.-1)
then
688 call new_name(list_name, my_table%types(h)%models(i)%variables(j)%keys(k),&
689 my_table%types(h)%models(i)%variables(j)%values(k) )
691 do m=1,
size(my_table%types(h)%models(i)%variables(j)%attributes(subparamindex)%keys)
694 if (trim(my_table%types(h)%models(i)%variables(j)%values(k)).eq.
'fm_yaml_null')
then
697 fm_yaml_null = trim(my_table%types(h)%models(i)%variables(j)%values(k))//
'/'
699 method_control = trim(my_table%types(h)%models(i)%variables(j)%keys(k))//
"/"//&
700 &trim(fm_yaml_null)//&
701 &trim(my_table%types(h)%models(i)%variables(j)%attributes(subparamindex)%keys(m))
702 subparamvalue = trim(my_table%types(h)%models(i)%variables(j)%attributes(subparamindex)%values(m))
703 call new_name(list_name, method_control, subparamvalue)
713 if (
present(nfields)) nfields = num_fields
725 character(len=*),
intent(in) :: list_name
726 character(len=*),
intent(in) :: method_name_in
728 character(len=*),
intent(inout) :: val_name_in
731 character(len=fm_string_len) :: method_name
732 character(len=fm_string_len) :: val_name
733 integer,
dimension(:),
allocatable :: end_val
734 integer,
dimension(:),
allocatable :: start_val
740 logical :: append_new
742 real(r8_kind) :: val_real
746 method_name = trim(method_name_in)
756 do i = 1, len_trim(val_name_in)
757 if ( val_name_in(i:i) == comma )
then
758 num_elem = num_elem + 1
762 allocate(start_val(num_elem))
763 allocate(end_val(num_elem))
765 end_val(:) = len_trim(val_name_in)
768 do i = 1, len_trim(val_name_in)
769 if ( val_name_in(i:i) == comma )
then
770 end_val(num_elem) = i-1
771 start_val(num_elem+1) = i+1
772 num_elem = num_elem + 1
778 if ( i .gt. 1 .or. index_t .eq. 0 )
then
782 val_type = string_type
783 val_name = val_name_in(start_val(i):end_val(i))
786 if ( scan(val_name(1:1), setnum ) > 0 )
then
787 if ( scan(val_name, set_nonexp ) .le. 0 )
then
788 if ( scan(val_name,
'.') > 0 .or. scan(val_name,
'e') > 0 .or. scan(val_name,
'E') > 0)
then
789 read(val_name, *) val_real
792 read(val_name, *) val_int
793 val_type = integer_type
798 if ( len_trim(val_name) == 1 .or. len_trim(val_name) == 3)
then
799 if ( val_name ==
't' .or. val_name ==
'T' .or. val_name ==
'.t.' .or. val_name ==
'.T.' )
then
801 val_type = logical_type
803 if ( val_name ==
'f' .or. val_name ==
'F' .or. val_name ==
'.f.' .or. val_name ==
'.F.' )
then
805 val_type = logical_type
808 if ( trim(lowercase(val_name)) ==
'true' .or. trim(lowercase(val_name)) ==
'.true.' )
then
810 val_type = logical_type
812 if ( trim(lowercase(val_name)) ==
'false' .or. trim(lowercase(val_name)) ==
'.false.' )
then
814 val_type = logical_type
817 select case(val_type)
820 if (
fm_new_value( method_name, val_int, create = .true., index = index_t, append = append_new ) < 0 ) &
821 call mpp_error(fatal, trim(error_header)//
'Could not set "' // trim(val_name) //
'" for '//trim(method_name)//&
822 ' (I) for '//trim(list_name))
825 if (
fm_new_value( method_name, val_logic, create = .true., index = index_t, append = append_new) < 0 ) &
826 call mpp_error(fatal, trim(error_header)//
'Could not set "' // trim(val_name) //
'" for '//trim(method_name)//&
827 ' (L) for '//trim(list_name))
830 if (
fm_new_value( method_name, val_real, create = .true., index = index_t, append = append_new) < 0 ) &
831 call mpp_error(fatal, trim(error_header)//
'Could not set "' // trim(val_name) //
'" for '//trim(method_name)//&
832 ' (R) for '//trim(list_name))
835 if (
fm_new_value( method_name, val_name, create = .true., index = index_t, append = append_new) < 0 ) &
836 call mpp_error(fatal, trim(error_header)//
'Could not set "' // trim(val_name) //
'" for '//trim(method_name)//&
837 ' (S) for '//trim(list_name))
839 call mpp_error(fatal, trim(error_header)//
'Could not find a valid type to set the '//trim(method_name)//&
840 ' for '//trim(list_name))
845 deallocate(start_val)
860 integer,
intent(out),
optional :: nfields
861 character(len=fm_string_len),
intent(in),
optional :: table_name
864 character(len=1024) :: record
865 character(len=fm_string_len) :: control_str
866 character(len=FMS_PATH_LEN) :: list_name
867 character(len=fm_string_len) :: method_name
868 character(len=fm_string_len) :: name_str
869 character(len=fm_string_len) :: type_str
870 character(len=fm_string_len) :: val_name
871 character(len=fm_string_len) :: tbl_name
872 integer :: control_array(MAX_FIELDS,3)
875 integer :: index_list_name
885 logical :: flag_method
886 logical :: fm_success
893 if (.not.
PRESENT(table_name))
then
894 tbl_name =
'field_table'
896 tbl_name = trim(table_name)
898 if (.not. file_exists(trim(tbl_name)))
then
899 if(
present(nfields)) nfields = 0
903 allocate(
fields(max_fields))
905 open(newunit=iunit, file=trim(tbl_name), action=
'READ', iostat=io_status)
906 if(io_status/=0)
call mpp_error(fatal,
'field_manager_mod: Error in opening file '//trim(tbl_name))
911 read(iunit,
'(a)',
end=89,err=99) record
912 write( log_unit,
'(a)' )record
913 if (record(1:1) ==
"#" ) cycle
914 ltrec = len_trim(record)
915 if (ltrec .le. 0 ) cycle
920 if (record(l:l) ==
'"' )
then
924 if (icount > 6 )
then
925 call mpp_error(fatal,trim(error_header)//
'Too many fields in field table header entry.'//trim(record))
930 read(record,*,
end=79,err=79) text_names
931 text_names%fld_type = lowercase(trim(text_names%fld_type))
932 text_names%mod_name = lowercase(trim(text_names%mod_name))
933 text_names%fld_name = lowercase(trim(text_names%fld_name))
936 read(record,*,
end=79,err=79) text_names_short
937 text_names%fld_type = lowercase(trim(text_names_short%fld_type))
938 text_names%mod_name = lowercase(trim(text_names_short%mod_name))
939 text_names%fld_name = lowercase(trim(text_names_short%mod_name))
943 read(record,*,
end=79,err=79) text_names_short
944 text_names%fld_type = lowercase(trim(text_names_short%fld_type))
945 text_names%mod_name = lowercase(trim(text_names_short%mod_name))
946 text_names%fld_name = lowercase(trim(text_names_short%mod_name))
949 text_names%fld_type =
" "
950 text_names%mod_name = lowercase(trim(record))
951 text_names%fld_name =
" "
956 list_name = list_sep//trim(text_names%mod_name)//list_sep//trim(text_names%fld_type)//&
957 list_sep//trim(text_names%fld_name)
959 index_list_name =
fm_new_list(list_name, create = .true.)
960 if ( index_list_name ==
no_field ) &
961 call mpp_error(fatal, trim(error_header)//
'Could not set field list for '//trim(list_name))
964 select case (text_names%mod_name)
976 call mpp_error(fatal, trim(error_header)//
'The model name is unrecognised : '//trim(text_names%mod_name))
979 num_fields = num_fields + 1
981 if (num_fields > max_fields)
call mpp_error(fatal,trim(error_header)//
'max fields exceeded')
982 fields(num_fields)%model = model
983 fields(num_fields)%field_name = lowercase(trim(text_names%fld_name))
984 fields(num_fields)%field_type = lowercase(trim(text_names%fld_type))
985 fields(num_fields)%num_methods = 0
986 allocate(
fields(num_fields)%methods(max_field_methods))
987 call check_for_name_duplication
990 if ( record(len_trim(record):len_trim(record)) == list_sep) cycle
994 do while (flag_method)
995 read(iunit,
'(a)',
end=99,err=99) record
997 if (len_trim(record) .le. 0) cycle
999 if ( record(len_trim(record):len_trim(record)) == list_sep)
then
1000 flag_method = .false.
1001 if (len_trim(record) == 1) cycle
1002 record = record(:len_trim(record)-1)
1005 if (len_trim(record) .le. 0) cycle
1007 if (record(1:1) == comment ) cycle
1010 do l= 1, len_trim(record)
1011 if (record(l:l) == dquote )
then
1015 if (icount > 6 )
call mpp_error(fatal,trim(error_header)//
'Too many fields in field entry.'//trim(record))
1018 call mpp_error(fatal, trim(error_header)//
'Could not change to '//trim(list_name)//
' list')
1020 select case (icount)
1022 read(record,*,
end=99,err=99) text_method
1023 fields(num_fields)%methods(m)%method_type = lowercase(trim(text_method%method_type))
1024 fields(num_fields)%methods(m)%method_name = lowercase(trim(text_method%method_name))
1025 fields(num_fields)%methods(m)%method_control = lowercase(trim(text_method%method_control))
1027 type_str = text_method%method_type
1028 name_str = text_method%method_name
1029 control_str = text_method%method_control
1033 read(record,*,
end=99,err=99) text_method_short
1034 fields(num_fields)%methods(m)%method_type =&
1035 & lowercase(trim(text_method_short%method_type))
1036 fields(num_fields)%methods(m)%method_name =&
1037 & lowercase(trim(text_method_short%method_name))
1038 fields(num_fields)%methods(m)%method_control =
" "
1040 type_str = text_method_short%method_type
1042 control_str = text_method_short%method_name
1047 read(record,*,
end=99,err=99) text_method_very_short
1048 fields(num_fields)%methods(m)%method_type = lowercase(trim(text_method_very_short%method_type))
1049 fields(num_fields)%methods(m)%method_name =
" "
1050 fields(num_fields)%methods(m)%method_control =
" "
1054 control_str = text_method_very_short%method_type
1057 read(record,
'(A)',
end=99,err=99) control_str
1062 call mpp_error(fatal,trim(error_header)//
'Unterminated field in field entry.'//trim(record))
1074 ltrec= len_trim(control_str)
1075 control_array(:,1) = 1
1076 control_array(:,2:3) = ltrec
1079 if (control_str(l:l) == equal )
then
1081 control_array(icount,2) = l
1082 elseif (control_str(l:l) == comma )
then
1083 if (icount .eq. 0)
then
1084 call mpp_error(fatal,trim(error_header) // &
1085 ' Bad format for field entry (comma without equals sign): ''' // &
1086 trim(control_str) //
'''')
1087 elseif (icount .gt. max_fields)
then
1088 call mpp_error(fatal,trim(error_header) // &
1089 ' Too many fields in field entry: ''' // &
1090 trim(control_str) //
'''')
1092 control_array(icount,3) = l-1
1093 control_array(min(max_fields,icount+1),1) = l+1
1102 if (control_str(ltrec:ltrec) .ne. comma)
then
1103 control_array(max(1,icount),3) = ltrec
1106 if ( icount == 0 )
then
1107 method_name = type_str
1108 if (len_trim(method_name) > 0 )
then
1109 method_name = trim(method_name)//list_sep// trim(name_str)
1111 method_name = trim(name_str)
1113 val_name = control_str
1115 call new_name(list_name, method_name, val_name )
1120 startcont = control_array(l,1)
1121 midcont = control_array(l,2)
1122 endcont = control_array(l,3)
1124 method_name = trim(type_str)
1125 if (len_trim(method_name) > 0 )
then
1126 method_name = trim(method_name)//list_sep// trim(name_str)
1128 method_name = trim(name_str)
1131 if (len_trim(method_name) > 0 )
then
1132 method_name = trim(method_name)//list_sep//&
1133 trim(control_str(startcont:midcont-1))
1135 method_name = trim(control_str(startcont:midcont-1))
1137 val_name = trim(control_str(midcont+1:endcont))
1139 call new_name(list_name, method_name, val_name )
1144 fields(num_fields)%num_methods =
fields(num_fields)%num_methods + 1
1145 if (
fields(num_fields)%num_methods > max_field_methods) &
1146 call mpp_error(fatal,trim(error_header)//
'Maximum number of methods for field exceeded')
1150 flag_method = .true.
1151 do while (flag_method)
1152 read(iunit,
'(A)',
end=99,err=99) record
1153 if ( record(len_trim(record):len_trim(record)) == list_sep)
then
1154 flag_method = .false.
1162 close(iunit, iostat=io_status)
1163 if(io_status/=0)
call mpp_error(fatal,
'field_manager_mod: Error in closing file '//trim(tbl_name))
1166 if(
present(nfields)) nfields = num_fields
1168 default_method%method_type =
'none'
1169 default_method%method_name =
'none'
1170 default_method%method_control =
'none'
1175 call mpp_error(fatal,trim(error_header)//
' Error reading field table. Record = '//trim(record))
1179 subroutine check_for_name_duplication
1184 if (
fields(i)%field_type ==
fields(num_fields)%field_type .and. &
1186 fields(i)%field_name ==
fields(num_fields)%field_name )
then
1187 if (
mpp_pe() .eq. mpp_root_pe())
then
1188 call mpp_error(warning,
'Error in field_manager_mod. Duplicate field name: Field type='//&
1189 trim(
fields(i)%field_type)// &
1191 ', Duplicated name='//trim(
fields(i)%field_name))
1196 end subroutine check_for_name_duplication
1206 subroutine new_name ( list_name, method_name_in , val_name_in)
1207 character(len=*),
intent(in) :: list_name
1208 character(len=*),
intent(in) :: method_name_in
1210 character(len=*),
intent(inout) :: val_name_in
1213 character(len=fm_string_len) :: method_name
1214 character(len=fm_string_len) :: val_name
1215 integer,
dimension(MAX_FIELDS) :: end_val
1216 integer,
dimension(MAX_FIELDS) :: start_val
1225 logical :: append_new
1226 logical :: val_logic
1227 real(r8_kind) :: val_real
1231 method_name = trim(method_name_in)
1236 append_new = .false.
1238 end_val(:) = len_trim(val_name_in)
1243 do i = 1, len_trim(val_name_in)
1244 if ( val_name_in(i:i) == comma )
then
1245 end_val(num_elem) = i-1
1246 start_val(num_elem+1) = i+1
1247 num_elem = num_elem + 1
1252 left_br = scan(method_name,
'[')
1253 right_br = scan(method_name,
']')
1254 if ( num_elem .eq. 1 )
then
1255 if ( left_br > 0 .and. right_br == 0 ) &
1256 call mpp_error(fatal, trim(error_header)//
"Left bracket present without right bracket in "//trim(method_name))
1257 if ( left_br== 0 .and. right_br > 0 ) &
1258 call mpp_error(fatal, trim(error_header)//
"Right bracket present without left bracket in "//trim(method_name))
1259 if ( left_br > 0 .and. right_br > 0 )
then
1260 if ( scan( method_name(left_br+1:right_br -1), set ) > 0 ) &
1261 call mpp_error(fatal, trim(error_header)//
"Using a non-numeric value for index in "//trim(method_name))
1262 read(method_name(left_br+1:right_br -1), *) index_t
1263 method_name = method_name(:left_br -1)
1267 if ( left_br > 0 .or. right_br > 0 ) &
1268 call mpp_error(fatal, &
1269 trim(error_header)//
"Using a comma delimited list with an indexed array element in "//trim(method_name))
1274 if ( i .gt. 1 .or. index_t .eq. 0 )
then
1278 val_type = string_type
1279 val_name = val_name_in(start_val(i):end_val(i))
1287 length = len_trim(val_name)
1288 if (val_name(1:1) .eq. squote)
then
1290 if (val_name(length:length) .eq. squote)
then
1291 val_name = val_name(2:length-1)//repeat(
" ",len(val_name)-length+2)
1292 val_type = string_type
1293 elseif (val_name(length:length) .eq. dquote)
then
1294 call mpp_error(fatal, trim(error_header) //
' Quotes do not match in ' // trim(val_name) // &
1295 ' for ' // trim(method_name) //
' of ' // trim(list_name))
1297 call mpp_error(fatal, trim(error_header) //
' No trailing quote in ' // trim(val_name) // &
1298 ' for ' // trim(method_name) //
' of ' // trim(list_name))
1301 elseif (val_name(1:1) .eq. dquote .or. val_name(length:length) .eq. dquote)
then
1303 call mpp_error(fatal, trim(error_header) //
' Double quotes not allowed in ' // trim(val_name) // &
1304 ' for ' // trim(method_name) //
' of ' // trim(list_name))
1306 elseif (val_name(length:length) .eq. squote)
then
1308 call mpp_error(fatal, trim(error_header) //
' No leading quote in ' // trim(val_name) // &
1309 ' for ' // trim(method_name) //
' of ' // trim(list_name))
1317 if ( scan(val_name(1:1), setnum ) > 0 )
then
1321 if ( scan(val_name, set_nonexp ) .le. 0 )
then
1323 if ( scan(val_name,
'.') > 0 .or. scan(val_name,
'e') > 0 .or. scan(val_name,
'E') > 0)
then
1324 read(val_name, *) val_real
1325 val_type = real_type
1327 read(val_name, *) val_int
1328 val_type = integer_type
1335 if ( len_trim(val_name) == 1 .or. len_trim(val_name) == 3)
then
1336 if ( val_name ==
't' .or. val_name ==
'T' .or. val_name ==
'.t.' .or. val_name ==
'.T.' )
then
1338 val_type = logical_type
1340 if ( val_name ==
'f' .or. val_name ==
'F' .or. val_name ==
'.f.' .or. val_name ==
'.F.' )
then
1342 val_type = logical_type
1345 if ( trim(lowercase(val_name)) ==
'true' .or. trim(lowercase(val_name)) ==
'.true.' )
then
1347 val_type = logical_type
1349 if ( trim(lowercase(val_name)) ==
'false' .or. trim(lowercase(val_name)) ==
'.false.' )
then
1351 val_type = logical_type
1355 select case(val_type)
1358 if (
fm_new_value( method_name, val_int, create = .true., index = index_t, append = append_new ) < 0 ) &
1359 call mpp_error(fatal, trim(error_header)//
'Could not set "' // trim(val_name) //
'" for '//trim(method_name)//&
1360 ' (I) for '//trim(list_name))
1363 if (
fm_new_value( method_name, val_logic, create = .true., index = index_t, append = append_new) < 0 ) &
1364 call mpp_error(fatal, trim(error_header)//
'Could not set "' // trim(val_name) //
'" for '//trim(method_name)//&
1365 ' (L) for '//trim(list_name))
1368 if (
fm_new_value( method_name, val_real, create = .true., index = index_t, append = append_new) < 0 ) &
1369 call mpp_error(fatal, trim(error_header)//
'Could not set "' // trim(val_name) //
'" for '//trim(method_name)//&
1370 ' (R) for '//trim(list_name))
1373 if (
fm_new_value( method_name, val_name, create = .true., index = index_t, append = append_new) < 0 ) &
1374 call mpp_error(fatal, trim(error_header)//
'Could not set "' // trim(val_name) //
'" for '//trim(method_name)//&
1375 ' (S) for '//trim(list_name))
1377 call mpp_error(fatal, trim(error_header)//
'Could not find a valid type to set the '//trim(method_name)//&
1378 ' for '//trim(list_name))
1393 module_is_initialized = .false.
1396 if(
allocated(
fields(j)%methods))
deallocate(
fields(j)%methods)
1407 character(len=*),
intent(inout) :: name
1409 name = trim(adjustl(name))
1421 integer,
intent(in) :: model
1422 character(len=*),
intent(in) :: field_name
1429 if (
fields(i)%model == model .and.
fields(i)%field_name == lowercase(field_name))
then
1441 character(len=*),
intent(in) :: field_name
1460 integer,
intent(in) :: n
1461 character (len=*),
intent(out) :: fld_type
1462 character (len=*),
intent(out) :: fld_name
1463 integer,
intent(out) :: model
1464 integer,
intent(out) :: num_methods
1466 if (n < 1 .or. n > num_fields)
call mpp_error(fatal,trim(error_header)//
'Invalid field index')
1468 fld_type =
fields(n)%field_type
1469 fld_name =
fields(n)%field_name
1471 num_methods =
fields(n)%num_methods
1481 integer,
intent(in) :: n
1482 integer,
intent(in) :: m
1485 if (n < 1 .or. n > num_fields)
call mpp_error(fatal,trim(error_header)//
'Invalid field index')
1486 if (m < 1 .or. m >
fields(n)%num_methods)
call mpp_error(fatal,trim(error_header)//
'Invalid method index')
1488 method =
fields(n)%methods(m)
1498 integer,
intent(in) :: n
1501 if (n < 1 .or. n > num_fields) &
1502 call mpp_error(fatal,trim(error_header)//
'Invalid field index')
1504 if (
size(methods(:)) <
fields(n)%num_methods) &
1505 call mpp_error(fatal,trim(error_header)//
'Method array too small')
1507 methods = default_method
1516 character(len=*),
intent(in) :: text
1517 character(len=*),
intent(in) :: label
1518 integer,
intent(out) :: values(:)
1524 character(len=*),
intent(in) :: text
1525 character(len=*),
intent(in) :: label
1526 character(len=*),
intent(out) :: values(:)
1532 character(len=*),
intent(in) :: text
1533 character(len=*),
intent(in) :: label
1534 integer,
intent(out) :: parse_ival
1537 integer :: values(1)
1540 if (
parse > 0) parse_ival = values(1)
1544 character(len=*),
intent(in) :: text
1545 character(len=*),
intent(in) :: label
1546 character(len=*),
intent(out) :: parse_sval
1549 character(len=len(parse_sval)) :: values(1)
1552 if (
parse > 0) parse_sval = values(1)
1569 character(len=*),
intent(in) :: name
1571 integer :: error, out_unit
1574 if (.not.
associated(parent_p) .or. name .eq.
' ')
then
1580 allocate(list_p, stat = error)
1581 if (error .ne. 0)
then
1582 write (out_unit,*) trim(error_header),
'Error ', error, &
1583 ' allocating memory for list ', trim(name)
1590 nullify(list_p%next)
1591 list_p%prev => parent_p%last_field
1592 nullify(list_p%first_field)
1593 nullify(list_p%last_field)
1595 list_p%field_type = null_type
1596 list_p%max_index = 0
1597 list_p%array_dim = 0
1598 if (
allocated(list_p%i_value))
deallocate(list_p%i_value)
1599 if (
allocated(list_p%l_value))
deallocate(list_p%l_value)
1600 if (
allocated(list_p%r_value))
deallocate(list_p%r_value)
1601 if (
allocated(list_p%s_value))
deallocate(list_p%s_value)
1604 if (parent_p%length .le. 0)
then
1605 parent_p%first_field => list_p
1607 parent_p%last_field%next => list_p
1610 parent_p%last_field => list_p
1612 parent_p%length = parent_p%length + 1
1614 list_p%index = parent_p%length
1616 list_p%parent => parent_p
1630 logical recursive function
dump_list(list_p,
recursive, depth, out_unit) result(success)
1633 logical,
intent(in) ::
recursive
1634 integer,
intent(in) :: depth
1636 integer,
intent(in) :: out_unit
1640 character(len=fm_field_name_len) :: num, scratch
1641 type (
field_def),
pointer :: this_field_p
1642 character(len=depth+fm_field_name_len) :: blank
1648 if (.not.
associated(list_p))
then
1650 elseif (list_p%field_type .ne. list_type)
then
1658 write (out_unit,
'(a,a,a)') blank(1:depth), trim(list_p%name), list_sep
1665 this_field_p => list_p%first_field
1667 do while (
associated(this_field_p))
1669 select case(this_field_p%field_type)
1674 success =
dump_list(this_field_p, .true., depthp1, out_unit)
1675 if (.not.success)
exit
1677 write (out_unit,
'(a,a,a)') blank(1:depthp1), trim(this_field_p%name), list_sep
1681 if (this_field_p%max_index .eq. 0)
then
1682 write (out_unit,
'(a,a,a)') blank(1:depthp1), trim(this_field_p%name),
' = NULL'
1683 elseif (this_field_p%max_index .eq. 1)
then
1684 write (scratch,*) this_field_p%i_value(1)
1685 write (out_unit,
'(a,a,a,a)') blank(1:depthp1), trim(this_field_p%name),
' = ', &
1686 trim(adjustl(scratch))
1688 do j = 1, this_field_p%max_index
1689 write (scratch,*) this_field_p%i_value(j)
1691 write (out_unit,
'(a,a,a,a,a,a)') blank(1:depthp1), trim(this_field_p%name), &
1692 '[', trim(adjustl(num)),
'] = ', trim(adjustl(scratch))
1697 if (this_field_p%max_index .eq. 0)
then
1698 write (out_unit,
'(a,a,a)') blank(1:depthp1), trim(this_field_p%name),
' = NULL'
1699 elseif (this_field_p%max_index .eq. 1)
then
1700 write (scratch,
'(l1)') this_field_p%l_value(1)
1701 write (out_unit,
'(a,a,a,a)') blank(1:depthp1), trim(this_field_p%name),
' = ', &
1702 trim(adjustl(scratch))
1704 do j = 1, this_field_p%max_index
1705 write (scratch,
'(l1)') this_field_p%l_value(j)
1707 write (out_unit,
'(a,a,a,a,a,a)') blank(1:depthp1), trim(this_field_p%name), &
1708 '[', trim(adjustl(num)),
'] = ', trim(adjustl(scratch))
1713 if (this_field_p%max_index .eq. 0)
then
1714 write (out_unit,
'(a,a,a)') blank(1:depthp1), trim(this_field_p%name),
' = NULL'
1715 elseif (this_field_p%max_index .eq. 1)
then
1716 write (scratch,*) this_field_p%r_value(1)
1717 write (out_unit,
'(a,a,a,a)') blank(1:depthp1), trim(this_field_p%name),
' = ', &
1718 trim(adjustl(scratch))
1720 do j = 1, this_field_p%max_index
1721 write (scratch,*) this_field_p%r_value(j)
1723 write (out_unit,
'(a,a,a,a,a,a)') blank(1:depthp1), trim(this_field_p%name), &
1724 '[', trim(adjustl(num)),
'] = ', trim(adjustl(scratch))
1729 if (this_field_p%max_index .eq. 0)
then
1730 write (out_unit,
'(a,a,a)') blank(1:depthp1), trim(this_field_p%name),
' = NULL'
1731 elseif (this_field_p%max_index .eq. 1)
then
1732 write (out_unit,
'(a,a,a,a)') blank(1:depthp1), trim(this_field_p%name),
' = ', &
1733 ''''//trim(this_field_p%s_value(1))//
''''
1735 do j = 1, this_field_p%max_index
1737 write (out_unit,
'(a,a,a,a,a,a)') blank(1:depthp1), trim(this_field_p%name), &
1738 '[', trim(adjustl(num)),
'] = ',
''''//trim(this_field_p%s_value(j))//
''''
1748 this_field_p => this_field_p%next
1761 character(len=*),
intent(in) :: name
1762 character(len=*),
intent(out) :: path
1763 character(len=*),
intent(out) :: base
1770 length = max(len_trim(name),0)
1771 if (length .eq. 0)
then
1778 do while (name(length:length) .eq. list_sep)
1780 if (length .eq. 0)
then
1784 if (length .eq. 0)
then
1791 i = index(name(1:length), list_sep, back = .true.)
1796 base = name(1:length)
1801 base = name(i+1:length)
1819 character(len=*),
intent(in) :: name
1820 type (
field_def),
pointer :: this_list_p
1823 type (
field_def),
pointer,
save :: temp_p
1828 if (name .eq.
'.')
then
1831 field_p => this_list_p
1832 elseif (name .eq.
'..')
then
1834 field_p => this_list_p%parent
1837 temp_p => this_list_p%first_field
1839 do while (
associated(temp_p))
1842 if (temp_p%name .eq. name)
then
1847 temp_p => temp_p%next
1863 character(len=*),
intent(in) :: name
1864 character(len=*),
intent(out) :: head
1865 character(len=*),
intent(out) :: rest
1869 i = index(name, list_sep)
1872 do while (i .le. len(name))
1873 if (name(i+1:i+1) .eq. list_sep)
then
1885 elseif (i .eq. len(name))
then
1910 character(len=*),
intent(in) :: path
1912 logical,
intent(in) :: create
1914 character(len=FMS_PATH_LEN) :: working_path
1915 character(len=FMS_PATH_LEN) :: rest
1916 character(len=fm_field_name_len) :: this_list
1917 integer :: i, out_unit
1918 type (
field_def),
pointer,
save :: working_path_p
1919 type (
field_def),
pointer,
save :: this_list_p
1924 if (path .eq.
' ')
then
1926 list_p => relative_p
1932 if (path(1:1) .eq. list_sep)
then
1933 working_path_p => root_p
1934 working_path = path(2:)
1936 working_path_p => relative_p
1940 do while (working_path .ne.
' ')
1942 call find_head(working_path, this_list, rest)
1945 if (this_list .eq.
' ')
then
1950 i = len_trim(this_list)
1951 do while (i .gt. 0 .and. this_list(i:i) .eq. list_sep)
1952 this_list(i:i) =
' '
1956 this_list_p =>
find_field(this_list, working_path_p)
1958 if (.not.
associated(this_list_p))
then
1961 this_list_p =>
make_list(working_path_p, this_list)
1962 if (.not.
associated(this_list_p))
then
1975 if (this_list_p%field_type .eq. list_type)
then
1976 working_path_p => this_list_p
1983 list_p => working_path_p
1998 character(len=*),
intent(in) :: name
2000 type (
field_def),
pointer,
save :: temp_p
2002 if (.not. module_is_initialized)
then
2006 temp_p =>
find_list(name, current_list_p, .false.)
2008 if (
associated(temp_p))
then
2009 current_list_p => temp_p
2030 character(len=*),
intent(in) :: name
2032 type (
field_def),
pointer,
save :: temp_list_p
2035 if (.not. module_is_initialized)
then
2040 if (name .eq.
' ')
then
2045 temp_list_p =>
find_list(name, current_list_p, .false.)
2047 if (
associated(temp_list_p))
then
2049 if (save_root_name .ne.
' ')
then
2050 root_p%name = save_root_name
2051 root_p%parent => save_root_parent_p
2054 root_p => temp_list_p
2056 save_root_name = root_p%name
2057 save_root_parent_p => root_p%parent
2060 nullify(root_p%parent)
2063 current_list_p => root_p
2079 character(len=*),
intent(in) :: name
2080 logical,
intent(in),
optional ::
recursive
2082 integer,
intent(in),
optional :: unit
2084 logical :: recursive_t
2085 type (
field_def),
pointer,
save :: temp_list_p
2088 if (
present(unit))
then
2094 recursive_t = .false.
2095 if (
present(
recursive)) recursive_t =
recursive
2098 if (name .eq.
' ')
then
2100 temp_list_p => current_list_p
2104 temp_list_p =>
find_list(name, current_list_p, .false.)
2105 if (
associated(temp_list_p))
then
2113 success =
dump_list(temp_list_p, recursive_t, 0, out_unit)
2125 character(len=*),
intent(in) :: name
2127 type (
field_def),
pointer,
save :: dummy_p
2129 if (.not. module_is_initialized)
then
2133 dummy_p =>
get_field(name, current_list_p)
2134 success =
associated(dummy_p)
2148 character(len=*),
intent(in) :: name
2150 type (
field_def),
pointer,
save :: temp_field_p
2155 if (.not. module_is_initialized)
then
2159 if (name .eq.
' ')
then
2164 temp_field_p =>
get_field(name, current_list_p)
2165 if (
associated(temp_field_p))
then
2167 index = temp_field_p%index
2181 character(len=FMS_PATH_LEN) :: path
2183 type (
field_def),
pointer,
save :: temp_list_p
2185 if (.not. module_is_initialized)
then
2190 temp_list_p => current_list_p
2193 do while (
associated(temp_list_p))
2196 if (temp_list_p%name .eq.
' ')
then
2200 path = list_sep // trim(temp_list_p%name) // path
2202 temp_list_p => temp_list_p%parent
2205 if (.not.
associated(temp_list_p))
then
2209 elseif (path .eq.
' ')
then
2226 character(len=*),
intent(in) :: name
2228 type (
field_def),
pointer,
save :: temp_field_p
2233 if (.not. module_is_initialized)
then
2237 if (name .eq.
' ')
then
2242 temp_field_p =>
get_field(name, current_list_p)
2244 if (
associated(temp_field_p))
then
2246 if (temp_field_p%field_type .eq. list_type)
then
2247 length = temp_field_p%length
2249 length = temp_field_p%max_index
2265 result(name_field_type)
2266 character(len=8) :: name_field_type
2267 character(len=*),
intent(in) :: name
2269 type (
field_def),
pointer,
save :: temp_field_p
2274 if (.not. module_is_initialized)
then
2278 if (name .eq.
' ')
then
2279 name_field_type =
' '
2283 temp_field_p =>
get_field(name, current_list_p)
2285 if (
associated(temp_field_p))
then
2287 name_field_type = field_type_name(temp_field_p%field_type)
2289 name_field_type =
' '
2299 character(len=*),
intent(in) :: name
2300 integer,
intent(out) :: get_ival
2301 integer,
intent(in),
optional :: index
2304 type (
field_def),
pointer,
save :: temp_field_p
2309 if (.not. module_is_initialized)
then
2313 if (name .eq.
' ')
then
2319 if (
present(index))
then
2325 temp_field_p =>
get_field(name, current_list_p)
2327 if (
associated(temp_field_p))
then
2329 if (temp_field_p%field_type .eq. integer_type)
then
2330 if (index_t .lt. 1 .or. index_t .gt. temp_field_p%max_index)
then
2336 get_ival = temp_field_p%i_value(index_t)
2356 character(len=*),
intent(in) :: name
2357 logical,
intent(out) :: get_lval
2358 integer,
intent(in),
optional :: index
2361 type (
field_def),
pointer,
save :: temp_field_p
2366 if (.not. module_is_initialized)
then
2370 if (name .eq.
' ')
then
2376 if (
present(index))
then
2382 temp_field_p =>
get_field(name, current_list_p)
2384 if (
associated(temp_field_p))
then
2386 if (temp_field_p%field_type .eq. logical_type)
then
2388 if (index_t .lt. 1 .or. index_t .gt. temp_field_p%max_index)
then
2394 get_lval = temp_field_p%l_value(index_t)
2414 character(len=*),
intent(in) :: name
2415 character(len=*),
intent(out) :: get_sval
2416 integer,
intent(in),
optional :: index
2419 type (
field_def),
pointer,
save :: temp_field_p
2424 if (.not. module_is_initialized)
then
2428 if (name .eq.
' ')
then
2434 if (
present(index))
then
2440 temp_field_p =>
get_field(name, current_list_p)
2442 if (
associated(temp_field_p))
then
2444 if (temp_field_p%field_type .eq. string_type)
then
2445 if (index_t .lt. 1 .or. index_t .gt. temp_field_p%max_index)
then
2451 get_sval = temp_field_p%s_value(index_t)
2472 character(len=*),
intent(in) :: list
2473 character(len=*),
intent(out) :: name
2474 character(len=fm_type_name_len),
intent(out) :: field_type
2475 integer,
intent(out) :: index
2481 if (.not. module_is_initialized)
then
2485 if (list .eq. loop_list .and.
associated(loop_list_p))
then
2487 loop_list_p => loop_list_p%next
2489 elseif (list .eq.
' ')
then
2492 loop_list_p => current_list_p%first_field
2497 loop_list_p =>
find_list(loop_list, current_list_p, .false.)
2498 if (
associated(loop_list_p))
then
2499 loop_list_p => loop_list_p%first_field
2519 if (
associated(loop_list_p))
then
2520 name = loop_list_p%name
2521 field_type = field_type_name(loop_list_p%field_type)
2522 index = loop_list_p%index
2539 character(len=*) ,
intent(in) :: loop_list
2544 if (loop_list==
' ')
then
2545 iter%ptr => current_list_p%first_field
2547 iter%ptr =>
find_list(loop_list,current_list_p,.false.)
2548 if (
associated(iter%ptr)) iter%ptr => iter%ptr%first_field
2556 result(success) ;
logical success
2558 character(len=*),
intent(out) :: name
2559 character(len=*),
intent(out) :: field_type
2560 integer ,
intent(out) :: index
2563 if (
associated(iter%ptr))
then
2564 name = iter%ptr%name
2565 field_type = field_type_name(iter%ptr%field_type)
2566 index = iter%ptr%index
2568 iter%ptr => iter%ptr%next
2585 character(len=*),
intent(in) :: name
2586 logical,
intent(in),
optional :: create
2587 logical,
intent(in),
optional :: keep
2591 character(len=FMS_PATH_LEN) :: path
2592 character(len=fm_field_name_len) :: base
2593 type (
field_def),
pointer,
save :: temp_list_p
2598 if (.not. module_is_initialized)
then
2602 if (name .eq.
' ')
then
2607 if (
present(create))
then
2613 if (
present(keep))
then
2621 temp_list_p =>
find_list(path, current_list_p, create_t)
2623 if (
associated(temp_list_p))
then
2625 temp_list_p =>
make_list(temp_list_p, base)
2626 if (
associated(temp_list_p))
then
2629 current_list_p => temp_list_p
2631 index = temp_list_p%index
2645 integer :: field_index
2646 character(len=*),
intent(in) :: name
2648 integer,
intent(in) :: new_ival
2650 logical,
intent(in),
optional :: create
2652 integer,
intent(in),
optional :: index
2654 logical,
intent(in),
optional :: append
2660 integer,
pointer,
dimension(:) :: temp_i_value
2661 character(len=FMS_PATH_LEN) :: path
2662 character(len=fm_field_name_len) :: base
2663 type (
field_def),
pointer,
save :: temp_list_p
2664 type (
field_def),
pointer,
save :: temp_field_p
2669 if (.not. module_is_initialized)
then
2673 if (name .eq.
' ')
then
2678 if (
present(create))
then
2684 if (
present(index) .and.
present(append))
then
2685 if (append .and. index .gt. 0)
then
2691 if (
present(index))
then
2693 if (index_t .lt. 0)
then
2703 temp_list_p =>
find_list(path, current_list_p, create_t)
2705 if (
associated(temp_list_p))
then
2706 temp_field_p =>
find_field(base, temp_list_p)
2707 if (.not.
associated(temp_field_p))
then
2711 if (
associated(temp_field_p))
then
2714 if (temp_field_p%field_type == real_type )
then
2717 field_index =
fm_new_value(name, real(new_ival,r8_kind), create, index, append)
2719 else if (temp_field_p%field_type /= integer_type )
then
2722 temp_field_p%max_index = 0
2725 temp_field_p%field_type = integer_type
2727 if (
present(append))
then
2729 index_t = temp_field_p%max_index + 1
2733 if (index_t .gt. temp_field_p%max_index + 1)
then
2738 elseif (index_t .eq. 0 .and. &
2739 temp_field_p%max_index .gt. 0)
then
2744 elseif (.not.
allocated(temp_field_p%i_value) .and. &
2745 index_t .gt. 0)
then
2747 allocate(temp_field_p%i_value(1))
2748 temp_field_p%max_index = 1
2749 temp_field_p%array_dim = 1
2750 elseif (index_t .gt. temp_field_p%array_dim)
then
2753 temp_field_p%array_dim = temp_field_p%array_dim + array_increment
2754 allocate (temp_i_value(temp_field_p%array_dim))
2755 do i = 1, temp_field_p%max_index
2756 temp_i_value(i) = temp_field_p%i_value(i)
2758 if (
allocated(temp_field_p%i_value))
deallocate(temp_field_p%i_value)
2759 temp_field_p%i_value = temp_i_value
2760 temp_field_p%max_index = index_t
2764 if (index_t .gt. 0)
then
2765 temp_field_p%i_value(index_t) = new_ival
2766 if (index_t .gt. temp_field_p%max_index)
then
2767 temp_field_p%max_index = index_t
2770 field_index = temp_field_p%index
2785 integer :: field_index
2786 character(len=*),
intent(in) :: name
2788 logical,
intent(in) :: new_lval
2790 logical,
intent(in),
optional :: create
2792 integer,
intent(in),
optional :: index
2794 logical,
intent(in),
optional :: append
2797 character(len=FMS_PATH_LEN) :: path
2798 character(len=fm_field_name_len) :: base
2802 logical,
dimension(:),
pointer :: temp_l_value
2803 type (
field_def),
pointer,
save :: temp_list_p
2804 type (
field_def),
pointer,
save :: temp_field_p
2809 if (.not. module_is_initialized)
then
2813 if (name .eq.
' ')
then
2818 if (
present(create))
then
2824 if (
present(index) .and.
present(append))
then
2825 if (append .and. index .gt. 0)
then
2831 if (
present(index))
then
2833 if (index_t .lt. 0)
then
2843 temp_list_p =>
find_list(path, current_list_p, create_t)
2845 if (
associated(temp_list_p))
then
2846 temp_field_p =>
find_field(base, temp_list_p)
2847 if (.not.
associated(temp_field_p))
then
2851 if (
associated(temp_field_p))
then
2854 if (temp_field_p%field_type /= logical_type )
then
2855 temp_field_p%max_index = 0
2858 temp_field_p%field_type = logical_type
2860 if (
present(append))
then
2862 index_t = temp_field_p%max_index + 1
2866 if (index_t .gt. temp_field_p%max_index + 1)
then
2871 elseif (index_t .eq. 0 .and. &
2872 temp_field_p%max_index .gt. 0)
then
2877 elseif (.not.
allocated(temp_field_p%l_value) .and. &
2878 index_t .gt. 0)
then
2880 allocate(temp_field_p%l_value(1))
2881 temp_field_p%max_index = 1
2882 temp_field_p%array_dim = 1
2884 elseif (index_t .gt. temp_field_p%array_dim)
then
2887 temp_field_p%array_dim = temp_field_p%array_dim + array_increment
2888 allocate (temp_l_value(temp_field_p%array_dim))
2889 do i = 1, temp_field_p%max_index
2890 temp_l_value(i) = temp_field_p%l_value(i)
2892 if (
allocated(temp_field_p%l_value))
deallocate(temp_field_p%l_value)
2893 temp_field_p%l_value = temp_l_value
2894 temp_field_p%max_index = index_t
2899 if (index_t .gt. 0)
then
2900 temp_field_p%l_value(index_t) = new_lval
2901 if (index_t .gt. temp_field_p%max_index)
then
2902 temp_field_p%max_index = index_t
2905 field_index = temp_field_p%index
2919 integer :: field_index
2920 character(len=*),
intent(in) :: name
2922 character(len=*),
intent(in) :: new_sval
2924 logical,
intent(in),
optional :: create
2926 integer,
intent(in),
optional :: index
2928 logical,
intent(in),
optional :: append
2930 character(len=fm_string_len),
dimension(:),
pointer :: temp_s_value
2931 character(len=FMS_PATH_LEN) :: path
2932 character(len=fm_field_name_len) :: base
2936 type (
field_def),
save,
pointer :: temp_list_p
2937 type (
field_def),
save,
pointer :: temp_field_p
2942 if (.not. module_is_initialized)
then
2946 if (name .eq.
' ')
then
2951 if (
present(create))
then
2957 if (
present(index) .and.
present(append))
then
2958 if (append .and. index .gt. 0)
then
2964 if (
present(index))
then
2966 if (index_t .lt. 0)
then
2976 temp_list_p =>
find_list(path, current_list_p, create_t)
2978 if (
associated(temp_list_p))
then
2979 temp_field_p =>
find_field(base, temp_list_p)
2980 if (.not.
associated(temp_field_p))
then
2984 if (
associated(temp_field_p))
then
2987 if (temp_field_p%field_type /= string_type )
then
2988 temp_field_p%max_index = 0
2991 temp_field_p%field_type = string_type
2993 if (
present(append))
then
2995 index_t = temp_field_p%max_index + 1
2999 if (index_t .gt. temp_field_p%max_index + 1)
then
3004 elseif (index_t .eq. 0 .and. &
3005 temp_field_p%max_index .gt. 0)
then
3010 elseif (.not.
allocated(temp_field_p%s_value) .and. &
3011 index_t .gt. 0)
then
3013 allocate(temp_field_p%s_value(1))
3014 temp_field_p%max_index = 1
3015 temp_field_p%array_dim = 1
3017 elseif (index_t .gt. temp_field_p%array_dim)
then
3020 temp_field_p%array_dim = temp_field_p%array_dim + array_increment
3021 allocate (temp_s_value(temp_field_p%array_dim))
3022 do i = 1, temp_field_p%max_index
3023 temp_s_value(i) = temp_field_p%s_value(i)
3025 if (
allocated(temp_field_p%s_value))
deallocate(temp_field_p%s_value)
3026 temp_field_p%s_value = temp_s_value
3027 temp_field_p%max_index = index_t
3032 if (index_t .gt. 0)
then
3033 temp_field_p%s_value(index_t) = new_sval
3034 if (index_t .gt. temp_field_p%max_index)
then
3035 temp_field_p%max_index = index_t
3038 field_index = temp_field_p%index
3054 if (.not. module_is_initialized)
then
3059 nullify(loop_list_p)
3071 if (.not. module_is_initialized)
then
3075 root_p%name = save_root_name
3076 root_p%parent => save_root_parent_p
3080 save_root_name =
' '
3081 nullify(save_root_parent_p)
3091 character(len=*),
intent(in) :: name
3092 type (
field_def),
pointer :: this_list_p
3095 character(len=FMS_PATH_LEN) :: path
3096 character(len=fm_field_name_len) :: base
3097 type (
field_def),
pointer,
save :: temp_p
3103 if (path .ne.
' ')
then
3104 temp_p =>
find_list(path, this_list_p, .false.)
3105 if (
associated(temp_p))
then
3126 character(len=*),
intent(in) :: oldname
3128 character(len=*),
intent(in) :: newname
3131 character(len=FMS_PATH_LEN) :: path
3132 character(len=fm_field_name_len) :: base
3133 type (
field_def),
pointer,
save :: list_p
3134 type (
field_def),
pointer,
save :: temp_p
3139 if (path .ne.
' ')
then
3140 temp_p =>
find_list(path, current_list_p, .false.)
3141 if (
associated(temp_p))
then
3143 if (
associated(list_p))
then
3144 list_p%name = newname
3152 if (
associated(list_p))
then
3153 list_p%name = newname
3167 if (.not. module_is_initialized)
then
3169 read (input_nml_file, nml=field_manager_nml, iostat=io)
3170 ierr = check_nml_error(io,
"field_manager_nml")
3173 if (
mpp_pe() == mpp_root_pe())
write (logunit, nml=field_manager_nml)
3177 field_type_name(integer_type) =
'integer'
3178 field_type_name(list_type) =
'list'
3179 field_type_name(logical_type) =
'logical'
3180 field_type_name(real_type) =
'real'
3181 field_type_name(string_type) =
'string'
3185 root%parent => root_p
3187 root%field_type = list_type
3190 nullify(root%first_field)
3191 nullify(root%last_field)
3194 if (
allocated(root%i_value))
deallocate(root%i_value)
3195 if (
allocated(root%l_value))
deallocate(root%l_value)
3196 if (
allocated(root%r_value))
deallocate(root%r_value)
3197 if (
allocated(root%s_value))
deallocate(root%s_value)
3202 current_list_p => root
3204 nullify(loop_list_p)
3207 nullify(save_root_parent_p)
3208 save_root_name =
' '
3210 module_is_initialized = .true.
3224 type (
field_def),
pointer :: this_list_p
3225 character(len=*),
intent(in) :: name
3227 type (
field_def),
pointer,
save :: dummy_p
3235 if (
associated(dummy_p))
then
3243 if (.not.
associated(list_p))
then
3249 list_p%field_type = list_type
3250 if (
allocated(list_p%i_value))
deallocate(list_p%i_value)
3251 if (
allocated(list_p%l_value))
deallocate(list_p%l_value)
3252 if (
allocated(list_p%r_value))
deallocate(list_p%r_value)
3253 if (
allocated(list_p%s_value))
deallocate(list_p%s_value)
3268 character(len=*),
intent(in) :: name
3269 character(len=*),
intent(out) :: method_name
3270 character(len=*),
intent(out) :: method_control
3272 character(len=FMS_PATH_LEN) :: path
3273 character(len=FMS_PATH_LEN) :: base
3274 character(len=FMS_PATH_LEN) :: name_loc
3275 logical :: recursive_t
3276 type (
field_def),
pointer,
save :: temp_list_p
3277 type (
field_def),
pointer,
save :: temp_value_p
3278 type (
field_def),
pointer,
save :: this_field_p
3283 recursive_t = .true.
3285 method_control =
" "
3288 name_loc = lowercase(name)
3291 temp_list_p =>
find_list(name_loc, current_list_p, .false.)
3293 if (
associated(temp_list_p))
then
3295 success =
query_method(temp_list_p, recursive_t, base, method_name, method_control)
3300 temp_value_p =>
find_list(path, current_list_p, .false.)
3301 if (
associated(temp_value_p))
then
3303 this_field_p => temp_value_p%first_field
3305 do while (
associated(this_field_p))
3306 if ( this_field_p%name == base )
then
3307 method_name = this_field_p%s_value(1)
3314 this_field_p => this_field_p%next
3329 recursive function query_method(list_p, recursive, name, method_name, method_control) &
3333 logical,
intent(in) ::
recursive
3334 character(len=*),
intent(in) :: name
3335 character(len=*),
intent(out) :: method_name
3336 character(len=*),
intent(out) :: method_control
3339 character(len=64) :: scratch
3340 type (
field_def),
pointer :: this_field_p
3346 if (.not.
associated(list_p) .or. list_p%field_type .ne. list_type)
then
3353 this_field_p => list_p%first_field
3355 do while (
associated(this_field_p))
3356 select case(this_field_p%field_type)
3360 if (.not.
query_method(this_field_p, .true., this_field_p%name, method_name, method_control))
then
3364 method_name = trim(method_name)//trim(this_field_p%name)
3369 write (scratch,*) this_field_p%i_value
3370 call concat_strings(method_control, comma//trim(this_field_p%name)//
' = '//trim(adjustl(scratch)))
3373 write (scratch,
'(l1)')this_field_p%l_value
3374 call concat_strings(method_control, comma//trim(this_field_p%name)//
' = '//trim(adjustl(scratch)))
3377 write (scratch,*) this_field_p%r_value
3378 call concat_strings(method_control, comma//trim(this_field_p%name)//
' = '//trim(adjustl(scratch)))
3381 call concat_strings(method_control, comma//trim(this_field_p%name)//
' = '//trim(this_field_p%s_value(1)))
3382 do i = 2, this_field_p%max_index
3383 call concat_strings(method_control, comma//trim(this_field_p%s_value(i)))
3391 this_field_p => this_field_p%next
3399 character(*),
intent(inout) :: str1
3400 character(*),
intent(in) :: str2
3402 character(64) :: n1,n2
3404 if (len_trim(str1)+len_trim(str2)>len(str1))
then
3405 write(n1,*)len(str1)
3406 write(n2,*)len_trim(str1)+len_trim(str2)
3407 call mpp_error(fatal,
'length of output string ('//trim(adjustl(n1))&
3408 //
') is not enough for the result of concatenation (len='&
3409 //trim(adjustl(n2))//
')')
3411 str1 = trim(str1)//trim(str2)
3424 character(len=*),
intent(in) :: list_name
3425 character(len=*),
intent(in) :: suffix
3427 logical,
intent(in),
optional :: create
3429 character(len=fm_string_len),
dimension(:),
allocatable :: control
3430 character(len=fm_string_len),
dimension(:),
allocatable :: method
3431 character(len=fm_string_len) :: head
3432 character(len=fm_string_len) :: list_name_new
3433 character(len=fm_string_len) :: tail
3434 character(len=fm_string_len) :: val_str
3438 logical :: found_methods
3439 logical :: got_value
3440 logical :: recursive_t
3442 logical :: val_logical
3443 real(r8_kind) :: val_real
3444 type (
field_def),
pointer,
save :: temp_field_p
3445 type (
field_def),
pointer,
save :: temp_list_p
3452 list_name_new = trim(list_name)//trim(suffix)
3453 recursive_t = .true.
3455 if (.not. module_is_initialized)
then
3459 if (list_name .eq.
' ')
then
3461 temp_list_p => current_list_p
3465 temp_list_p =>
find_list(list_name, current_list_p, .false.)
3466 if (
associated(temp_list_p))
then
3476 do n = 1,
size(method)
3477 if (len_trim(method(n)) > 0 )
then
3478 index =
fm_new_list(trim(list_name_new)//list_sep//method(n), create = create)
3480 temp_field_p =>
find_list(trim(list_name)//list_sep//head,temp_list_p, .false.)
3481 temp_field_p =>
find_field(tail,temp_field_p)
3482 select case (temp_field_p%field_type)
3484 got_value =
fm_get_value( trim(list_name)//list_sep//method(n), val_int)
3485 if (
fm_new_value( trim(list_name_new)//list_sep//method(n), val_int, &
3486 create = create, append = .true.) < 0 ) &
3487 call mpp_error(fatal, trim(error_header)//
'Could not set the '//trim(method(n))//&
3488 ' for '//trim(list_name)//trim(suffix))
3491 got_value =
fm_get_value( trim(list_name)//list_sep//method(n), val_logical)
3492 if (
fm_new_value( trim(list_name_new)//list_sep//method(n), val_logical, &
3493 create = create, append = .true.) < 0 ) &
3494 call mpp_error(fatal, trim(error_header)//
'Could not set the '//trim(method(n))//&
3495 ' for '//trim(list_name)//trim(suffix))
3498 got_value =
fm_get_value( trim(list_name)//list_sep//method(n), val_real)
3499 if (
fm_new_value( trim(list_name_new)//list_sep//method(n), val_real, &
3500 create = create, append = .true.) < 0 ) &
3501 call mpp_error(fatal, trim(error_header)//
'Could not set the '//trim(method(n))//&
3502 ' for '//trim(list_name)//trim(suffix))
3505 got_value =
fm_get_value( trim(list_name)//list_sep//method(n), val_str)
3506 if (
fm_new_value( trim(list_name_new)//list_sep//method(n), val_str, &
3507 create = create, append = .true.) < 0 ) &
3508 call mpp_error(fatal, trim(error_header)//
'Could not set the '//trim(method(n))//&
3509 ' for '//trim(list_name)//trim(suffix))
3528 character(len=*),
intent(in) :: list_name
3529 character(len=*),
intent(out),
dimension(:) :: methods
3530 character(len=*),
intent(out),
dimension(:) :: control
3533 logical :: recursive_t
3534 type (
field_def),
pointer,
save :: temp_list_p
3540 recursive_t = .true.
3542 if (.not. module_is_initialized)
then
3546 if (list_name .eq.
' ')
then
3548 temp_list_p => current_list_p
3552 temp_list_p =>
find_list(list_name, current_list_p, .false.)
3553 if (
associated(temp_list_p))
then
3562 success =
find_method(temp_list_p, recursive_t, num_meth, methods, control)
3571 recursive function find_method(list_p, recursive, num_meth, method, control) &
3575 logical,
intent(in) ::
recursive
3576 integer,
intent(inout) :: num_meth
3577 character(len=*),
intent(out),
dimension(:) :: method
3578 character(len=*),
intent(out),
dimension(:) :: control
3580 character(len=FMS_PATH_LEN) :: scratch
3583 type (
field_def),
pointer,
save :: this_field_p
3588 if (.not.
associated(list_p) .or. list_p%field_type .ne. list_type)
then
3594 this_field_p => list_p%first_field
3596 do while (
associated(this_field_p))
3597 select case(this_field_p%field_type)
3600 if ( this_field_p%length > 1)
then
3601 do n = num_meth+1, num_meth + this_field_p%length - 1
3602 write (method(n),
'(a,a,a,$)') trim(method(num_meth)), &
3603 trim(this_field_p%name), list_sep
3605 write (method(num_meth),
'(a,a,a,$)') trim(method(num_meth)), &
3606 trim(this_field_p%name), list_sep
3608 write (method(num_meth),
'(a,a,a,$)') trim(method(num_meth)), &
3609 trim(this_field_p%name), list_sep
3611 success =
find_method(this_field_p, .true., num_meth, method, control)
3614 write (scratch,*) this_field_p%i_value
3616 write (method(num_meth),
'(a,a)') trim(method(num_meth)), &
3617 trim(this_field_p%name)
3618 write (control(num_meth),
'(a)') &
3620 num_meth = num_meth + 1
3625 write (method(num_meth),
'(a,a)') trim(method(num_meth)), &
3626 trim(this_field_p%name)
3627 write (control(num_meth),
'(l1)') &
3628 this_field_p%l_value
3629 num_meth = num_meth + 1
3633 if(
allocated(this_field_p%r_value))
write (scratch,*) this_field_p%r_value
3635 write (method(num_meth),
'(a,a)') trim(method(num_meth)), &
3636 trim(this_field_p%name)
3637 write (control(num_meth),
'(a)') &
3639 num_meth = num_meth + 1
3643 write (method(num_meth),
'(a,a)') trim(method(num_meth)), &
3644 trim(this_field_p%name)
3645 write (control(num_meth),
'(a)') &
3646 trim(this_field_p%s_value(1))
3647 do i = 2, this_field_p%max_index
3648 write (control(num_meth),
'(a,a,$)') comma//trim(this_field_p%s_value(i))
3650 num_meth = num_meth + 1
3659 this_field_p => this_field_p%next
3665 #include "field_manager_r4.fh"
3666 #include "field_manager_r8.fh"
3668 end module field_manager_mod
integer function parse_integer(text, label, parse_ival)
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.
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...
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.
subroutine, private find_base(name, path, base)
A subroutine that splits a listname into a path and a base.
integer function fm_new_value_integer(name, new_ival, create, index, append)
Assigns a given value to a given field.
integer, parameter, public fm_string_len
The length of a character string representing character values for the field.
integer function fm_new_value_logical(name, new_lval, create, index, append)
Assigns a given value to a given field.
logical function set_list_stuff()
If the pointer matches to the right list, extract the field information. Used in fm_loop_over_list.
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.
subroutine strip_front_blanks(name)
A routine to strip whitespace from the start of character strings.
integer, parameter, public model_land
Land model.
function parse_strings(text, label, values)
subroutine concat_strings(str1, str2)
private function: appends str2 to the end of str1, with length check
integer function find_field_index_new(field_name)
integer function, public fm_get_length(name)
A function to return how many elements are contained within the named list or entry.
logical function fm_get_value_integer(name, get_ival, index)
character(len=8) function, public fm_get_type(name)
A function to return the type of the named field.
subroutine, public fm_reset_loop
Resets the loop variable. For use in conjunction with fm_loop_over_list.
logical function, public fm_exists(name)
A function to test whether a named field exists.
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.
subroutine read_field_table_yaml(nfields, table_name)
Routine to read and parse the field table yaml.
integer function, public fm_new_list(name, create, keep)
A function to create a new list.
type(field_mgr_type), dimension(:), allocatable, private fields
fields of field_mgr_type
subroutine, public get_field_methods(n, methods)
A routine to obtain all the methods associated with a field.
character(len=fms_path_len) function, public fm_get_current_list()
A function to return the full path of the current list.
subroutine, private find_head(name, head, rest)
Find the first list for a name by splitting the name into a head and the rest.
integer function, public fm_get_index(name)
A function to return the index of a named field.
subroutine, public field_manager_end
Destructor for field manager.
integer function find_field_index_old(model, field_name)
Function to return the index of the field.
subroutine new_name_yaml(list_name, method_name_in, val_name_in)
Subroutine to add new values to list parameters.
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 field_manager_init(nfields, table_name)
Routine to initialize the field manager.
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, parameter, public model_coupler
Ice model.
subroutine, private initialize_module_variables
A function to initialize the values of the pointers. This will remove all fields and reset the field ...
integer, parameter, public fm_field_name_len
The length of a character string representing the field name.
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.
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...
subroutine, public get_field_method(n, m, method)
A routine to get a specified method.
subroutine, public get_field_info(n, fld_type, fld_name, model, num_methods)
This routine allows access to field information given an index.
logical function fm_get_value_logical(name, get_lval, index)
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 read_field_table_legacy(nfields, table_name)
Routine to read and parse the field table yaml.
logical function, public fm_modify_name(oldname, newname)
This function allows a user to rename a field without modifying the contents of the field.
logical function, public fm_dump_list(name, recursive, unit)
A function to list properties associated with a field.
logical recursive function, private dump_list(list_p, recursive, depth, out_unit)
This is a function that lists the parameters of a field.
integer, parameter, public model_ocean
Ocean model.
subroutine, public fm_return_root
Return the root list to the value at initialization.
integer, parameter, public no_field
The value returned if a field is not defined.
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...
function parse_integers(text, label, values)
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...
integer, parameter, public model_ice
Ice model.
integer function fm_new_value_string(name, new_sval, create, index, append)
Assigns a given value to a given field.
logical function, public fm_change_root(name)
Change the root list.
subroutine new_name(list_name, method_name_in, val_name_in)
Subroutine to add new values to list parameters.
integer function parse_string(text, label, parse_sval)
integer, parameter, public model_atmos
Atmospheric model.
integer, parameter, public num_models
Number of models (ATMOS, OCEAN, LAND, ICE, COUPLER).
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.
logical function, public fm_find_methods(list_name, methods, control)
This function retrieves all the methods associated with a field.
logical function fm_loop_over_list_old(list, name, field_type, index)
Iterates through the given list.
logical function fm_get_value_string(name, get_sval, index)
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.
integer function, public check_nml_error(IOSTAT, NML_NAME)
Checks the iostat argument that is returned after reading a namelist and determines if the error code...
subroutine, public write_version_number(version, tag, unit)
Prints to the log file (or a specified unit) the version id string and tag name.
integer function stdout()
This function returns the current standard fortran unit numbers for output.
integer function stdlog()
This function returns the current standard fortran unit numbers for log messages. Log messages,...
integer function mpp_pe()
Returns processor ID.