diff --git a/scripts/ccpp_prebuild.py b/scripts/ccpp_prebuild.py index c42e5141..4a66cc5e 100755 --- a/scripts/ccpp_prebuild.py +++ b/scripts/ccpp_prebuild.py @@ -3,6 +3,7 @@ # Standard modules import argparse import collections +import copy import filecmp import importlib import itertools @@ -23,6 +24,7 @@ TypedefsMakefile, TypedefsCMakefile, TypedefsSourcefile from mkdoc import metadata_to_html, metadata_to_latex from mkstatic import API, Suite, Group +from mkstatic import CCPP_SUITE_VARIABLES ############################################################################### # Set up the command line argument parser and other global variables # @@ -35,6 +37,7 @@ parser.add_argument('--debug', action='store_true', help='enable debugging features in auto-generated code', default=False) parser.add_argument('--suites', action='store', help='suite definition files to use (comma-separated, without path)', default='') parser.add_argument('--builddir', action='store', help='relative path to CCPP build directory', required=False, default=None) +parser.add_argument('--namespace', action='store', help='namespace suffix to be added to the name of static api module', required=False, default='') # BASEDIR is the current directory where this script is executed BASEDIR = os.getcwd() @@ -56,7 +59,8 @@ def parse_arguments(): else: sdfs = None builddir = args.builddir - return (success, configfile, clean, verbose, debug, sdfs, builddir) + namespace = args.namespace + return (success, configfile, clean, verbose, debug, sdfs, builddir, namespace) def import_config(configfile, builddir): """Import the configuration from a given configuration file""" @@ -95,13 +99,14 @@ def import_config(configfile, builddir): config['caps_cmakefile'] = ccpp_prebuild_config.CAPS_CMAKEFILE.format(build_dir=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['suites_dir'] = ccpp_prebuild_config.SUITES_DIR.format(build_dir=builddir) 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) - # Location of static API file, and shell script to source + # Location of static API file, shell script to source, cmake include file config['static_api_dir'] = ccpp_prebuild_config.STATIC_API_DIR.format(build_dir=builddir) - config['static_api_srcfile'] = ccpp_prebuild_config.STATIC_API_SRCFILE.format(build_dir=builddir) + config['static_api_sourcefile'] = ccpp_prebuild_config.STATIC_API_SOURCEFILE.format(build_dir=builddir) + config['static_api_cmakefile'] = ccpp_prebuild_config.STATIC_API_CMAKEFILE.format(build_dir=builddir) # To handle new metadata: import DDT references (if exist) try: @@ -127,10 +132,14 @@ def setup_logging(verbose): logging.info('Logging level set to INFO') return success -def clean_files(config): +def clean_files(config, namespace): """Clean files created by ccpp_prebuild.py""" success = True logging.info('Performing clean ....') + if namespace: + static_api_file = '{api}.F90'.format(api=CCPP_STATIC_API_MODULE+'_'+namespace) + else: + static_api_file = '{api}.F90'.format(api=CCPP_STATIC_API_MODULE) # Create list of files to remove, use wildcards where necessary files_to_remove = [ config['typedefs_makefile'], @@ -145,8 +154,8 @@ def clean_files(config): config['html_vartable_file'], config['latex_vartable_file'], os.path.join(config['caps_dir'], 'ccpp_*_cap.F90'), - os.path.join(config['static_api_dir'], '{api}.F90'.format(api=CCPP_STATIC_API_MODULE)), - config['static_api_srcfile'], + os.path.join(config['static_api_dir'], static_api_file), + config['static_api_sourcefile'], ] # Not very pythonic, but the easiest way w/o importing another Python module cmd = 'rm -vf {0}'.format(' '.join(files_to_remove)) @@ -329,6 +338,19 @@ def collect_physics_subroutines(scheme_files): os.chdir(BASEDIR) return (success, metadata_request, arguments_request, dependencies_request, schemes_in_files) +def check_schemes_in_suites(arguments, suites): + """Check that all schemes that are requested in the suites exist""" + success = True + logging.info("Checking for existence of schemes in suites ...") + for suite in suites: + for group in suite.groups: + for subcycle in group.subcycles: + for scheme_name in subcycle.schemes: + if not scheme_name in arguments.keys(): + success = False + logging.critical("Scheme {} in suite {} cannot be found".format(scheme_name, suite.name)) + return success + def filter_metadata(metadata, arguments, dependencies, schemes_in_files, suites): """Remove all variables from metadata that are not used in the given suite; also remove information on argument lists, dependencies and schemes in files""" @@ -376,6 +398,16 @@ def filter_metadata(metadata, arguments, dependencies, schemes_in_files, suites) schemes_in_files_filtered[scheme] = schemes_in_files[scheme] return (success, metadata_filtered, arguments_filtered, dependencies_filtered, schemes_in_files_filtered) +def add_ccpp_suite_variables(metadata): + """ Add variables that are required to construct CCPP suites to the list of requested variables""" + success = True + logging.info("Adding CCPP suite variables to list of requested variables") + for var_name in CCPP_SUITE_VARIABLES.keys(): + if not var_name in metadata.keys(): + metadata[var_name] = [copy.deepcopy(CCPP_SUITE_VARIABLES[var_name])] + logging.debug("Adding CCPP suite variable {0} to list of requested variables".format(var_name)) + return (success, metadata) + def generate_list_of_schemes_and_dependencies_to_compile(schemes_in_files, dependencies1, dependencies2): """Generate a flat list of schemes and dependencies in two dependency dictionaries to compile""" success = True @@ -489,7 +521,7 @@ def generate_suite_and_group_caps(suites, metadata_request, metadata_define, arg success = False return (success, suite_and_group_caps) -def generate_static_api(suites, static_api_dir): +def generate_static_api(suites, static_api_dir, namespace): """Generate static API for given suite(s)""" success = True # Change to caps directory, create if necessary @@ -497,6 +529,12 @@ def generate_static_api(suites, static_api_dir): os.makedirs(static_api_dir) os.chdir(static_api_dir) api = API(suites=suites, directory=static_api_dir) + if namespace: + base = os.path.splitext(os.path.basename(api.filename))[0] + logging.info('Static API file name is ''{}'''.format(api.filename)) + api.filename = base+'_'+namespace+'.F90' + api.module = base+'_'+namespace + logging.info('Static API file name is changed to ''{}'''.format(api.filename)) logging.info('Generating static API {0} in {1} ...'.format(api.filename, static_api_dir)) api.write() os.chdir(BASEDIR) @@ -655,7 +693,7 @@ def generate_caps_makefile(caps, caps_makefile, caps_cmakefile, caps_sourcefile, def main(): """Main routine that handles the CCPP prebuild for different host models.""" # Parse command line arguments - (success, configfile, clean, verbose, debug, sdfs, builddir) = parse_arguments() + (success, configfile, clean, verbose, debug, sdfs, builddir, namespace) = parse_arguments() if not success: raise Exception('Call to parse_arguments failed.') @@ -669,7 +707,7 @@ def main(): # Perform clean if requested, then exit if clean: - success = clean_files(config) + success = clean_files(config, namespace) logging.info('CCPP prebuild clean completed successfully, exiting.') sys.exit(0) @@ -699,12 +737,22 @@ def main(): if not success: raise Exception('Call to collect_physics_subroutines failed.') + # Check that the schemes requested in the suites exist + success = check_schemes_in_suites(arguments_request, suites) + if not success: + raise Exception('Call to check_schemes_in_suites failed.') + # Filter metadata/arguments - remove whatever is not included in suite definition files (success, metadata_request, arguments_request, dependencies_request, schemes_in_files) = filter_metadata( metadata_request, arguments_request, dependencies_request, schemes_in_files, suites) if not success: raise Exception('Call to filter_metadata failed.') + # Add variables that are required to construct CCPP suites to the list of requested variables + (success, metadata_request) = add_ccpp_suite_variables(metadata_request) + if not success: + raise Exception('Call to add_ccpp_suite_variables failed.') + (success, schemes_and_dependencies_to_compile) = generate_list_of_schemes_and_dependencies_to_compile( schemes_in_files, dependencies_request, dependencies_define) if not success: @@ -739,13 +787,17 @@ def main(): if not success: raise Exception('Call to generate_suite_and_group_caps failed.') - (success, api) = generate_static_api(suites, config['static_api_dir']) - if not success: + (success, api) = generate_static_api(suites, config['static_api_dir'], namespace) + if not success: raise Exception('Call to generate_static_api failed.') - success = api.write_sourcefile(config['static_api_srcfile']) - if not success: - raise Exception("Writing API sourcefile {sourcefile} failed".format(sourcefile=config['static_api_srcfile'])) + success = api.write_includefile(config['static_api_sourcefile'], type='shell') + if not success: + raise Exception("Writing API sourcefile {sourcefile} failed".format(sourcefile=config['static_api_sourcefile'])) + + success = api.write_includefile(config['static_api_cmakefile'], type='cmake') + if not success: + raise Exception("Writing API cmakefile {cmakefile} failed".format(cmakefile=config['static_api_cmakefile'])) # Add filenames of caps to makefile/cmakefile/shell script all_caps = suite_and_group_caps diff --git a/scripts/metadata_parser.py b/scripts/metadata_parser.py index cf6aa6ea..00a0acd7 100755 --- a/scripts/metadata_parser.py +++ b/scripts/metadata_parser.py @@ -9,6 +9,7 @@ from xml.etree import ElementTree as ET from common import encode_container, CCPP_STAGES +from common import CCPP_ERROR_CODE_VARIABLE, CCPP_ERROR_MSG_VARIABLE from mkcap import Var sys.path.append(os.path.join(os.path.split(__file__)[0], 'fortran_tools')) @@ -38,28 +39,28 @@ # Mandatory variables that every scheme needs to have CCPP_MANDATORY_VARIABLES = { - 'ccpp_error_message' : Var(local_name = 'errmsg', - standard_name = 'ccpp_error_message', - long_name = 'error message for error handling in CCPP', - units = 'none', - type = 'character', - dimensions = [], - rank = '', - kind = 'len=*', - intent = 'out', - active = 'T', - ), - 'ccpp_error_code' : Var(local_name = 'ierr', - standard_name = 'ccpp_error_code', - long_name = 'error code for error handling in CCPP', - units = '1', - type = 'integer', - dimensions = [], - rank = '', - kind = '', - intent = 'out', - active = 'T', - ), + CCPP_ERROR_MSG_VARIABLE : Var(local_name = 'errmsg', + standard_name = CCPP_ERROR_MSG_VARIABLE, + long_name = 'error message for error handling in CCPP', + units = 'none', + type = 'character', + dimensions = [], + rank = '', + kind = 'len=*', + intent = 'out', + active = 'T', + ), + CCPP_ERROR_CODE_VARIABLE : Var(local_name = 'ierr', + standard_name = CCPP_ERROR_CODE_VARIABLE, + long_name = 'error code for error handling in CCPP', + units = '1', + type = 'integer', + dimensions = [], + rank = '', + kind = '', + intent = 'out', + active = 'T', + ), } # Save metadata to avoid repeated parsing of type/variable definition files diff --git a/scripts/mkdoc.py b/scripts/mkdoc.py index f74049f7..018f88f6 100755 --- a/scripts/mkdoc.py +++ b/scripts/mkdoc.py @@ -127,7 +127,7 @@ def metadata_to_latex(metadata_define, metadata_request, model, filename): target = 'MISSING' local_name = 'MISSING' if var_name in metadata_request.keys(): - requested_list = [ escape_tex(decode_container(v.container)) for v in metadata_request[var_name] ] + requested_list = [ escape_tex(decode_container(v.container)) if v.container else 'none' for v in metadata_request[var_name] ] # for the purpose of the table, just output the name of the subroutine for i in range(len(requested_list)): entry = requested_list[i] diff --git a/scripts/mkstatic.py b/scripts/mkstatic.py index 7c94a04e..2722388e 100755 --- a/scripts/mkstatic.py +++ b/scripts/mkstatic.py @@ -20,6 +20,7 @@ from common import FORTRAN_CONDITIONAL_REGEX_WORDS, FORTRAN_CONDITIONAL_REGEX from common import CCPP_TYPE, STANDARD_VARIABLE_TYPES, STANDARD_CHARACTER_TYPE from common import CCPP_STATIC_API_MODULE, CCPP_STATIC_SUBROUTINE_NAME +from metadata_parser import CCPP_MANDATORY_VARIABLES from mkcap import Var ############################################################################### @@ -27,6 +28,32 @@ # Maximum number of dimensions of an array allowed by the Fortran 2008 standard FORTRAN_ARRAY_MAX_DIMS = 15 +# These variables always need to be present for creating suite and group caps +CCPP_SUITE_VARIABLES = { **CCPP_MANDATORY_VARIABLES, + CCPP_LOOP_COUNTER : Var(local_name = 'loop_cnt', + standard_name = CCPP_LOOP_COUNTER, + long_name = 'loop counter for subcycling loops in CCPP', + units = 'index', + type = 'integer', + dimensions = [], + rank = '', + kind = '', + intent = 'in', + active = 'T', + ), + CCPP_LOOP_EXTENT : Var(local_name = 'loop_max', + standard_name = CCPP_LOOP_EXTENT, + long_name = 'loop counter for subcycling loops in CCPP', + units = 'count', + type = 'integer', + dimensions = [], + rank = '', + kind = '', + intent = 'in', + active = 'T', + ), + } + ############################################################################### def extract_parents_and_indices_from_local_name(local_name): @@ -252,6 +279,10 @@ def module(self): '''Get the module name of the API.''' return self._module + @module.setter + def module(self, value): + self._module = value + @property def subroutines(self): '''Get the subroutines names of the API to.''' @@ -406,7 +437,7 @@ def write(self): self.update_api = True return - def write_sourcefile(self, source_filename): + def write_includefile(self, source_filename, type): success = True filepath = os.path.split(source_filename)[0] if filepath and not os.path.isdir(filepath): @@ -422,14 +453,30 @@ def write_sourcefile(self, source_filename): else: write_to_test_file = False f = open(source_filename, 'w') - # Contents of shell/source file - contents = """# The CCPP static API is defined here. + + if type == 'shell': + # Contents of shell/source file + contents = """# The CCPP static API is defined here. # # This file is auto-generated using ccpp_prebuild.py # at compile time, do not edit manually. # export CCPP_STATIC_API=\"{filename}\" """.format(filename=os.path.abspath(os.path.join(self.directory,self.filename))) + elif type == 'cmake': + # Contents of cmake include file + contents = """# The CCPP static API is defined here. +# +# This file is auto-generated using ccpp_prebuild.py +# at compile time, do not edit manually. +# +set(API \"{filename}\") +""".format(filename=os.path.abspath(os.path.join(self.directory,self.filename))) + else: + logging.error('Encountered unknown type of file "{type}" when writing include file for static API'.format(type=type)) + success = False + return + f.write(contents) f.close() # See comment above on updating the API or not @@ -904,11 +951,8 @@ def write(self, metadata_request, metadata_define, arguments, debug): # First get target names of standard CCPP variables for subcycling and error handling ccpp_loop_counter_target_name = metadata_request[CCPP_LOOP_COUNTER][0].target - if CCPP_LOOP_EXTENT in metadata_request.keys(): - ccpp_loop_extent_target_name = metadata_request[CCPP_LOOP_EXTENT][0].target - else: - ccpp_loop_extent_target_name = None - ccpp_error_flag_target_name = metadata_request[CCPP_ERROR_CODE_VARIABLE][0].target + ccpp_loop_extent_target_name = metadata_request[CCPP_LOOP_EXTENT][0].target + ccpp_error_code_target_name = metadata_request[CCPP_ERROR_CODE_VARIABLE][0].target ccpp_error_msg_target_name = metadata_request[CCPP_ERROR_MSG_VARIABLE][0].target # module_use = '' @@ -1445,7 +1489,7 @@ def write(self, metadata_request, metadata_define, arguments, debug): ierr={target_name_flag} return end if -'''.format(target_name_flag=ccpp_error_flag_target_name, target_name_msg=ccpp_error_msg_target_name, subroutine_name=subroutine_name) +'''.format(target_name_flag=ccpp_error_code_target_name, target_name_msg=ccpp_error_msg_target_name, subroutine_name=subroutine_name) subcycle_body += ''' {subroutine_call} {error_check} @@ -1461,14 +1505,14 @@ def write(self, metadata_request, metadata_define, arguments, debug): ''' subcycle_body_suffix = '' if self.parents[ccpp_stage]: - # Set subcycle loop extent if requested by any scheme - if ccpp_loop_extent_target_name and ccpp_stage == 'run': + # Set subcycle loop extent + if ccpp_stage == 'run': subcycle_body_prefix += ''' ! Set loop extent variable for the following subcycle {loop_extent_var_name} = {loop_cnt_max} '''.format(loop_extent_var_name=ccpp_loop_extent_target_name, loop_cnt_max=subcycle.loop) - elif ccpp_loop_extent_target_name: + else: subcycle_body_prefix += ''' ! Set loop extent variable for the following subcycle {loop_extent_var_name} = 1 @@ -1507,13 +1551,13 @@ def write(self, metadata_request, metadata_define, arguments, debug): # at least one subroutine that gets called from this group), or skip. if self.arguments[ccpp_stage]: initialized_test_block = Group.initialized_test_blocks[ccpp_stage].format( - target_name_flag=ccpp_error_flag_target_name, + target_name_flag=ccpp_error_code_target_name, target_name_msg=ccpp_error_msg_target_name, name=self._name) else: initialized_test_block = '' initialized_set_block = Group.initialized_set_blocks[ccpp_stage].format( - target_name_flag=ccpp_error_flag_target_name, + target_name_flag=ccpp_error_code_target_name, target_name_msg=ccpp_error_msg_target_name, name=self._name) # Create subroutine diff --git a/stub/CMakeLists.txt b/stub/CMakeLists.txt new file mode 100644 index 00000000..9ee7ce9f --- /dev/null +++ b/stub/CMakeLists.txt @@ -0,0 +1,84 @@ +#------------------------------------------------------------------------------ +cmake_minimum_required(VERSION 3.0) + +project(ccppstub + VERSION 1.0.0 + LANGUAGES Fortran) + +#------------------------------------------------------------------------------ +# Request a static build +option(BUILD_SHARED_LIBS "Build a shared library" OFF) + +#------------------------------------------------------------------------------ +# Set the sources: physics type definitions +set(TYPEDEFS $ENV{CCPP_TYPEDEFS}) +if(TYPEDEFS) + message(STATUS "Got CCPP TYPEDEFS from environment variable: ${TYPEDEFS}") +else(TYPEDEFS) + include(${CMAKE_CURRENT_SOURCE_DIR}/CCPP_TYPEDEFS.cmake) + message(STATUS "Got CCPP TYPEDEFS from cmakefile include file: ${TYPEDEFS}") +endif(TYPEDEFS) + +# Generate list of Fortran modules from the CCPP type +# definitions that need need to be installed +foreach(typedef_module ${TYPEDEFS}) + list(APPEND MODULES_F90 ${CMAKE_CURRENT_BINARY_DIR}/${typedef_module}) +endforeach() + +#------------------------------------------------------------------------------ +# Set the sources: physics schemes +set(SCHEMES $ENV{CCPP_SCHEMES}) +if(SCHEMES) + message(STATUS "Got CCPP SCHEMES from environment variable: ${SCHEMES}") +else(SCHEMES) + include(${CMAKE_CURRENT_SOURCE_DIR}/CCPP_SCHEMES.cmake) + message(STATUS "Got CCPP SCHEMES from cmakefile include file: ${SCHEMES}") +endif(SCHEMES) + +# Set the sources: physics scheme caps +set(CAPS $ENV{CCPP_CAPS}) +if(CAPS) + message(STATUS "Got CCPP CAPS from environment variable: ${CAPS}") +else(CAPS) + include(${CMAKE_CURRENT_SOURCE_DIR}/CCPP_CAPS.cmake) + message(STATUS "Got CCPP CAPS from cmakefile include file: ${CAPS}") +endif(CAPS) + +# Set the sources: physics scheme caps +set(API $ENV{CCPP_API}) +if(API) + message(STATUS "Got CCPP API from environment variable: ${API}") +else(API) + include(${CMAKE_CURRENT_SOURCE_DIR}/CCPP_API.cmake) + message(STATUS "Got CCPP API from cmakefile include file: ${API}") +endif(API) + +#------------------------------------------------------------------------------ +add_library(ccppstub STATIC ${SCHEMES} ${CAPS} ${API}) +# Generate list of Fortran modules from defined sources +foreach(source_f90 ${CAPS} ${API}) + get_filename_component(tmp_source_f90 ${source_f90} NAME) + string(REGEX REPLACE ".F90" ".mod" tmp_module_f90 ${tmp_source_f90}) + string(TOLOWER ${tmp_module_f90} module_f90) + list(APPEND MODULES_F90 ${CMAKE_CURRENT_BINARY_DIR}/${module_f90}) +endforeach() + +set_target_properties(ccppstub PROPERTIES VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR}) + +# Define where to install the library +install(TARGETS ccppstub + EXPORT ccppstub-targets + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION lib +) +# Export our configuration +install(EXPORT ccppstub-targets + FILE ccppstub-config.cmake + DESTINATION lib/cmake +) +# Define where to install the C headers and Fortran modules +#install(FILES ${HEADERS_C} DESTINATION include) +install(FILES ${MODULES_F90} DESTINATION include) + diff --git a/stub/README.md b/stub/README.md new file mode 100644 index 00000000..e641aece --- /dev/null +++ b/stub/README.md @@ -0,0 +1,12 @@ +# How to build the stub + +Note: build is in-source for now + +1. Set compiler environment as appropriate for your system +2. Run the following commands: +``` +cd stub +../scripts/ccpp_prebuild.py --config=ccpp_prebuild_config.py +cmake . 2>&1 | tee log.cmake +make 2>&1 | tee log.make +``` diff --git a/stub/ccpp_prebuild_config.py b/stub/ccpp_prebuild_config.py new file mode 100755 index 00000000..31aeccfb --- /dev/null +++ b/stub/ccpp_prebuild_config.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python + +# CCPP prebuild config for GFDL Finite-Volume Cubed-Sphere Model (FV3) + + +############################################################################### +# Definitions # +############################################################################### + +HOST_MODEL_IDENTIFIER = "FV3" + +# Add all files with metadata tables on the host model side and in CCPP, +# relative to basedir = top-level directory of host model. This includes +# kind and type definitions used in CCPP physics. Also add any internal +# dependencies of these files to the list. +VARIABLE_DEFINITION_FILES = [ + # actual variable definition files + '../src/ccpp_types.F90', + 'data.F90', + ] + +TYPEDEFS_NEW_METADATA = { + 'ccpp_types' : { + 'ccpp_types' : '', + 'ccpp_t' : 'ccpp_data', + }, + } + +# Add all physics scheme files relative to basedir +SCHEME_FILES = [ + 'stub.F90', + ] + +# Default build dir, relative to current working directory, +# if not specified as command-line argument +DEFAULT_BUILD_DIR = '.' + +# Auto-generated makefile/cmakefile snippets that contain all type definitions +TYPEDEFS_MAKEFILE = '{build_dir}/CCPP_TYPEDEFS.mk' +TYPEDEFS_CMAKEFILE = '{build_dir}/CCPP_TYPEDEFS.cmake' +TYPEDEFS_SOURCEFILE = '{build_dir}/CCPP_TYPEDEFS.sh' + +# Auto-generated makefile/cmakefile snippets that contain all schemes +SCHEMES_MAKEFILE = '{build_dir}/CCPP_SCHEMES.mk' +SCHEMES_CMAKEFILE = '{build_dir}/CCPP_SCHEMES.cmake' +SCHEMES_SOURCEFILE = '{build_dir}/CCPP_SCHEMES.sh' + +# Auto-generated makefile/cmakefile snippets that contain all caps +CAPS_MAKEFILE = '{build_dir}/CCPP_CAPS.mk' +CAPS_CMAKEFILE = '{build_dir}/CCPP_CAPS.cmake' +CAPS_SOURCEFILE = '{build_dir}/CCPP_CAPS.sh' + +# Directory where to put all auto-generated physics caps +CAPS_DIR = '{build_dir}' + +# Directory where the suite definition files are stored +SUITES_DIR = '{build_dir}' + +# Optional arguments - only required for schemes that use +# optional arguments. ccpp_prebuild.py will throw an exception +# if it encounters a scheme subroutine with optional arguments +# if no entry is made here. Possible values are: 'all', 'none', +# or a list of standard_names: [ 'var1', 'var3' ]. +OPTIONAL_ARGUMENTS = {} + +# Directory where to write static API to +STATIC_API_DIR = '{build_dir}' +STATIC_API_CMAKEFILE = '{build_dir}/CCPP_API.cmake' +STATIC_API_SOURCEFILE = '{build_dir}/CCPP_API.sh' + +# Directory for writing HTML pages generated from metadata files +METADATA_HTML_OUTPUT_DIR = '{build_dir}' + +# HTML document containing the model-defined CCPP variables +HTML_VARTABLE_FILE = '{build_dir}/CCPP_VARIABLES_STUB.html' + +# LaTeX document containing the provided vs requested CCPP variables +LATEX_VARTABLE_FILE = '{build_dir}/CCPP_VARIABLES_STUB.tex' diff --git a/stub/data.F90 b/stub/data.F90 new file mode 100644 index 00000000..d2a21c15 --- /dev/null +++ b/stub/data.F90 @@ -0,0 +1,17 @@ +module data + +!! \section arg_table_data Argument Table +!! \htmlinclude data.html +!! + + use ccpp_types, only: ccpp_t + + implicit none + + private + + public ccpp_data + + type(ccpp_t), save, target :: ccpp_data + +end module data diff --git a/stub/data.meta b/stub/data.meta new file mode 100644 index 00000000..55600b1a --- /dev/null +++ b/stub/data.meta @@ -0,0 +1,14 @@ +[ccpp-table-properties] + name = data + type = module + dependencies = + +[ccpp-arg-table] + name = data + type = module +[ccpp_data] + standard_name = ccpp_t_instance + long_name = instance of derived data type ccpp_t + units = DDT + dimensions = () + type = ccpp_t diff --git a/stub/stub.F90 b/stub/stub.F90 new file mode 100644 index 00000000..0b392daa --- /dev/null +++ b/stub/stub.F90 @@ -0,0 +1,35 @@ +!>\file stub.F90 +!! This file contains a stub CCPP scheme that does nothing +!! except requesting the minimum, mandatory variables. + +module stub + + implicit none + private + public :: stub_init, stub_finalize + + contains + +!! \section arg_table_stub_init Argument Table +!! \htmlinclude stub_init.html +!! + subroutine stub_init(errmsg, errflg) + character(len=*), intent(out) :: errmsg + integer, intent(out) :: errflg + ! Initialize CCPP error handling variables + errmsg = '' + errflg = 0 + end subroutine stub_init + +!! \section arg_table_stub_finalize Argument Table +!! \htmlinclude stub_finalize.html +!! + subroutine stub_finalize(errmsg, errflg) + character(len=*), intent(out) :: errmsg + integer, intent(out) :: errflg + ! Initialize CCPP error handling variables + errmsg = '' + errflg = 0 + end subroutine stub_finalize + +end module stub diff --git a/stub/stub.meta b/stub/stub.meta new file mode 100644 index 00000000..3cc30d59 --- /dev/null +++ b/stub/stub.meta @@ -0,0 +1,45 @@ +[ccpp-table-properties] + name = stub + type = scheme + dependencies = + +######################################################################## +[ccpp-arg-table] + name = stub_init + type = scheme +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out + +######################################################################## +[ccpp-arg-table] + name = stub_finalize + type = scheme +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out + diff --git a/stub/suite_stub.xml b/stub/suite_stub.xml new file mode 100644 index 00000000..46d25f9f --- /dev/null +++ b/stub/suite_stub.xml @@ -0,0 +1,9 @@ + + + + + + stub + + +