diff --git a/scripts/framework_env.py b/scripts/framework_env.py index c0bb4139..88c9c204 100644 --- a/scripts/framework_env.py +++ b/scripts/framework_env.py @@ -25,7 +25,8 @@ def __init__(self, logger, ndict=None, verbose=0, clean=False, host_files=None, scheme_files=None, suites=None, preproc_directives=[], generate_docfiles=False, host_name='', kind_types=[], use_error_obj=False, force_overwrite=False, - output_root=os.getcwd(), ccpp_datafile="datatable.xml"): + output_root=os.getcwd(), ccpp_datafile="datatable.xml", + debug=False): """Initialize a new CCPPFrameworkEnv object from the input arguments. is a dict with the parsed command-line arguments (or a dictionary created with the necessary arguments). @@ -198,6 +199,13 @@ def __init__(self, logger, ndict=None, verbose=0, clean=False, self.__datatable_file = os.path.join(self.output_dir, self.datatable_file) # end if + # Enable or disable variable allocation checks + if ndict and ('debug' in ndict): + self.__debug = ndict['debug'] + del ndict['debug'] + else: + self.__debug = debug + # end if self.__logger = logger ## Check to see if anything is left in dictionary if ndict: @@ -311,6 +319,12 @@ def datatable_file(self): CCPPFrameworkEnv object.""" return self.__datatable_file + @property + def debug(self): + """Return the property for this + CCPPFrameworkEnv object.""" + return self.__debug + @property def logger(self): """Return the property for this CCPPFrameworkEnv object.""" @@ -386,7 +400,11 @@ def parse_command_line(args, description, logger=None): help="""Overwrite all CCPP-generated files, even if unmodified""") + parser.add_argument("--debug", action='store_true', default=False, + help="Add variable allocation checks to assist debugging") + parser.add_argument("--verbose", action='count', default=0, help="Log more activity, repeat for increased output") + pargs = parser.parse_args(args) return CCPPFrameworkEnv(logger, vars(pargs)) diff --git a/scripts/metavar.py b/scripts/metavar.py index 0c5a87d2..eb1973e1 100755 --- a/scripts/metavar.py +++ b/scripts/metavar.py @@ -23,6 +23,7 @@ from parse_tools import check_molar_mass from parse_tools import ParseContext, ParseSource, type_name from parse_tools import ParseInternalError, ParseSyntaxError, CCPPError +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 @@ -302,6 +303,8 @@ def __init__(self, prop_dict, source, run_env, context=None, if 'units' not in prop_dict: prop_dict['units'] = "" # end if + # DH* To investigate later: Why is the DDT type + # copied into the kind attribute? Can we remove this? prop_dict['kind'] = prop_dict['ddt_type'] del prop_dict['ddt_type'] self.__intrinsic = False @@ -975,6 +978,53 @@ def has_vertical_dimension(self, dims=None): # end if return find_vertical_dimension(vdims)[0] + def conditional(self, vdicts): + """Convert conditional expression from active attribute + (i.e. in standard name format) to local names based on vdict. + Return conditional and a list of variables needed to evaluate + the conditional. + >>> Var({'local_name' : 'foo', 'standard_name' : 'hi_mom', 'units' : 'm s-1', 'dimensions' : '()', 'type' : 'real',}, ParseSource('vname', 'HOST', ParseContext()), _MVAR_DUMMY_RUN_ENV).conditional([{}]) + ('.true.', []) + >>> Var({'local_name' : 'foo', 'standard_name' : 'hi_mom', 'units' : 'm s-1', 'dimensions' : '()', 'type' : 'real', 'active' : 'False'}, ParseSource('vname', 'HOST', ParseContext()), _MVAR_DUMMY_RUN_ENV).conditional([VarDictionary('bar', _MVAR_DUMMY_RUN_ENV, variables={})]) #doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + Exception: Cannot find variable 'false' for generating conditional for 'False' + >>> Var({'local_name' : 'foo', 'standard_name' : 'hi_mom', 'units' : 'm s-1', 'dimensions' : '()', 'type' : 'real', 'active' : 'mom_gone'}, ParseSource('vname', 'HOST', ParseContext()), _MVAR_DUMMY_RUN_ENV).conditional([ VarDictionary('bar', _MVAR_DUMMY_RUN_ENV, variables=[Var({'local_name' : 'bar', 'standard_name' : 'mom_home', 'units' : '', 'dimensions' : '()', 'type' : 'logical'}, ParseSource('vname', 'HOST', ParseContext()), _MVAR_DUMMY_RUN_ENV)]) ]) #doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + Exception: Cannot find variable 'mom_gone' for generating conditional for 'mom_gone' + >>> Var({'local_name' : 'foo', 'standard_name' : 'hi_mom', 'units' : 'm s-1', 'dimensions' : '()', 'type' : 'real', 'active' : 'mom_home'}, ParseSource('vname', 'HOST', ParseContext()), _MVAR_DUMMY_RUN_ENV).conditional([ VarDictionary('bar', _MVAR_DUMMY_RUN_ENV, variables=[Var({'local_name' : 'bar', 'standard_name' : 'mom_home', 'units' : '', 'dimensions' : '()', 'type' : 'logical'}, ParseSource('vname', 'HOST', ParseContext()), _MVAR_DUMMY_RUN_ENV)]) ])[0] + 'bar' + >>> len(Var({'local_name' : 'foo', 'standard_name' : 'hi_mom', 'units' : 'm s-1', 'dimensions' : '()', 'type' : 'real', 'active' : 'mom_home'}, ParseSource('vname', 'HOST', ParseContext()), _MVAR_DUMMY_RUN_ENV).conditional([ VarDictionary('bar', _MVAR_DUMMY_RUN_ENV, variables=[Var({'local_name' : 'bar', 'standard_name' : 'mom_home', 'units' : '', 'dimensions' : '()', 'type' : 'logical'}, ParseSource('vname', 'HOST', ParseContext()), _MVAR_DUMMY_RUN_ENV)]) ])[1]) + 1 + """ + + active = self.get_prop_value('active') + conditional = '' + vars_needed = [] + + # Find all words in the conditional, for each of them look + # for a matching standard name in the list of known variables + items = FORTRAN_CONDITIONAL_REGEX.findall(active) + for item in items: + item = item.lower() + if item in FORTRAN_CONDITIONAL_REGEX_WORDS: + conditional += item + else: + # Keep integers + try: + int(item) + conditional += item + except ValueError: + dvar = None + for vdict in vdicts: + dvar = vdict.find_variable(standard_name=item, any_scope=True) # or any_scope=False ? + if dvar: + break + if not dvar: + raise Exception(f"Cannot find variable '{item}' for generating conditional for '{active}'") + conditional += dvar.get_prop_value('local_name') + vars_needed.append(dvar) + return (conditional, vars_needed) + def write_def(self, outfile, indent, wdict, allocatable=False, dummy=False, add_intent=None, extra_space=0, public=False): """Write the definition line for the variable to . diff --git a/scripts/parse_tools/__init__.py b/scripts/parse_tools/__init__.py index 4990da88..309bbda0 100644 --- a/scripts/parse_tools/__init__.py +++ b/scripts/parse_tools/__init__.py @@ -30,6 +30,7 @@ from xml_tools import find_schema_file, find_schema_version from xml_tools import read_xml_file, validate_xml_file from xml_tools import PrettyElementTree +from fortran_conditional import FORTRAN_CONDITIONAL_REGEX_WORDS, FORTRAN_CONDITIONAL_REGEX # pylint: enable=wrong-import-position __all__ = [ @@ -74,5 +75,7 @@ 'set_log_to_stdout', 'type_name', 'unique_standard_name', - 'validate_xml_file' + 'validate_xml_file', + 'FORTRAN_CONDITIONAL_REGEX_WORDS', + 'FORTRAN_CONDITIONAL_REGEX' ] diff --git a/scripts/parse_tools/fortran_conditional.py b/scripts/parse_tools/fortran_conditional.py new file mode 100755 index 00000000..b1ec7eeb --- /dev/null +++ b/scripts/parse_tools/fortran_conditional.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +# + +"""Definitions to convert a conditional statement in the metadata, expressed in standard names, +into a Fortran conditional (used in an if statement), expressed in local names. +""" + +import re + +FORTRAN_CONDITIONAL_REGEX_WORDS = [' ', '(', ')', '==', '/=', '<=', '>=', '<', '>', '.eqv.', '.neqv.', + '.true.', '.false.', '.lt.', '.le.', '.eq.', '.ge.', '.gt.', '.ne.', + '.not.', '.and.', '.or.', '.xor.'] +FORTRAN_CONDITIONAL_REGEX = re.compile(r"[\w']+|" + "|".join([word.replace('(','\(').replace(')', '\)') for word in FORTRAN_CONDITIONAL_REGEX_WORDS])) diff --git a/scripts/suite_objects.py b/scripts/suite_objects.py old mode 100644 new mode 100755 index b97c9ce6..96d6649c --- a/scripts/suite_objects.py +++ b/scripts/suite_objects.py @@ -897,7 +897,7 @@ def match_variable(self, var, run_env): # end if # end if # end if - return found_var, var_vdim, new_vdims, missing_vert, compat_obj + return found_var, dict_var, var_vdim, new_vdims, missing_vert, compat_obj def in_process_split(self): """Find out if we are in a process-split region""" @@ -1080,6 +1080,7 @@ def __init__(self, scheme_xml, context, parent, run_env): self.__lib = scheme_xml.get('lib', None) self.__has_vertical_dimension = False self.__group = None + self.__var_debug_checks = list() self.__forward_transforms = list() self.__reverse_transforms = list() super().__init__(name, context, parent, run_env, active_call_list=True) @@ -1150,8 +1151,13 @@ def analyze(self, phase, group, scheme_library, suite_vars, level): vdims = var.get_dimensions() vintent = var.get_prop_value('intent') args = self.match_variable(var, self.run_env) - found, vert_dim, new_dims, missing_vert, compat_obj = args + found, dict_var, vert_dim, new_dims, missing_vert, compat_obj = args if found: + if self.__group.run_env.debug: + # Add variable allocation checks for group, suite and host variables + if dict_var: + self.add_var_debug_check(dict_var) + # end if if not self.has_vertical_dim: self.__has_vertical_dimension = vert_dim is not None # end if @@ -1222,6 +1228,276 @@ def analyze(self, phase, group, scheme_library, suite_vars, level): # end if return scheme_mods + def add_var_debug_check(self, var): + """Add a debug check for a given variable var (host model variable, + suite variable or group module variable) for this scheme. + Return the variable and an associated dummy variable that is + managed by the group subroutine that calls the scheme, and + which is used to assign the scalar or the lower and upper bounds + of the array to if the intent is 'inout' or 'out'. + """ + # Get the basic attributes that decide whether we need + # to check the variable when we write the group + standard_name = var.get_prop_value('standard_name') + dimensions = var.get_dimensions() + active = var.get_prop_value('active') + var_dicts = [ self.__group.call_list ] + self.__group.suite_dicts() + + # If the variable isn't active, skip it + if active.lower() =='.false.': + return + # Also, if the variable is one of the CCPP error handling messages, skip it + # since it is defined as intent(out) and we can't do meaningful checks on it + elif standard_name == 'ccpp_error_code' or standard_name == 'ccpp_error_message': + return + # To perform allocation checks, we need to know all variables + # that are part of the 'active' attribute conditional and add + # it to the group's call list. + else: + (_, vars_needed) = var.conditional(var_dicts) + for var_needed in vars_needed: + self.update_group_call_list_variable(var_needed) + + # For scalars and arrays, need an internal_var variable (same kind and type) + # that we can assign the scalar or the lbound/ubound of the array to. + # We need to treat DDTs and variables with kind attributes slightly + # differently, and make sure there are no duplicate variables. We + # also need to assign a bogus standard name to these local variables. + vtype = var.get_prop_value('type') + if var.is_ddt(): + vkind = '' + units = '' + else: + vkind = var.get_prop_value('kind') + units = var.get_prop_value('units') + if vkind: + internal_var_lname = f'internal_var_{vtype.replace("=","_")}_{vkind.replace("=","_")}' + else: + internal_var_lname = f'internal_var_{vtype.replace("=","_")}' + if var.is_ddt(): + internal_var = Var({'local_name':internal_var_lname, 'standard_name':f'{internal_var_lname}_local', + 'ddt_type':vtype, 'kind':vkind, 'units':units, 'dimensions':'()'}, + _API_LOCAL, self.run_env) + else: + internal_var = Var({'local_name':internal_var_lname, 'standard_name':f'{internal_var_lname}_local', + 'type':vtype, 'kind':vkind, 'units':units, 'dimensions':'()'}, + _API_LOCAL, self.run_env) + found = self.__group.find_variable(source_var=internal_var, any_scope=False) + if not found: + self.__group.manage_variable(internal_var) + + # For arrays, we need to get information on the dimensions and add it to + # the group's call list so that we can test for the correct size later on + if dimensions: + for dim in dimensions: + if not ':' in dim: + dim_var = self.find_variable(standard_name=dim) + if not dim_var: + raise Exception(f"No dimension with standard name '{dim}'") + self.update_group_call_list_variable(dim_var) + else: + (ldim, udim) = dim.split(":") + ldim_var = self.find_variable(standard_name=ldim) + if not ldim_var: + raise Exception(f"No dimension with standard name '{ldim}'") + self.update_group_call_list_variable(ldim_var) + udim_var = self.find_variable(standard_name=udim) + if not udim_var: + raise Exception(f"No dimension with standard name '{udim}'") + self.update_group_call_list_variable(udim_var) + + # Add the variable to the list of variables to check. Record which internal_var to use. + self.__var_debug_checks.append([var, internal_var]) + + def replace_horiz_dim_debug_check(self, dim, cldicts, var_in_call_list): + """Determine the correct horizontal dimension to use for a given variable, + depending on the CCPP phase and origin of the variable (from the host/suite + or defined as a module variable for the parent group, or local to the group. + Return the dimension length and other properties needed for debug checks.""" + if not is_horizontal_dimension(dim): + raise Exception(f"Dimension {dim} is not a horizontal dimension") + if self.run_phase(): + if var_in_call_list and \ + self.find_variable(standard_name="horizontal_loop_extent"): + ldim = "ccpp_constant_one" + udim = "horizontal_loop_extent" + else: + ldim = "horizontal_loop_begin" + udim = "horizontal_loop_end" + else: + ldim = "ccpp_constant_one" + udim = "horizontal_dimension" + # Get dimension for lower bound + for var_dict in cldicts: + dvar = var_dict.find_variable(standard_name=ldim, any_scope=False) + if dvar is not None: + break + if not dvar: + raise Exception(f"No variable with standard name '{ldim}' in cldicts") + ldim_lname = dvar.get_prop_value('local_name') + # Get dimension for upper bound + for var_dict in cldicts: + dvar = var_dict.find_variable(standard_name=udim, any_scope=False) + if dvar is not None: + break + if not dvar: + raise Exception(f"No variable with standard name '{udim}' in cldicts") + udim_lname = dvar.get_prop_value('local_name') + # Assemble dimensions and bounds for size checking + dim_length = f'{udim_lname}-{ldim_lname}+1' + # If the variable that uses these dimensions is not in the group's call + # list, then it is defined as a module variable for this group and the + # dimensions run from ldim to udim, otherwise from 1:dim_length. + if not var_in_call_list: + dim_string = f"{ldim_lname}:{udim_lname}" + lbound_string = ldim_lname + ubound_string = udim_lname + else: + dim_string = ":" + lbound_string = '1' + ubound_string = f'{udim_lname}-{ldim_lname}+1' + return (dim_length, dim_string, lbound_string, ubound_string) + + def write_var_debug_check(self, var, internal_var, cldicts, outfile, errcode, errmsg, indent): + """Write the variable debug check for the given variable, as determined + in a previous step (add_var_debug_check). Assign the scalar or lower and + upper bounds of the array to the internal_var variable, and for arrays also check + that the size of the array matches the dimensions from the metadata. + """ + # Get the basic attributes for writing the check + standard_name = var.get_prop_value('standard_name') + dimensions = var.get_dimensions() + active = var.get_prop_value('active') + allocatable = var.get_prop_value('allocatable') + + # Need the local name from the group call list, + # from the locally-defined variables of the group, + # or from the suite, not how it is called in the scheme (var) + # First, check if the variable is in the call list. + dvar = self.__group.call_list.find_variable(standard_name=standard_name, any_scope=False) + if dvar: + var_in_call_list = True + else: + var_in_call_list = False + # If it is not in the call list, try to find it + # in the local variables of this group subroutine. + dvar = self.__group.find_variable(standard_name=standard_name, any_scope=False) + if not dvar: + # This variable is handled by the group + # and is declared as a module variable + for var_dict in self.__group.suite_dicts(): + dvar = var_dict.find_variable(standard_name=standard_name, any_scope=False) + if dvar: + break + if not dvar: + raise Exception(f"No variable with standard name '{standard_name}' in cldicts") + local_name = dvar.get_prop_value('local_name') + + # If the variable is allocatable and the intent for the scheme is 'out', + # then we can't test anything because the scheme is going to allocate + # the variable. We don't have this information earlier in + # add_var_debug_check, therefore need to back out here, + # using the information from the scheme variable (call list). + svar = self.call_list.find_variable(standard_name=standard_name, any_scope=False) + intent = svar.get_prop_value('intent') + if intent == 'out' and allocatable: + return + + # Get the condition on which the variable is active + (conditional, _) = var.conditional(cldicts) + + # For scalars, assign to internal_var variable if the variable intent is in/inout + if not dimensions: + if not intent == 'out': + internal_var_lname = internal_var.get_prop_value('local_name') + outfile.write(f"if ({conditional}) then", indent) + outfile.write(f"! Assign value of {local_name} to internal_var", indent+1) + outfile.write(f"{internal_var_lname} = {local_name}", indent+1) + outfile.write(f"end if", indent) + # For arrays, check size of array against dimensions in metadata, then assign + # the lower and upper bounds to the internal_var variable if the intent is in/inout + else: + array_size = 1 + dim_strings = [] + lbound_strings = [] + ubound_strings = [] + for dim in dimensions: + if not ':' in dim: + # In capgen, any true dimension (that is not a single index) does + # have a colon (:) in the dimension, therefore this is an index + for var_dict in cldicts: + dvar = var_dict.find_variable(standard_name=dim, any_scope=False) + if dvar is not None: + break + if not dvar: + raise Exception(f"No variable with standard name '{dim}' in cldicts") + dim_lname = dvar.get_prop_value('local_name') + dim_length = 1 + dim_strings.append(dim_lname) + lbound_strings.append(dim_lname) + ubound_strings.append(dim_lname) + else: + # Horizontal dimension needs to be dealt with separately, because it + # depends on the CCPP phase, whether the variable is a host/suite + # variable or locally defined on the group level. + if is_horizontal_dimension(dim): + (dim_length, dim_string, lbound_string, ubound_string) = \ + self.replace_horiz_dim_debug_check(dim, cldicts, var_in_call_list) + else: + (ldim, udim) = dim.split(":") + # Get dimension for lower bound + for var_dict in cldicts: + dvar = var_dict.find_variable(standard_name=ldim, any_scope=False) + if dvar is not None: + break + if not dvar: + raise Exception(f"No variable with standard name '{ldim}' in cldicts") + ldim_lname = dvar.get_prop_value('local_name') + # Get dimension for upper bound + for var_dict in cldicts: + dvar = var_dict.find_variable(standard_name=udim, any_scope=False) + if dvar is not None: + break + if not dvar: + raise Exception(f"No variable with standard name '{udim}' in cldicts") + udim_lname = dvar.get_prop_value('local_name') + # Assemble dimensions and bounds for size checking + dim_length = f'{udim_lname}-{ldim_lname}+1' + dim_string = ":" + lbound_string = ldim_lname + ubound_string = udim_lname + # end if + dim_strings.append(dim_string) + lbound_strings.append(lbound_string) + ubound_strings.append(ubound_string) + array_size = f'{array_size}*({dim_length})' + + # Various strings needed to get the right size + # and lower/upper bound of the array + dim_string = '(' + ','.join(dim_strings) + ')' + lbound_string = '(' + ','.join(lbound_strings) + ')' + ubound_string = '(' + ','.join(ubound_strings) + ')' + + # Write size check + outfile.write(f"if ({conditional}) then", indent) + outfile.write(f"! Check size of array {local_name}", indent+1) + outfile.write(f"if (size({local_name}{dim_string}) /= {array_size}) then", indent+1) + outfile.write(f"write({errmsg}, '(a)') 'In group {self.__group.name} before {self.__subroutine_name}:'", indent+2) + outfile.write(f"write({errmsg}, '(2(a,i8))') 'for array {local_name}, expected size ', {array_size}, ' but got ', size({local_name})", indent+2) + outfile.write(f"{errcode} = 1", indent+2) + outfile.write(f"return", indent+2) + outfile.write(f"end if", indent+1) + outfile.write(f"end if", indent) + + # Assign lower/upper bounds to internal_var (scalar) if intent is not out + if not intent == 'out': + internal_var_lname = internal_var.get_prop_value('local_name') + outfile.write(f"if ({conditional}) then", indent) + outfile.write(f"! Assign lower/upper bounds of {local_name} to internal_var", indent+1) + outfile.write(f"{internal_var_lname} = {local_name}{lbound_string}", indent+1) + outfile.write(f"{internal_var_lname} = {local_name}{ubound_string}", indent+1) + outfile.write(f"end if", indent) + def add_var_transform(self, var, compat_obj, vert_dim): """Register any variable transformation needed by for this Scheme. For any transformation identified in , create dummy variable @@ -1297,7 +1573,7 @@ def write_var_transform(self, var, dummy, rindices, lindices, compat_obj, rvar_indices=lindices) outfile.write(stmt, indent+1) - def write(self, outfile, errcode, indent): + def write(self, outfile, errcode, errmsg, indent): # Unused arguments are for consistent write interface # pylint: disable=unused-argument """Write code to call this Scheme to """ @@ -1310,6 +1586,12 @@ def write(self, outfile, errcode, indent): subname=self.subroutine_name) outfile.write('if ({} == 0) then'.format(errcode), indent) + + # Write debug checks (operating on variables + # coming from the group's call list) + for (var, internal_var) in self.__var_debug_checks: + stmt = self.write_var_debug_check(var, internal_var, cldicts, outfile, errcode, errmsg, indent) + # Write any reverse (pre-Scheme) transforms. for (dummy, var, rindices, lindices, compat_obj) in self.__reverse_transforms: tstmt = self.write_var_transform(var, dummy, rindices, lindices, compat_obj, outfile, indent, False) @@ -1435,13 +1717,13 @@ def analyze(self, phase, group, scheme_library, suite_vars, level): # end for return scheme_mods - def write(self, outfile, errcode, indent): + def write(self, outfile, errcode, errmsg, indent): """Write code for the vertical loop, including contents, to """ outfile.write('do {} = 1, {}'.format(self.name, self.dimension_name), indent) # Note that 'scheme' may be a sybcycle or other construct for item in self.parts: - item.write(outfile, errcode, indent+1) + item.write(outfile, errcode, errmsg, indent+1) # end for outfile.write('end do', 2) @@ -1500,12 +1782,12 @@ def analyze(self, phase, group, scheme_library, suite_vars, level): # end for return scheme_mods - def write(self, outfile, errcode, indent): + def write(self, outfile, errcode, errmsg, indent): """Write code for the subcycle loop, including contents, to """ outfile.write('do {} = 1, {}'.format(self.name, self.loop), indent) # Note that 'scheme' may be a sybcycle or other construct for item in self.parts: - item.write(outfile, errcode, indent+1) + item.write(outfile, errcode, errmsg, indent+1) # end for outfile.write('end do', 2) @@ -1550,11 +1832,11 @@ def analyze(self, phase, group, scheme_library, suite_vars, level): # end for return scheme_mods - def write(self, outfile, errcode, indent): + def write(self, outfile, errcode, errmsg, indent): """Write code for this TimeSplit section, including contents, to """ for item in self.parts: - item.write(outfile, errcode, indent) + item.write(outfile, errcode, errmsg, indent) # end for ############################################################################### @@ -1579,7 +1861,7 @@ def analyze(self, phase, group, scheme_library, suite_vars, level): # Handle all the suite objects inside of this group raise CCPPError('ProcessSplit not yet implemented') - def write(self, outfile, errcode, indent): + def write(self, outfile, errcode, errmsg, indent): """Write code for this ProcessSplit section, including contents, to """ raise CCPPError('ProcessSplit not yet implemented') @@ -1978,7 +2260,7 @@ def write(self, outfile, host_arglist, indent, const_mod, # end for # Write the scheme and subcycle calls for item in self.parts: - item.write(outfile, errcode, indent + 1) + item.write(outfile, errcode, errmsg, indent + 1) # end for # Deallocate local arrays for lname in allocatable_var_set: diff --git a/scripts/var_props.py b/scripts/var_props.py index dc16fd0f..c61d9ae4 100755 --- a/scripts/var_props.py +++ b/scripts/var_props.py @@ -151,7 +151,7 @@ def standard_name_to_long_name(prop_dict, context=None): ... parse_source.CCPPError: No standard name to convert to long name, at foo.F90:4 """ - # We assume that standar_name has been checked for validity + # We assume that standard_name has been checked for validity # Make the first char uppercase and replace each underscore with a space if 'standard_name' in prop_dict: standard_name = prop_dict['standard_name'] diff --git a/test/advection_test/CMakeLists.txt b/test/advection_test/CMakeLists.txt index 10ada283..4aacdc18 100644 --- a/test/advection_test/CMakeLists.txt +++ b/test/advection_test/CMakeLists.txt @@ -149,6 +149,7 @@ while (VERBOSITY GREATER 0) list(APPEND CAPGEN_CMD "--verbose") MATH(EXPR VERBOSITY "${VERBOSITY} - 1") endwhile () +list(APPEND CAPGEN_CMD "--debug") string(REPLACE ";" " " CAPGEN_STRING "${CAPGEN_CMD}") MESSAGE(STATUS "Running: ${CAPGEN_STRING}") EXECUTE_PROCESS(COMMAND ${CAPGEN_CMD} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} diff --git a/test/advection_test/run_test b/test/advection_test/run_test index b014470a..9c75aa08 100755 --- a/test/advection_test/run_test +++ b/test/advection_test/run_test @@ -131,18 +131,23 @@ suite_list="cld_suite" required_vars="ccpp_error_code,ccpp_error_message" required_vars="${required_vars},cloud_ice_dry_mixing_ratio" required_vars="${required_vars},cloud_liquid_dry_mixing_ratio" +required_vars="${required_vars},horizontal_dimension" required_vars="${required_vars},horizontal_loop_begin" required_vars="${required_vars},horizontal_loop_end" required_vars="${required_vars},surface_air_pressure" required_vars="${required_vars},temperature" required_vars="${required_vars},time_step_for_physics" +required_vars="${required_vars},vertical_layer_dimension" required_vars="${required_vars},water_temperature_at_freezing" required_vars="${required_vars},water_vapor_specific_humidity" input_vars="cloud_ice_dry_mixing_ratio,cloud_liquid_dry_mixing_ratio" +input_vars="${input_vars},horizontal_dimension" input_vars="${input_vars},horizontal_loop_begin" input_vars="${input_vars},horizontal_loop_end" input_vars="${input_vars},surface_air_pressure,temperature" -input_vars="${input_vars},time_step_for_physics,water_temperature_at_freezing" +input_vars="${input_vars},time_step_for_physics" +input_vars="${input_vars},vertical_layer_dimension" +input_vars="${input_vars},water_temperature_at_freezing" input_vars="${input_vars},water_vapor_specific_humidity" output_vars="ccpp_error_code,ccpp_error_message" output_vars="${output_vars},cloud_ice_dry_mixing_ratio" diff --git a/test/advection_test/test_reports.py b/test/advection_test/test_reports.py index 17e9a2ad..6d84616b 100644 --- a/test/advection_test/test_reports.py +++ b/test/advection_test/test_reports.py @@ -72,13 +72,19 @@ def usage(errmsg=None): "time_step_for_physics", "water_temperature_at_freezing", "water_vapor_specific_humidity", "cloud_ice_dry_mixing_ratio", - "cloud_liquid_dry_mixing_ratio"] + "cloud_liquid_dry_mixing_ratio", + # Added by --debug option + "horizontal_dimension", + "vertical_layer_dimension"] _INPUT_VARS_CLD = ["surface_air_pressure", "temperature", "horizontal_loop_begin", "horizontal_loop_end", "time_step_for_physics", "water_temperature_at_freezing", "water_vapor_specific_humidity", "cloud_ice_dry_mixing_ratio", - "cloud_liquid_dry_mixing_ratio"] + "cloud_liquid_dry_mixing_ratio", + # Added by --debug option + "horizontal_dimension", + "vertical_layer_dimension"] _OUTPUT_VARS_CLD = ["ccpp_error_code", "ccpp_error_message", "water_vapor_specific_humidity", "temperature", "cloud_ice_dry_mixing_ratio", diff --git a/test/capgen_test/CMakeLists.txt b/test/capgen_test/CMakeLists.txt index f02213a0..ccae4f08 100644 --- a/test/capgen_test/CMakeLists.txt +++ b/test/capgen_test/CMakeLists.txt @@ -149,6 +149,7 @@ while (VERBOSITY GREATER 0) list(APPEND CAPGEN_CMD "--verbose") MATH(EXPR VERBOSITY "${VERBOSITY} - 1") endwhile () +list(APPEND CAPGEN_CMD "--debug") string(REPLACE ";" " " CAPGEN_STRING "${CAPGEN_CMD}") MESSAGE(STATUS "Running: ${CAPGEN_STRING}") EXECUTE_PROCESS(COMMAND ${CAPGEN_CMD} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} diff --git a/test/capgen_test/run_test b/test/capgen_test/run_test index 4dfd490f..0d5d44f7 100755 --- a/test/capgen_test/run_test +++ b/test/capgen_test/run_test @@ -148,20 +148,24 @@ output_vars_ddt="${output_vars_ddt},model_times,number_of_model_times" required_vars_temp="ccpp_error_code,ccpp_error_message,horizontal_dimension" required_vars_temp="${required_vars_temp},horizontal_loop_begin" required_vars_temp="${required_vars_temp},horizontal_loop_end" +required_vars_temp="${required_vars_temp},index_of_water_vapor_specific_humidity" required_vars_temp="${required_vars_temp},potential_temperature" required_vars_temp="${required_vars_temp},potential_temperature_at_interface" required_vars_temp="${required_vars_temp},potential_temperature_increment" required_vars_temp="${required_vars_temp},surface_air_pressure" required_vars_temp="${required_vars_temp},time_step_for_physics" +required_vars_temp="${required_vars_temp},vertical_interface_dimension" required_vars_temp="${required_vars_temp},vertical_layer_dimension" required_vars_temp="${required_vars_temp},water_vapor_specific_humidity" input_vars_temp="horizontal_dimension" input_vars_temp="${input_vars_temp},horizontal_loop_begin" input_vars_temp="${input_vars_temp},horizontal_loop_end" +input_vars_temp="${input_vars_temp},index_of_water_vapor_specific_humidity" input_vars_temp="${input_vars_temp},potential_temperature" input_vars_temp="${input_vars_temp},potential_temperature_at_interface" input_vars_temp="${input_vars_temp},potential_temperature_increment" input_vars_temp="${input_vars_temp},surface_air_pressure,time_step_for_physics" +input_vars_temp="${input_vars_temp},vertical_interface_dimension" input_vars_temp="${input_vars_temp},vertical_layer_dimension" input_vars_temp="${input_vars_temp},water_vapor_specific_humidity" output_vars_temp="ccpp_error_code,ccpp_error_message,potential_temperature" diff --git a/test/capgen_test/test_host_data.meta b/test/capgen_test/test_host_data.meta index 8a54a3ed..df4b92b4 100644 --- a/test/capgen_test/test_host_data.meta +++ b/test/capgen_test/test_host_data.meta @@ -49,3 +49,4 @@ kind = kind_phys units = kg kg-1 dimensions = (horizontal_dimension, vertical_layer_dimension) + active = (index_of_water_vapor_specific_humidity > 0) diff --git a/test/capgen_test/test_reports.py b/test/capgen_test/test_reports.py index e8237476..da02aeea 100644 --- a/test/capgen_test/test_reports.py +++ b/test/capgen_test/test_reports.py @@ -78,7 +78,10 @@ def usage(errmsg=None): "number_of_model_times"] _REQUIRED_VARS_DDT = _INPUT_VARS_DDT + _OUTPUT_VARS_DDT _PROT_VARS_TEMP = ["horizontal_loop_begin", "horizontal_loop_end", - "horizontal_dimension", "vertical_layer_dimension"] + "horizontal_dimension", "vertical_layer_dimension", + # Added for --debug + "index_of_water_vapor_specific_humidity", + "vertical_interface_dimension"] _REQUIRED_VARS_TEMP = ["ccpp_error_code", "ccpp_error_message", "potential_temperature", "potential_temperature_at_interface", diff --git a/test/run_fortran_tests.sh b/test/run_fortran_tests.sh index cd6436fb..ccfc85f9 100755 --- a/test/run_fortran_tests.sh +++ b/test/run_fortran_tests.sh @@ -37,12 +37,12 @@ if [ $res -ne 0 ]; then echo "Failure running advection test" fi -# Run var_compatability test - ./var_compatability_test/run_test +# Run var_compatibility test + ./var_compatibility_test/run_test res=$? errcnt=$((errcnt + res)) if [ $res -ne 0 ]; then - echo "Failure running var_compatability test" + echo "Failure running var_compatibility test" fi if [ $errcnt -eq 0 ]; then diff --git a/test/var_compatability_test/.gitignore b/test/var_compatibility_test/.gitignore similarity index 100% rename from test/var_compatability_test/.gitignore rename to test/var_compatibility_test/.gitignore diff --git a/test/var_compatability_test/CMakeLists.txt b/test/var_compatibility_test/CMakeLists.txt similarity index 98% rename from test/var_compatability_test/CMakeLists.txt rename to test/var_compatibility_test/CMakeLists.txt index 7e3590a6..8cbd7e44 100644 --- a/test/var_compatability_test/CMakeLists.txt +++ b/test/var_compatibility_test/CMakeLists.txt @@ -19,9 +19,9 @@ get_filename_component(CCPP_ROOT "${TEST_ROOT}" DIRECTORY) # Paths should be relative to CMAKE_SOURCE_DIR (this file's directory) # #------------------------------------------------------------------------------ -LIST(APPEND SCHEME_FILES "var_compatability_files.txt") +LIST(APPEND SCHEME_FILES "var_compatibility_files.txt") LIST(APPEND HOST_FILES "test_host_data" "test_host_mod") -LIST(APPEND SUITE_FILES "var_compatability_suite.xml") +LIST(APPEND SUITE_FILES "var_compatibility_suite.xml") # HOST is the name of the executable we will build. # We assume there are files ${HOST}.meta and ${HOST}.F90 in CMAKE_SOURCE_DIR SET(HOST "${CMAKE_PROJECT_NAME}") @@ -149,6 +149,7 @@ while (VERBOSITY GREATER 0) list(APPEND CAPGEN_CMD "--verbose") MATH(EXPR VERBOSITY "${VERBOSITY} - 1") endwhile () +list(APPEND CAPGEN_CMD "--debug") string(REPLACE ";" " " CAPGEN_STRING "${CAPGEN_CMD}") MESSAGE(STATUS "Running: ${CAPGEN_STRING}") EXECUTE_PROCESS(COMMAND ${CAPGEN_CMD} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} diff --git a/test/var_compatability_test/README.md b/test/var_compatibility_test/README.md similarity index 58% rename from test/var_compatability_test/README.md rename to test/var_compatibility_test/README.md index 066cf771..9b56ec9c 100644 --- a/test/var_compatability_test/README.md +++ b/test/var_compatibility_test/README.md @@ -1,6 +1,6 @@ -var_compatability test +var_compatibility test ================ -To build and run the var_compatability test, run ./run_test +To build and run the var_compatibility test, run ./run_test This script will build and run the test. The exit code is zero (0) on PASS and non-zero on FAIL. diff --git a/test/var_compatability_test/effr_calc.F90 b/test/var_compatibility_test/effr_calc.F90 similarity index 100% rename from test/var_compatability_test/effr_calc.F90 rename to test/var_compatibility_test/effr_calc.F90 diff --git a/test/var_compatability_test/effr_calc.meta b/test/var_compatibility_test/effr_calc.meta similarity index 100% rename from test/var_compatability_test/effr_calc.meta rename to test/var_compatibility_test/effr_calc.meta diff --git a/test/var_compatability_test/run_test b/test/var_compatibility_test/run_test similarity index 79% rename from test/var_compatability_test/run_test rename to test/var_compatibility_test/run_test index ca185966..ac86bf6f 100755 --- a/test/var_compatability_test/run_test +++ b/test/var_compatibility_test/run_test @@ -118,36 +118,38 @@ frame_src="${framework}/src" ## NB: This has to be after build_dir is finalized ## host_files="${build_dir}/ccpp/test_host_ccpp_cap.F90" -suite_files="${build_dir}/ccpp/ccpp_var_compatability_suite_cap.F90" +suite_files="${build_dir}/ccpp/ccpp_var_compatibility_suite_cap.F90" utility_files="${build_dir}/ccpp/ccpp_kinds.F90" utility_files="${utility_files},${frame_src}/ccpp_constituent_prop_mod.F90" utility_files="${utility_files},${frame_src}/ccpp_hashable.F90" utility_files="${utility_files},${frame_src}/ccpp_hash_table.F90" ccpp_files="${utility_files}" ccpp_files="${ccpp_files},${build_dir}/ccpp/test_host_ccpp_cap.F90" -ccpp_files="${ccpp_files},${build_dir}/ccpp/ccpp_var_compatability_suite_cap.F90" +ccpp_files="${ccpp_files},${build_dir}/ccpp/ccpp_var_compatibility_suite_cap.F90" #process_list="" module_list="effr_calc" #dependencies="" -suite_list="var_compatability_suite" -required_vars_var_compatability="ccpp_error_code,ccpp_error_message" -required_vars_var_compatability="${required_vars_var_compatability},effective_radius_of_stratiform_cloud_ice_particle" -required_vars_var_compatability="${required_vars_var_compatability},effective_radius_of_stratiform_cloud_liquid_water_particle" -required_vars_var_compatability="${required_vars_var_compatability},effective_radius_of_stratiform_cloud_rain_particle" -required_vars_var_compatability="${required_vars_var_compatability},effective_radius_of_stratiform_cloud_snow_particle" -required_vars_var_compatability="${required_vars_var_compatability},horizontal_loop_begin" -required_vars_var_compatability="${required_vars_var_compatability},horizontal_loop_end" -required_vars_var_compatability="${required_vars_var_compatability},vertical_layer_dimension" -input_vars_var_compatability="effective_radius_of_stratiform_cloud_liquid_water_particle" -input_vars_var_compatability="${input_vars_var_compatability},effective_radius_of_stratiform_cloud_rain_particle" -input_vars_var_compatability="${input_vars_var_compatability},effective_radius_of_stratiform_cloud_snow_particle" -input_vars_var_compatability="${input_vars_var_compatability},horizontal_loop_begin" -input_vars_var_compatability="${input_vars_var_compatability},horizontal_loop_end" -input_vars_var_compatability="${input_vars_var_compatability},vertical_layer_dimension" -output_vars_var_compatability="ccpp_error_code,ccpp_error_message" -output_vars_var_compatability="${output_vars_var_compatability},effective_radius_of_stratiform_cloud_ice_particle" -output_vars_var_compatability="${output_vars_var_compatability},effective_radius_of_stratiform_cloud_liquid_water_particle" -output_vars_var_compatability="${output_vars_var_compatability},effective_radius_of_stratiform_cloud_snow_particle" +suite_list="var_compatibility_suite" +required_vars_var_compatibility="ccpp_error_code,ccpp_error_message" +required_vars_var_compatibility="${required_vars_var_compatibility},effective_radius_of_stratiform_cloud_ice_particle" +required_vars_var_compatibility="${required_vars_var_compatibility},effective_radius_of_stratiform_cloud_liquid_water_particle" +required_vars_var_compatibility="${required_vars_var_compatibility},effective_radius_of_stratiform_cloud_rain_particle" +required_vars_var_compatibility="${required_vars_var_compatibility},effective_radius_of_stratiform_cloud_snow_particle" +required_vars_var_compatibility="${required_vars_var_compatibility},horizontal_dimension" +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},vertical_layer_dimension" +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" +input_vars_var_compatibility="${input_vars_var_compatibility},effective_radius_of_stratiform_cloud_snow_particle" +input_vars_var_compatibility="${input_vars_var_compatibility},horizontal_dimension" +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},vertical_layer_dimension" +output_vars_var_compatibility="ccpp_error_code,ccpp_error_message" +output_vars_var_compatibility="${output_vars_var_compatibility},effective_radius_of_stratiform_cloud_ice_particle" +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" ## ## Run a database report and check the return string @@ -215,13 +217,13 @@ check_datatable ${report_prog} ${datafile} "--module-list" ${module_list} #check_datatable ${report_prog} ${datafile} "--dependencies" ${dependencies} check_datatable ${report_prog} ${datafile} "--suite-list" ${suite_list} \ --sep ";" -echo -e "\nChecking variables for var_compatability suite from command line" +echo -e "\nChecking variables for var_compatibility suite from command line" check_datatable ${report_prog} ${datafile} "--required-variables" \ - ${required_vars_var_compatability} "var_compatability_suite" + ${required_vars_var_compatibility} "var_compatibility_suite" check_datatable ${report_prog} ${datafile} "--input-variables" \ - ${input_vars_var_compatability} "var_compatability_suite" + ${input_vars_var_compatibility} "var_compatibility_suite" check_datatable ${report_prog} ${datafile} "--output-variables" \ - ${output_vars_var_compatability} "var_compatability_suite" + ${output_vars_var_compatibility} "var_compatibility_suite" # Run make make res=$? diff --git a/test/var_compatability_test/test_host.F90 b/test/var_compatibility_test/test_host.F90 similarity index 99% rename from test/var_compatability_test/test_host.F90 rename to test/var_compatibility_test/test_host.F90 index 6de9597c..25129405 100644 --- a/test/var_compatability_test/test_host.F90 +++ b/test/var_compatibility_test/test_host.F90 @@ -375,7 +375,7 @@ program test logical :: run_okay ! Setup expected test suite info - test_suites(1)%suite_name = 'var_compatability_suite' + test_suites(1)%suite_name = 'var_compatibility_suite' test_suites(1)%suite_parts => test_parts1 test_suites(1)%suite_input_vars => test_invars1 test_suites(1)%suite_output_vars => test_outvars1 diff --git a/test/var_compatability_test/test_host.meta b/test/var_compatibility_test/test_host.meta similarity index 100% rename from test/var_compatability_test/test_host.meta rename to test/var_compatibility_test/test_host.meta diff --git a/test/var_compatability_test/test_host_data.F90 b/test/var_compatibility_test/test_host_data.F90 similarity index 100% rename from test/var_compatability_test/test_host_data.F90 rename to test/var_compatibility_test/test_host_data.F90 diff --git a/test/var_compatability_test/test_host_data.meta b/test/var_compatibility_test/test_host_data.meta similarity index 100% rename from test/var_compatability_test/test_host_data.meta rename to test/var_compatibility_test/test_host_data.meta diff --git a/test/var_compatability_test/test_host_mod.F90 b/test/var_compatibility_test/test_host_mod.F90 similarity index 100% rename from test/var_compatability_test/test_host_mod.F90 rename to test/var_compatibility_test/test_host_mod.F90 diff --git a/test/var_compatability_test/test_host_mod.meta b/test/var_compatibility_test/test_host_mod.meta similarity index 100% rename from test/var_compatability_test/test_host_mod.meta rename to test/var_compatibility_test/test_host_mod.meta diff --git a/test/var_compatability_test/test_reports.py b/test/var_compatibility_test/test_reports.py similarity index 95% rename from test/var_compatability_test/test_reports.py rename to test/var_compatibility_test/test_reports.py index a8dc6eea..4c8f9da6 100755 --- a/test/var_compatability_test/test_reports.py +++ b/test/var_compatibility_test/test_reports.py @@ -57,17 +57,17 @@ def usage(errmsg=None): # Check data _HOST_FILES = [os.path.join(_BUILD_DIR, "ccpp", "test_host_ccpp_cap.F90")] -_SUITE_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_var_compatability_suite_cap.F90")] +_SUITE_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_var_compatibility_suite_cap.F90")] _UTILITY_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_kinds.F90"), os.path.join(_SRC_DIR, "ccpp_constituent_prop_mod.F90"), os.path.join(_SRC_DIR, "ccpp_hashable.F90"), os.path.join(_SRC_DIR, "ccpp_hash_table.F90")] _CCPP_FILES = _UTILITY_FILES + \ [os.path.join(_BUILD_DIR, "ccpp", "test_host_ccpp_cap.F90"), - os.path.join(_BUILD_DIR, "ccpp", "ccpp_var_compatability_suite_cap.F90")] + os.path.join(_BUILD_DIR, "ccpp", "ccpp_var_compatibility_suite_cap.F90")] _MODULE_LIST = ["effr_calc"] -_SUITE_LIST = ["var_compatability_suite"] -_INPUT_VARS_VAR_ACTION = ["horizontal_loop_begin", "horizontal_loop_end", "vertical_layer_dimension", +_SUITE_LIST = ["var_compatibility_suite"] +_INPUT_VARS_VAR_ACTION = ["horizontal_loop_begin", "horizontal_loop_end", "horizontal_dimension", "vertical_layer_dimension", "effective_radius_of_stratiform_cloud_liquid_water_particle", "effective_radius_of_stratiform_cloud_rain_particle", "effective_radius_of_stratiform_cloud_snow_particle"] @@ -140,15 +140,15 @@ def check_datatable(database, report_type, check_list, _MODULE_LIST) NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("suite_list"), _SUITE_LIST) -print("\nChecking variables for var_compatability suite from python") +print("\nChecking variables for var_compatibility suite from python") NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("required_variables", - value="var_compatability_suite"), + value="var_compatibility_suite"), _REQUIRED_VARS_VAR_ACTION) NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("input_variables", - value="var_compatability_suite"), + value="var_compatibility_suite"), _INPUT_VARS_VAR_ACTION) NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("output_variables", - value="var_compatability_suite"), + value="var_compatibility_suite"), _OUTPUT_VARS_VAR_ACTION) sys.exit(NUM_ERRORS) diff --git a/test/var_compatability_test/var_compatability_files.txt b/test/var_compatibility_test/var_compatibility_files.txt similarity index 100% rename from test/var_compatability_test/var_compatability_files.txt rename to test/var_compatibility_test/var_compatibility_files.txt diff --git a/test/var_compatability_test/var_compatability_suite.xml b/test/var_compatibility_test/var_compatibility_suite.xml similarity index 69% rename from test/var_compatability_test/var_compatability_suite.xml rename to test/var_compatibility_test/var_compatibility_suite.xml index ae75d9f7..4b70fe48 100644 --- a/test/var_compatability_test/var_compatability_suite.xml +++ b/test/var_compatibility_test/var_compatibility_suite.xml @@ -1,6 +1,6 @@ - + effr_calc diff --git a/test_prebuild/test_blocked_data/README.md b/test_prebuild/test_blocked_data/README.md index ad977913..8802e812 100644 --- a/test_prebuild/test_blocked_data/README.md +++ b/test_prebuild/test_blocked_data/README.md @@ -10,4 +10,5 @@ mkdir build cd build cmake .. 2>&1 | tee log.cmake make 2>&1 | tee log.make +./test_blocked_data.x ```