diff --git a/scripts/ccpp_datafile.py b/scripts/ccpp_datafile.py index e02061fc..9ceee5b8 100755 --- a/scripts/ccpp_datafile.py +++ b/scripts/ccpp_datafile.py @@ -890,7 +890,7 @@ def _new_var_entry(parent, var, full_entry=True): >>> var = Var({'local_name' : 'foo', 'standard_name' : 'hi_mom', 'units' : 'm s-1', 'dimensions' : '(horizontal_loop_extent)', 'type' : 'real', 'intent' : 'in'}, ParseSource('vname', 'DDT', ParseContext()), _MVAR_DUMMY_RUN_ENV) >>> _new_var_entry(parent, var) >>> table_entry_pretty_print(parent, 0) - '\\n \\n \\n horizontal_loop_extent\\n \\n \\n ddt\\n \\n \\n vname\\n \\n \\n\\n' + '\\n \\n \\n horizontal_loop_extent\\n \\n \\n ddt\\n \\n \\n vname\\n \\n \\n\\n' >>> parent = ET.fromstring('') >>> _new_var_entry(parent, var, full_entry=False) diff --git a/scripts/constituents.py b/scripts/constituents.py index bb83c3c7..e7e182c0 100644 --- a/scripts/constituents.py +++ b/scripts/constituents.py @@ -300,6 +300,7 @@ def write_constituent_routines(self, outfile, indent, suite_name, err_vars): # end if outfile.write("index = index + 1", indent+1) long_name = var.get_prop_value('long_name') + diag_name = var.get_prop_value('diagnostic_name') units = var.get_prop_value('units') dims = var.get_dim_stdnames() default_value = var.get_prop_value('default_value') @@ -311,7 +312,7 @@ def write_constituent_routines(self, outfile, indent, suite_name, err_vars): vertical_dim = '' # end if advect_str = self.TF_string(var.get_prop_value('advected')) - init_args = [f'{std_name=}', f'{long_name=}', + init_args = [f'{std_name=}', f'{long_name=}', f'{diag_name=}', f'{units=}', f'{vertical_dim=}', f'advected={advect_str}', f'errcode={errvar_names["ccpp_error_code"]}', diff --git a/scripts/metavar.py b/scripts/metavar.py index 62badfd7..cafdbf9f 100755 --- a/scripts/metavar.py +++ b/scripts/metavar.py @@ -26,7 +26,7 @@ from parse_tools import FORTRAN_CONDITIONAL_REGEX_WORDS, FORTRAN_CONDITIONAL_REGEX from var_props import CCPP_LOOP_DIM_SUBSTS, VariableProperty, VarCompatObj from var_props import find_horizontal_dimension, find_vertical_dimension -from var_props import standard_name_to_long_name, default_kind_val +from var_props import standard_name_to_long_name, local_name_to_diag_name, default_kind_val ############################################################################## @@ -174,6 +174,9 @@ class Var: check_fn_in=check_cf_standard_name), VariableProperty('long_name', str, optional_in=True, default_fn_in=standard_name_to_long_name), + VariableProperty('diagnostic_name', str, optional_in=True, + default_fn_in=local_name_to_diag_name, + check_fn_in=check_diagnostic_id), VariableProperty('units', str, check_fn_in=check_units), VariableProperty('dimensions', list, @@ -189,9 +192,6 @@ class Var: optional_in=True, default_in=False), VariableProperty('allocatable', bool, optional_in=True, default_in=False), - VariableProperty('diagnostic_name', str, - optional_in=True, default_in='', - check_fn_in=check_diagnostic_id), VariableProperty('diagnostic_name_fixed', str, optional_in=True, default_in='', check_fn_in=check_diagnostic_fixed), diff --git a/scripts/var_props.py b/scripts/var_props.py index a53e8b68..fc217548 100755 --- a/scripts/var_props.py +++ b/scripts/var_props.py @@ -128,6 +128,44 @@ def find_vertical_dimension(dims): # end for return (var_vdim, vindex) +######################################################################## +def local_name_to_diag_name(prop_dict, context=None): +######################################################################## + """ + Translate a local_name to its default diagnostic name. + Currently, this is just equal to the local name. If no local name + exists in the property dictionary, a truncation of the standard + name is used. (256 characters = max length of NetCDF variable name) + >>> local_name_to_diag_name({'local_name':'foo', 'standard_nam':'cloud_optical_depth'}) + 'foo' + >>> local_name_to_diag_name({'standard_name':'cloud_optical_depth_layers_from_0p55mu_to_0p99mu'}) + 'cloud_optical_depth_layers_from_0p55mu_to_0p99mu' + >>> local_name_to_diag_name({'units':'km'}) #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + parse_source.CCPPError: No standard name or local name to convert to diagnostic name + """ + diag_name = None + if 'local_name' in prop_dict: + locname = prop_dict['local_name'] + if locname: + diag_name = prop_dict['local_name'] + # end if + elif 'standard_name' in prop_dict: + stdname = prop_dict['standard_name'] + if stdname: + maxlen = 256 + diag_name = stdname[:maxlen] + # end if + # end if + + if not diag_name: + emsg = 'No standard name or local name to convert to diagnostic name' + raise CCPPError(emsg) + # end if + + return diag_name + ######################################################################## def standard_name_to_long_name(prop_dict, context=None): ######################################################################## diff --git a/src/ccpp_constituent_prop_mod.F90 b/src/ccpp_constituent_prop_mod.F90 index a08291b6..29e8a365 100644 --- a/src/ccpp_constituent_prop_mod.F90 +++ b/src/ccpp_constituent_prop_mod.F90 @@ -34,6 +34,7 @@ module ccpp_constituent_prop_mod ! for a constituent species and provides interfaces to access that data. character(len=:), private, allocatable :: var_std_name character(len=:), private, allocatable :: var_long_name + character(len=:), private, allocatable :: var_diag_name character(len=:), private, allocatable :: var_units character(len=:), private, allocatable :: vert_dim integer, private :: const_ind = int_unassigned @@ -60,6 +61,7 @@ module ccpp_constituent_prop_mod procedure :: is_instantiated => ccp_is_instantiated procedure :: standard_name => ccp_get_standard_name procedure :: long_name => ccp_get_long_name + procedure :: diagnostic_name => ccp_get_diagnostic_name procedure :: units => ccp_get_units procedure :: is_layer_var => ccp_is_layer_var procedure :: is_interface_var => ccp_is_interface_var @@ -103,6 +105,7 @@ module ccpp_constituent_prop_mod ! Informational methods procedure :: standard_name => ccpt_get_standard_name procedure :: long_name => ccpt_get_long_name + procedure :: diagnostic_name => ccpt_get_diagnostic_name procedure :: units => ccpt_get_units procedure :: is_layer_var => ccpt_is_layer_var procedure :: is_interface_var => ccpt_is_interface_var @@ -219,6 +222,7 @@ subroutine copyConstituent(outConst, inConst) outConst%var_std_name = inConst%var_std_name outConst%var_long_name = inConst%var_long_name + outConst%var_diag_name = inConst%var_diag_name outConst%vert_dim = inConst%vert_dim outConst%const_ind = inConst%const_ind outConst%advected = inConst%advected @@ -373,8 +377,8 @@ end function ccp_is_instantiated !####################################################################### - subroutine ccp_instantiate(this, std_name, long_name, units, vertical_dim, & - advected, default_value, min_value, molar_mass, water_species, & + subroutine ccp_instantiate(this, std_name, long_name, diag_name, units, & + vertical_dim, advected, default_value, min_value, molar_mass, water_species, & mixing_ratio_type, errcode, errmsg) ! Initialize all fields in @@ -382,6 +386,7 @@ subroutine ccp_instantiate(this, std_name, long_name, units, vertical_dim, & class(ccpp_constituent_properties_t), intent(inout) :: this character(len=*), intent(in) :: std_name character(len=*), intent(in) :: long_name + character(len=*), intent(in) :: diag_name character(len=*), intent(in) :: units character(len=*), intent(in) :: vertical_dim logical, optional, intent(in) :: advected @@ -404,6 +409,7 @@ subroutine ccp_instantiate(this, std_name, long_name, units, vertical_dim, & end if if (errcode == 0) then this%var_long_name = trim(long_name) + this%var_diag_name = trim(diag_name) this%var_units = trim(units) this%vert_dim = trim(vertical_dim) if (present(advected)) then @@ -479,6 +485,9 @@ subroutine ccp_deallocate(this) if (allocated(this%var_long_name)) then deallocate(this%var_long_name) end if + if (allocated(this%var_diag_name)) then + deallocate(this%var_diag_name) + end if if (allocated(this%vert_dim)) then deallocate(this%vert_dim) end if @@ -530,6 +539,25 @@ end subroutine ccp_get_long_name !####################################################################### + subroutine ccp_get_diagnostic_name(this, diag_name, errcode, errmsg) + ! Return this constituent's diagnostic name + + ! Dummy arguments + class(ccpp_constituent_properties_t), intent(in) :: this + character(len=*), intent(out) :: diag_name + integer, optional, intent(out) :: errcode + character(len=*), optional, intent(out) :: errmsg + + if (this%is_instantiated(errcode, errmsg)) then + diag_name = this%var_diag_name + else + diag_name = '' + end if + + end subroutine ccp_get_diagnostic_name + + !####################################################################### + subroutine ccp_get_units(this, units, errcode, errmsg) ! Return this constituent's units @@ -763,6 +791,7 @@ subroutine ccp_is_equivalent(this, oconst, equiv, errcode, errmsg) oconst%is_instantiated(errcode, errmsg)) then equiv = (trim(this%var_std_name) == trim(oconst%var_std_name)) .and. & (trim(this%var_long_name) == trim(oconst%var_long_name)) .and. & + (trim(this%var_diag_name) == trim(oconst%var_diag_name)) .and. & (trim(this%vert_dim) == trim(oconst%vert_dim)) .and. & (trim(this%var_units) == trim(oconst%var_units)) .and. & (this%advected .eqv. oconst%advected) .and. & @@ -1007,7 +1036,6 @@ logical function ccp_is_match(this, comp_props) result(is_match) ! Local variable logical :: val, comp_val character(len=stdname_len) :: char_val, char_comp_val - logical :: check ! By default, every constituent is a match is_match = .true. @@ -1989,6 +2017,29 @@ end subroutine ccpt_get_long_name !####################################################################### + subroutine ccpt_get_diagnostic_name(this, diag_name, errcode, errmsg) + ! Return this constituent's diagnostic name + + ! Dummy arguments + class(ccpp_constituent_prop_ptr_t), intent(in) :: this + character(len=*), intent(out) :: diag_name + integer, optional, intent(out) :: errcode + character(len=*), optional, intent(out) :: errmsg + ! Local variable + character(len=*), parameter :: subname = 'ccpt_get_diagnostic_name' + + if (associated(this%prop)) then + call this%prop%diagnostic_name(diag_name, errcode, errmsg) + else + diag_name = '' + call append_errvars(1, ": invalid constituent pointer", & + subname, errcode=errcode, errmsg=errmsg) + end if + + end subroutine ccpt_get_diagnostic_name + + !####################################################################### + subroutine ccpt_get_units(this, units, errcode, errmsg) ! Return this constituent's units diff --git a/test/advection_test/cld_ice.F90 b/test/advection_test/cld_ice.F90 index 759bcab1..15f5b502 100644 --- a/test/advection_test/cld_ice.F90 +++ b/test/advection_test/cld_ice.F90 @@ -34,13 +34,13 @@ subroutine cld_ice_register(dyn_const_ice, errmsg, errcode) return end if call dyn_const_ice(1)%instantiate(std_name='dyn_const1', long_name='dyn const1', & - units='kg kg-1', default_value=0._kind_phys, & - vertical_dim='vertical_layer_dimension', advected=.true., & - min_value=1000._kind_phys, water_species=.true., mixing_ratio_type='wet', & + diag_name='DYNCONST1', units='kg kg-1', default_value=0._kind_phys, & + vertical_dim='vertical_layer_dimension', advected=.true., & + min_value=1000._kind_phys, water_species=.true., mixing_ratio_type='wet', & errcode=errcode, errmsg=errmsg) call dyn_const_ice(2)%instantiate(std_name='dyn_const2_wrt_moist_air', long_name='dyn const2', & - units='kg kg-1', default_value=0._kind_phys, & - vertical_dim='vertical_layer_dimension', advected=.true., & + diag_name='DYNCONST2', units='kg kg-1', default_value=0._kind_phys, & + vertical_dim='vertical_layer_dimension', advected=.true., & water_species=.false., errcode=errcode, errmsg=errmsg) end subroutine cld_ice_register diff --git a/test/advection_test/cld_liq.F90 b/test/advection_test/cld_liq.F90 index 023a608c..83a6f961 100644 --- a/test/advection_test/cld_liq.F90 +++ b/test/advection_test/cld_liq.F90 @@ -31,7 +31,7 @@ subroutine cld_liq_register(dyn_const, errmsg, errflg) return end if call dyn_const(1)%instantiate(std_name="dyn_const3_wrt_moist_air_and_condensed_water", long_name='dyn const3', & - units='kg kg-1', default_value=1._kind_phys, & + diag_name='DYNCONST3', units='kg kg-1', default_value=1._kind_phys, & vertical_dim='vertical_layer_dimension', advected=.true., & water_species=.true., mixing_ratio_type='dry', & errcode=errflg, errmsg=errmsg) diff --git a/test/advection_test/cld_liq.meta b/test/advection_test/cld_liq.meta index e55dcfe7..b3ef3a0d 100644 --- a/test/advection_test/cld_liq.meta +++ b/test/advection_test/cld_liq.meta @@ -105,6 +105,7 @@ intent = in [ cld_liq_array ] standard_name = cloud_liquid_dry_mixing_ratio + diagnostic_name = CLDLIQ advected = .true. units = kg kg-1 dimensions = (horizontal_dimension, vertical_layer_dimension) diff --git a/test/advection_test/dlc_liq.F90 b/test/advection_test/dlc_liq.F90 index 93230f81..db456073 100644 --- a/test/advection_test/dlc_liq.F90 +++ b/test/advection_test/dlc_liq.F90 @@ -31,7 +31,7 @@ subroutine dlc_liq_init(dyn_const, errmsg, errflg) return end if call dyn_const(1)%instantiate(std_name="dyn_const3", long_name='dyn const3', & - units='kg kg-1', default_value=1._kind_phys, & + diag_name='DYNCONST3', units='kg kg-1', default_value=1._kind_phys, & vertical_dim='vertical_layer_dimension', advected=.true., & errcode=errflg, errmsg=errmsg) call dyn_const(1)%standard_name(stdname, errcode=errflg, errmsg=errmsg) diff --git a/test/advection_test/test_host.F90 b/test/advection_test/test_host.F90 index c1482a93..30a618e8 100644 --- a/test/advection_test/test_host.F90 +++ b/test/advection_test/test_host.F90 @@ -266,12 +266,12 @@ subroutine test_host(retval, test_suites) 'constituent with this name already exists' allocate(host_constituents(2)) call host_constituents(1)%instantiate(std_name="specific_humidity", & - long_name="Specific humidity", units="kg kg-1", & + long_name="Specific humidity", diag_name='H2O', units="kg kg-1", & vertical_dim="vertical_layer_dimension", advected=.true., & min_value=1000._kind_phys, molar_mass=2000._kind_phys, & errcode=errflg, errmsg=errmsg) call host_constituents(2)%instantiate(std_name="specific_humidity", & - long_name="Specific humidity", units="kg kg", & + long_name="Specific humidity", diag_name='H2O', units="kg kg", & vertical_dim="vertical_layer_dimension", advected=.true., & min_value=1000._kind_phys, molar_mass=2000._kind_phys, & errcode=errflg, errmsg=errmsg) @@ -309,12 +309,12 @@ subroutine test_host(retval, test_suites) end do allocate(host_constituents(2)) call host_constituents(1)%instantiate(std_name="specific_humidity", & - long_name="Specific humidity", units="kg kg-1", & + long_name="Specific humidity", diag_name='H2O', units="kg kg-1", & vertical_dim="vertical_layer_dimension", advected=.true., & - min_value=1000._kind_phys, molar_mass=2000._kind_phys, & + min_value=1000._kind_phys, molar_mass=2000._kind_phys, & errcode=errflg, errmsg=errmsg) call host_constituents(2)%instantiate(std_name="specific_humidity", & - long_name="Specific humidity", units="kg kg-1", & + long_name="Specific humidity", diag_name='H2O', units="kg kg-1", & vertical_dim="vertical_layer_dimension", advected=.true., & min_value=1000._kind_phys, molar_mass=2000._kind_phys, & errcode=errflg, errmsg=errmsg) @@ -480,6 +480,63 @@ subroutine test_host(retval, test_suites) ! Reset error flag to continue testing other properties: errflg = 0 end if + + ! Diagnostic name: + call const_props(index_liq)%diagnostic_name(const_str, errflg, errmsg) + if (errflg /= 0) then + write(6, '(a,i0,a,i0,/,a)') "ERROR: Error, ", errflg, " trying ", & + "to get diagnostic name for cld_liq index = ", & + index_liq, trim(errmsg) + errflg_final = -1 ! Notify test script that a failure occured + end if + if (errflg == 0) then + if (trim(const_str) /= 'CLDLIQ') then + write(6, *) "ERROR: diagnostic name, '", trim(const_str), & + "' should be 'CLDLIQ'" + errflg_final = -1 ! Notify test script that a failure occured + end if + else + ! Reset error flag to continue testing other properties: + errflg = 0 + end if + ! Check default diagnostic name is set correctly + call const_props(index_ice)%diagnostic_name(const_str, errflg, errmsg) + if (errflg /= 0) then + write(6, '(a,i0,a,i0,/,a)') "ERROR: Error, ", errflg, " trying ", & + "to get diagnostic name for cld_ice index = ", & + index_ice, trim(errmsg) + errflg_final = -1 ! Notify test script that a failure occured + end if + if (errflg == 0) then + if (trim(const_str) /= 'cld_ice_array') then + write(6, *) "ERROR: diagnostic name, '", trim(const_str), & + "' should be 'cld_ice_array'" + errflg_final = -1 ! Notify test script that a failure occured + end if + else + ! Reset error flag to continue testing other properties: + errflg = 0 + end if + ! Check diagnostic name of a dynamic constituent + call const_props(index_dyn2)%diagnostic_name(const_str, errflg, & + errmsg) + if (errflg /= 0) then + write(6, '(a,i0,a,a,i0,/,a)') "ERROR: Error, ", errflg, " trying ", & + "to get diagnostic name for dyn_const2 index = ", & + index_dyn2, trim(errmsg) + errflg_final = -1 ! Notify test script that a failure occured + end if + if (errflg == 0) then + if (trim(const_str) /= 'DYNCONST2') then + write(6, *) "ERROR: diagnostic name, '", trim(const_str), & + "' should be 'DYNCONST2'" + errflg_final = -1 ! Notify test script that a failure occured + end if + else + ! Reset error flag to continue testing other properties: + errflg = 0 + end if + ! Mass mixing ratio: call const_props(index_ice)%is_mass_mixing_ratio(const_log, errflg, & errmsg) diff --git a/test/unit_tests/sample_scheme_files/temp_adjust.F90 b/test/unit_tests/sample_scheme_files/temp_adjust.F90 index 7b1d0cbb..70613ba1 100644 --- a/test/unit_tests/sample_scheme_files/temp_adjust.F90 +++ b/test/unit_tests/sample_scheme_files/temp_adjust.F90 @@ -29,7 +29,7 @@ subroutine temp_adjust_register(config_var, dyn_const, errflg, errmsg) allocate(dyn_const(1)) call dyn_const(1)%instantiate(std_name="dyn_const", long_name='dyn const', & - units='kg kg-1', default_value=1._kind_phys, & + diag_name='DYNCONST', units='kg kg-1', default_value=1._kind_phys, & vertical_dim='vertical_layer_dimension', advected=.true., & errcode=errflg, errmsg=errmsg)