Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of CCPP timestep_init and timestep_final phases #344

Merged
merged 4 commits into from
Jan 8, 2021
Merged
Show file tree
Hide file tree
Changes from 3 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
5 changes: 4 additions & 1 deletion scripts/ccpp_prebuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

# CCPP framework imports
from common import encode_container, decode_container, decode_container_as_dict, execute
from common import CCPP_INTERNAL_VARIABLES, CCPP_STATIC_API_MODULE, CCPP_INTERNAL_VARIABLE_DEFINITON_FILE
from common import CCPP_STAGES, CCPP_INTERNAL_VARIABLES, CCPP_STATIC_API_MODULE, CCPP_INTERNAL_VARIABLE_DEFINITON_FILE
from common import STANDARD_VARIABLE_TYPES, STANDARD_INTEGER_TYPE, CCPP_TYPE
from common import SUITE_DEFINITION_FILENAME_PATTERN
from common import split_var_name_and_array_reference
Expand Down Expand Up @@ -341,6 +341,9 @@ def filter_metadata(metadata, arguments, dependencies, schemes_in_files, suites)
for var in metadata[var_name][:]:
container_string = decode_container(var.container)
subroutine = container_string[container_string.find('SUBROUTINE')+len('SUBROUTINE')+1:]
# Replace the full CCPP stage name with the abbreviated version
for ccpp_stage in CCPP_STAGES.keys():
subroutine = subroutine.replace(ccpp_stage, CCPP_STAGES[ccpp_stage])
for suite in suites:
if subroutine in suite.all_subroutines_called:
keep = True
Expand Down
12 changes: 11 additions & 1 deletion scripts/common.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
#!/usr/bin/env python

from collections import OrderedDict
import keyword
import logging
import os
import re
import subprocess
import sys

CCPP_STAGES = [ 'init', 'run', 'finalize' ]
# This dictionary contains short names for the different CCPP stages,
# because Fortran does not allow subroutine names with more than 63 characters
# Important: 'timestep_init' and 'timestep_finalize' need to come first so that
# a pattern match won't pick "init" for a CCPP subroutine name "xyz_timestep_init"
CCPP_STAGES = OrderedDict()
CCPP_STAGES['timestep_init'] = 'tsinit'
CCPP_STAGES['timestep_finalize'] = 'tsfinal'
CCPP_STAGES['init'] = 'init'
CCPP_STAGES['run'] = 'run'
CCPP_STAGES['finalize'] = 'final'

CCPP_ERROR_FLAG_VARIABLE = 'ccpp_error_flag'
CCPP_ERROR_MSG_VARIABLE = 'ccpp_error_message'
Expand Down
48 changes: 15 additions & 33 deletions scripts/metadata_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import collections
import logging
import os
import re
import subprocess
import sys
from xml.etree import ElementTree as ET

from common import encode_container
from common import encode_container, CCPP_STAGES
from mkcap import Var

import sys, os
sys.path.append(os.path.join(os.path.split(__file__)[0], 'fortran_tools'))
from parse_fortran import Ftype_type_decl
from metadata_table import MetadataHeader
Expand Down Expand Up @@ -182,7 +184,7 @@ def read_new_metadata(filename, module_name, table_name, scheme_name = None, sub
legacy_note = ' replaced by horizontal loop extent (legacy extension)'
# Adjust dimensions
dimensions = new_var.get_prop_value('dimensions')
if scheme_name and (table_name.endswith("_init") or table_name.endswith("finalize")) \
if scheme_name and (table_name.endswith("_init") or table_name.endswith("_finalize")) \
and 'horizontal_loop_extent' in dimensions:
logging.warn("Legacy extension - replacing dimension 'horizontal_loop_extent' with 'horizontal_dimension' " + \
"for variable {} in table {}".format(standard_name,table_name))
Expand Down Expand Up @@ -508,9 +510,6 @@ def parse_scheme_tables(filepath, filename):
# Set debug to true if logging level is debug
debug = logging.getLogger().getEffectiveLevel() == logging.DEBUG

# Valid suffices for physics scheme routines
subroutine_suffices = [ 'init', 'run', 'finalize']

# Final metadata container for all variables in file
metadata = collections.OrderedDict()

Expand Down Expand Up @@ -596,9 +595,16 @@ def parse_scheme_tables(filepath, filename):
subroutine_name = words[j+1].split('(')[0].strip()
# Consider the last substring separated by a '_' of the subroutine name as a 'postfix'
if subroutine_name.find('_') >= 0:
subroutine_suffix = subroutine_name.split('_')[-1]
if subroutine_suffix in subroutine_suffices:
scheme_name = subroutine_name[0:subroutine_name.rfind('_')]
scheme_name = None
subroutine_suffix = None
for ccpp_stage in CCPP_STAGES:
pattern = '^(.*)_{}$'.format(ccpp_stage)
match = re.match(pattern, subroutine_name)
if match:
scheme_name = match.group(1)
subroutine_suffix = ccpp_stage
break
if match:
if not scheme_name == module_name:
raise Exception('Scheme name differs from module name: module_name="{0}" vs. scheme_name="{1}"'.format(
module_name, scheme_name))
Expand Down Expand Up @@ -720,30 +726,6 @@ def parse_scheme_tables(filepath, filename):
raise Exception('Mandatory CCPP variable {0} not declared in metadata table of subroutine {1}'.format(
var_name, subroutine_name))

# For CCPP-compliant files (i.e. files with metadata tables, perform additional checks)
if len(metadata.keys()) > 0:
# Check that all subroutine "root" names in the current module are equal to scheme_name
# and that there are exactly three subroutines for scheme X: X_init, X_run, X_finalize
message = ''
abort = False
for scheme_name in registry[module_name].keys():
# Pre-generate error message
message += 'Check that all subroutines in module {0} have the same root name:\n'.format(module_name)
message += ' i.e. scheme_A_init, scheme_A_run, scheme_A_finalize\n'
message += 'Here is a list of the subroutine names for scheme {0}:\n'.format(scheme_name)
message += '{0}\n\n'.format(', '.join(sorted(registry[module_name][scheme_name].keys())))
if (not len(registry[module_name][scheme_name].keys()) == 3):
logging.exception(message)
abort = True
else:
for suffix in subroutine_suffices:
subroutine_name = '{0}_{1}'.format(scheme_name, suffix)
if not subroutine_name in registry[module_name][scheme_name].keys():
logging.exception(message)
abort = True
if abort:
raise Exception(message)

# Debugging output to screen and to XML
if debug and len(metadata.keys()) > 0:
# To screen
Expand Down
Loading