Skip to content

Commit

Permalink
Address review comments and suggestions.
Browse files Browse the repository at this point in the history
  • Loading branch information
nusbaume committed Aug 26, 2021
1 parent 2c5891f commit 1e56860
Show file tree
Hide file tree
Showing 45 changed files with 1,153 additions and 570 deletions.
12 changes: 5 additions & 7 deletions cime_config/buildlib
Original file line number Diff line number Diff line change
Expand Up @@ -104,19 +104,17 @@ def _build_cam():
# End for

# Add dynamics source code directories:
for direc in config.get_value("dyn_src_dirs").split(","):
dyn_dir = os.path.join(atm_root, "src", "dynamics")
for subdir in direc.split("/"):
dyn_dir = os.path.join(dyn_dir, subdir)
for direc in config.get_value("dyn_src_dirs"):
dyn_dir = os.path.join(atm_root, "src", "dynamics", direc)
if dyn_dir not in paths:
#Add to list of filepaths if not already present:
if dyn_dir not in paths:
paths.append(dyn_dir)
paths.append(dyn_dir)

# Add analytical IC source code directories:
paths.append(os.path.join(atm_root, "src", "dynamics", "tests")) #Required due to namelist call.
if dycore != "none":
paths.append(os.path.join(atm_root, "src", "dynamics", "tests",
"initial_conditions"))
"initial_conditions"))

# If using the CMEPS/NUOPC coupler, then add additional path:
if case.get_value("COMP_INTERFACE") == "nuopc":
Expand Down
2 changes: 1 addition & 1 deletion cime_config/buildnml
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ def buildnml(case, caseroot, compname):
nmlgen.init_defaults(namelist_infile_list, cam_nml_dict,
skip_default_for_groups=\
filter(lambda group: group !='vert_coord_nl',
config.nml_groups))
config.nml_groups))

#--------------------------------------------
# Set "nlev" namelist attribute to equal pver
Expand Down
4 changes: 2 additions & 2 deletions cime_config/cam_autogen.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,9 +469,9 @@ def generate_physics_suites(ccpp_scripts_path, build_cache, preproc_defs, host_n

# Convert preproc defs to string:
if preproc_defs:
preproc_cache_str = ', '.join(preproc_defs)
preproc_cache_str = ', '.join(preproc_defs)
else:
preproc_cache_str = 'UNSET'
preproc_cache_str = 'UNSET'

if os.path.exists(genccpp_dir):
do_gen_ccpp = force or build_cache.ccpp_mismatch(sdfs, scheme_files,
Expand Down
236 changes: 212 additions & 24 deletions cime_config/cam_config.py

Large diffs are not rendered by default.

59 changes: 44 additions & 15 deletions cime_config/namelist_definition_cam.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7222,6 +7222,7 @@
<values>
<value>30</value>
<value phys_suite="cam4">26</value>
<value phys_suite="cam5">30</value>
<value phys_suite="cam6">32</value>
</values>
</entry>
Expand Down Expand Up @@ -10781,7 +10782,7 @@
<!-- Dycore air composition -->

<entry id="dry_air_species">
<type>char*6(20)</type>
<type>char*80(20)</type>
<category>physconst</category>
<group>air_composition_nl</group>
<desc>
Expand All @@ -10790,33 +10791,61 @@
dry air are constant. If set then the list of major species is assumed to
have 'N2' listed last. This information is currently used only for
computing the variable properties of air in WACCM-X configurations.
Default: ['O', 'O2', 'H', 'N2'] if WACCM-X, otherwise None.
Default if WACCM-X:

['O_mixing_ratio_wrt_dry_air', 'O2_mixing_ratio_wrt_dry_air',
'H_mixing_ratio_wrt_dry_air', 'N2_mixing_ratio_wrt_dry_air']

Otherwise default is None.
</desc>
<values>
<value>""</value>
<value waccmx="1">O, O2, H, N2</value>
<value waccmx="1">
O_mixing_ratio_wrt_dry_air, O2_mixing_ratio_wrt_dry_air, H_mixing_ratio_wrt_dry_air, N2_mixing_ratio_wrt_dry_air
</value>
</values>
</entry>

<entry id="water_species_in_air">
<type>char*6(20)</type>
<type>char*80(20)</type>
<category>physconst</category>
<group>air_composition_nl</group>
<desc>
List of water species that are included in "moist" air. This is currently
used only by the SE dycore to generalize the computation of the moist air
mass and thermodynamic properties.
Default:
['Q','CLDLIQ','RAINQM'] if CAM4, CAM5, or Kessler physics is used.
['Q','CLDLIQ','CLDICE','RAINQM','SNOWQM'] if CAM6 physics is used.
['Q'] for all other physics choices.
</desc>
<values>
<value>Q</value>
<value phys_suite="kessler">Q, CLDLIQ, RAINQM</value>
<value phys_suite="cam4">Q, CLDLIQ, RAINQM</value>
<value phys_suite="cam5">Q, CLDLIQ, RAINQM</value>
<value phys_suite="cam6">Q, CLDLIQ, CLDICE, RAINQM, SNOWQM</value>
Default if CAM4, CAM5, or Kessler physics is used:

['specific_humidity',
'cloud_liquid_water_mixing_ratio_wrt_dry_air',
'rain_mixing_ratio_wrt_dry_air']

Default if CAM6 physics is used:

['specific_humidity',
'cloud_liquid_water_mixing_ratio_wrt_dry_air',
'cloud_ice_mixing_ratio_wrt_dry_air',
'rain_mixing_ratio_wrt_dry_air',
'snow_mixing_ratio_wrt_dry_air']

Otherwise default is: ['specific_humidity']
</desc>
<values>
<value>
specific_humidity
</value>
<value phys_suite="kessler">
specific_humidity, cloud_liquid_water_mixing_ratio_wrt_dry_air, rain_mixing_ratio_wrt_dry_air
</value>
<value phys_suite="cam4">
specific_humidity, cloud_liquid_water_mixing_ratio_wrt_dry_air, rain_mixing_ratio_wrt_dry_air
</value>
<value phys_suite="cam5">
specific_humidity, cloud_liquid_water_mixing_ratio_wrt_dry_air, rain_mixing_ratio_wrt_dry_air
</value>
<value phys_suite="cam6">
specific_humidity, cloud_liquid_water_mixing_ratio_wrt_dry_air, cloud_ice_mixing_ratio_wrt_dry_air, rain_mixing_ratio_wrt_dry_air, rain_mixing_ratio_wrt_dry_air
</value>
</values>
</entry>

Expand Down
128 changes: 116 additions & 12 deletions src/data/generate_registry_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ class VarBase:
def __init__(self, elem_node, local_name, dimensions, known_types,
type_default, units_default="", kind_default='',
protected=False, index_name='', local_index_name='',
local_index_name_str='', alloc_default='none'):
local_index_name_str='', alloc_default='none',
tstep_init_default=False):
self.__local_name = local_name
self.__dimensions = dimensions
self.__units = elem_node.get('units', default=units_default)
Expand All @@ -157,6 +158,8 @@ def __init__(self, elem_node, local_name, dimensions, known_types,
self.__local_index_name = local_index_name
self.__local_index_name_str = local_index_name_str
self.__allocatable = elem_node.get('allocatable', default=alloc_default)
self.__tstep_init = elem_node.get("phys_timestep_init_zero",
default=tstep_init_default)
if self.__allocatable == "none":
self.__allocatable = ""
# end if
Expand Down Expand Up @@ -188,6 +191,11 @@ def __init__(self, elem_node, local_name, dimensions, known_types,
# end if
# pylint: enable=bad-continuation

if self.__tstep_init == "true":
self.__tstep_init = True
elif self.__tstep_init == "false":
self.__tstep_init = False

def write_metadata(self, outfile):
"""Write out this variable as CCPP metadata"""
outfile.write('[ {} ]\n'.format(self.local_name))
Expand All @@ -207,7 +215,8 @@ def write_metadata(self, outfile):
outfile.write(' {} = {}\n'.format('dimensions',
self.dimension_string))

def write_initial_value(self, outfile, indent, init_var, ddt_str):
def write_initial_value(self, outfile, indent, init_var, ddt_str,
tstep_init=False):
"""Write the code for the initial value of this variable
and/or one of its array elements."""
#Check if variable has associated array index
Expand Down Expand Up @@ -240,11 +249,18 @@ def write_initial_value(self, outfile, indent, init_var, ddt_str):
init_val = ''
# end if
# end if
if init_val:
#Time-step initialization, which is always zero:
if tstep_init:
if self.kind:
outfile.write("{} = 0._{}".format(var_name, self.kind), indent)
else:
#Assume variable is an integer:
outfile.write("{} = 0".format(var_name), indent)
# end if
elif init_val:
outfile.write("if ({}) then".format(init_var), indent)
outfile.write("{} = {}".format(var_name, init_val), indent+1)
outfile.write("end if", indent)
# end if
# end if

@property
Expand Down Expand Up @@ -340,13 +356,19 @@ def is_ddt(self):
"""Return True iff this variable is a derived type"""
return self.__type.ddt

@property
def tstep_init(self):
"""Return True if variable will be set to zero every physics timestep."""
return self.__tstep_init

###############################################################################
class ArrayElement(VarBase):
###############################################################################
"""Documented array element of a registry Variable"""

def __init__(self, elem_node, parent_name, dimensions, known_types,
parent_type, parent_kind, parent_units, parent_alloc, vdict):
parent_type, parent_kind, parent_units, parent_alloc,
parent_tstep_init, vdict):
"""Initialize the Arary Element information by identifying its
metadata properties
"""
Expand Down Expand Up @@ -401,7 +423,8 @@ def __init__(self, elem_node, parent_name, dimensions, known_types,
index_name=index_name,
local_index_name=local_index_name,
local_index_name_str=local_index_name_str,
alloc_default=parent_alloc)
alloc_default=parent_alloc,
tstep_init_default=parent_tstep_init)

@property
def index_string(self):
Expand Down Expand Up @@ -438,7 +461,7 @@ class Variable(VarBase):

__VAR_ATTRIBUTES = ["access", "allocatable", "dycore", "extends",
"kind", "local_name", "name", "standard_name",
"type", "units", "version"]
"type", "units", "version", "phys_timestep_init_zero"]

def __init__(self, var_node, known_types, vdict, logger):
# pylint: disable=too-many-locals
Expand Down Expand Up @@ -526,7 +549,7 @@ def __init__(self, var_node, known_types, vdict, logger):
my_dimensions, known_types,
ttype, self.kind,
self.units, allocatable,
vdict))
self.tstep_init, vdict))

# end if (all other processing done above)
# end for
Expand Down Expand Up @@ -642,7 +665,6 @@ def write_allocate_routine(self, outfile, indent,
<init_var> is a string to use to write initialization test code.
<reall_var> is a string to use to write reallocate test code.
<ddt_str> is a prefix string (e.g., state%).
<known_types> is a TypeRegistry.
"""
# Be careful about dimensions, scalars have none, not '()'
if self.dimensions:
Expand Down Expand Up @@ -700,6 +722,61 @@ def write_allocate_routine(self, outfile, indent,
# end for
# end if

def write_tstep_init_routine(self, outfile, indent,
ddt_str, init_val=False):
"""
Write the code to iniitialize this variable to zero at the
start of each physics timestep.
<ddt_str> is a prefix string (e.g., state%).
<init_val> is an optional variable that forces the writing
of the variable initiliazation code even if not
directly specified in the registry itself.
"""

# Be careful about dimensions, scalars have none, not '()'
if self.dimensions:
dimension_string = self.dimension_string
else:
dimension_string = ''
# end if
my_ddt = self.is_ddt
if my_ddt: # This is a DDT object, allocate entries

subi = indent
sub_ddt_str = '{}{}%'.format(ddt_str, self.local_name)
if dimension_string:
emsg = "Arrays of DDT objects not implemented"
raise ParseInternalError(emsg)
# end if
for var in my_ddt.variable_list():
var.write_tstep_init_routine(outfile, subi, sub_ddt_str,
init_val=self.tstep_init)
else:

# Do nothing if a parameter
if self.allocatable == "parameter":
return

# Check if variable should be initialized:
if init_val or self.tstep_init:
# Set variables needed for writing source code
if self.long_name:
comment = ' ! ' + self.local_name + ": " + self.long_name
else:
comment = (' ! ' + self.local_name + ": " +
convert_to_long_name(self.standard_name))

# Write source code
outfile.write("", 0)
outfile.write(comment, indent)

# Initialize the variable:
self.write_initial_value(outfile, indent, "", ddt_str,
tstep_init=True)

# end if

@classmethod
def constant_dimension(cls, dim):
"""Return dimension value if <dim> is a constant dimension, else None"""
Expand Down Expand Up @@ -1180,17 +1257,25 @@ def write_source(self, outdir, indent, logger):
outfile.write('!! public interfaces', 0)
outfile.write('public :: {}'.format(self.allocate_routine_name()),
1)
outfile.write('public :: {}'.format(self.tstep_init_routine_name()),
1)
# end of module header
outfile.end_module_header()
outfile.write("", 0)
# Write data management subroutines
self.write_allocate_routine(outfile)
self.write_tstep_init_routine(outfile)

# end with

def allocate_routine_name(self):
"""Return the name of the allocate routine for this module"""
return 'allocate_{}_fields'.format(self.name)

def tstep_init_routine_name(self):
"""Return the name of the physics timestep init routine for this module"""
return "{}_tstep_init".format(self.name)

def write_allocate_routine(self, outfile):
"""Write a subroutine to allocate all the data in this module"""
subname = self.allocate_routine_name()
Expand Down Expand Up @@ -1241,6 +1326,24 @@ def write_allocate_routine(self, outfile):
# end for
outfile.write('end subroutine {}'.format(subname), 1)

def write_tstep_init_routine(self, outfile):
"""
Write a subroutine to initialize registered variables
to zero at the beginning of each physics timestep.
"""
subname = self.tstep_init_routine_name()
outfile.write('', 0)
outfile.write('subroutine {}()'.format(subname), 1)
outfile.write('', 0)
outfile.write('!! Local variables', 2)
subn_str = 'character(len=*), parameter :: subname = "{}"'
outfile.write(subn_str.format(subname), 2)
for var in self.__var_dict.variable_list():
var.write_tstep_init_routine(outfile, 2, '')
# end for
outfile.write('', 0)
outfile.write('end subroutine {}'.format(subname), 1)

@property
def name(self):
"""Return this File's name"""
Expand Down Expand Up @@ -1291,7 +1394,7 @@ def parse_command_line(args, description):
help="Dycore (EUL, FV, FV3, MPAS, SE, none)")
parser.add_argument("--config", type=str, required=True,
metavar='CONFIG (required)',
help=("Comma-separated onfig items "
help=("Comma-separated config items "
"(e.g., gravity_waves=True)"))
parser.add_argument("--output-dir", type=str, default=None,
help="Directory where output files will be written")
Expand Down Expand Up @@ -1562,9 +1665,10 @@ def main():
else:
loglevel = logging.INFO
# end if

retcode, files = gen_registry(args.registry_file, args.dycore.lower(),
args.config, outdir, args.source_mods,
args.source_root, args.indent,
args.config, outdir, args.indent,
args.source_mods, args.source_root,
loglevel=loglevel)
return retcode, files

Expand Down
Loading

0 comments on commit 1e56860

Please sign in to comment.