From f0e8cab3d8e58195f7c2663b84fd0bed12fa8b64 Mon Sep 17 00:00:00 2001 From: Ryan Mulhall <35538242+rem1776@users.noreply.github.com> Date: Tue, 14 Feb 2023 08:51:17 -0500 Subject: [PATCH] feat: log_diag_field_info updates from diag rewrite (#1117) --- diag_manager/diag_manager.F90 | 110 ++++++++++++++++++---------------- diag_manager/diag_util.F90 | 95 +++++++++++++---------------- 2 files changed, 102 insertions(+), 103 deletions(-) diff --git a/diag_manager/diag_manager.F90 b/diag_manager/diag_manager.F90 index 01f0ad6f8b..c726b109f3 100644 --- a/diag_manager/diag_manager.F90 +++ b/diag_manager/diag_manager.F90 @@ -201,9 +201,6 @@ MODULE diag_manager_mod ! The values are defined as GLO_REG_VAL (-999) and GLO_REG_VAL_ALT ! (-1) in diag_data_mod. ! - ! - ! Set to true, diag_manager uses mpp_io. Default is fms2_io. - ! ! USE time_manager_mod, ONLY: set_time, set_date, get_time, time_type, OPERATOR(>=), OPERATOR(>),& @@ -216,12 +213,12 @@ MODULE diag_manager_mod USE fms_mod, ONLY: error_mesg, FATAL, WARNING, NOTE, stdout, stdlog, write_version_number,& & fms_error_handler, check_nml_error, lowercase USE diag_axis_mod, ONLY: diag_axis_init, get_axis_length, get_axis_num, get_domain2d, get_tile_count,& - & diag_axis_add_attribute, axis_compatible_check, CENTER, NORTH, EAST + & diag_axis_add_attribute, axis_compatible_check, CENTER, NORTH, EAST, get_diag_axis_name USE diag_util_mod, ONLY: get_subfield_size, log_diag_field_info, update_bounds,& & check_out_of_bounds, check_bounds_are_exact_dynamic, check_bounds_are_exact_static,& & diag_time_inc, find_input_field, init_input_field, init_output_field,& & diag_data_out, write_static, get_date_dif, get_subfield_vert_size, sync_file_times,& - & prepend_attribute, attribute_init, diag_util_init + & prepend_attribute, attribute_init, diag_util_init, field_log_separator USE diag_data_mod, ONLY: max_files, CMOR_MISSING_VALUE, DIAG_OTHER, DIAG_OCEAN, DIAG_ALL, EVERY_TIME,& & END_OF_RUN, DIAG_SECONDS, DIAG_MINUTES, DIAG_HOURS, DIAG_DAYS, DIAG_MONTHS, DIAG_YEARS, num_files,& & max_input_fields, max_output_fields, num_output_fields, EMPTY, FILL_VALUE, null_axis_id,& @@ -378,17 +375,19 @@ MODULE diag_manager_mod INTEGER FUNCTION register_diag_field_scalar(module_name, field_name, init_time, & & long_name, units, missing_value, range, standard_name, do_not_log, err_msg,& & area, volume, realm) - CHARACTER(len=*), INTENT(in) :: module_name, field_name - TYPE(time_type), OPTIONAL, INTENT(in) :: init_time - CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name, units, standard_name - CLASS(*), OPTIONAL, INTENT(in) :: missing_value - CLASS(*), DIMENSION(:), OPTIONAL, INTENT(in) :: range - LOGICAL, OPTIONAL, INTENT(in) :: do_not_log !< if TRUE, field information is not logged - CHARACTER(len=*), OPTIONAL, INTENT(out):: err_msg - INTEGER, OPTIONAL, INTENT(in) :: area, volume - CHARACTER(len=*), OPTIONAL, INTENT(in):: realm !< String to set as the value to the modeling_realm attribute - - IF ( PRESENT(err_msg) ) err_msg = '' + CHARACTER(len=*), INTENT(in) :: module_name !< Module where the field comes from + CHARACTER(len=*), INTENT(in) :: field_name !< Name of the field + TYPE(time_type), OPTIONAL, INTENT(in) :: init_time !< Time to start writing data from + CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name !< Long_name to add as a variable attribute + CHARACTER(len=*), OPTIONAL, INTENT(in) :: units !< Units to add as a variable_attribute + CHARACTER(len=*), OPTIONAL, INTENT(in) :: standard_name !< Standard_name to name the variable in the file + CLASS(*), OPTIONAL, INTENT(in) :: missing_value !< Missing value to add as a variable attribute + CLASS(*), OPTIONAL, INTENT(in) :: range(:) !< Range to add a variable attribute + LOGICAL, OPTIONAL, INTENT(in) :: do_not_log !< If TRUE, field information is not logged + CHARACTER(len=*), OPTIONAL, INTENT(out):: err_msg !< Error_msg from call + INTEGER, OPTIONAL, INTENT(in) :: area !< Id of the area field + INTEGER, OPTIONAL, INTENT(in) :: volume !< Id of the volume field + CHARACTER(len=*), OPTIONAL, INTENT(in) :: realm !< String to set as the modeling_realm attribute ! Fatal error if range is present and its extent is not 2. IF ( PRESENT(range) ) THEN @@ -415,23 +414,27 @@ END FUNCTION register_diag_field_scalar INTEGER FUNCTION register_diag_field_array(module_name, field_name, axes, init_time, & & long_name, units, missing_value, range, mask_variant, standard_name, verbose,& & do_not_log, err_msg, interp_method, tile_count, area, volume, realm) - CHARACTER(len=*), INTENT(in) :: module_name, field_name - INTEGER, INTENT(in) :: axes(:) - TYPE(time_type), INTENT(in) :: init_time - CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name, units, standard_name - CLASS(*), OPTIONAL, INTENT(in) :: missing_value - CLASS(*), DIMENSION(:), OPTIONAL, INTENT(in) :: range - LOGICAL, OPTIONAL, INTENT(in) :: mask_variant,verbose - LOGICAL, OPTIONAL, INTENT(in) :: do_not_log !< if TRUE, field info is not logged - CHARACTER(len=*), OPTIONAL, INTENT(out):: err_msg + CHARACTER(len=*), INTENT(in) :: module_name !< Module where the field comes from + CHARACTER(len=*), INTENT(in) :: field_name !< Name of the field + INTEGER, INTENT(in) :: axes(:) !< Ids corresponding to the variable axis + TYPE(time_type), OPTIONAL, INTENT(in) :: init_time !< Time to start writing data from + CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name !< Long_name to add as a variable attribute + CHARACTER(len=*), OPTIONAL, INTENT(in) :: units !< Units to add as a variable_attribute + CLASS(*), OPTIONAL, INTENT(in) :: missing_value !< Missing value to add as a variable attribute + CLASS(*), OPTIONAL, INTENT(in) :: range(:) !< Range to add a variable attribute + LOGICAL, OPTIONAL, INTENT(in) :: mask_variant !< Mask variant + CHARACTER(len=*), OPTIONAL, INTENT(in) :: standard_name !< Standard_name to name the variable in the file + LOGICAL, OPTIONAL, INTENT(in) :: verbose !< Print more information + LOGICAL, OPTIONAL, INTENT(in) :: do_not_log !< If TRUE, field information is not logged + CHARACTER(len=*), OPTIONAL, INTENT(out):: err_msg !< Error_msg from call CHARACTER(len=*), OPTIONAL, INTENT(in) :: interp_method !< The interp method to be used when !! regridding the field in post-processing. !! Valid options are "conserve_order1", !! "conserve_order2", and "none". - INTEGER, OPTIONAL, INTENT(in) :: tile_count - INTEGER, OPTIONAL, INTENT(in) :: area !< diag_field_id containing the cell area field - INTEGER, OPTIONAL, INTENT(in) :: volume !< diag_field_id containing the cell volume field - CHARACTER(len=*), OPTIONAL, INTENT(in):: realm !< String to set as the value to the modeling_realm attribute + INTEGER, OPTIONAL, INTENT(in) :: tile_count !< The current tile number + INTEGER, OPTIONAL, INTENT(in) :: area !< Id of the area field + INTEGER, OPTIONAL, INTENT(in) :: volume !< Id of the volume field + CHARACTER(len=*), OPTIONAL, INTENT(in) :: realm !< String to set as the modeling_realm attribute INTEGER :: field, j, ind, file_num, freq INTEGER :: output_units @@ -634,7 +637,8 @@ INTEGER FUNCTION register_static_field(module_name, field_name, axes, long_name, INTEGER :: tile, file_num LOGICAL :: mask_variant1, dynamic1, allow_log CHARACTER(len=128) :: msg - INTEGER :: domain_type + INTEGER :: domain_type, i + character(len=256) :: axes_list, axis_name ! Fatal error if the module has not been initialized. IF ( .NOT.module_is_initialized ) THEN @@ -691,12 +695,16 @@ INTEGER FUNCTION register_static_field(module_name, field_name, axes, long_name, END IF END IF - ! Namelist do_diag_field_log is by default false. Thus to log the - ! registration of the data field, but the OPTIONAL parameter - ! do_not_log == .FALSE. and the namelist variable - ! do_diag_field_log == .TRUE.. + ! only writes log if do_diag_field_log is true in the namelist (default false) + ! if do_diag_field_log is true and do_not_log arg is present as well, it will only print if do_not_log = false IF ( do_diag_field_log.AND.allow_log ) THEN - CALL log_diag_field_info (module_name, field_name, axes, & + axes_list='' + DO i = 1, SIZE(axes) + CALL get_diag_axis_name(axes(i),axis_name) + IF ( TRIM(axes_list) /= '' ) axes_list = TRIM(axes_list)//',' + axes_list = TRIM(axes_list)//TRIM(axis_name) + END DO + CALL log_diag_field_info (module_name, field_name, axes, axes_list, & & long_name, units, missing_value=missing_value, range=range, & & DYNAMIC=dynamic1) END IF @@ -1094,9 +1102,9 @@ INTEGER FUNCTION get_diag_field_id(module_name, field_name) CHARACTER(len=*), INTENT(in) :: module_name !< Module name that registered the variable CHARACTER(len=*), INTENT(in) :: field_name !< Variable name - ! find_input_field will return DIAG_FIELD_NOT_FOUND if the field is not - ! included in the diag_table - get_diag_field_id = find_input_field(module_name, field_name, tile_count=1) + ! find_input_field will return DIAG_FIELD_NOT_FOUND if the field is not + ! included in the diag_table + get_diag_field_id = find_input_field(module_name, field_name, tile_count=1) END FUNCTION get_diag_field_id !> @brief Finds the corresponding related output field and file for a given input field @@ -3645,7 +3653,6 @@ SUBROUTINE diag_manager_init(diag_model_subset, time_init, err_msg) INTEGER, DIMENSION(6), OPTIONAL, INTENT(IN) :: time_init !< Model time diag_manager initialized CHARACTER(len=*), INTENT(out), OPTIONAL :: err_msg - CHARACTER(len=*), PARAMETER :: SEP = '|' INTEGER, PARAMETER :: FltKind = R4_KIND INTEGER, PARAMETER :: DblKind = R8_KIND @@ -3660,7 +3667,7 @@ SUBROUTINE diag_manager_init(diag_model_subset, time_init, err_msg) & max_input_fields, max_axes, do_diag_field_log, write_bytes_in_file, debug_diag_manager,& & max_num_axis_sets, max_files, use_cmor, issue_oor_warnings,& & oor_warnings_fatal, max_out_per_in_field, flush_nc_files, region_out_use_alt_value, max_field_attributes,& - & max_file_attributes, max_axis_attributes, prepend_date, use_mpp_io + & max_file_attributes, max_axis_attributes, prepend_date, use_mpp_io, field_log_separator ! If the module was already initialized do nothing IF ( module_is_initialized ) RETURN @@ -3755,9 +3762,9 @@ SUBROUTINE diag_manager_init(diag_model_subset, time_init, err_msg) ALLOCATE(fileobj(max_files)) ALLOCATE(fileobjND(max_files)) ALLOCATE(fnum_for_domain(max_files)) - !> Initialize fnum_for_domain with "dn" which stands for done + !> Initialize fnum_for_domain with "dn" which stands for done fnum_for_domain(:) = "dn" - CALL error_mesg('diag_manager_mod::diag_manager_init',& + CALL error_mesg('diag_manager_mod::diag_manager_init',& & 'diag_manager is using fms2_io', NOTE) else CALL error_mesg('diag_manager_mod::diag_manager_init',& @@ -3780,23 +3787,24 @@ SUBROUTINE diag_manager_init(diag_model_subset, time_init, err_msg) END IF END IF - CALL parse_diag_table(DIAG_SUBSET=diag_subset_output, ISTAT=mystat, ERR_MSG=err_msg_local) - IF ( mystat /= 0 ) THEN + CALL parse_diag_table(DIAG_SUBSET=diag_subset_output, ISTAT=mystat, ERR_MSG=err_msg_local) + IF ( mystat /= 0 ) THEN IF ( fms_error_handler('diag_manager_mod::diag_manager_init',& & 'Error parsing diag_table. '//TRIM(err_msg_local), err_msg) ) RETURN - END IF + END IF !initialize files%bytes_written to zero files(:)%bytes_written = 0 ! open diag field log file IF ( do_diag_field_log.AND.mpp_pe().EQ.mpp_root_pe() ) THEN - open(newunit=diag_log_unit, file='diag_field_log.out', action='WRITE') - WRITE (diag_log_unit,'(777a)') & - & 'Module', SEP, 'Field', SEP, 'Long Name', SEP,& - & 'Units', SEP, 'Number of Axis', SEP, 'Time Axis', SEP,& - & 'Missing Value', SEP, 'Min Value', SEP, 'Max Value', SEP,& - & 'AXES LIST' + open(newunit=diag_log_unit, file='diag_field_log.out', action='WRITE') + WRITE (diag_log_unit,'(777a)') & + & 'Module', FIELD_LOG_SEPARATOR, 'Field', FIELD_LOG_SEPARATOR, & + & 'Long Name', FIELD_LOG_SEPARATOR, 'Units', FIELD_LOG_SEPARATOR, & + & 'Number of Axis', FIELD_LOG_SEPARATOR, 'Time Axis', FIELD_LOG_SEPARATOR, & + & 'Missing Value', FIELD_LOG_SEPARATOR, 'Min Value', FIELD_LOG_SEPARATOR, & + & 'Max Value', FIELD_LOG_SEPARATOR, 'AXES LIST' END IF module_is_initialized = .TRUE. diff --git a/diag_manager/diag_util.F90 b/diag_manager/diag_util.F90 index a676fefede..ad9e9ef0ab 100644 --- a/diag_manager/diag_util.F90 +++ b/diag_manager/diag_util.F90 @@ -106,6 +106,9 @@ MODULE diag_util_mod LOGICAL :: module_initialized = .FALSE. + character(len=1), public :: field_log_separator = '|' !< separator used for csv-style log of registered fields + !! set by nml in diag_manager init + CONTAINS @@ -621,11 +624,12 @@ END FUNCTION get_index !! code uses a do_not_log parameter in the registration calls, !! and subsequently calls this subroutine to log field information !! under a generic name. - SUBROUTINE log_diag_field_info(module_name, field_name, axes, long_name, units,& - & missing_value, range, dynamic) + SUBROUTINE log_diag_field_info(module_name, field_name, axes, axes_list, long_name, units,& + & missing_value, range, dynamic ) CHARACTER(len=*), INTENT(in) :: module_name !< Module name CHARACTER(len=*), INTENT(in) :: field_name !< Field name INTEGER, DIMENSION(:), INTENT(in) :: axes !< Axis IDs + CHARACTER(len=*), INTENT(in) :: axes_list !< Comma seperated list of axes names CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name !< Long name for field. CHARACTER(len=*), OPTIONAL, INTENT(in) :: units !< Unit of field. CLASS(*), OPTIONAL, INTENT(in) :: missing_value !< Missing value value. @@ -636,99 +640,86 @@ SUBROUTINE log_diag_field_info(module_name, field_name, axes, long_name, units,& CHARACTER(len=256) :: lmodule, lfield, lname, lunits CHARACTER(len=64) :: lmissval, lmin, lmax CHARACTER(len=8) :: numaxis, timeaxis - CHARACTER(len=1) :: sep = '|' - CHARACTER(len=256) :: axis_name, axes_list INTEGER :: i REAL :: missing_value_use !< Local copy of missing_value REAL, DIMENSION(2) :: range_use !< Local copy of range - - IF ( .NOT.do_diag_field_log ) RETURN IF ( mpp_pe().NE.mpp_root_pe() ) RETURN ! Fatal error if range is present and its extent is not 2. IF ( PRESENT(range) ) THEN - IF ( SIZE(range) .NE. 2 ) THEN - ! extent of range should be 2 - CALL error_mesg ('diag_util_mod::log_diag_field_info', 'extent of range should be 2', FATAL) - END IF + IF ( SIZE(range) .NE. 2 ) THEN + CALL error_mesg('diag_util_mod::fms_log_field_info', 'extent of range should be 2', FATAL) + END IF END IF lmodule = TRIM(module_name) lfield = TRIM(field_name) IF ( PRESENT(long_name) ) THEN - lname = TRIM(long_name) + lname = TRIM(long_name) ELSE - lname = '' + lname = '' END IF IF ( PRESENT(units) ) THEN - lunits = TRIM(units) + lunits = TRIM(units) ELSE - lunits = '' + lunits = '' END IF WRITE (numaxis,'(i1)') SIZE(axes) IF (PRESENT(missing_value)) THEN - IF ( use_cmor ) THEN - WRITE (lmissval,*) CMOR_MISSING_VALUE - ELSE - SELECT TYPE (missing_value) + IF ( use_cmor ) THEN + WRITE (lmissval,*) CMOR_MISSING_VALUE + ELSE + SELECT TYPE (missing_value) TYPE IS (real(kind=r4_kind)) - missing_value_use = missing_value + missing_value_use = missing_value TYPE IS (real(kind=r8_kind)) - missing_value_use = real(missing_value) + missing_value_use = real(missing_value) CLASS DEFAULT - CALL error_mesg ('diag_util_mod::log_diag_field_info',& - & 'The missing_value is not one of the supported types of real(kind=4) or real(kind=8)', FATAL) - END SELECT - WRITE (lmissval,*) missing_value_use - END IF + CALL error_mesg ('diag_util_mod::log_diag_field_info',& + & 'The missing_value is not one of the supported types of real(kind=4) or real(kind=8)', FATAL) + END SELECT + WRITE (lmissval,*) missing_value_use + END IF ELSE - lmissval = '' + lmissval = '' ENDIF IF ( PRESENT(range) ) THEN - SELECT TYPE (range) - TYPE IS (real(kind=r4_kind)) + SELECT TYPE (range) + TYPE IS (real(kind=r4_kind)) range_use = range - TYPE IS (real(kind=r8_kind)) + TYPE IS (real(kind=r8_kind)) range_use = real(range) - CLASS DEFAULT + CLASS DEFAULT CALL error_mesg ('diag_util_mod::log_diag_field_info',& - & 'The range is not one of the supported types of real(kind=4) or real(kind=8)', FATAL) - END SELECT - WRITE (lmin,*) range_use(1) - WRITE (lmax,*) range_use(2) + & 'The range is not one of the supported types of real(kind=4) or real(kind=8)', FATAL) + END SELECT + WRITE (lmin,*) range_use(1) + WRITE (lmax,*) range_use(2) ELSE - lmin = '' - lmax = '' + lmin = '' + lmax = '' END IF IF ( PRESENT(dynamic) ) THEN - IF (dynamic) THEN + IF (dynamic) THEN timeaxis = 'T' - ELSE + ELSE timeaxis = 'F' - END IF + END IF ELSE - timeaxis = '' + timeaxis = '' END IF - axes_list='' - DO i = 1, SIZE(axes) - CALL get_diag_axis_name(axes(i),axis_name) - IF ( TRIM(axes_list) /= '' ) axes_list = TRIM(axes_list)//',' - axes_list = TRIM(axes_list)//TRIM(axis_name) - END DO - - !write (diag_log_unit,'(8(a,a),a)') & WRITE (diag_log_unit,'(777a)') & - & TRIM(lmodule), sep, TRIM(lfield), sep, TRIM(lname), sep,& - & TRIM(lunits), sep, TRIM(numaxis), sep, TRIM(timeaxis), sep,& - & TRIM(lmissval), sep, TRIM(lmin), sep, TRIM(lmax), sep,& - & TRIM(axes_list) + & TRIM(lmodule), field_log_separator, TRIM(lfield), field_log_separator, TRIM(lname), field_log_separator,& + & TRIM(lunits), field_log_separator, TRIM(numaxis), field_log_separator, TRIM(timeaxis), field_log_separator,& + & TRIM(lmissval), field_log_separator, TRIM(lmin), field_log_separator, TRIM(lmax), field_log_separator,& + & TRIM(axes_list) END SUBROUTINE log_diag_field_info !> @brief Update the output_fields x, y, and z min and max boundaries (array indices).