diff --git a/diag_manager/fms_diag_yaml.F90 b/diag_manager/fms_diag_yaml.F90
index 9a423697e0..6e184bfc58 100644
--- a/diag_manager/fms_diag_yaml.F90
+++ b/diag_manager/fms_diag_yaml.F90
@@ -32,6 +32,7 @@ module fms_diag_yaml_mod
#ifdef use_yaml
use fms_diag_yaml_object_mod, only: diagYamlFiles_type, diagYamlFilesVar_type, diag_yaml_files_obj_init, &
NUM_SUB_REGION_ARRAY
+use diag_data_mod, only: DIAG_NULL
use yaml_parser_mod
use mpp_mod
@@ -40,6 +41,7 @@ module fms_diag_yaml_mod
private
public :: diag_yaml_object_init, diag_yaml_object_end
+public :: diagYamlObject_type, get_diag_yaml_obj, get_title, get_basedate, get_diag_files, get_diag_fields
!> @}
integer, parameter :: basedate_size = 6
@@ -54,6 +56,8 @@ module fms_diag_yaml_mod
contains
procedure :: get_title !< Returns the title
procedure :: get_basedate !< Returns the basedate array
+ procedure :: get_diag_files !< Returns the diag_files array
+ procedure :: get_diag_fields !< Returns the diag_field array
end type diagYamlObject_type
type (diagYamlObject_type) :: diag_yaml !< Obj containing the contents of the diag_table.yaml
@@ -62,9 +66,19 @@ module fms_diag_yaml_mod
!> @{
contains
+!> @brief gets the diag_yaml module variable
+!! @return a copy of the diag_yaml module variable
+function get_diag_yaml_obj() &
+result(res)
+ type (diagYamlObject_type) :: res
+
+ res = diag_yaml
+end function get_diag_yaml_obj
+
!> @brief get the basedate of a diag_yaml type
!! @return the basedate as an integer array
-pure function get_basedate (diag_yaml) result (diag_basedate)
+pure function get_basedate (diag_yaml) &
+result (diag_basedate)
class (diagYamlObject_type), intent(in) :: diag_yaml !< The diag_yaml
integer, dimension (basedate_size) :: diag_basedate !< Basedate array result to return
@@ -73,13 +87,34 @@ end function get_basedate
!> @brief get the title of a diag_yaml type
!! @return the title of the diag table as an allocated string
-pure function get_title (diag_yaml) result (diag_title)
+pure function get_title (diag_yaml) &
+ result (diag_title)
class (diagYamlObject_type), intent(in) :: diag_yaml !< The diag_yaml
character(len=:),allocatable :: diag_title !< Basedate array result to return
diag_title = diag_yaml%diag_title
end function get_title
+!> @brief get the diag_files of a diag_yaml type
+!! @return the diag_files
+pure function get_diag_files(diag_yaml) &
+result(diag_files)
+ class (diagYamlObject_type), intent(in) :: diag_yaml !< The diag_yaml
+ type(diagYamlFiles_type), allocatable, dimension (:) :: diag_files!< History file info
+
+ diag_files = diag_yaml%diag_files
+end function get_diag_files
+
+!> @brief get the diag_fields of a diag_yaml type
+!! @return the diag_fields
+pure function get_diag_fields(diag_yaml) &
+result(diag_fields)
+ class (diagYamlObject_type), intent(in) :: diag_yaml !< The diag_yaml
+ type(diagYamlFilesVar_type), allocatable, dimension (:) :: diag_fields !< Diag fields info
+
+ diag_fields = diag_yaml%diag_fields
+end function get_diag_fields
+
!> @brief Uses the yaml_parser_mod to read in the diag_table and fill in the
!! diag_yaml object
subroutine diag_yaml_object_init
@@ -114,9 +149,16 @@ subroutine diag_yaml_object_init
nvars = get_num_blocks(diag_yaml_id, "varlist", parent_block_id=diag_file_ids(i))
allocate(var_ids(nvars))
call get_block_ids(diag_yaml_id, "varlist", var_ids, parent_block_id=diag_file_ids(i))
+ allocate(diag_yaml%diag_files(i)%file_varlist(nvars))
nvars_loop: do j = 1, nvars
var_count = var_count + 1
+ !> Save the filename in the diag_field type
+ diag_yaml%diag_fields(var_count)%var_fname = diag_yaml%diag_files(i)%file_fname
+
call fill_in_diag_fields(diag_yaml_id, var_ids(j), diag_yaml%diag_fields(var_count))
+
+ !> Save the variable name in the diag_file type
+ diag_yaml%diag_files(i)%file_varlist(j) = diag_yaml%diag_fields(var_count)%var_varname
enddo nvars_loop
deallocate(var_ids)
enddo nfiles_loop
@@ -129,6 +171,7 @@ subroutine diag_yaml_object_end()
integer :: i !< For do loops
do i = 1, size(diag_yaml%diag_files, 1)
+ if(allocated(diag_yaml%diag_files(i)%file_varlist)) deallocate(diag_yaml%diag_files(i)%file_varlist)
if(allocated(diag_yaml%diag_files(i)%file_global_meta)) deallocate(diag_yaml%diag_files(i)%file_global_meta)
if(allocated(diag_yaml%diag_files(i)%file_sub_region%lat_lon_sub_region)) &
deallocate(diag_yaml%diag_files(i)%file_sub_region%lat_lon_sub_region)
@@ -162,18 +205,27 @@ subroutine fill_in_diag_files(diag_yaml_id, diag_file_id, fileobj)
call diag_get_value_from_key(diag_yaml_id, diag_file_id, "file_name", fileobj%file_fname)
call diag_get_value_from_key(diag_yaml_id, diag_file_id, "freq_units", fileobj%file_frequnit)
call get_value_from_key(diag_yaml_id, diag_file_id, "freq", fileobj%file_freq)
+ call check_file_freq(fileobj)
+
call diag_get_value_from_key(diag_yaml_id, diag_file_id, "unlimdim", fileobj%file_unlimdim)
call diag_get_value_from_key(diag_yaml_id, diag_file_id, "time_units", fileobj%file_timeunit)
+ call check_file_time_units(fileobj)
+
call diag_get_value_from_key(diag_yaml_id, diag_file_id, "write_file", fileobj%string_file_write, is_optional=.true.)
if (fileobj%string_file_write .eq. "false") fileobj%file_write = .false.
call diag_get_value_from_key(diag_yaml_id, diag_file_id, "realm", fileobj%file_realm, is_optional=.true.)
+ call check_file_realm(fileobj)
+
call get_value_from_key(diag_yaml_id, diag_file_id, "new_file_freq", fileobj%file_new_file_freq, is_optional=.true.)
call diag_get_value_from_key(diag_yaml_id, diag_file_id, "new_file_freq_units", fileobj%file_new_file_freq_units, &
is_optional=.true.)
+ call check_new_file_freq(fileobj)
+
call diag_get_value_from_key(diag_yaml_id, diag_file_id, "start_time", fileobj%file_start_time, is_optional=.true.)
call get_value_from_key(diag_yaml_id, diag_file_id, "file_duration", fileobj%file_duration, is_optional=.true.)
call diag_get_value_from_key(diag_yaml_id, diag_file_id, "file_duration_units", fileobj%file_duration_units, &
- is_optional=.true.)
+ is_optional=.true.)
+ call check_file_duration(fileobj)
nsubregion = 0
nsubregion = get_num_blocks(diag_yaml_id, "sub_region", parent_block_id=diag_file_id)
@@ -182,13 +234,19 @@ subroutine fill_in_diag_files(diag_yaml_id, diag_file_id, fileobj)
call diag_get_value_from_key(diag_yaml_id, sub_region_id(1), "grid_type", fileobj%file_sub_region%grid_type)
if (trim(fileobj%file_sub_region%grid_type) .eq. "latlon") then
allocate(fileobj%file_sub_region%lat_lon_sub_region(8))
+ fileobj%file_sub_region%lat_lon_sub_region = DIAG_NULL
call get_sub_region(diag_yaml_id, sub_region_id(1), fileobj%file_sub_region%lat_lon_sub_region)
elseif (trim(fileobj%file_sub_region%grid_type) .eq. "index") then
allocate(fileobj%file_sub_region%index_sub_region(8))
+ fileobj%file_sub_region%index_sub_region = DIAG_NULL
call get_sub_region(diag_yaml_id, sub_region_id(1), fileobj%file_sub_region%index_sub_region)
call get_value_from_key(diag_yaml_id, sub_region_id(1), "tile", fileobj%file_sub_region%tile, is_optional=.true.)
if (fileobj%file_sub_region%tile .eq. 0) call mpp_error(FATAL, "The tile number is required when defining a "//&
"subregion. Check your subregion entry for "//trim(fileobj%file_fname))
+ else
+ call mpp_error(FATAL, trim(fileobj%file_sub_region%grid_type)//" is not a valid region type. &
+ &The acceptable values are latlon and index. &
+ &Check your entry for file:"//trim(fileobj%file_fname))
endif
elseif (nsubregion .ne. 0) then
call mpp_error(FATAL, "diag_yaml_object_init: file "//trim(fileobj%file_fname)//" has multiple region blocks")
@@ -219,8 +277,7 @@ subroutine fill_in_diag_files(diag_yaml_id, diag_file_id, fileobj)
subroutine fill_in_diag_fields(diag_file_id, var_id, field)
integer, intent(in) :: diag_file_id !< Id of the file block in the yaml file
integer, intent(in) :: var_id !< Id of the variable block in the yaml file
- type(diagYamlFilesVar_type), intent(out) :: field !< diagYamlFilesVar_type obj to read the contents into
-
+ type(diagYamlFilesVar_type), intent(inout) :: field !< diagYamlFilesVar_type obj to read the contents into
integer :: natt !< Number of attributes in variable
integer :: var_att_id(1) !< Id of the variable attribute block
@@ -232,8 +289,12 @@ subroutine fill_in_diag_fields(diag_file_id, var_id, field)
field%var_write = .true.
call diag_get_value_from_key(diag_file_id, var_id, "var_name", field%var_varname)
call diag_get_value_from_key(diag_file_id, var_id, "reduction", field%var_reduction)
+ call check_field_reduction(field)
+
call diag_get_value_from_key(diag_file_id, var_id, "module", field%var_module)
call diag_get_value_from_key(diag_file_id, var_id, "kind", field%var_skind)
+ call check_field_kind(field)
+
call diag_get_value_from_key(diag_file_id, var_id, "write_var", field%string_var_write, is_optional=.true.)
if (trim(field%string_var_write) .eq. "false") field%var_write = .false.
@@ -313,6 +374,139 @@ function get_total_num_vars(diag_yaml_id, diag_file_ids) &
end do
end function
+!> @brief This checks if the file frequency in a diag file is valid and crashes if it isn't
+subroutine check_file_freq(fileobj)
+ type(diagYamlFiles_type), intent(inout) :: fileobj !< diagYamlFiles_type obj to check
+
+ if (fileobj%file_freq < 1 ) &
+ call mpp_error(FATAL, "freq must be greater than 0. &
+ &Check you entry for"//trim(fileobj%file_fname))
+ if(.not. is_valid_time_units(fileobj%file_frequnit)) &
+ call mpp_error(FATAL, trim(fileobj%file_frequnit)//" is not a valid file_frequnit. &
+ &The acceptable values are seconds, minuts, hours, days, months, years. &
+ &Check your entry for file:"//trim(fileobj%file_fname))
+end subroutine check_file_freq
+
+!> @brief This checks if the time unit in a diag file is valid and crashes if it isn't
+subroutine check_file_time_units (fileobj)
+ type(diagYamlFiles_type), intent(inout) :: fileobj !< diagYamlFiles_type obj to checK
+
+ if(.not. is_valid_time_units(fileobj%file_timeunit)) &
+ call mpp_error(FATAL, trim(fileobj%file_timeunit)//" is not a valid time_unit. &
+ &The acceptable values are seconds, minuts, hours, days, months, years. &
+ &Check your entry for file:"//trim(fileobj%file_fname))
+end subroutine check_file_time_units
+
+!> @brief This checks if the realm in a diag file is valid and crashes if it isn't
+subroutine check_file_realm(fileobj)
+ type(diagYamlFiles_type), intent(inout) :: fileobj !< diagYamlFiles_type obj to checK
+
+ select case (TRIM(fileobj%file_realm))
+ case ("ATM", "OCN", "LND", "ICE", "")
+ case default
+ call mpp_error(FATAL, trim(fileobj%file_realm)//" is an invalid realm! &
+ &The acceptable values are ATM, OCN, LND, ICE. &
+ &Check your entry for file:"//trim(fileobj%file_fname))
+ end select
+
+end subroutine check_file_realm
+
+!> @brief This checks if the new file frequency in a diag file is valid and crashes if it isn't
+subroutine check_new_file_freq(fileobj)
+ type(diagYamlFiles_type), intent(inout) :: fileobj !< diagYamlFiles_type obj to check
+
+ if (fileobj%file_new_file_freq > 0) then
+ if (trim(fileobj%file_new_file_freq_units) .eq. "") &
+ call mpp_error(FATAL, "new_file_freq_units is required if using new_file_freq. &
+ &Check your entry for file:"//trim(fileobj%file_fname))
+
+ if (.not. is_valid_time_units(fileobj%file_new_file_freq_units)) &
+ call mpp_error(FATAL, trim(fileobj%file_new_file_freq_units)//" is not a valid new_file_freq_units. &
+ &The acceptable values are seconds, minuts, hours, days, months, years. &
+ &Check your entry for file:"//trim(fileobj%file_fname))
+ endif
+end subroutine check_new_file_freq
+
+!> @brief This checks if the file duration in a diag file is valid and crashes if it isn't
+subroutine check_file_duration(fileobj)
+ type(diagYamlFiles_type), intent(inout) :: fileobj !< diagYamlFiles_type obj to check
+
+ if (fileobj%file_duration > 0) then
+ if(trim(fileobj%file_duration_units) .eq. "") &
+ call mpp_error(FATAL, "file_duration_units is required if using file_duration. &
+ &Check your entry for file:"//trim(fileobj%file_fname))
+
+ if (.not. is_valid_time_units(fileobj%file_duration_units)) &
+ call mpp_error(FATAL, trim(fileobj%file_duration_units)//" is not a valid file_duration_units. &
+ &The acceptable values are seconds, minuts, hours, days, months, years. &
+ &Check your entry for file:"//trim(fileobj%file_duration_units))
+ endif
+end subroutine check_file_duration
+
+!> @brief This checks if the kind of a diag field is valid and crashes if it isn't
+subroutine check_field_kind(field)
+ type(diagYamlFilesVar_type), intent(in) :: field !< diagYamlFilesVar_type obj to read the contents into
+
+ select case (TRIM(field%var_skind))
+ case ("double", "float")
+ case default
+ call mpp_error(FATAL, trim(field%var_skind)//" is an invalid kind! &
+ &The acceptable values are double and float. &
+ &Check your entry for file:"//trim(field%var_varname)//" in file "//trim(field%var_fname))
+ end select
+
+end subroutine check_field_kind
+
+!> @brief This checks if the reduction of a diag field is valid and crashes if it isn't
+subroutine check_field_reduction(field)
+ type(diagYamlFilesVar_type), intent(in) :: field !< diagYamlFilesVar_type obj to read the contents into
+
+ integer :: n_diurnal !< number of diurnal samples
+ integer :: pow_value !< The power value
+ integer :: ioerror !< io error status after reading in the diurnal samples
+
+ n_diurnal = 0
+ pow_value = 0
+ ioerror = 0
+ if (field%var_reduction(1:7) .eq. "diurnal") then
+ READ (UNIT=field%var_reduction(8:LEN_TRIM(field%var_reduction)), FMT=*, IOSTAT=ioerror) n_diurnal
+ if (ioerror .ne. 0) &
+ call mpp_error(FATAL, "Error getting the number of diurnal samples from "//trim(field%var_reduction))
+ if (n_diurnal .le. 0) &
+ call mpp_error(FATAL, "Diurnal samples should be greater than 0. &
+ & Check your entry for file:"//trim(field%var_varname)//" in file "//trim(field%var_fname))
+ elseif (field%var_reduction(1:3) .eq. "pow") then
+ READ (UNIT=field%var_reduction(4:LEN_TRIM(field%var_reduction)), FMT=*, IOSTAT=ioerror) pow_value
+ if (ioerror .ne. 0) &
+ call mpp_error(FATAL, "Error getting the power value from "//trim(field%var_reduction))
+ if (pow_value .le. 0) &
+ call mpp_error(FATAL, "The power value should be greater than 0. &
+ & Check your entry for file:"//trim(field%var_varname)//" in file "//trim(field%var_fname))
+ else
+ select case (TRIM(field%var_reduction))
+ case ("none", "average", "min", "max", "rms")
+ case default
+ call mpp_error(FATAL, trim(field%var_reduction)//" is an invalid reduction method! &
+ &The acceptable values are none, average, pow##, diurnal##, min, max, and rms. &
+ &Check your entry for file:"//trim(field%var_varname)//" in file "//trim(field%var_fname))
+ end select
+ endif
+end subroutine check_field_reduction
+
+!> @brief This checks if a time unit is valid
+!! @return Flag indicating if the time units are valid
+pure function is_valid_time_units(time_units) &
+result(is_valid)
+ character(len=*), intent(in) :: time_units
+ logical :: is_valid
+
+ select case (TRIM(time_units))
+ case ("seconds", "minutes", "hours", "days", "months", "years")
+ is_valid = .true.
+ case default
+ is_valid = .false.
+ end select
+end function is_valid_time_units
#endif
end module fms_diag_yaml_mod
!> @}
diff --git a/diag_manager/fms_diag_yaml_object.F90 b/diag_manager/fms_diag_yaml_object.F90
index e406885084..7cc6db38f3 100644
--- a/diag_manager/fms_diag_yaml_object.F90
+++ b/diag_manager/fms_diag_yaml_object.F90
@@ -99,6 +99,7 @@ module fms_diag_yaml_object_mod
procedure :: get_file_duration_units
procedure :: get_file_varlist
procedure :: get_file_global_meta
+ procedure :: is_global_meta
end type diagYamlFiles_type
@@ -129,7 +130,7 @@ module fms_diag_yaml_object_mod
procedure :: get_var_units
procedure :: get_var_write
procedure :: get_var_attributes
-
+ procedure :: is_var_attributes
end type diagYamlFilesVar_type
contains
@@ -239,6 +240,15 @@ pure function get_file_global_meta (diag_files_obj) result (res)
character (:), allocatable :: res(:,:) !< What is returned
res = diag_files_obj%file_global_meta
end function get_file_global_meta
+!> @brief Inquiry for whether file_global_meta is allocated
+!! @return Flag indicating if file_global_meta is allocated
+function is_global_meta(diag_files_obj) result(res)
+ class (diagYamlFiles_type), intent(in) :: diag_files_obj !< The object being inquiried
+ logical :: res
+ res = .false.
+ if (allocated(diag_files_obj%file_global_meta)) &
+ res = .true.
+end function
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@@ -316,6 +326,15 @@ pure function get_var_attributes(diag_var_obj) result (res)
character (len=MAX_STR_LEN), allocatable :: res (:,:) !< What is returned
res = diag_var_obj%var_attributes
end function get_var_attributes
+!> @brief Inquiry for whether var_attributes is allocated
+!! @return Flag indicating if var_attributes is allocated
+function is_var_attributes(diag_var_obj) result(res)
+ class (diagYamlFilesVar_type), intent(in) :: diag_var_obj !< The object being inquiried
+ logical :: res
+ res = .false.
+ if (allocated(diag_var_obj%var_attributes)) &
+ res = .true.
+end function is_var_attributes
!> @brief Initializes the non string values of a diagYamlFiles_type to its
!! default values
@@ -325,8 +344,7 @@ subroutine diag_yaml_files_obj_init(obj)
obj%file_freq = 0
obj%file_write = .true.
obj%file_duration = 0
- obj%file_sub_region%lat_lon_sub_region = -999.
- obj%file_sub_region%index_sub_region = -999
+ obj%file_new_file_freq = 0
obj%file_sub_region%tile = 0
end subroutine diag_yaml_files_obj_init
diff --git a/test_fms/diag_manager/Makefile.am b/test_fms/diag_manager/Makefile.am
index 05fd840297..1c55871f00 100644
--- a/test_fms/diag_manager/Makefile.am
+++ b/test_fms/diag_manager/Makefile.am
@@ -29,11 +29,12 @@ LDADD = $(top_builddir)/libFMS/libFMS.la
# Build this test program.
check_PROGRAMS = test_diag_manager test_diag_manager_time test_diag_object_container \
- test_diag_dlinked_list
+ test_diag_dlinked_list test_diag_yaml
# This is the source code for the test.
test_diag_manager_SOURCES = test_diag_manager.F90
test_diag_manager_time_SOURCES = test_diag_manager_time.F90
+test_diag_yaml_SOURCES = test_diag_yaml.F90
test_diag_object_container_SOURCES = test_diag_object_container.F90
test_diag_dlinked_list_SOURCES = test_diag_dlinked_list.F90
@@ -41,7 +42,14 @@ test_diag_dlinked_list_SOURCES = test_diag_dlinked_list.F90
TESTS = test_diag_manager2.sh
# Copy over other needed files to the srcdir
-EXTRA_DIST = input.nml_base diagTables test_diag_manager2.sh
+EXTRA_DIST = input.nml_base diagTables test_diag_manager2.sh check_crashes.sh
-# Clean up
-CLEANFILES = input.nml *.nc *.out diag_table
+if SKIP_PARSER_TESTS
+skipflag="skip"
+else
+skipflag=""
+endif
+
+TESTS_ENVIRONMENT = parser_skip=${skipflag}
+
+CLEANFILES = *.yaml input.nml *.nc *.out diag_table
diff --git a/test_fms/diag_manager/check_crashes.sh b/test_fms/diag_manager/check_crashes.sh
new file mode 100755
index 0000000000..da68fdf81f
--- /dev/null
+++ b/test_fms/diag_manager/check_crashes.sh
@@ -0,0 +1,163 @@
+#!/bin/sh
+
+#***********************************************************************
+#* GNU Lesser General Public License
+#*
+#* This file is part of the GFDL Flexible Modeling System (FMS).
+#*
+#* FMS is free software: you can redistribute it and/or modify it under
+#* the terms of the GNU Lesser General Public License as published by
+#* the Free Software Foundation, either version 3 of the License, or (at
+#* your option) any later version.
+#*
+#* FMS is distributed in the hope that it will be useful, but WITHOUT
+#* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+#* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+#* for more details.
+#*
+#* You should have received a copy of the GNU Lesser General Public
+#* License along with FMS. If not, see .
+#***********************************************************************
+
+# This is part of the GFDL FMS package. This is a shell script to
+# execute tests in the test_fms/data_override directory.
+
+# Set common test settings.
+. ../test_common.sh
+
+printf "&check_crashes_nml \n checking_crashes = .true. \n/" | cat > input.nml
+
+echo "Test 27: Missing tile when using the 'index' grid type"
+touch input.nml
+sed '/tile/d' $top_srcdir/test_fms/diag_manager/diagTables/diag_table_yaml_26 > diag_table.yaml
+run_test test_diag_yaml 1 $parser_skip && echo "It worked?"
+if [ $? -eq 0 ]; then
+ echo "Test should have failed since 'tile' was missing and the 'index' grid type was used"
+ exit 3
+fi
+
+echo "Test 28: Missing new_file_freq_units when using new_file_freq_units"
+touch input.nml
+sed '/new_file_freq_units/d' $top_srcdir/test_fms/diag_manager/diagTables/diag_table_yaml_26 > diag_table.yaml
+run_test test_diag_yaml 1 $parser_skip && echo "It worked?"
+if [ $? -eq 0 ]; then
+ echo "Test should have failed since 'new_file_freq_units' was missing and new_file_freq was used"
+ exit 3
+fi
+
+echo "Test 29: new_file_freq_units is not valid"
+touch input.nml
+sed 's/new_file_freq_units: hours/new_file_freq_units: mullions/g' $top_srcdir/test_fms/diag_manager/diagTables/diag_table_yaml_26 > diag_table.yaml
+run_test test_diag_yaml 1 $parser_skip && echo "It worked?"
+if [ $? -eq 0 ]; then
+ echo "Test should have failed since 'new_file_freq_units' is not valid"
+ exit 3
+fi
+
+echo "Test 30: Missing file_duration_units when using file_duration"
+touch input.nml
+sed '/file_duration_units/d' $top_srcdir/test_fms/diag_manager/diagTables/diag_table_yaml_26 > diag_table.yaml
+run_test test_diag_yaml 1 $parser_skip && echo "It worked?"
+if [ $? -eq 0 ]; then
+ echo "Test should have failed since 'file_duration_units' was missing and file_duration was used"
+ exit 3
+fi
+
+echo "Test 31: file_duration_units is not valid"
+touch input.nml
+sed 's/file_duration_units: hours/file_duration_units: mullions/g' $top_srcdir/test_fms/diag_manager/diagTables/diag_table_yaml_26 > diag_table.yaml
+run_test test_diag_yaml 1 $parser_skip && echo "It worked?"
+if [ $? -eq 0 ]; then
+ echo "Test should have failed since 'file_duration_units' is not valid"
+ exit 3
+fi
+
+echo "Test 32: freq units is not valid"
+touch input.nml
+sed 's/freq_units: hours/freq_units: mullions/g' $top_srcdir/test_fms/diag_manager/diagTables/diag_table_yaml_26 > diag_table.yaml
+run_test test_diag_yaml 1 $parser_skip && echo "It worked?"
+if [ $? -eq 0 ]; then
+ echo "Test should have failed since the freq units is not valid"
+ exit 3
+fi
+
+echo "Test 33: freq is less than 0"
+touch input.nml
+sed 's/freq: 6/freq: -666/g' $top_srcdir/test_fms/diag_manager/diagTables/diag_table_yaml_26 > diag_table.yaml
+run_test test_diag_yaml 1 $parser_skip && echo "It worked?"
+if [ $? -eq 0 ]; then
+ echo "Test should have failed since freq is not valid"
+ exit 3
+fi
+
+echo "Test 34: realm is not valid"
+touch input.nml
+sed 's/realm: ATM/realm: mullions/g' $top_srcdir/test_fms/diag_manager/diagTables/diag_table_yaml_26 > diag_table.yaml
+run_test test_diag_yaml 1 $parser_skip && echo "It worked?"
+if [ $? -eq 0 ]; then
+ echo "Test should have failed since realm is not valid"
+ exit 3
+fi
+
+echo "Test 35: kind is not valid"
+touch input.nml
+sed 's/kind: float/kind: mullions/g' $top_srcdir/test_fms/diag_manager/diagTables/diag_table_yaml_26 > diag_table.yaml
+run_test test_diag_yaml 1 $parser_skip && echo "It worked?"
+if [ $? -eq 0 ]; then
+ echo "Test should have failed since the kind is not valid"
+ exit 3
+fi
+
+echo "Test 36: reduction is not valid"
+touch input.nml
+sed 's/reduction: average/reduction: mullions/g' $top_srcdir/test_fms/diag_manager/diagTables/diag_table_yaml_26 > diag_table.yaml
+run_test test_diag_yaml 1 $parser_skip && echo "It worked?"
+if [ $? -eq 0 ]; then
+ echo "Test should have failed since the reduction method is not valid"
+ exit 3
+fi
+
+echo "Test 37: diurnal samples is less than 0"
+touch input.nml
+sed 's/reduction: average/reduction: diurnal0/g' $top_srcdir/test_fms/diag_manager/diagTables/diag_table_yaml_26 > diag_table.yaml
+run_test test_diag_yaml 1 $parser_skip && echo "It worked?"
+if [ $? -eq 0 ]; then
+ echo "Test should have failed since the number of diurnal samples is less than 0"
+ exit 3
+fi
+
+echo "Test 38: diurnal samples is not an integer"
+touch input.nml
+sed 's/reduction: average/reduction: diurnal99r/g' $top_srcdir/test_fms/diag_manager/diagTables/diag_table_yaml_26 > diag_table.yaml
+run_test test_diag_yaml 1 $parser_skip && echo "It worked?"
+if [ $? -eq 0 ]; then
+ echo "Test should have failed since the number of diurnal samples is not valid"
+ exit 3
+fi
+
+echo "Test 39: power value is less than 0"
+touch input.nml
+sed 's/reduction: average/reduction: pow0/g' $top_srcdir/test_fms/diag_manager/diagTables/diag_table_yaml_26 > diag_table.yaml
+run_test test_diag_yaml 1 $parser_skip && echo "It worked?"
+if [ $? -eq 0 ]; then
+ echo "Test should have failed since the power value is less than"
+ exit 3
+fi
+
+echo "Test 40: power value is not an integer"
+touch input.nml
+sed 's/reduction: average/reduction: pow99r/g' $top_srcdir/test_fms/diag_manager/diagTables/diag_table_yaml_26 > diag_table.yaml
+run_test test_diag_yaml 1 $parser_skip && echo "It worked?"
+if [ $? -eq 0 ]; then
+ echo "Test should have failed since the power value is not valid"
+ exit 3
+fi
+
+echo "Test 41: the sub_region grid_type is not valid"
+touch input.nml
+sed 's/grid_type: latlon/grid_type: ice_cream/g' $top_srcdir/test_fms/diag_manager/diagTables/diag_table_yaml_26 > diag_table.yaml
+run_test test_diag_yaml 1 $parser_skip && echo "It worked?"
+if [ $? -eq 0 ]; then
+ echo "Test should have failed since the sub_region grid_type"
+ exit 3
+fi
diff --git a/test_fms/diag_manager/diagTables/diag_table_yaml_26 b/test_fms/diag_manager/diagTables/diag_table_yaml_26
new file mode 100644
index 0000000000..d82038bd6a
--- /dev/null
+++ b/test_fms/diag_manager/diagTables/diag_table_yaml_26
@@ -0,0 +1,61 @@
+title: test_diag_manager
+base_date: 2 1 1 0 0 0
+diag_files:
+- file_name: wild_card_name%4yr%2mo%2dy%2hr
+ freq: 6
+ freq_units: hours
+ time_units: hours
+ unlimdim: time
+ new_file_freq: 6
+ new_file_freq_units: hours
+ start_time: 2 1 1 0 0 0
+ file_duration: 12
+ file_duration_units: hours
+ write_file: false
+ realm: ATM
+ varlist:
+ - module: test_diag_manager_mod
+ var_name: sst
+ output_name: sst
+ reduction: average
+ kind: float
+ write_var: false
+ global_meta:
+ - is_a_file: true
+- file_name: normal
+ freq: 24
+ freq_units: days
+ time_units: hours
+ unlimdim: records
+ varlist:
+ - module: test_diag_manager_mod
+ var_name: sst
+ output_name: sst
+ reduction: average
+ kind: float
+ write_var: true
+ attributes:
+ - do_sst: .true.
+ sub_region:
+ - grid_type: latlon
+ dim1_begin: 64.0
+ dim3_end: 20.0
+- file_name: normal2
+ freq: 24
+ freq_units: days
+ time_units: hours
+ unlimdim: records
+ write_file: true
+ varlist:
+ - module: test_diag_manager_mod
+ var_name: sstt
+ output_name: sstt
+ reduction: average
+ kind: float
+ long_name: S S T
+ sub_region:
+ - grid_type: index
+ tile: 1
+ dim2_begin: 10
+ dim2_end: 20
+ dim1_begin: 10
diff --git a/test_fms/diag_manager/test_diag_manager2.sh b/test_fms/diag_manager/test_diag_manager2.sh
index d424ec55d0..355912924a 100755
--- a/test_fms/diag_manager/test_diag_manager2.sh
+++ b/test_fms/diag_manager/test_diag_manager2.sh
@@ -102,6 +102,13 @@ touch input.nml
cp $top_srcdir/test_fms/diag_manager/diagTables/diag_table_25 diag_table
run_test test_diag_manager_time 1
+echo "Test 26: diag_yaml_init"
+touch input.nml
+cp $top_srcdir/test_fms/diag_manager/diagTables/diag_table_yaml_26 diag_table.yaml
+run_test test_diag_yaml 1 $parser_skip
+
+. $top_srcdir/test_fms/diag_manager/check_crashes.sh
+
echo "Test container"
rm -f input.nml diag_table
touch input.nml
diff --git a/test_fms/diag_manager/test_diag_yaml.F90 b/test_fms/diag_manager/test_diag_yaml.F90
new file mode 100644
index 0000000000..d939de7b91
--- /dev/null
+++ b/test_fms/diag_manager/test_diag_yaml.F90
@@ -0,0 +1,311 @@
+!***********************************************************************
+!* GNU Lesser General Public License
+!*
+!* This file is part of the GFDL Flexible Modeling System (FMS).
+!*
+!* FMS is free software: you can redistribute it and/or modify it under
+!* the terms of the GNU Lesser General Public License as published by
+!* the Free Software Foundation, either version 3 of the License, or (at
+!* your option) any later version.
+!*
+!* FMS is distributed in the hope that it will be useful, but WITHOUT
+!* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+!* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+!* for more details.
+!*
+!* You should have received a copy of the GNU Lesser General Public
+!* License along with FMS. If not, see .
+!***********************************************************************
+
+!> @brief This program tests the diag_yaml_object_init and diag_yaml_object_end subroutines
+!! in fms_diag_yaml_mod
+program test_diag_yaml
+
+#ifdef use_yaml
+use FMS_mod, only: fms_init, fms_end
+use fms_diag_yaml_mod
+use fms_diag_yaml_object_mod
+use mpp_mod
+use platform_mod
+
+implicit none
+
+!< @brief Interface used to compare two different values
+interface compare_result
+subroutine compare_result_0d(key_name, res, expected_res)
+ character(len=*), intent(in) :: key_name !< Name of the key to compare
+ class(*), intent(in) :: res !< Value obtained from reading the file
+ class(*), intent(in) :: expected_res !< Value expected
+end subroutine compare_result_0d
+
+subroutine compare_result_1d(key_name, res, expected_res)
+ character(len=*), intent(in) :: key_name !< Name of the key to compare
+ class(*), intent(in) :: res(:) !< Value obtained from reading the file
+ class(*), intent(in) :: expected_res(:) !< Value expected
+end subroutine compare_result_1d
+end interface compare_result
+
+type(diagYamlObject_type) :: my_yaml !< diagYamlObject obtained from diag_yaml_object_init
+type(diagYamlObject_type) :: ans !< expected diagYamlObject
+logical :: checking_crashes = .false.!< Flag indicating that you are checking crashes
+integer :: i !< For do loops
+integer :: io_status !< The status after reading the input.nml
+
+type(diagYamlFiles_type), allocatable, dimension (:) :: diag_files !< Files from the diag_yaml
+type(diagYamlFilesVar_type), allocatable, dimension(:) :: diag_fields !< Fields from the diag_yaml
+
+namelist / check_crashes_nml / checking_crashes
+
+call fms_init()
+
+read (input_nml_file, check_crashes_nml, iostat=io_status)
+if (io_status > 0) call mpp_error(FATAL,'=>check_crashes: Error reading input.nml')
+
+call diag_yaml_object_init
+
+my_yaml = get_diag_yaml_obj()
+
+if (.not. checking_crashes) then
+ call compare_result("base_date", my_yaml%get_basedate(), (/2, 1, 1, 0, 0 , 0 /))
+ call compare_result("title", my_yaml%get_title(), "test_diag_manager")
+
+ diag_files = my_yaml%get_diag_files()
+ call compare_result("nfiles", size(diag_files), 3)
+ call compare_diag_files(diag_files)
+
+ diag_fields = my_yaml%get_diag_fields()
+ call compare_result("nfields", size(diag_fields), 3)
+ call compare_diag_fields(diag_fields)
+
+endif
+deallocate(diag_files)
+deallocate(diag_fields)
+
+call diag_yaml_object_end
+
+call fms_end()
+
+contains
+
+!> @brief Compares a diagYamlFilesVar_type with the expected result and
+!! crashes if they don't match
+subroutine compare_diag_fields(res)
+ type(diagYamlFilesVar_type), intent(in) :: res(:) !< diag_field info read from yaml file
+ character (len=255), dimension(:, :), allocatable :: var_attributes !< Variable attributes
+
+ call compare_result("var_fname 1", res(1)%get_var_fname(), "wild_card_name%4yr%2mo%2dy%2hr")
+ call compare_result("var_fname 2", res(2)%get_var_fname(), "normal")
+ call compare_result("var_fname 3", res(3)%get_var_fname(), "normal2")
+
+ call compare_result("var_varname 1", res(1)%get_var_varname(), "sst")
+ call compare_result("var_varname 2", res(2)%get_var_varname(), "sst")
+ call compare_result("var_varname 3", res(3)%get_var_varname(), "sstt")
+
+ call compare_result("var_reduction 1", res(1)%get_var_reduction(), "average")
+ call compare_result("var_reduction 2", res(2)%get_var_reduction(), "average")
+ call compare_result("var_reduction 3", res(3)%get_var_reduction(), "average")
+
+ call compare_result("var_module 1", res(1)%get_var_module(), "test_diag_manager_mod")
+ call compare_result("var_module 2", res(2)%get_var_module(), "test_diag_manager_mod")
+ call compare_result("var_module 3", res(3)%get_var_module(), "test_diag_manager_mod")
+
+ call compare_result("var_skind 1", res(1)%get_var_skind(), "float")
+ call compare_result("var_skind 2", res(2)%get_var_skind(), "float")
+ call compare_result("var_skind 3", res(3)%get_var_skind(), "float")
+
+ call compare_result("var_write 1", res(1)%get_var_write(), .false.)
+ call compare_result("var_write 2", res(2)%get_var_write(), .true.)
+ call compare_result("var_write 3", res(3)%get_var_write(), .true.)
+
+ call compare_result("var_outname 1", res(1)%get_var_outname(), "sst")
+ call compare_result("var_outname 2", res(2)%get_var_outname(), "sst")
+ call compare_result("var_outname 3", res(3)%get_var_outname(), "sstt")
+
+ call compare_result("var_longname 1", res(1)%get_var_longname(), "")
+ call compare_result("var_longname 2", res(2)%get_var_longname(), "")
+ call compare_result("var_longname 3", res(3)%get_var_longname(), "S S T")
+
+ if (res(1)%is_var_attributes()) call mpp_error(FATAL, "The variable attributes for the first file was set?")
+
+ var_attributes = res(2)%get_var_attributes()
+ if (.not. allocated(var_attributes)) call mpp_error(FATAL, "The variable attributes for the second file was not set")
+ call compare_result("var attributes key", var_attributes(1,1), "do_sst")
+ call compare_result("var attributes value", var_attributes(1,2), ".true.")
+ deallocate(var_attributes)
+
+ if (res(3)%is_var_attributes()) call mpp_error(FATAL, "The variable attributes for the third file was set?")
+
+end subroutine
+
+!> @brief Compares a diagYamlFiles_type with the expected result and
+!! crashes if they don't match
+subroutine compare_diag_files(res)
+ type(diagYamlFiles_type), intent(in) :: res(:) !< diag_file info read from yaml file
+
+ character (len=255), dimension(:), allocatable :: varlist !< List of variables
+ character (len=255), dimension(:, :), allocatable :: global_meta !< List of global meta
+
+ call compare_result("file_fname 1", res(1)%get_file_fname(), "wild_card_name%4yr%2mo%2dy%2hr")
+ call compare_result("file_fname 2", res(2)%get_file_fname(), "normal")
+ call compare_result("file_fname 3", res(3)%get_file_fname(), "normal2")
+
+ call compare_result("file_freq 1", res(1)%get_file_freq(), 6)
+ call compare_result("file_freq 2", res(2)%get_file_freq(), 24)
+ call compare_result("file_freq 3", res(3)%get_file_freq(), 24)
+
+ call compare_result("file_frequnit 1", res(1)%get_file_frequnit(), "hours")
+ call compare_result("file_frequnit 2", res(2)%get_file_frequnit(), "days")
+ call compare_result("file_frequnit 3", res(3)%get_file_frequnit(), "days")
+
+ call compare_result("file_timeunit 1", res(1)%get_file_timeunit(), "hours")
+ call compare_result("file_timeunit 2", res(2)%get_file_timeunit(), "hours")
+ call compare_result("file_timeunit 3", res(3)%get_file_timeunit(), "hours")
+
+ call compare_result("file_unlimdim 1", res(1)%get_file_unlimdim(), "time")
+ call compare_result("file_unlimdim 2", res(2)%get_file_unlimdim(), "records")
+ call compare_result("file_unlimdim 3", res(3)%get_file_unlimdim(), "records")
+
+ call compare_result("file_realm 1", res(1)%get_file_realm(), "ATM")
+ call compare_result("file_realm 2", res(2)%get_file_realm(), "")
+ call compare_result("file_realm 3", res(3)%get_file_realm(), "")
+
+ call compare_result("file_write 1", res(1)%get_file_write(), .false.)
+ call compare_result("file_write 2", res(2)%get_file_write(), .true.)
+ call compare_result("file_write 3", res(3)%get_file_write(), .true.)
+
+ call compare_result("file_new_file_freq 1", res(1)%get_file_new_file_freq(), 6)
+ call compare_result("file_new_file_freq 2", res(2)%get_file_new_file_freq(), 0)
+ call compare_result("file_new_file_freq 3", res(3)%get_file_new_file_freq(), 0)
+
+ call compare_result("file_new_file_freq_units 1", res(1)%get_file_new_file_freq_units(), "hours")
+ call compare_result("file_new_file_freq_units 2", res(2)%get_file_new_file_freq_units(), "")
+ call compare_result("file_new_file_freq_units 3", res(3)%get_file_new_file_freq_units(), "")
+
+ call compare_result("file_duration 1", res(1)%get_file_duration(), 12)
+ call compare_result("file_duration 2", res(2)%get_file_duration(), 0)
+ call compare_result("file_duration 3", res(3)%get_file_duration(), 0)
+
+ call compare_result("file_duration_units 1", res(1)%get_file_duration_units(), "hours")
+ call compare_result("file_duration_units 2", res(2)%get_file_duration_units(), "")
+ call compare_result("file_duration_units 3", res(3)%get_file_duration_units(), "")
+
+ call compare_result("file_start_time 1", res(1)%get_file_start_time(), "2 1 1 0 0 0")
+ call compare_result("file_start_time 2", res(2)%get_file_start_time(), "")
+ call compare_result("file_start_time 3", res(3)%get_file_start_time(), "")
+
+ varlist = res(1)%get_file_varlist()
+ if (.not. allocated(varlist)) call mpp_error(FATAL, "The varlist for the first file was not set")
+ call compare_result("number_variables 1", size(varlist), 1)
+ call compare_result("varlist 1", varlist(1), "sst")
+ deallocate(varlist)
+
+ varlist = res(2)%get_file_varlist()
+ if (.not. allocated(varlist)) call mpp_error(FATAL, "The varlist for the first file was not set")
+ call compare_result("number_variables 2", size(varlist), 1)
+ call compare_result("varlist 2", varlist(1), "sst")
+ deallocate(varlist)
+
+ varlist = res(3)%get_file_varlist()
+ if (.not. allocated(varlist)) call mpp_error(FATAL, "The varlist for the first file was not set")
+ call compare_result("number_variables 3", size(varlist), 1)
+ call compare_result("varlist 3", varlist(1), "sstt")
+ deallocate(varlist)
+
+ global_meta= res(1)%get_file_global_meta()
+ if (.not. allocated(global_meta)) call mpp_error(FATAL, "The global meta for the first file was not set")
+ call compare_result("attributes key", global_meta(1,1), "is_a_file")
+ call compare_result("attributes value", global_meta(1,2), "true")
+ deallocate(global_meta)
+
+ if (res(2)%is_global_meta()) call mpp_error(FATAL, "The global meta for the second file was set?")
+ if (res(3)%is_global_meta()) call mpp_error(FATAL, "The global meta for the third file was set?")
+
+end subroutine compare_diag_files
+
+#endif
+end program test_diag_yaml
+
+#ifdef use_yaml
+!< @brief Compare a key value with the expected result
+subroutine compare_result_0d(key_name, res, expected_res)
+ use platform_mod
+ use mpp_mod
+ character(len=*), intent(in) :: key_name !< Name of the key to compare
+ class(*), intent(in) :: res !< Value obtained from reading the file
+ class(*), intent(in) :: expected_res !< Value expected
+
+ print *, "Comparing ", trim(key_name)
+ select type(res)
+ type is(character(len=*))
+ select type(expected_res)
+ type is(character(len=*))
+ if(trim(res) .ne. trim(expected_res)) &
+ call mpp_error(FATAL, "Error!: "//trim(key_name)//" is not the expected result. "//trim(res)//" ne "//&
+ trim(expected_res)//".")
+ end select
+ type is (integer(kind=i4_kind))
+ select type(expected_res)
+ type is(integer(kind=i4_kind))
+ if (res .ne. expected_res) then
+ print *, res, " ne ", expected_res
+ call mpp_error(FATAL, "Error!: "//trim(key_name)//" is not the expected result.")
+ endif
+ end select
+ type is (logical)
+ select type(expected_res)
+ type is(logical)
+ if ((res .and. .not. expected_res) .or. (.not. res .and. expected_res)) then
+ print*, res, " ne ", expected_res
+ call mpp_error(FATAL, "Error!:"//trim(key_name)//" is not the expected result")
+ endif
+ end select
+ end select
+
+end subroutine compare_result_0d
+
+!< @brief Compare a 1d key value with the expected result
+subroutine compare_result_1d(key_name, res, expected_res)
+ use platform_mod
+ use mpp_mod
+ character(len=*), intent(in) :: key_name !< Name of the key to compare
+ class(*), intent(in) :: res(:) !< Value obtained from reading the file
+ class(*), intent(in) :: expected_res(:) !< Value expected
+
+ integer :: i
+
+ print *, "Comparing ", trim(key_name)
+
+ select type(res)
+ type is (integer(kind=i4_kind))
+ select type(expected_res)
+ type is (integer(kind=i4_kind))
+ do i = 1, size(res,1)
+ if( res(i) .ne. expected_res(i)) then
+ print *, res, " ne ", expected_res
+ call mpp_error(FATAL, "Error!: "//trim(key_name)//" is not the expected result. ")
+ endif
+ enddo
+ end select
+ type is (real(kind=r4_kind))
+ select type(expected_res)
+ type is (real(kind=r4_kind))
+ do i = 1, size(res,1)
+ if( res(i) .ne. expected_res(i)) then
+ print *, res, " ne ", expected_res
+ call mpp_error(FATAL, "Error!: "//trim(key_name)//" is not the expected result. ")
+ endif
+ enddo
+ end select
+ type is (real(kind=r8_kind))
+ select type(expected_res)
+ type is (real(kind=r8_kind))
+ do i = 1, size(res,1)
+ if( res(i) .ne. expected_res(i)) then
+ print *, res, " ne ", expected_res
+ call mpp_error(FATAL, "Error!: "//trim(key_name)//" is not the expected result. ")
+ endif
+ enddo
+ end select
+ end select
+end subroutine compare_result_1d
+#endif