Skip to content

Commit d326c9c

Browse files
authored
acg3 nondefault tk
* Update on precision * declare pointer using typekind; unit tests pass * Update CHANGELOG.md
1 parent 5c472db commit d326c9c

3 files changed

Lines changed: 110 additions & 15 deletions

File tree

Apps/MAPL_GridCompSpecs_ACGv3.py

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,30 @@
88
from functools import partial, reduce
99
from operator import concat
1010
from re import compile
11+
from enum import Enum
12+
import logging
13+
import io
14+
15+
# ESMF_TYPEKIND enum
16+
class TYPEKIND_Type:
17+
__slots__=('type', 'kind', 'variable_type')
18+
def __init__(self, ftype: str, kind: str):
19+
self.type = ftype
20+
self.kind = kind
21+
self.variable_type = '{}(kind={})'.format(ftype, kind)
22+
23+
class ESMF_Typekind(TYPEKIND_Type, Enum):
24+
R4 = ('real', 'ESMF_KIND_R4')
25+
R8 = ('real', 'ESMF_KIND_R8')
26+
I4 = ('integer', 'ESMF_KIND_I4')
27+
I8 = ('integer', 'ESMF_KIND_I8')
28+
ESMF_TYPEKIND_R4 = R4
29+
ESMF_TYPEKIND_R8 = R8
30+
ESMF_TYPEKIND_I4 = I4
31+
ESMF_TYPEKIND_I8 = I8
32+
33+
def __str__(self):
34+
return self.variable_type
1135

1236
################################# CONSTANTS ####################################
1337
# str constants internal to script
@@ -23,6 +47,7 @@
2347
INDENT = SPACE * SIZE_INDENT
2448
DIMSTR = ':'
2549
DIMDELIM = ','
50+
DEFAULT_TYPEKIND = 'ESMF_TYPEKIND_R4'
2651

2752
# str flags
2853
AS = 'as'
@@ -43,7 +68,8 @@
4368
GET = 'get'
4469
MAKE_BLOCK = 'make_block'
4570
INTENT_PREFIX = 'ESMF_STATEINTENT_'
46-
MAPPED = 'mapped'
71+
KIND = 'kind'
72+
MAPPED = 'mapped'
4773
MAPPING = 'mapping'
4874
MISSING_MANDATORY = 'missing_mandatory'
4975
NONES = 'nones'
@@ -54,6 +80,7 @@
5480
STORE = 'store'
5581
STRING = 'string'
5682
STRLOGICAL = 'strlogical'
83+
TYPE = 'type'
5784
VALUES_NOT_FOUND = 'values_not_found'
5885

5986
# These are column names. A few are "special" column names used internally.
@@ -79,6 +106,7 @@
79106
STATE_ARG = 'state_arg'
80107
STATE_INTENT = 'state_intent'
81108
STRINGVECTOR = 'string_vector'
109+
TYPEKIND = 'typekind'
82110
UNGRIDDED_DIMS = 'ungridded_dims'
83111
USE_FIELD_DICTIONARY = 'use_field_dictionary'
84112
VSTAGGER = 'vstagger'
@@ -182,8 +210,8 @@ def get_options(args):
182210
'REQUIRED': 'MAPL_RESTART_REQUIRED',
183211
'BOOT': 'MAPL_RESTART_BOOT',
184212
'SKIP_INITIAL': 'MAPL_RESTART_SKIP_INITIAL'}},
185-
STATE: {FLAGS: {MANDATORY, STORE}},
186-
'typekind': {MAPPING: {
213+
STATE: {FLAGS: {MANDATORY, STORE}},
214+
TYPEKIND: {MAPPING: {
187215
'R4': 'ESMF_Typekind_R4',
188216
'R8': 'ESMF_Typekind_R8',
189217
'I4': 'ESMF_Typekind_I4',
@@ -264,17 +292,27 @@ def emit_declare_pointers(specs, states=None):
264292
"""Emit pointer declarations from Iterable of spec instances."""
265293
# filter on state
266294
f = state_filter(states)
267-
return DECLARE, [emit_declare_pointer(spec) for spec in specs if f(spec)]
295+
declarations = []
296+
for spec in specs:
297+
if not f(spec):
298+
continue
299+
try:
300+
declaration = emit_declare_pointer(spec)
301+
except RuntimeError as ex:
302+
raise RuntimeError(f'Error pointer declaration for spec {spec}: {str(ex)}')
303+
declarations.append(declaration)
304+
return DECLARE, declarations
268305

269306
def emit_declare_pointer(spec):
270307
"""Emit individual pointer declartion."""
271-
# get precision of pointer
272-
precision = spec.get(PRECISION)
273-
# declaration preamble
274-
decl = 'real{}, pointer'.format('(kind={})'.format(precision) if precision else EMPTY)
308+
# get fortran type and kind of pointer
309+
typekind = spec.get(TYPEKIND, DEFAULT_TYPEKIND)
310+
if not hasattr(ESMF_Typekind, typekind):
311+
raise RuntimeError(f'Unsupported typekind: {typekind}')
312+
ftypekind = "{}, pointer".format(str(ESMF_Typekind[typekind]))
275313
# pointer variable
276314
var = f'{spec[INTERNAL_NAME]}({DIMDELIM.join(DIMSTR*spec[RANK])})'
277-
return ' :: '.join([decl, var])
315+
return f'{ftypekind} :: {var}'
278316

279317
def emit_get_pointers(specs, states=None):
280318
"""Emit pointer get statements from an Iterable of spec instances."""
@@ -401,7 +439,7 @@ def get_from_values(keys, values, args):
401439

402440
def digest_spec(spec, options):
403441
"""Process an individual spec."""
404-
# Get the key/value pairs that have a matching option key and a value that evaluates False.
442+
# Get the key/value pairs that have a matching option key and a value that evaluates True.
405443
tuples = [(k, spec[k]) for k, v in spec.items() if k in options and spec[k]]
406444
# Get the options corresponding to the spec keys.
407445
spec_options = [options[k] for k, _ in tuples]
@@ -530,7 +568,10 @@ def emit_values(specs, options):
530568
# Emit all get_pointer calls and pointer declartions.
531569
emitters = {DECLARE: emit_declare_pointers, GET: emit_get_pointers}
532570
for key in set(emitters) & set(args):
533-
_, emitted = emitters[key](specs, states)
571+
try:
572+
_, emitted = emitters[key](specs, states)
573+
except Exception as ex:
574+
raise RuntimeError
534575
with open_file(component, args[key], key, 'pointer') as f:
535576
f.writelines(add_newlines(emitted))
536577

@@ -711,7 +752,7 @@ def inner(*args):
711752
return inner
712753

713754
# Main Procedure (Added to facilitate testing.)
714-
def main():
755+
def main(logger):
715756
exit_code = ERROR
716757

717758
# Process command line arguments
@@ -746,6 +787,12 @@ def main():
746787
#############################################
747788

748789
if __name__ == "__main__":
749-
main()
790+
logger = logging.getLogger(__name__)
791+
logger.setLevel(logging.WARNING)
792+
log_stream = io.StringIO()
793+
streamHandler = logging.StreamHandler(log_stream)
794+
logger.addHandler(streamHandler)
795+
main(logger)
796+
messages = log_stream.getvalue().splitlines()
750797
# FIN
751798
sys.exit(SUCCESS)

Apps/tests/acg3/acg3_unittests.py

100755100644
Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,55 @@ def test_make_else_block(self):
293293
r = acg3.make_else_block(name)
294294
with self.subTest(test=test, msg=msg):
295295
test(r, msg)
296-
297-
test_cases = (TestMappings, TestHelpers, TestColumns)
296+
297+
def test_emit_declare_pointer(self):
298+
INTERNAL_NAME = 'GX'
299+
RANK = 4
300+
make_spec = lambda tk: {acg3.TYPEKIND: tk, acg3.INTERNAL_NAME: INTERNAL_NAME,
301+
acg3.RANK: RANK}
302+
equal_test = lambda expected: make_equal_test(self, expected)
303+
typekinds = ('ESMF_TYPEKIND_R4',)
304+
expecteds = (f'real(kind=ESMF_KIND_R4), pointer :: {INTERNAL_NAME}(:,:,:,:)',)
305+
params = zip(typekinds, expecteds)
306+
for tk, ex in params:
307+
spec = make_spec(tk)
308+
msg = general_msg('Pointer declaration', ex)
309+
test = equal_test(ex)
310+
value = acg3.emit_declare_pointer(spec)
311+
with self.subTest(value=value, test=test, msg=msg):
312+
test(value, msg)
313+
314+
def test_emit_declare_pointer_unsupported_type(self):
315+
spec = {acg3.TYPEKIND: 'X4', acg3.INTERNAL_NAME: 'GX', acg3.RANK: 4}
316+
self.assertRaises(RuntimeError, acg3.emit_declare_pointer, spec)
317+
318+
class TestTypes(unittest.TestCase):
319+
320+
def test_ESMF_Typekind(self):
321+
ESMF_Typekind = acg3.ESMF_Typekind
322+
equal_test = lambda expected: make_equal_test(self, expected)
323+
params = zip(('R4 R8 I4 I8'
324+
+ ' ESMF_TYPEKIND_R4 ESMF_TYPEKIND_R8'
325+
+ ' ESMF_TYPEKIND_I4 ESMF_TYPEKIND_I8').split(),
326+
(ESMF_Typekind.R4, ESMF_Typekind.R8, ESMF_Typekind.I4, ESMF_Typekind.I8,
327+
ESMF_Typekind.R4, ESMF_Typekind.R8, ESMF_Typekind.I4, ESMF_Typekind.I8))
328+
test_params = (TestParams(v, equal_test(e), general_msg('Enum member', e))
329+
for v, e in params)
330+
331+
for value, test, msg in test_params:
332+
with self.subTest(value=value, test=test, msg=msg):
333+
test(ESMF_Typekind[value], msg)
334+
335+
def test_ESMF_Typekind_variable_type(self):
336+
ESMF_Typekind = acg3.ESMF_Typekind
337+
equal_test = lambda expected: make_equal_test(self, expected)
338+
params = ((ESMF_Typekind[t], e) for t, e in (('R4', 'real(kind=ESMF_KIND_R4)'),))
339+
for en, ex in params:
340+
value, test, msg = str(en), equal_test(ex), general_msg('Variable type', ex)
341+
with self.subTest(value=value, test=test, msg=msg):
342+
test(value, msg)
343+
344+
test_cases = (TestMappings, TestHelpers, TestColumns, TestTypes)
298345

299346
def load_tests(loader, tests, pattern):
300347
suite = unittest.TestSuite()

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
129129
- Workaround for GCC 15 bug (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120179)
130130
- Fixed handling of invalid value for RESTART column in ACG3
131131
- Fixed initialization of field in test_min_accumulate_R4` in `Test_MinTransform.pf`
132+
- Fixed the precision of the pointer variable in ACG3
132133

133134
## [Unreleased]
134135

0 commit comments

Comments
 (0)