Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/data/generate_registry_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -1405,6 +1405,15 @@ def write_allocate_routine(self, outfile, physconst_vars, var_module_dict):
#then this section of code will likely need to be modified:
if ('number_of_ccpp_constituents' in self.__var_dict.known_dimensions):
outfile.write("use cam_constituents, only: number_of_ccpp_constituents=>num_constituents", 2)

# Collect self-referential dimensions (defined in this module)
self_ref_dims = []
for dim in sorted(self.__var_dict.known_dimensions):
if dim not in var_module_dict and dim != 'number_of_ccpp_constituents':
var = self.__var_dict.find_variable_by_standard_name(dim)
if var and var.local_name != dim:
self_ref_dims.append((dim, var.local_name))

outfile.blank_line()

# Dummy arguments
Expand All @@ -1425,6 +1434,8 @@ def write_allocate_routine(self, outfile, physconst_vars, var_module_dict):
outfile.write(f'logical :: {reall_var}', 2)
subn_str = f'character(len=*), parameter :: subname = "{subname}"'
outfile.write(subn_str, 2)
for dim_std, _ in self_ref_dims:
outfile.write(f'integer :: {dim_std}', 2)
outfile.write('', 0)
outfile.write('! Set optional argument values', 2)
outfile.write(f'if (present({init_var}_in)) then', 2)
Expand All @@ -1437,6 +1448,11 @@ def write_allocate_routine(self, outfile, physconst_vars, var_module_dict):
outfile.write('else', 2)
outfile.write(f'{reall_var} = .false.', 3)
outfile.write('end if', 2)
if self_ref_dims:
outfile.blank_line()
outfile.write('! Set self-referential dimension variables', 2)
for dim_std, dim_loc in self_ref_dims:
outfile.write(f'{dim_std} = {dim_loc}', 2)
outfile.write('', 0)
for var in self.__var_dict.variable_list():
var.write_allocate_routine(outfile, 2, init_var, reall_var, '', physconst_vars)
Expand Down
54 changes: 54 additions & 0 deletions src/data/registry.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1491,6 +1491,18 @@
<ic_file_input_names>pbuf_VPWP_CLUBB_GW</ic_file_input_names>
</variable>

<!-- Aerosol model properties -->
<variable local_name="ndust"
standard_name="dust_size_bin_dimension"
units="count" type="integer">
<long_name>number of dust size bins used in aerosol model</long_name>
<initial_value>4</initial_value>
<!-- this is not runtime configurable, and
not even easily compile-time configurable, because the assumption that
there are four dust bins is deeply embedded in the microphysics and
coupling to the land model (see dstdry1/2/3/4, dstwet1/2/3/4) -->
</variable>

<!-- Gravity wave variables - need to be kept in the CAM registry -->
<variable local_name="kvt"
standard_name="molecular_kinematic_temperature_conductivity_at_interfaces"
Expand Down Expand Up @@ -1707,6 +1719,48 @@
<ic_file_input_names>dust4 pbuf_dust4 cnst_dust4</ic_file_input_names>
</variable>

<!-- Aerosol nucleation/activation data into microphysics -->
<variable local_name="naai"
standard_name="tendency_of_number_concentration_of_activated_ice_nuclei"
units="kg-1 s-1" type="real" kind="kind_phys"
allocatable="allocatable">
<dimensions>horizontal_dimension vertical_layer_dimension</dimensions>
<initial_value>0.0_kind_phys</initial_value>
<ic_file_input_names>pbuf_NAAI</ic_file_input_names>
</variable>
<variable local_name="naai_hom"
standard_name="tendency_of_number_concentration_of_activated_ice_nuclei_due_to_homogenous_freezing"
units="kg-1 s-1" type="real" kind="kind_phys"
allocatable="allocatable">
<dimensions>horizontal_dimension vertical_layer_dimension</dimensions>
<initial_value>0.0_kind_phys</initial_value>
<ic_file_input_names>pbuf_NAAI_HOM</ic_file_input_names>
</variable>
<variable local_name="npccn"
standard_name="tendency_of_activated_cloud_condensation_nuclei_mass_number_concentration"
units="kg-1 s-1" type="real" kind="kind_phys"
allocatable="allocatable">
<dimensions>horizontal_dimension vertical_layer_dimension</dimensions>
<initial_value>0.0_kind_phys</initial_value>
<ic_file_input_names>pbuf_NPCCN</ic_file_input_names>
</variable>
<variable local_name="nacon"
standard_name="dust_number_concentration_by_size_bin_for_contact_freezing"
units="m-3" type="real" kind="kind_phys"
allocatable="allocatable">
<dimensions>horizontal_dimension vertical_layer_dimension dust_size_bin_dimension</dimensions>
<initial_value>0.0_kind_phys</initial_value>
<ic_file_input_names>pbuf_NACON</ic_file_input_names>
</variable>
<variable local_name="rndst"
standard_name="dust_radii_by_size_bin"
units="m" type="real" kind="kind_phys"
allocatable="allocatable">
<dimensions>horizontal_dimension vertical_layer_dimension dust_size_bin_dimension</dimensions>
<initial_value>0.0_kind_phys</initial_value>
<ic_file_input_names>pbuf_RNDST</ic_file_input_names>
</variable>

<!-- Zhang McFarlane (ZM) Variables -->
<variable local_name="ql"
standard_name="in_cloud_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water_due_to_deep_convection"
Expand Down
4 changes: 4 additions & 0 deletions test/unit/python/sample_files/physics_types_parameter.F90
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ subroutine allocate_physics_types_parameter_fields(set_init_val_in, reallocate_i
logical :: set_init_val
logical :: reallocate
character(len=*), parameter :: subname = "allocate_physics_types_parameter_fields"
integer :: horizontal_dimension

! Set optional argument values
if (present(set_init_val_in)) then
Expand All @@ -65,6 +66,9 @@ subroutine allocate_physics_types_parameter_fields(set_init_val_in, reallocate_i
reallocate = .false.
end if

! Set self-referential dimension variables
horizontal_dimension = ncol

if (set_init_val) then
ncol = 0
end if
Expand Down
105 changes: 105 additions & 0 deletions test/unit/python/sample_files/physics_types_self_ref_dim.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
!
! This work (Common Community Physics Package Framework), identified by
! NOAA, NCAR, CU/CIRES, is free of known copyright restrictions and is
! placed in the public domain.
!
! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
! THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
! IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
! CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

!>
!! @brief Auto-generated Variables for registry source file, physics_types_self_ref_dim
!!
!
module physics_types_self_ref_dim

use ccpp_kinds, only: kind_phys


implicit none
private

!> \section arg_table_physics_types_self_ref_dim Argument Table
!! \htmlinclude physics_types_self_ref_dim.html
! ncol: Number of horizontal columns
integer, public, protected :: ncol = 0
! pver: Number of vertical layers
integer, public, protected :: pver = 0
! ndust: Number of dust size bins
integer, public :: ndust = 4
! rndst: Dust radii by size bin
real(kind_phys), public, allocatable :: rndst(:, :, :)

!! public interfaces
public :: allocate_physics_types_self_ref_dim_fields
public :: physics_types_self_ref_dim_tstep_init

contains

subroutine allocate_physics_types_self_ref_dim_fields(set_init_val_in, reallocate_in)
use shr_infnan_mod, only: nan => shr_infnan_nan, assignment(=)
use cam_abortutils, only: endrun


!! Dummy arguments
logical, optional, intent(in) :: set_init_val_in
logical, optional, intent(in) :: reallocate_in

!! Local variables
logical :: set_init_val
logical :: reallocate
character(len=*), parameter :: subname = "allocate_physics_types_self_ref_dim_fields"
integer :: dust_size_bin_dimension
integer :: horizontal_dimension
integer :: vertical_layer_dimension

! Set optional argument values
if (present(set_init_val_in)) then
set_init_val = set_init_val_in
else
set_init_val = .true.
end if
if (present(reallocate_in)) then
reallocate = reallocate_in
else
reallocate = .false.
end if

! Set self-referential dimension variables
dust_size_bin_dimension = ndust
horizontal_dimension = ncol
vertical_layer_dimension = pver

if (set_init_val) then
ncol = 0
end if
if (set_init_val) then
pver = 0
end if
if (set_init_val) then
ndust = 4
end if
if (allocated(rndst)) then
if (reallocate) then
deallocate(rndst)
else
call endrun(subname//": rndst is already allocated, cannot allocate")
end if
end if
allocate(rndst(horizontal_dimension, vertical_layer_dimension, dust_size_bin_dimension))
if (set_init_val) then
rndst = 0.0_kind_phys
end if
end subroutine allocate_physics_types_self_ref_dim_fields

subroutine physics_types_self_ref_dim_tstep_init()

!! Local variables
character(len=*), parameter :: subname = "physics_types_self_ref_dim_tstep_init"

end subroutine physics_types_self_ref_dim_tstep_init

end module physics_types_self_ref_dim
31 changes: 31 additions & 0 deletions test/unit/python/sample_files/physics_types_self_ref_dim.meta
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[ccpp-table-properties]
name = physics_types_self_ref_dim
type = module
[ccpp-arg-table]
name = physics_types_self_ref_dim
type = module
[ ncol ]
standard_name = horizontal_dimension
long_name = Number of horizontal columns
units = count
type = integer
dimensions = ()
protected = True
[ pver ]
standard_name = vertical_layer_dimension
long_name = Number of vertical layers
units = count
type = integer
dimensions = ()
protected = True
[ ndust ]
standard_name = dust_size_bin_dimension
long_name = Number of dust size bins
units = count
type = integer
dimensions = ()
[ rndst ]
standard_name = dust_radii_by_size_bin
units = m
type = real | kind = kind_phys
dimensions = (horizontal_dimension, vertical_layer_dimension, dust_size_bin_dimension)
4 changes: 4 additions & 0 deletions test/unit/python/sample_files/physics_types_simple.F90
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ subroutine allocate_physics_types_simple_fields(set_init_val_in, reallocate_in)
logical :: set_init_val
logical :: reallocate
character(len=*), parameter :: subname = "allocate_physics_types_simple_fields"
integer :: horizontal_dimension

! Set optional argument values
if (present(set_init_val_in)) then
Expand All @@ -63,6 +64,9 @@ subroutine allocate_physics_types_simple_fields(set_init_val_in, reallocate_in)
reallocate = .false.
end if

! Set self-referential dimension variables
horizontal_dimension = ncol

if (set_init_val) then
ncol = 0
end if
Expand Down
27 changes: 27 additions & 0 deletions test/unit/python/sample_files/reg_good_self_ref_dim.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>

<registry name="cam_registry" version="1.0">
<file name="physics_types_self_ref_dim" type="module">
<use module="ccpp_kinds" reference="kind_phys"/>
<variable local_name="ncol" standard_name="horizontal_dimension"
units="count" type="integer" access="protected">
<long_name>Number of horizontal columns</long_name>
<initial_value>0</initial_value>
</variable>
<variable local_name="pver" standard_name="vertical_layer_dimension"
units="count" type="integer" access="protected">
<long_name>Number of vertical layers</long_name>
<initial_value>0</initial_value>
</variable>
<variable local_name="ndust" standard_name="dust_size_bin_dimension"
units="count" type="integer">
<long_name>Number of dust size bins</long_name>
<initial_value>4</initial_value>
</variable>
<variable local_name="rndst" standard_name="dust_radii_by_size_bin"
units="m" type="real" kind="kind_phys" allocatable="allocatable">
<dimensions>horizontal_dimension vertical_layer_dimension dust_size_bin_dimension</dimensions>
<initial_value>0.0_kind_phys</initial_value>
</variable>
</file>
</registry>
35 changes: 35 additions & 0 deletions test/unit/python/test_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,41 @@ def test_good_complete_registry(self):
amsg = f"Expected 14 metadata variables, found {num_vars}"
self.assertEqual(num_vars, 14, msg=amsg)

def test_good_self_ref_dim_registry(self):
"""Test that a registry with self-referential dimensions
(dimensions defined as variables in the same module) generates
correct local aliases in the allocate subroutine."""
# Setup test
filename = os.path.join(_SAMPLE_FILES_DIR, "reg_good_self_ref_dim.xml")
out_source_name = "physics_types_self_ref_dim"
in_source = os.path.join(_SAMPLE_FILES_DIR, out_source_name + '.F90')
in_meta = os.path.join(_SAMPLE_FILES_DIR, out_source_name + '.meta')
out_source = os.path.join(_TMP_DIR, out_source_name + '.F90')
out_meta = os.path.join(_TMP_DIR, out_source_name + '.meta')
remove_files([out_source, out_meta])
# Run test
retcode, files, _, _, _ = gen_registry(filename, 'fv', _TMP_DIR, 2,
_SRC_MOD_DIR, _CAM_ROOT,
loglevel=logging.ERROR,
error_on_no_validate=True)
# Check return code
amsg = f"Test failure: retcode={retcode}"
self.assertEqual(retcode, 0, msg=amsg)
flen = len(files)
amsg = f"Test failure: Found {flen} files, expected 1"
self.assertEqual(flen, 1, msg=amsg)
# Make sure each output file was created
amsg = f"{out_meta} does not exist"
self.assertTrue(os.path.exists(out_meta), msg=amsg)
amsg = f"{out_source} does not exist"
self.assertTrue(os.path.exists(out_source), msg=amsg)
# For each output file, make sure it matches input file
amsg = f"{out_meta} does not match {in_meta}"
self.assertTrue(filecmp.cmp(out_meta, in_meta, shallow=False), msg=amsg)
amsg = f"{out_source} does not match {in_source}"
self.assertTrue(filecmp.cmp(out_source, in_source, shallow=False),
msg=amsg)

def test_no_metadata_file_registry(self):
"""Test code and metadata generation from a good registry with
a non-existent metadata file.
Expand Down
Loading