diff --git a/scripts/common.py b/scripts/common.py index 88d3ac43..5de12ce0 100755 --- a/scripts/common.py +++ b/scripts/common.py @@ -22,6 +22,7 @@ CCPP_ERROR_FLAG_VARIABLE = 'ccpp_error_flag' CCPP_ERROR_MSG_VARIABLE = 'ccpp_error_message' CCPP_LOOP_COUNTER = 'ccpp_loop_counter' +CCPP_LOOP_EXTENT = 'ccpp_loop_extent' CCPP_BLOCK_NUMBER = 'ccpp_block_number' CCPP_BLOCK_COUNT = 'ccpp_block_count' CCPP_BLOCK_SIZES = 'ccpp_block_sizes' diff --git a/scripts/mkstatic.py b/scripts/mkstatic.py index d97d9e6c..5064bb50 100755 --- a/scripts/mkstatic.py +++ b/scripts/mkstatic.py @@ -14,7 +14,7 @@ from common import encode_container from common import CCPP_STAGES -from common import CCPP_ERROR_FLAG_VARIABLE, CCPP_ERROR_MSG_VARIABLE, CCPP_LOOP_COUNTER +from common import CCPP_ERROR_FLAG_VARIABLE, CCPP_ERROR_MSG_VARIABLE, CCPP_LOOP_COUNTER, CCPP_LOOP_EXTENT from common import CCPP_BLOCK_NUMBER, CCPP_BLOCK_COUNT, CCPP_BLOCK_SIZES, CCPP_INTERNAL_VARIABLES from common import CCPP_HORIZONTAL_DIMENSION, CCPP_HORIZONTAL_LOOP_EXTENT from common import FORTRAN_CONDITIONAL_REGEX_WORDS, FORTRAN_CONDITIONAL_REGEX @@ -900,6 +900,10 @@ def write(self, metadata_request, metadata_define, arguments): # 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_FLAG_VARIABLE][0].target ccpp_error_msg_target_name = metadata_request[CCPP_ERROR_MSG_VARIABLE][0].target # @@ -930,10 +934,8 @@ def write(self, metadata_request, metadata_define, arguments): conditionals = {} # for subcycle in self._subcycles: - if subcycle.loop > 1 and ccpp_stage == 'run': - body += ''' - associate(cnt => {loop_var_name}) - do cnt=1,{loop_cnt}\n\n'''.format(loop_var_name=ccpp_loop_counter_target_name,loop_cnt=subcycle.loop) + subcycle_body = '' + # Call all schemes for scheme_name in subcycle.schemes: # actions_before and actions_after capture operations such # as unit conversions, transformations that have to happen @@ -1348,18 +1350,47 @@ def write(self, metadata_request, metadata_define, arguments): return end if '''.format(target_name_flag=ccpp_error_flag_target_name, target_name_msg=ccpp_error_msg_target_name, subroutine_name=subroutine_name) - body += ''' + subcycle_body += ''' {subroutine_call} {error_check} '''.format(subroutine_call=subroutine_call, error_check=error_check) module_use += ' use {m}, only: {s}\n'.format(m=module_name, s=subroutine_name) - if subcycle.loop > 1 and ccpp_stage == 'run': - body += ''' + # If this subcycle calls any schemes, i.e. has any variables registered + # that need to be passed to the group for this stage, then handle the + # subcycle loops by prepending/appending the necessary code to subcycle_body + subcycle_body_prefix = ''' + ! Start of next subcycle +''' + 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': + subcycle_body_prefix += ''' + ! Set loop extent variable for the following subcycle + {loop_extent_var_name} = {loop_cnt_max}\n\n'''.format(loop_extent_var_name=ccpp_loop_extent_target_name, + loop_cnt_max=subcycle.loop) + elif ccpp_loop_extent_target_name: + subcycle_body_prefix += ''' + ! Set loop extent variable for the following subcycle + {loop_extent_var_name} = 1\n\n'''.format(loop_extent_var_name=ccpp_loop_extent_target_name) + # Create subcycle (Fortran do loop) if needed + if subcycle.loop > 1 and ccpp_stage == 'run': + subcycle_body_prefix += ''' + associate(cnt => {loop_var_name}) + do cnt=1,{loop_cnt_max}\n\n'''.format(loop_var_name=ccpp_loop_counter_target_name, + loop_cnt_max=subcycle.loop) + subcycle_body_suffix += ''' end do end associate ''' + else: + subcycle_body_prefix += ''' + {loop_var_name} = 1\n'''.format(loop_var_name=ccpp_loop_counter_target_name) + + # Add this subcycle's Fortran body to the group body + body += subcycle_body_prefix + subcycle_body + subcycle_body_suffix # Get list of arguments, module use statement and variable definitions for this subroutine (=stage for the group) (self.arguments[ccpp_stage], sub_module_use, sub_var_defs) = create_arguments_module_use_var_defs( diff --git a/src/ccpp_types.F90 b/src/ccpp_types.F90 index 903efd98..10bb3e84 100644 --- a/src/ccpp_types.F90 +++ b/src/ccpp_types.F90 @@ -30,6 +30,7 @@ module ccpp_types !> @var The default loop counter indicating outside of a subcycle loop integer, parameter :: CCPP_DEFAULT_LOOP_CNT = -999 + integer, parameter :: CCPP_DEFAULT_LOOP_MAX = -999 !> @var The default values for block and thread numbers indicating invalid data integer, parameter :: CCPP_DEFAULT_BLOCK_AND_THREAD_NUMBER = -999 @@ -51,6 +52,7 @@ module ccpp_types integer :: errflg = 0 character(len=512) :: errmsg = '' integer :: loop_cnt = CCPP_DEFAULT_LOOP_CNT + integer :: loop_max = CCPP_DEFAULT_LOOP_MAX integer :: blk_no = CCPP_DEFAULT_BLOCK_AND_THREAD_NUMBER integer :: thrd_no = CCPP_DEFAULT_BLOCK_AND_THREAD_NUMBER diff --git a/src/ccpp_types.meta b/src/ccpp_types.meta index a090e6d8..fa337801 100644 --- a/src/ccpp_types.meta +++ b/src/ccpp_types.meta @@ -41,6 +41,12 @@ units = index dimensions = () type = integer +[loop_max] + standard_name = ccpp_loop_extent + long_name = loop extent for subcycling loops in CCPP + units = count + dimensions = () + type = integer [blk_no] standard_name = ccpp_block_number long_name = number of block for explicit data blocking in CCPP