diff --git a/scripts/ccpp_prebuild.py b/scripts/ccpp_prebuild.py index ce37fdce..d773dc78 100755 --- a/scripts/ccpp_prebuild.py +++ b/scripts/ccpp_prebuild.py @@ -96,7 +96,6 @@ def import_config(configfile, builddir): config['caps_sourcefile'] = ccpp_prebuild_config.CAPS_SOURCEFILE.format(build_dir=builddir) config['caps_dir'] = ccpp_prebuild_config.CAPS_DIR.format(build_dir=builddir) config['suites_dir'] = ccpp_prebuild_config.SUITES_DIR - config['optional_arguments'] = ccpp_prebuild_config.OPTIONAL_ARGUMENTS config['host_model'] = ccpp_prebuild_config.HOST_MODEL_IDENTIFIER config['html_vartable_file'] = ccpp_prebuild_config.HTML_VARTABLE_FILE.format(build_dir=builddir) config['latex_vartable_file'] = ccpp_prebuild_config.LATEX_VARTABLE_FILE.format(build_dir=builddir) @@ -387,95 +386,9 @@ def generate_list_of_schemes_and_dependencies_to_compile(schemes_in_files, depen # Remove duplicates return (success, list(set(schemes_and_dependencies_to_compile))) -def check_optional_arguments(metadata, arguments, optional_arguments): - """Check if for each subroutine with optional arguments, an entry exists in the - optional_arguments dictionary. This is required to generate the caps correctly - and to assess whether the variable is required from the host model. Optional - arguments that are not requested by the model as specified in the dictionary - optional_arguments are deleted from the list of requested data individually - for each subroutine.""" - logging.info('Checking optional arguments in physics schemes ...') - success = True - - # First make sure that the CCPP prebuild config entry doesn't contain any variables that are unknown - # (by standard name), or that it lists variables as optional arguments that aren't declared as optional - for scheme_name in optional_arguments.keys(): - # Skip modules that have been filtered out (because they are not used by the selected suites, for example) - if scheme_name in arguments.keys(): - for subroutine_name in optional_arguments[scheme_name].keys(): - # If optional arguments are listed individually, check each of them - if isinstance(optional_arguments[scheme_name][subroutine_name], list): - for var_name in optional_arguments[scheme_name][subroutine_name]: - if not var_name in arguments[scheme_name][subroutine_name]: - raise Exception("Explicitly requested optional argument '{}' not known to {}/{}".format( - var_name, scheme_name, subroutine_name)) - else: - for var in metadata[var_name][:]: - for item in var.container.split(' '): - subitems = item.split('_') - if subitems[0] == 'MODULE': - module_name_test = '_'.join(subitems[1:]) - elif subitems[0] == 'SCHEME': - scheme_name_test = '_'.join(subitems[1:]) - elif subitems[0] == 'SUBROUTINE': - subroutine_name_test = '_'.join(subitems[1:]) - else: - success = False - logging.error('Invalid identifier {0} in container value {1} of requested variable {2}'.format( - subitems[0], var.container, var_name)) - if scheme_name_test == scheme_name and subroutine_name_test == subroutine_name and not var.optional in ['t', 'T']: - raise Exception("Variable {} in {}/{}".format(var_name, scheme_name, subroutine_name) + \ - " is not an optional argument, but listed as such in the CCPP prebuild config") - - for var_name in sorted(metadata.keys()): - # The notation metadata[var_name][:] is a convenient way to make a copy - # of the metadata[var_name] list, which allows removing items as we go - for var in metadata[var_name][:]: - if var.optional in ['t', 'T']: - for item in var.container.split(' '): - subitems = item.split('_') - if subitems[0] == 'MODULE': - module_name = '_'.join(subitems[1:]) - elif subitems[0] == 'SCHEME': - scheme_name = '_'.join(subitems[1:]) - elif subitems[0] == 'SUBROUTINE': - subroutine_name = '_'.join(subitems[1:]) - else: - raise Exception('Invalid identifier {0} in container value {1} of requested variable {2}'.format( - subitems[0], var.container, var_name)) - if not scheme_name in optional_arguments.keys() or not \ - subroutine_name in optional_arguments[scheme_name].keys(): - raise Exception('No entry found in optional_arguments dictionary for optional argument ' + \ - '{0} to subroutine {1} in module {2}'.format(var_name, subroutine_name, scheme_name)) - if type(optional_arguments[scheme_name][subroutine_name]) is list: - if var_name in optional_arguments[scheme_name][subroutine_name]: - logging.debug('Optional argument {0} to subroutine {1} in module {2} is required, keep in list'.format( - var_name, subroutine_name, scheme_name)) - else: - logging.debug('Optional argument {0} to subroutine {1} in module {2} is not required, remove from list'.format( - var_name, subroutine_name, scheme_name)) - # Remove this var instance from list of var instances for this var_name - metadata[var_name].remove(var) - # Remove var_name from list of calling arguments for that subroutine - # (unless that module has been filtered out because none of the suites uses it) - if scheme_name in arguments.keys(): - arguments[scheme_name][subroutine_name].remove(var_name) - elif optional_arguments[scheme_name][subroutine_name] == 'all': - logging.debug('optional argument {0} to subroutine {1} in module {2} is required, keep in list'.format( - var_name, subroutine_name, scheme_name)) - - # If metadata[var_name] is now empty, i.e. the variable is not - # requested at all by the model, remove the entry from metadata - if not metadata[var_name]: - del metadata[var_name] - - return (success, metadata, arguments) - def compare_metadata(metadata_define, metadata_request): """Compare the requested metadata to the defined one. For each requested entry, a - single (i.e. non-ambiguous entry) must be present in the defined entries. All optional - arguments that are still in the list of required variables for a scheme are needed, - since they were checked in the routine check_optional_arguments beforehand.""" + single (i.e. non-ambiguous entry) must be present in the defined entries.""" logging.info('Comparing metadata for requested and provided variables ...') success = True @@ -796,12 +709,6 @@ def main(): if not success: raise Exception('Call to generate_list_of_schemes_and_dependencies_to_compile failed.') - # Process optional arguments based on configuration in above dictionary optional_arguments - (success, metadata_request, arguments_request) = check_optional_arguments(metadata_request,arguments_request, - config['optional_arguments']) - if not success: - raise Exception('Call to check_optional_arguments failed.') - # Create a LaTeX table with all variables requested by the pool of physics and/or provided by the host model success = metadata_to_latex(metadata_define, metadata_request, config['host_model'], config['latex_vartable_file']) if not success: diff --git a/scripts/metadata_parser.py b/scripts/metadata_parser.py index e3ac7440..e7351a52 100755 --- a/scripts/metadata_parser.py +++ b/scripts/metadata_parser.py @@ -23,11 +23,10 @@ # commented out, no check is performed. This is the case for 'type' and 'kind' right now, since models use their # own derived data types and kind types. VALID_ITEMS = { - 'header' : ['local_name', 'standard_name', 'long_name', 'units', 'rank', 'type', 'kind', 'intent', 'optional'], + 'header' : ['local_name', 'standard_name', 'long_name', 'units', 'rank', 'type', 'kind', 'intent'], #'type' : ['character', 'integer', 'real', ...], #'kind' : ['default', 'kind_phys', ...], 'intent' : ['none', 'in', 'out', 'inout'], - 'optional' : ['T', 'F'], } # Mandatory variables that every scheme needs to have @@ -41,7 +40,6 @@ rank = '', kind = 'len=*', intent = 'out', - optional = 'F', active = 'T', ), 'ccpp_error_flag' : Var(local_name = 'ierr', @@ -53,7 +51,6 @@ rank = '', kind = '', intent = 'out', - optional = 'F', active = 'T', ), } @@ -222,7 +219,6 @@ def read_new_metadata(filename, module_name, table_name, scheme_name = None, sub container = container, kind = kind, intent = new_var.get_prop_value('intent'), - optional = 'T' if new_var.get_prop_value('optional') else 'F', active = active, ) # Check for duplicates in same table diff --git a/scripts/metavar.py b/scripts/metavar.py index d7fb1173..23529526 100755 --- a/scripts/metavar.py +++ b/scripts/metavar.py @@ -462,7 +462,7 @@ class Var(object): >>> Var.get_prop('dimensions').valid_value(['Bob', 'Ray']) ['Bob', 'Ray'] - >>> Var.get_prop('active') + >>> Var.get_prop('active').valid_value('.true.') '.true.' >>> Var.get_prop('active').valid_value('flag_for_aerosol_physics') 'flag_for_aerosol_physics' @@ -490,6 +490,9 @@ class Var(object): >>> Var({'local_name' : 'foo', 'standard_name' : 'hi_mom', 'units' : 'm/s', 'dimensions' : '()', 'type' : 'real', 'intent' : 'ino'}, ParseSource('vname', 'SCHEME', ParseContext())) #doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ParseSyntaxError: Invalid intent variable property, 'ino', at :1 + >>> Var({'local_name' : 'foo', 'standard_name' : 'hi_mom', 'units' : 'm/s', 'dimensions' : '()', 'type' : 'real', 'intent' : 'in', 'optional' : 'false'}, ParseSource('vname', 'SCHEME', ParseContext())) #doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ParseSyntaxError: Invalid variable property name, 'optional', at :1 """ ## Prop lists below define all the allowed CCPP Metadata attributes @@ -512,8 +515,6 @@ class Var(object): default_fn_in=default_kind_val), VariableProperty('state_variable', bool, optional_in=True, default_in=False), - VariableProperty('optional', bool, - optional_in=True, default_in=False), VariableProperty('protected', bool, optional_in=True, default_in=False), VariableProperty('allocatable', bool, diff --git a/scripts/mkcap.py b/scripts/mkcap.py index 06e59d37..b3891974 100755 --- a/scripts/mkcap.py +++ b/scripts/mkcap.py @@ -32,7 +32,6 @@ def __init__(self, **kwargs): self._container = None self._kind = None self._intent = None - self._optional = None self._active = None self._target = None self._actions = { 'in' : None, 'out' : None } @@ -123,17 +122,6 @@ def intent(self, value): raise ValueError('Invalid value {0} for variable property intent'.format(value)) self._intent = value - @property - def optional(self): - '''Get the optional attribute of the variable.''' - return self._optional - - @optional.setter - def optional(self, value): - if not value in ['T', 'F']: - raise ValueError('Invalid value {0} for variable property optional'.format(value)) - self._optional = value - @property def active(self): '''Get the active attribute of the variable.''' @@ -281,7 +269,6 @@ def print_debug(self): rank = {s.rank} * kind = {s.kind} * intent = {s.intent} - optional = {s.optional} active = {s.active} target = {s.target} container = {s.container} diff --git a/scripts/mkstatic.py b/scripts/mkstatic.py index 9f8e7c22..30801fc7 100755 --- a/scripts/mkstatic.py +++ b/scripts/mkstatic.py @@ -1047,7 +1047,6 @@ def write(self, metadata_request, metadata_define, arguments, debug): # of host model variables and set necessary default values var = copy.deepcopy(metadata_define[var_standard_name][0]) var.intent = 'in' - var.optional = 'F' if not var_standard_name in local_vars.keys(): # The full name of the variable as known to the host model diff --git a/scripts/parse_tools/parse_checkers.py b/scripts/parse_tools/parse_checkers.py index 07ae0c43..450e906a 100755 --- a/scripts/parse_tools/parse_checkers.py +++ b/scripts/parse_tools/parse_checkers.py @@ -52,7 +52,7 @@ def check_units(test_val, prop_dict, error): # DH* 20210812 # Temporary workaround to convert unit 'none' (used for # dimensionless quantities in ccpp-physics/UFS/SCM) to '1' - if test_val.lower() == 'none': + if test_val and test_val.lower() == 'none': test_val = '1' # *DH 20210812