From d4d89a0b429be8acf3973e39c054e297142ad566 Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Fri, 14 Jun 2024 21:59:58 +0000 Subject: [PATCH 01/12] Add support and testing for equivalent units --- scripts/conversion_tools/unit_conversion.py | 11 +++++++++++ scripts/var_props.py | 2 +- test/var_compatibility_test/effr_calc.F90 | 4 +++- test/var_compatibility_test/effr_calc.meta | 8 ++++++++ test/var_compatibility_test/run_test | 3 +++ test/var_compatibility_test/test_host.F90 | 11 +++++++---- test/var_compatibility_test/test_host_data.F90 | 2 +- test/var_compatibility_test/test_host_data.meta | 7 +++++++ test/var_compatibility_test/test_host_mod.F90 | 1 + test/var_compatibility_test/test_reports.py | 4 +++- 10 files changed, 45 insertions(+), 8 deletions(-) diff --git a/scripts/conversion_tools/unit_conversion.py b/scripts/conversion_tools/unit_conversion.py index b9afa144..42d352f2 100755 --- a/scripts/conversion_tools/unit_conversion.py +++ b/scripts/conversion_tools/unit_conversion.py @@ -176,3 +176,14 @@ def W_m_minus_2__to__erg_cm_minus_2_s_minus_1(): def erg_cm_minus_2_s_minus_1__to__W_m_minus_2(): """Convert erg per square centimeter and second to Watt per square meter""" return '1.0E-3{kind}*{var}' + +################## +# Equivalent units # +################## +def m2_s_minus_2__to__J_kg_minus_1(): + """Equivalent units""" + return None + +def J_kg_minus_1__to__m2_s_minus_2(): + """Equivalent units""" + return None diff --git a/scripts/var_props.py b/scripts/var_props.py index 9a2fd7d0..97be3364 100755 --- a/scripts/var_props.py +++ b/scripts/var_props.py @@ -1426,7 +1426,7 @@ def has_unit_transforms(self): and arguments to produce code to transform one variable into the correct units of the other. """ - return self.__unit_transforms is not None + return self.__unit_transforms is not None and self.__unit_transforms[0] def __bool__(self): """Return True if this object describes two Var objects which are diff --git a/test/var_compatibility_test/effr_calc.F90 b/test/var_compatibility_test/effr_calc.F90 index 6dbbb722..d96cb0e0 100644 --- a/test/var_compatibility_test/effr_calc.F90 +++ b/test/var_compatibility_test/effr_calc.F90 @@ -17,7 +17,7 @@ module effr_calc !! subroutine effr_calc_run(ncol, nlev, effrr_in, effrg_in, ncg_in, nci_out, & effrl_inout, effri_out, effrs_inout, ncl_out, & - has_graupel, scalar_var, errmsg, errflg) + has_graupel, scalar_var, tke_inout, errmsg, errflg) integer, intent(in) :: ncol integer, intent(in) :: nlev @@ -33,6 +33,8 @@ subroutine effr_calc_run(ncol, nlev, effrr_in, effrg_in, ncg_in, nci_out, & character(len=512), intent(out) :: errmsg integer, intent(out) :: errflg real(kind_phys), intent(out),optional :: ncl_out(:,:) + real(kind_phys), intent(inout) :: tke_inout + !---------------------------------------------------------------- real(kind_phys), parameter :: re_qc_min = 2.5 ! microns diff --git a/test/var_compatibility_test/effr_calc.meta b/test/var_compatibility_test/effr_calc.meta index 73c36ace..7265f398 100644 --- a/test/var_compatibility_test/effr_calc.meta +++ b/test/var_compatibility_test/effr_calc.meta @@ -103,6 +103,14 @@ type = real kind = kind_phys intent = inout +[ tke_inout ] + standard_name = turbulent_kinetic_energy + long_name = turbulent_kinetic_energy + units = m2 s-2 + dimensions = () + type = real + kind = kind_phys + intent = inout [ errmsg ] standard_name = ccpp_error_message long_name = Error message for error handling in CCPP diff --git a/test/var_compatibility_test/run_test b/test/var_compatibility_test/run_test index a5edac37..311c256f 100755 --- a/test/var_compatibility_test/run_test +++ b/test/var_compatibility_test/run_test @@ -144,6 +144,7 @@ required_vars_var_compatibility="${required_vars_var_compatibility},horizontal_d required_vars_var_compatibility="${required_vars_var_compatibility},horizontal_loop_begin" required_vars_var_compatibility="${required_vars_var_compatibility},horizontal_loop_end" required_vars_var_compatibility="${required_vars_var_compatibility},scalar_variable_for_testing" +required_vars_var_compatibility="${required_vars_var_compatibility},turbulent_kinetic_energy" required_vars_var_compatibility="${required_vars_var_compatibility},vertical_layer_dimension" input_vars_var_compatibility="cloud_graupel_number_concentration" #input_vars_var_compatibility="${input_vars_var_compatibility},cloud_ice_number_concentration" @@ -157,6 +158,7 @@ input_vars_var_compatibility="${input_vars_var_compatibility},horizontal_dimensi input_vars_var_compatibility="${input_vars_var_compatibility},horizontal_loop_begin" input_vars_var_compatibility="${input_vars_var_compatibility},horizontal_loop_end" input_vars_var_compatibility="${input_vars_var_compatibility},scalar_variable_for_testing" +input_vars_var_compatibility="${input_vars_var_compatibility},turbulent_kinetic_energy" input_vars_var_compatibility="${input_vars_var_compatibility},vertical_layer_dimension" output_vars_var_compatibility="ccpp_error_code,ccpp_error_message" output_vars_var_compatibility="${output_vars_var_compatibility},cloud_ice_number_concentration" @@ -164,6 +166,7 @@ output_vars_var_compatibility="${output_vars_var_compatibility},effective_radius output_vars_var_compatibility="${output_vars_var_compatibility},effective_radius_of_stratiform_cloud_liquid_water_particle" output_vars_var_compatibility="${output_vars_var_compatibility},effective_radius_of_stratiform_cloud_snow_particle" output_vars_var_compatibility="${output_vars_var_compatibility},scalar_variable_for_testing" +output_vars_var_compatibility="${output_vars_var_compatibility},turbulent_kinetic_energy" ## diff --git a/test/var_compatibility_test/test_host.F90 b/test/var_compatibility_test/test_host.F90 index 3a805a8e..4622d09c 100644 --- a/test/var_compatibility_test/test_host.F90 +++ b/test/var_compatibility_test/test_host.F90 @@ -351,26 +351,28 @@ program test character(len=cs), target :: test_parts1(1) = (/ 'radiation ' /) - character(len=cm), target :: test_invars1(8) = (/ & + character(len=cm), target :: test_invars1(9) = (/ & 'effective_radius_of_stratiform_cloud_rain_particle ', & 'effective_radius_of_stratiform_cloud_liquid_water_particle', & 'effective_radius_of_stratiform_cloud_snow_particle ', & 'effective_radius_of_stratiform_cloud_graupel ', & 'cloud_graupel_number_concentration ', & 'scalar_variable_for_testing ', & + 'turbulent_kinetic_energy ', & 'flag_indicating_cloud_microphysics_has_graupel ', & 'flag_indicating_cloud_microphysics_has_ice '/) - character(len=cm), target :: test_outvars1(7) = (/ & + character(len=cm), target :: test_outvars1(8) = (/ & 'ccpp_error_code ', & 'ccpp_error_message ', & 'effective_radius_of_stratiform_cloud_ice_particle ', & 'effective_radius_of_stratiform_cloud_liquid_water_particle', & 'effective_radius_of_stratiform_cloud_snow_particle ', & 'cloud_ice_number_concentration ', & - 'scalar_variable_for_testing ' /) + 'scalar_variable_for_testing ', & + 'turbulent_kinetic_energy '/) - character(len=cm), target :: test_reqvars1(12) = (/ & + character(len=cm), target :: test_reqvars1(13) = (/ & 'ccpp_error_code ', & 'ccpp_error_message ', & 'effective_radius_of_stratiform_cloud_rain_particle ', & @@ -381,6 +383,7 @@ program test 'cloud_graupel_number_concentration ', & 'cloud_ice_number_concentration ', & 'scalar_variable_for_testing ', & + 'turbulent_kinetic_energy ', & 'flag_indicating_cloud_microphysics_has_graupel ', & 'flag_indicating_cloud_microphysics_has_ice '/) diff --git a/test/var_compatibility_test/test_host_data.F90 b/test/var_compatibility_test/test_host_data.F90 index 9d0ca306..b2c152d1 100644 --- a/test/var_compatibility_test/test_host_data.F90 +++ b/test/var_compatibility_test/test_host_data.F90 @@ -12,7 +12,7 @@ module test_host_data effrg, & ! effective radius of cloud graupel ncg, & ! number concentration of cloud graupel nci ! number concentration of cloud ice - real(kind_phys) :: scalar_var + real(kind_phys) :: scalar_var, tke end type physics_state public allocate_physics_state diff --git a/test/var_compatibility_test/test_host_data.meta b/test/var_compatibility_test/test_host_data.meta index d3bca89b..9de0d647 100644 --- a/test/var_compatibility_test/test_host_data.meta +++ b/test/var_compatibility_test/test_host_data.meta @@ -59,3 +59,10 @@ dimensions = () type = real kind = kind_phys +[ tke ] + standard_name = turbulent_kinetic_energy + long_name = turbulent_kinetic_energy + units = J kg-1 + dimensions = () + type = real + kind = kind_phys \ No newline at end of file diff --git a/test/var_compatibility_test/test_host_mod.F90 b/test/var_compatibility_test/test_host_mod.F90 index ca1d2014..d6f4944e 100644 --- a/test/var_compatibility_test/test_host_mod.F90 +++ b/test/var_compatibility_test/test_host_mod.F90 @@ -37,6 +37,7 @@ subroutine init_data() phys_state%effri = 5.0E-5 ! 50 microns, in meter phys_state%nci = 80 endif + phys_state%tke = 10.0 !J kg-1 end subroutine init_data diff --git a/test/var_compatibility_test/test_reports.py b/test/var_compatibility_test/test_reports.py index aaf08953..0dedcfa1 100755 --- a/test/var_compatibility_test/test_reports.py +++ b/test/var_compatibility_test/test_reports.py @@ -74,6 +74,7 @@ def usage(errmsg=None): "effective_radius_of_stratiform_cloud_graupel", "cloud_graupel_number_concentration", "scalar_variable_for_testing", + "turbulent_kinetic_energy", "flag_indicating_cloud_microphysics_has_graupel", "flag_indicating_cloud_microphysics_has_ice"] _OUTPUT_VARS_VAR_ACTION = ["ccpp_error_code", "ccpp_error_message", @@ -81,7 +82,8 @@ def usage(errmsg=None): "effective_radius_of_stratiform_cloud_liquid_water_particle", "effective_radius_of_stratiform_cloud_snow_particle", "cloud_ice_number_concentration", - "scalar_variable_for_testing"] + "scalar_variable_for_testing", + "turbulent_kinetic_energy"] _REQUIRED_VARS_VAR_ACTION = _INPUT_VARS_VAR_ACTION + _OUTPUT_VARS_VAR_ACTION def fields_string(field_type, field_list, sep): From 0bfe13bdee306dae389853b495cddbeef9277e7d Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Thu, 2 Jan 2025 20:14:01 +0000 Subject: [PATCH 02/12] Return Var instead of None for equivalent units. Update tests. --- scripts/conversion_tools/unit_conversion.py | 4 ++-- test/var_compatibility_test/test_host.F90 | 2 +- test/var_compatibility_test/test_reports.py | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/conversion_tools/unit_conversion.py b/scripts/conversion_tools/unit_conversion.py index 42d352f2..b809430f 100755 --- a/scripts/conversion_tools/unit_conversion.py +++ b/scripts/conversion_tools/unit_conversion.py @@ -182,8 +182,8 @@ def erg_cm_minus_2_s_minus_1__to__W_m_minus_2(): ################## def m2_s_minus_2__to__J_kg_minus_1(): """Equivalent units""" - return None + return '{var}' def J_kg_minus_1__to__m2_s_minus_2(): """Equivalent units""" - return None + return '{var}' diff --git a/test/var_compatibility_test/test_host.F90 b/test/var_compatibility_test/test_host.F90 index 5e365bd2..6667e02c 100644 --- a/test/var_compatibility_test/test_host.F90 +++ b/test/var_compatibility_test/test_host.F90 @@ -362,7 +362,7 @@ program test 'flag_indicating_cloud_microphysics_has_graupel ', & 'flag_indicating_cloud_microphysics_has_ice '/) - character(len=cm), target :: test_outvars1(8) = (/ & + character(len=cm), target :: test_outvars1(9) = (/ & 'ccpp_error_code ', & 'ccpp_error_message ', & 'effective_radius_of_stratiform_cloud_ice_particle ', & diff --git a/test/var_compatibility_test/test_reports.py b/test/var_compatibility_test/test_reports.py index 72d26c8c..c18c258c 100755 --- a/test/var_compatibility_test/test_reports.py +++ b/test/var_compatibility_test/test_reports.py @@ -83,6 +83,7 @@ def usage(errmsg=None): "effective_radius_of_stratiform_cloud_snow_particle", "cloud_ice_number_concentration", "effective_radius_of_stratiform_cloud_rain_particle", + "turbulent_kinetic_energy", "scalar_variable_for_testing"] _REQUIRED_VARS_VAR_ACTION = _INPUT_VARS_VAR_ACTION + _OUTPUT_VARS_VAR_ACTION From 0c48024d6d3d5a07a2fff464a57e278712eae938 Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Mon, 14 Apr 2025 11:24:16 -0600 Subject: [PATCH 03/12] Update capgen var_compatibility_test for equivalent and identical units --- test/var_compatibility_test/effr_calc.F90 | 6 ++++-- test/var_compatibility_test/effr_calc.meta | 8 ++++++++ test/var_compatibility_test/run_test | 4 +++- test/var_compatibility_test/test_host.F90 | 11 +++++++---- test/var_compatibility_test/test_host_data.F90 | 2 +- test/var_compatibility_test/test_host_data.meta | 9 ++++++++- test/var_compatibility_test/test_reports.py | 2 ++ 7 files changed, 33 insertions(+), 9 deletions(-) diff --git a/test/var_compatibility_test/effr_calc.F90 b/test/var_compatibility_test/effr_calc.F90 index d96cb0e0..eb2e7e01 100644 --- a/test/var_compatibility_test/effr_calc.F90 +++ b/test/var_compatibility_test/effr_calc.F90 @@ -17,7 +17,8 @@ module effr_calc !! subroutine effr_calc_run(ncol, nlev, effrr_in, effrg_in, ncg_in, nci_out, & effrl_inout, effri_out, effrs_inout, ncl_out, & - has_graupel, scalar_var, tke_inout, errmsg, errflg) + has_graupel, scalar_var, tke_inout, tke2_inout, & + errmsg, errflg) integer, intent(in) :: ncol integer, intent(in) :: nlev @@ -34,7 +35,8 @@ subroutine effr_calc_run(ncol, nlev, effrr_in, effrg_in, ncg_in, nci_out, & integer, intent(out) :: errflg real(kind_phys), intent(out),optional :: ncl_out(:,:) real(kind_phys), intent(inout) :: tke_inout - + real(kind_phys), intent(inout) :: tke2_inout + !---------------------------------------------------------------- real(kind_phys), parameter :: re_qc_min = 2.5 ! microns diff --git a/test/var_compatibility_test/effr_calc.meta b/test/var_compatibility_test/effr_calc.meta index 7265f398..b69fee31 100644 --- a/test/var_compatibility_test/effr_calc.meta +++ b/test/var_compatibility_test/effr_calc.meta @@ -111,6 +111,14 @@ type = real kind = kind_phys intent = inout +[ tke2_inout ] + standard_name = turbulent_kinetic_energy2 + long_name = turbulent_kinetic_energy2 + units = m+2 s-2 + dimensions = () + type = real + kind = kind_phys + intent = inout [ errmsg ] standard_name = ccpp_error_message long_name = Error message for error handling in CCPP diff --git a/test/var_compatibility_test/run_test b/test/var_compatibility_test/run_test index 93d6199e..ae650a5c 100755 --- a/test/var_compatibility_test/run_test +++ b/test/var_compatibility_test/run_test @@ -145,9 +145,9 @@ required_vars_var_compatibility="${required_vars_var_compatibility},horizontal_l required_vars_var_compatibility="${required_vars_var_compatibility},horizontal_loop_end" required_vars_var_compatibility="${required_vars_var_compatibility},scalar_variable_for_testing" required_vars_var_compatibility="${required_vars_var_compatibility},turbulent_kinetic_energy" +required_vars_var_compatibility="${required_vars_var_compatibility},turbulent_kinetic_energy2" required_vars_var_compatibility="${required_vars_var_compatibility},vertical_layer_dimension" input_vars_var_compatibility="cloud_graupel_number_concentration" -#input_vars_var_compatibility="${input_vars_var_compatibility},cloud_ice_number_concentration" input_vars_var_compatibility="${input_vars_var_compatibility},effective_radius_of_stratiform_cloud_graupel" input_vars_var_compatibility="${input_vars_var_compatibility},effective_radius_of_stratiform_cloud_liquid_water_particle" input_vars_var_compatibility="${input_vars_var_compatibility},effective_radius_of_stratiform_cloud_rain_particle" @@ -159,6 +159,7 @@ input_vars_var_compatibility="${input_vars_var_compatibility},horizontal_loop_be input_vars_var_compatibility="${input_vars_var_compatibility},horizontal_loop_end" input_vars_var_compatibility="${input_vars_var_compatibility},scalar_variable_for_testing" input_vars_var_compatibility="${input_vars_var_compatibility},turbulent_kinetic_energy" +input_vars_var_compatibility="${input_vars_var_compatibility},turbulent_kinetic_energy2" input_vars_var_compatibility="${input_vars_var_compatibility},vertical_layer_dimension" output_vars_var_compatibility="ccpp_error_code,ccpp_error_message" output_vars_var_compatibility="${output_vars_var_compatibility},cloud_ice_number_concentration" @@ -168,6 +169,7 @@ output_vars_var_compatibility="${output_vars_var_compatibility},effective_radius output_vars_var_compatibility="${output_vars_var_compatibility},effective_radius_of_stratiform_cloud_snow_particle" output_vars_var_compatibility="${output_vars_var_compatibility},scalar_variable_for_testing" output_vars_var_compatibility="${output_vars_var_compatibility},turbulent_kinetic_energy" +output_vars_var_compatibility="${output_vars_var_compatibility},turbulent_kinetic_energy2" ## ## Run a database report and check the return string diff --git a/test/var_compatibility_test/test_host.F90 b/test/var_compatibility_test/test_host.F90 index 6667e02c..14bc7237 100644 --- a/test/var_compatibility_test/test_host.F90 +++ b/test/var_compatibility_test/test_host.F90 @@ -351,7 +351,7 @@ program test character(len=cs), target :: test_parts1(1) = (/ 'radiation ' /) - character(len=cm), target :: test_invars1(9) = (/ & + character(len=cm), target :: test_invars1(10) = (/ & 'effective_radius_of_stratiform_cloud_rain_particle ', & 'effective_radius_of_stratiform_cloud_liquid_water_particle', & 'effective_radius_of_stratiform_cloud_snow_particle ', & @@ -359,10 +359,11 @@ program test 'cloud_graupel_number_concentration ', & 'scalar_variable_for_testing ', & 'turbulent_kinetic_energy ', & + 'turbulent_kinetic_energy2 ', & 'flag_indicating_cloud_microphysics_has_graupel ', & 'flag_indicating_cloud_microphysics_has_ice '/) - character(len=cm), target :: test_outvars1(9) = (/ & + character(len=cm), target :: test_outvars1(10) = (/ & 'ccpp_error_code ', & 'ccpp_error_message ', & 'effective_radius_of_stratiform_cloud_ice_particle ', & @@ -371,9 +372,10 @@ program test 'effective_radius_of_stratiform_cloud_snow_particle ', & 'cloud_ice_number_concentration ', & 'scalar_variable_for_testing ', & - 'turbulent_kinetic_energy '/) + 'turbulent_kinetic_energy ', & + 'turbulent_kinetic_energy2 '/) - character(len=cm), target :: test_reqvars1(13) = (/ & + character(len=cm), target :: test_reqvars1(14) = (/ & 'ccpp_error_code ', & 'ccpp_error_message ', & 'effective_radius_of_stratiform_cloud_rain_particle ', & @@ -385,6 +387,7 @@ program test 'cloud_ice_number_concentration ', & 'scalar_variable_for_testing ', & 'turbulent_kinetic_energy ', & + 'turbulent_kinetic_energy2 ', & 'flag_indicating_cloud_microphysics_has_graupel ', & 'flag_indicating_cloud_microphysics_has_ice '/) diff --git a/test/var_compatibility_test/test_host_data.F90 b/test/var_compatibility_test/test_host_data.F90 index b2c152d1..5986383c 100644 --- a/test/var_compatibility_test/test_host_data.F90 +++ b/test/var_compatibility_test/test_host_data.F90 @@ -12,7 +12,7 @@ module test_host_data effrg, & ! effective radius of cloud graupel ncg, & ! number concentration of cloud graupel nci ! number concentration of cloud ice - real(kind_phys) :: scalar_var, tke + real(kind_phys) :: scalar_var, tke, tke2 end type physics_state public allocate_physics_state diff --git a/test/var_compatibility_test/test_host_data.meta b/test/var_compatibility_test/test_host_data.meta index 9de0d647..5782feab 100644 --- a/test/var_compatibility_test/test_host_data.meta +++ b/test/var_compatibility_test/test_host_data.meta @@ -65,4 +65,11 @@ units = J kg-1 dimensions = () type = real - kind = kind_phys \ No newline at end of file + kind = kind_phys +[ tke2 ] + standard_name = turbulent_kinetic_energy2 + long_name = turbulent_kinetic_energy2 + units = m2 s-2 + dimensions = () + type = real + kind = kind_phys diff --git a/test/var_compatibility_test/test_reports.py b/test/var_compatibility_test/test_reports.py index c18c258c..4a33a4af 100755 --- a/test/var_compatibility_test/test_reports.py +++ b/test/var_compatibility_test/test_reports.py @@ -75,6 +75,7 @@ def usage(errmsg=None): "cloud_graupel_number_concentration", "scalar_variable_for_testing", "turbulent_kinetic_energy", + "turbulent_kinetic_energy2", "flag_indicating_cloud_microphysics_has_graupel", "flag_indicating_cloud_microphysics_has_ice"] _OUTPUT_VARS_VAR_ACTION = ["ccpp_error_code", "ccpp_error_message", @@ -84,6 +85,7 @@ def usage(errmsg=None): "cloud_ice_number_concentration", "effective_radius_of_stratiform_cloud_rain_particle", "turbulent_kinetic_energy", + "turbulent_kinetic_energy2", "scalar_variable_for_testing"] _REQUIRED_VARS_VAR_ACTION = _INPUT_VARS_VAR_ACTION + _OUTPUT_VARS_VAR_ACTION From 30b98f26842fff1f7f52466fa88cf6aa057d618d Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Mon, 14 Apr 2025 11:38:07 -0600 Subject: [PATCH 04/12] Update ccpp_prebuild test test_unit_conv for equivalent and identical units --- test_prebuild/test_unit_conv/data.F90 | 3 ++- test_prebuild/test_unit_conv/data.meta | 7 +++++++ test_prebuild/test_unit_conv/main.F90 | 3 ++- .../test_unit_conv/unit_conv_scheme_1.F90 | 14 ++++++++++++-- .../test_unit_conv/unit_conv_scheme_1.meta | 8 ++++++++ .../test_unit_conv/unit_conv_scheme_2.F90 | 12 +++++++++++- .../test_unit_conv/unit_conv_scheme_2.meta | 8 ++++++++ 7 files changed, 50 insertions(+), 5 deletions(-) diff --git a/test_prebuild/test_unit_conv/data.F90 b/test_prebuild/test_unit_conv/data.F90 index f53c107e..c926122b 100644 --- a/test_prebuild/test_unit_conv/data.F90 +++ b/test_prebuild/test_unit_conv/data.F90 @@ -11,12 +11,13 @@ module data private public ncols, nspecies - public cdata, data_array, opt_array_flag + public cdata, data_array, data_array2, opt_array_flag integer, parameter :: ncols = 4 integer, parameter :: nspecies = 2 type(ccpp_t), target :: cdata real(kind_phys), dimension(1:ncols,1:nspecies) :: data_array + real(kind_phys), dimension(1:ncols) :: data_array2 logical :: opt_array_flag end module data diff --git a/test_prebuild/test_unit_conv/data.meta b/test_prebuild/test_unit_conv/data.meta index 895cd6c2..e709e4fc 100644 --- a/test_prebuild/test_unit_conv/data.meta +++ b/test_prebuild/test_unit_conv/data.meta @@ -37,6 +37,13 @@ dimensions = (horizontal_loop_extent) type = real kind = kind_phys +[data_array2] + standard_name = data_array2 + long_name = data array 2 in module + units = m2 s-2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys [opt_array_flag] standard_name = flag_for_opt_array long_name = flag for passing optional data array diff --git a/test_prebuild/test_unit_conv/main.F90 b/test_prebuild/test_unit_conv/main.F90 index 3f7ee103..3eb6462e 100644 --- a/test_prebuild/test_unit_conv/main.F90 +++ b/test_prebuild/test_unit_conv/main.F90 @@ -4,7 +4,7 @@ program test_unit_conv use ccpp_types, only: ccpp_t use data, only: ncols, nspecies - use data, only: cdata, data_array, opt_array_flag + use data, only: cdata, data_array, data_array2, opt_array_flag use ccpp_static_api, only: ccpp_physics_init, & ccpp_physics_timestep_init, & @@ -30,6 +30,7 @@ program test_unit_conv cdata%thrd_cnt = 1 data_array = 1.0_8 + data_array2 = 42.0_8 opt_array_flag = .true. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/test_prebuild/test_unit_conv/unit_conv_scheme_1.F90 b/test_prebuild/test_unit_conv/unit_conv_scheme_1.F90 index d9488789..9ef178ff 100644 --- a/test_prebuild/test_unit_conv/unit_conv_scheme_1.F90 +++ b/test_prebuild/test_unit_conv/unit_conv_scheme_1.F90 @@ -13,16 +13,18 @@ module unit_conv_scheme_1 !! This is for unit testing only real(kind_phys), parameter :: target_value = 1.0_kind_phys + real(kind_phys), parameter :: target_value2 = 42.0_kind_phys contains !! \section arg_table_unit_conv_scheme_1_run Argument Table !! \htmlinclude unit_conv_scheme_1_run.html !! - subroutine unit_conv_scheme_1_run(data_array, data_array_opt, errmsg, errflg) + subroutine unit_conv_scheme_1_run(data_array, data_array2, data_array_opt, errmsg, errflg) character(len=*), intent(out) :: errmsg integer, intent(out) :: errflg real(kind_phys), intent(inout) :: data_array(:) + real(kind_phys), intent(inout) :: data_array2(:) real(kind_phys), intent(inout), optional :: data_array_opt(:) ! Initialize CCPP error handling variables @@ -31,11 +33,19 @@ subroutine unit_conv_scheme_1_run(data_array, data_array_opt, errmsg, errflg) ! Check values in data array write(error_unit,'(a,e12.4)') 'In unit_conv_scheme_1_run: checking min/max values of data array to be approximately ', target_value if (minval(data_array)<0.99*target_value .or. maxval(data_array)>1.01*target_value) then - write(errmsg,'(3(a,e12.4),a)') "Error in unit_conv_scheme_1_run, expected values of approximately ", & + write(errmsg,'(3(a,e12.4),a)') "Error in unit_conv_scheme_1_run, expected values for data_array of approximately ", & target_value, " but got [ ", minval(data_array), " : ", maxval(data_array), " ]" errflg = 1 return end if + ! Check values in data array2 + write(error_unit,'(a,e12.4)') 'In unit_conv_scheme_1_run: checking min/max values of data array 2 to be approximately ', target_value2 + if (minval(data_array2)<0.99*target_value2 .or. maxval(data_array2)>1.01*target_value2) then + write(errmsg,'(3(a,e12.4),a)') "Error in unit_conv_scheme_1_run, expected values for data array 2 of approximately ", & + target_value2, " but got [ ", minval(data_array2), " : ", maxval(data_array2), " ]" + errflg = 1 + return + end if ! Check for presence of optional data array, then check its values write(error_unit,'(a)') 'In unit_conv_scheme_1_run: checking for presence of optional data array' if (.not. present(data_array_opt)) then diff --git a/test_prebuild/test_unit_conv/unit_conv_scheme_1.meta b/test_prebuild/test_unit_conv/unit_conv_scheme_1.meta index 91f22142..befb19bd 100644 --- a/test_prebuild/test_unit_conv/unit_conv_scheme_1.meta +++ b/test_prebuild/test_unit_conv/unit_conv_scheme_1.meta @@ -30,6 +30,14 @@ type = real kind = kind_phys intent = inout +[data_array2] + standard_name = data_array2 + long_name = data array in J kg-1 + units = J kg-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = inout [data_array_opt] standard_name = data_array_opt long_name = optional data array in m diff --git a/test_prebuild/test_unit_conv/unit_conv_scheme_2.F90 b/test_prebuild/test_unit_conv/unit_conv_scheme_2.F90 index 6b64402c..66f07d93 100644 --- a/test_prebuild/test_unit_conv/unit_conv_scheme_2.F90 +++ b/test_prebuild/test_unit_conv/unit_conv_scheme_2.F90 @@ -13,16 +13,18 @@ module unit_conv_scheme_2 !! This is for unit testing only real(kind_phys), parameter :: target_value = 1.0E-3_kind_phys + real(kind_phys), parameter :: target_value2 = 42.0_kind_phys contains !! \section arg_table_unit_conv_scheme_2_run Argument Table !! \htmlinclude unit_conv_scheme_2_run.html !! - subroutine unit_conv_scheme_2_run(data_array, data_array_opt, errmsg, errflg) + subroutine unit_conv_scheme_2_run(data_array, data_array2, data_array_opt, errmsg, errflg) character(len=*), intent(out) :: errmsg integer, intent(out) :: errflg real(kind_phys), intent(inout) :: data_array(:) + real(kind_phys), intent(inout) :: data_array2(:) real(kind_phys), intent(inout), optional :: data_array_opt(:) ! Initialize CCPP error handling variables @@ -36,6 +38,14 @@ subroutine unit_conv_scheme_2_run(data_array, data_array_opt, errmsg, errflg) errflg = 1 return end if + ! Check values in data array2 + write(error_unit,'(a,e12.4)') 'In unit_conv_scheme_2_run: checking min/max values of data array 2 to be approximately ', target_value2 + if (minval(data_array2)<0.99*target_value2 .or. maxval(data_array2)>1.01*target_value2) then + write(errmsg,'(3(a,e12.4),a)') "Error in unit_conv_scheme_2_run, expected values for data array 2 of approximately ", & + target_value2, " but got [ ", minval(data_array2), " : ", maxval(data_array2), " ]" + errflg = 1 + return + end if ! Check for presence of optional data array, then check its values write(error_unit,'(a)') 'In unit_conv_scheme_2_run: checking for presence of optional data array' if (.not. present(data_array_opt)) then diff --git a/test_prebuild/test_unit_conv/unit_conv_scheme_2.meta b/test_prebuild/test_unit_conv/unit_conv_scheme_2.meta index 534e3abe..68e4b063 100644 --- a/test_prebuild/test_unit_conv/unit_conv_scheme_2.meta +++ b/test_prebuild/test_unit_conv/unit_conv_scheme_2.meta @@ -30,6 +30,14 @@ type = real kind = kind_phys intent = inout +[data_array2] + standard_name = data_array2 + long_name = data array in m+2 s-2 + units = m+2 s-2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = inout [data_array_opt] standard_name = data_array_opt long_name = optional data array in km From c0e9ca7140a3928a42f08c6d0e42ad3018c953f1 Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Mon, 14 Apr 2025 11:43:48 -0600 Subject: [PATCH 05/12] Update capgen unit conversion logic to handle identical units (m2 s-2 vs m+2 s-2) and equivalent units - skip any conversions --- scripts/conversion_tools/unit_conversion.py | 17 +++-- scripts/parse_tools/parse_checkers.py | 7 +- scripts/var_props.py | 78 +++++++++++++++++---- 3 files changed, 82 insertions(+), 20 deletions(-) diff --git a/scripts/conversion_tools/unit_conversion.py b/scripts/conversion_tools/unit_conversion.py index b809430f..7fbf41a2 100755 --- a/scripts/conversion_tools/unit_conversion.py +++ b/scripts/conversion_tools/unit_conversion.py @@ -177,13 +177,22 @@ def erg_cm_minus_2_s_minus_1__to__W_m_minus_2(): """Convert erg per square centimeter and second to Watt per square meter""" return '1.0E-3{kind}*{var}' -################## +#################### # Equivalent units # -################## -def m2_s_minus_2__to__J_kg_minus_1(): +#################### + +def m_plus_2_s_minus_2__to__J_kg_minus_1(): + """Equivalent units""" + return '{var}' + +def J_kg_minus_1__to__m_plus_2_s_minus_2(): + """Equivalent units""" + return '{var}' + +def V_A__to__W(): """Equivalent units""" return '{var}' -def J_kg_minus_1__to__m2_s_minus_2(): +def W__to__V_A(): """Equivalent units""" return '{var}' diff --git a/scripts/parse_tools/parse_checkers.py b/scripts/parse_tools/parse_checkers.py index 469bf1d0..5479f0a6 100755 --- a/scripts/parse_tools/parse_checkers.py +++ b/scripts/parse_tools/parse_checkers.py @@ -16,7 +16,8 @@ _NON_LEADING_ZERO_NUM = "[1-9]\d*" _CHAR_WITH_UNDERSCORE = "([a-zA-Z]+_[a-zA-Z]+)+" _NEGATIVE_NON_LEADING_ZERO_NUM = f"[-]{_NON_LEADING_ZERO_NUM}" -_UNIT_EXPONENT = f"({_NEGATIVE_NON_LEADING_ZERO_NUM}|{_NON_LEADING_ZERO_NUM})" +_POSITIVE_NON_LEADING_ZERO_NUM = f"[+]{_NON_LEADING_ZERO_NUM}" +_UNIT_EXPONENT = f"({_NEGATIVE_NON_LEADING_ZERO_NUM}|{_POSITIVE_NON_LEADING_ZERO_NUM}|{_NON_LEADING_ZERO_NUM})" _UNIT_REGEX = f"[a-zA-Z]+{_UNIT_EXPONENT}?" _UNITS_REGEX = f"^({_CHAR_WITH_UNDERSCORE}|{_UNIT_REGEX}(\s{_UNIT_REGEX})*|{_UNITLESS_REGEX})$" _UNITS_RE = re.compile(_UNITS_REGEX) @@ -29,6 +30,10 @@ def check_units(test_val, prop_dict, error): 'm s-1' >>> check_units('kg m-3', None, True) 'kg m-3' + >>> check_units('m2 s-2', None, True) + 'm2 s-2' + >>> check_units('m+2 s-2', None, True) + 'm+2 s-2' >>> check_units('1', None, True) '1' >>> check_units('', None, False) diff --git a/scripts/var_props.py b/scripts/var_props.py index d4adc338..b903df21 100755 --- a/scripts/var_props.py +++ b/scripts/var_props.py @@ -852,6 +852,20 @@ class VarCompatObj: "var_stdname", "real", "kind_phys", "km",['horizontal_dimension', 'vertical_layer_dimension'], "var2_lname", True, \ _DOCTEST_RUNENV).reverse_transform("var1_lname", "var2_lname", ('i','k'), ('i','nk-k+1')) 'var1_lname(i,nk-k+1) = 1.0E+3_kind_phys*var2_lname(i,k)' + + # Test that a 2-D var with equivalent units works and that it + # produces the correct forward transformation + >>> VarCompatObj("var_stdname", "real", "kind_phys", "m2 s-2", ['horizontal_dimension'], "var1_lname", False, \ + "var_stdname", "real", "kind_phys", "J kg-1", ['horizontal_dimension'], "var2_lname", False, \ + _DOCTEST_RUNENV).forward_transform("var1_lname", "var2_lname", 'i', 'i') + 'var1_lname(i) = var2_lname(i)' + + # Test that a 2-D var with identical units works and that it + # skips any unit transformations + >>> VarCompatObj("var_stdname", "real", "kind_phys", "m2 s-2", ['horizontal_dimension'], "var1_lname", False, \ + "var_stdname", "real", "kind_phys", "m+2 s-2", ['horizontal_dimension'], "var2_lname", False, \ + _DOCTEST_RUNENV).forward_transform("var1_lname", "var2_lname", 'i', 'i') + 'var1_lname(i) = var2_lname(i)' """ def __init__(self, var1_stdname, var1_type, var1_kind, var1_units, @@ -960,20 +974,27 @@ def __init__(self, var1_stdname, var1_type, var1_kind, var1_units, # A tendency variable's units should be " s-1" tendency_split_units = var1_units.split('s-1')[0].strip() if tendency_split_units != var2_units: - # We don't currently support unit conversions for tendency variables - emsg = f"\nMismatch tendency variable units '{var1_units}'" - emsg += f" for variable '{var1_stdname}'." - emsg += " No variable transforms supported for tendencies." - emsg += f" Tendency units should be '{var2_units} s-1' to match state variable." - self.__equiv = False - self.__compat = False - incompat_reason.append(emsg) + # We don't currently support unit conversions for tendency variables, + # but we can check if the units are identical or equivalent + unit_transforms = self._get_unit_convstrs(tendency_split_units, + var2_units) + if not unit_transforms == (None, None): + emsg = f"\nMismatch tendency variable units '{var1_units}'" + emsg += f" for variable '{var1_stdname}'." + emsg += " No variable transforms supported for tendencies." + emsg += f" Tendency units should be '{var2_units} s-1' to match state variable." + self.__equiv = False + self.__compat = False + incompat_reason.append(emsg) # end if elif var1_units != var2_units: # Try to find a set of unit conversions - self.__equiv = False - self.__unit_transforms = self._get_unit_convstrs(var1_units, - var2_units) + unit_transforms = self._get_unit_convstrs(var1_units, + var2_units) + # Handle equivalent or identical units = (None, None) + if not unit_transforms == (None, None): + self.__equiv = False + self.__unit_transforms = unit_transforms # end if # end if if self.__compat: @@ -1148,7 +1169,8 @@ def _get_kind_convstrs(self, var1_kind, var2_kind, run_env): def _get_unit_convstrs(self, var1_units, var2_units): """Attempt to retrieve the forward and reverse unit transformations for transforming a variable in to / from a variable in - . + . Return (None, None) if units are equivalent or identical + after parsing (this can happen when comparing m2 and m+2). # Initial setup >>> from parse_tools import init_log, set_log_to_null @@ -1177,6 +1199,14 @@ def _get_unit_convstrs(self, var1_units, var2_units): ('1.0E+3{kind}*{var}', '1.0E-3{kind}*{var}') >>> _DOCTEST_VCOMPAT._get_unit_convstrs('C', 'K') ('{var}+273.15{kind}', '{var}-273.15{kind}') + >>> _DOCTEST_VCOMPAT._get_unit_convstrs('V A', 'W') + (None, None) + >>> _DOCTEST_VCOMPAT._get_unit_convstrs('m2 s-2', 'J kg-1') + (None, None) + >>> _DOCTEST_VCOMPAT._get_unit_convstrs('m+2 s-2', 'J kg-1') + (None, None) + >>> _DOCTEST_VCOMPAT._get_unit_convstrs('m+2 s-2', 'm2 s-2') + (None, None) # Try an invalid conversion >>> _DOCTEST_VCOMPAT._get_unit_convstrs('1', 'none') #doctest: +ELLIPSIS @@ -1192,6 +1222,11 @@ def _get_unit_convstrs(self, var1_units, var2_units): """ u1_str = self.units_to_string(var1_units, self.__v1_context) u2_str = self.units_to_string(var2_units, self.__v2_context) + # If u1_str and u2_str are identical, for example after parsing + # "m2 s-2" and "m+2 s-2", return (None, None) to signal that + # the units are in fact identical + if u1_str == u2_str: + return (None, None) unit_conv_str = "{0}__to__{1}".format(u1_str, u2_str) try: forward_transform = getattr(unit_conversion, unit_conv_str)() @@ -1210,7 +1245,11 @@ def _get_unit_convstrs(self, var1_units, var2_units): self.__stdname, context=self.__v1_context)) # end if - return (forward_transform, reverse_transform) + # For equivalent units, return (None, None) + if forward_transform == '{var}' and reverse_transform == '{var}': + return (None, None) + else: + return (forward_transform, reverse_transform) def _get_dim_transforms(self, var1_dims, var2_dims): """Attempt to find forward and reverse permutations for transforming a @@ -1355,8 +1394,17 @@ def units_to_string(self, units, context=None): """Replace variable unit description with string that is a legal Python identifier. If the resulting string is a Python keyword, raise an exception.""" - # Replace each whitespace with an underscore - string = units.replace(" ","_") + # Start with breaking up the string by spaces + items = units.split() + # Identify units with positive exponents + # without a plus sign (m2 instead of m+2). + pattern = re.compile(r"([a-zA-Z]+)([0-9]+)") + for index, item in enumerate(items): + match = pattern.match(item) + if match: + items[index] = "+".join(match.groups()) + # Combine list into string using underscores + string = "_".join(items) # Replace each minus sign with '_minus_' string = string.replace("-","_minus_") # Replace each plus sign with '_plus_' From 017d2c4023a65cfd6305d8092db29cc1138e8e18 Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Mon, 14 Apr 2025 11:44:13 -0600 Subject: [PATCH 06/12] Update ccpp-prebuild unit conversion logic to handle identical units (m2 s-2 vs m+2 s-2) and equivalent units - skip any conversions --- scripts/common.py | 15 +++++++++++++++ scripts/metadata_parser.py | 10 +++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/scripts/common.py b/scripts/common.py index f5ba7f1d..9de8cb66 100755 --- a/scripts/common.py +++ b/scripts/common.py @@ -177,6 +177,21 @@ def isstring(s): """Return true if a variable is a string""" return isinstance(s, str) +def insert_plus_sign_for_positive_exponents(string): + """Parse a string (a unit string) and instert plus (+) signs + for positive exponents where needed""" + # Break up the string by spaces + items = string.split() + # Identify units with positive exponents + # without a plus sign (m2 instead of m+2). + pattern = re.compile(r"([a-zA-Z]+)([0-9]+)") + for index, item in enumerate(items): + match = pattern.match(item) + if match: + items[index] = "+".join(match.groups()) + # Recombine items to string + return " ".join(items) + def string_to_python_identifier(string): """Replaces forbidden characters in strings with standard substitutions so that the result is a valid Python object (variable, function) name. diff --git a/scripts/metadata_parser.py b/scripts/metadata_parser.py index d1277ebe..3f1ee852 100755 --- a/scripts/metadata_parser.py +++ b/scripts/metadata_parser.py @@ -10,6 +10,7 @@ from common import encode_container, CCPP_STAGES from common import CCPP_ERROR_CODE_VARIABLE, CCPP_ERROR_MSG_VARIABLE +from common import insert_plus_sign_for_positive_exponents from mkcap import Var sys.path.append(os.path.join(os.path.split(__file__)[0], 'fortran_tools')) @@ -230,9 +231,16 @@ def read_new_metadata(filename, module_name, table_name, scheme_name = None, sub #kind = new_var.get_prop_value('kind') # *DH 20210812 + # DH* 20250414 + # Workaround to support units with positive exponents with + # and without a plus (+) sign. Internally, we convert all + # units from capgen to the "+"-format (i.e. "m2 s-2" --> "m+2 s-2") + units = insert_plus_sign_for_positive_exponents(new_var.get_prop_value('units')) + # *DH 20250414 + var = Var(standard_name = standard_name, long_name = new_var.get_prop_value('long_name') + legacy_note, - units = new_var.get_prop_value('units'), + units = units, local_name = new_var.get_prop_value('local_name'), type = new_var.get_prop_value('type').lower(), dimensions = dimensions, From 4849a32b72956490e4dc9ab24ff210815f1b292e Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Mon, 14 Apr 2025 13:35:06 -0600 Subject: [PATCH 07/12] Update capgen unit tests for unit conversions --- test/unit_tests/test_var_transforms.py | 30 +++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/test/unit_tests/test_var_transforms.py b/test/unit_tests/test_var_transforms.py index d0b5800e..7a2592b3 100755 --- a/test/unit_tests/test_var_transforms.py +++ b/test/unit_tests/test_var_transforms.py @@ -428,27 +428,47 @@ def test_compatible_tendency_variable(self): self.assertFalse(compat.has_dim_transforms) self.assertFalse(compat.has_unit_transforms) + def test_compatible_tendency_variable_equivalent_units(self): + """Test that a given tendency variable is compatible with + its corresponding state variable""" + real_array1 = self._new_var('real_stdname1', 'V A', + ['horizontal_dimension', + 'vertical_layer_dimension'], + 'real', vkind='kind_phys') + real_array2 = self._new_var('tendency_of_real_stdname1', 'W s-1', + ['horizontal_dimension', + 'vertical_layer_dimension'], + 'real', vkind='kind_phys') + compat = real_array2.compatible(real_array1, self.__run_env, is_tend=True) + self.assertIsInstance(compat, VarCompatObj, + msg=self.__inst_emsg.format(type(compat))) + self.assertTrue(compat) + self.assertTrue(compat.compat) + self.assertEqual(compat.incompat_reason, '') + self.assertFalse(compat.has_kind_transforms) + self.assertFalse(compat.has_dim_transforms) + self.assertFalse(compat.has_unit_transforms) + def test_incompatible_tendency_variable(self): """Test that the correct error is returned when a given tendency variable has inconsistent units vs the state variable""" - real_array1 = self._new_var('real_stdname1', 'C', + real_array1 = self._new_var('real_stdname1', 'm', ['horizontal_dimension', 'vertical_layer_dimension'], 'real', vkind='kind_phys') - real_array2 = self._new_var('tendency_of_real_stdname1', 'C kg s-1', + real_array2 = self._new_var('tendency_of_real_stdname1', 'cm s-1', ['horizontal_dimension', 'vertical_layer_dimension'], 'real', vkind='kind_phys') compat = real_array2.compatible(real_array1, self.__run_env, is_tend=True) self.assertIsInstance(compat, VarCompatObj, msg=self.__inst_emsg.format(type(compat))) - #Verify correct error message returned - emsg = "\nMismatch tendency variable units 'C kg s-1' for variable 'tendency_of_real_stdname1'. No variable transforms supported for tendencies. Tendency units should be 'C s-1' to match state variable." + # Verify correct error message returned + emsg = "\nMismatch tendency variable units 'cm s-1' for variable 'tendency_of_real_stdname1'. No variable transforms supported for tendencies. Tendency units should be 'm s-1' to match state variable." self.assertEqual(compat.incompat_reason, emsg) self.assertFalse(compat.has_kind_transforms) self.assertFalse(compat.has_dim_transforms) self.assertFalse(compat.has_unit_transforms) - #Verify correct error message returned if __name__ == "__main__": From 5338b392280698c5082572a396a9901d7a36977f Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Mon, 14 Apr 2025 14:38:46 -0600 Subject: [PATCH 08/12] Update scripts/var_props.py --- scripts/var_props.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/var_props.py b/scripts/var_props.py index b903df21..52800ba4 100755 --- a/scripts/var_props.py +++ b/scripts/var_props.py @@ -854,7 +854,7 @@ class VarCompatObj: 'var1_lname(i,nk-k+1) = 1.0E+3_kind_phys*var2_lname(i,k)' # Test that a 2-D var with equivalent units works and that it - # produces the correct forward transformation + # skips any unit transformations >>> VarCompatObj("var_stdname", "real", "kind_phys", "m2 s-2", ['horizontal_dimension'], "var1_lname", False, \ "var_stdname", "real", "kind_phys", "J kg-1", ['horizontal_dimension'], "var2_lname", False, \ _DOCTEST_RUNENV).forward_transform("var1_lname", "var2_lname", 'i', 'i') From db6b33c5fa4362f0a0e7ec33236a5ce2e920923c Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Mon, 14 Apr 2025 14:38:52 -0600 Subject: [PATCH 09/12] Update test/var_compatibility_test/test_host_mod.F90 --- test/var_compatibility_test/test_host_mod.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/test/var_compatibility_test/test_host_mod.F90 b/test/var_compatibility_test/test_host_mod.F90 index 06ee034c..e287009b 100644 --- a/test/var_compatibility_test/test_host_mod.F90 +++ b/test/var_compatibility_test/test_host_mod.F90 @@ -41,6 +41,7 @@ subroutine init_data() phys_state%nci = 80 endif phys_state%tke = 10.0 !J kg-1 + phys_state%tke2 = 42.0 !J kg-1 end subroutine init_data From 5a0c53cf4f4d3db30a76cbe06a19b0ea1905153c Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Fri, 18 Apr 2025 16:53:03 +0000 Subject: [PATCH 10/12] Check that equivalent units did change the answer. --- test/var_compatibility_test/test_host_mod.F90 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/var_compatibility_test/test_host_mod.F90 b/test/var_compatibility_test/test_host_mod.F90 index e287009b..5cd4846a 100644 --- a/test/var_compatibility_test/test_host_mod.F90 +++ b/test/var_compatibility_test/test_host_mod.F90 @@ -52,6 +52,7 @@ logical function compare_data() real(kind_phys), parameter :: effri_expected = 7.5E-5 ! 75 microns, in meter real(kind_phys), parameter :: effrs_expected = 5.1E-4 ! 510 microns, in meter real(kind_phys), parameter :: scalar_expected = 2.0E3 ! 2 km, in meter + real(kind_phys), parameter :: tke_expected = 10.0 ! 10 J kg-1 real(kind_phys), parameter :: tolerance = 1.0E-6 ! used as scaling factor for expected value compare_data = .true. @@ -86,6 +87,11 @@ logical function compare_data() compare_data = .false. end if + if (abs( phys_state%tke - tke_expected) > tolerance*tke_expected) then + write(6, '(a,e16.7,a,e16.7)') 'Error: max diff of tke from expected value exceeds tolerance: ', & + abs( phys_state%tke - tke_expected), ' > ', tolerance*tke_expected + compare_data = .false. + end if end function compare_data end module test_host_mod From f6edd8dec2f9eecd9ccb5b83b5dd6be8f5c447de Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Tue, 29 Apr 2025 07:38:29 -0600 Subject: [PATCH 11/12] Update scripts/common.py Co-authored-by: Michael Kavulich --- scripts/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/common.py b/scripts/common.py index 2b88907c..84520222 100755 --- a/scripts/common.py +++ b/scripts/common.py @@ -149,7 +149,7 @@ def isstring(s): return isinstance(s, str) def insert_plus_sign_for_positive_exponents(string): - """Parse a string (a unit string) and instert plus (+) signs + """Parse a string (a unit string) and insert plus (+) signs for positive exponents where needed""" # Break up the string by spaces items = string.split() From 365f3b9a2b4bb5911eec9c64bafd94b9777c3668 Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Tue, 29 Apr 2025 07:39:06 -0600 Subject: [PATCH 12/12] Update scripts/metadata_parser.py Co-authored-by: Michael Kavulich --- scripts/metadata_parser.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/metadata_parser.py b/scripts/metadata_parser.py index 3f1ee852..e8c3f987 100755 --- a/scripts/metadata_parser.py +++ b/scripts/metadata_parser.py @@ -231,12 +231,10 @@ def read_new_metadata(filename, module_name, table_name, scheme_name = None, sub #kind = new_var.get_prop_value('kind') # *DH 20210812 - # DH* 20250414 # Workaround to support units with positive exponents with # and without a plus (+) sign. Internally, we convert all # units from capgen to the "+"-format (i.e. "m2 s-2" --> "m+2 s-2") units = insert_plus_sign_for_positive_exponents(new_var.get_prop_value('units')) - # *DH 20250414 var = Var(standard_name = standard_name, long_name = new_var.get_prop_value('long_name') + legacy_note,