|
8 | 8 | from functools import partial, reduce |
9 | 9 | from operator import concat |
10 | 10 | 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 |
11 | 35 |
|
12 | 36 | ################################# CONSTANTS #################################### |
13 | 37 | # str constants internal to script |
|
23 | 47 | INDENT = SPACE * SIZE_INDENT |
24 | 48 | DIMSTR = ':' |
25 | 49 | DIMDELIM = ',' |
| 50 | +DEFAULT_TYPEKIND = 'ESMF_TYPEKIND_R4' |
26 | 51 |
|
27 | 52 | # str flags |
28 | 53 | AS = 'as' |
|
43 | 68 | GET = 'get' |
44 | 69 | MAKE_BLOCK = 'make_block' |
45 | 70 | INTENT_PREFIX = 'ESMF_STATEINTENT_' |
46 | | -MAPPED = 'mapped' |
| 71 | +KIND = 'kind' |
| 72 | +MAPPED = 'mapped' |
47 | 73 | MAPPING = 'mapping' |
48 | 74 | MISSING_MANDATORY = 'missing_mandatory' |
49 | 75 | NONES = 'nones' |
|
54 | 80 | STORE = 'store' |
55 | 81 | STRING = 'string' |
56 | 82 | STRLOGICAL = 'strlogical' |
| 83 | +TYPE = 'type' |
57 | 84 | VALUES_NOT_FOUND = 'values_not_found' |
58 | 85 |
|
59 | 86 | # These are column names. A few are "special" column names used internally. |
|
79 | 106 | STATE_ARG = 'state_arg' |
80 | 107 | STATE_INTENT = 'state_intent' |
81 | 108 | STRINGVECTOR = 'string_vector' |
| 109 | +TYPEKIND = 'typekind' |
82 | 110 | UNGRIDDED_DIMS = 'ungridded_dims' |
83 | 111 | USE_FIELD_DICTIONARY = 'use_field_dictionary' |
84 | 112 | VSTAGGER = 'vstagger' |
@@ -182,8 +210,8 @@ def get_options(args): |
182 | 210 | 'REQUIRED': 'MAPL_RESTART_REQUIRED', |
183 | 211 | 'BOOT': 'MAPL_RESTART_BOOT', |
184 | 212 | 'SKIP_INITIAL': 'MAPL_RESTART_SKIP_INITIAL'}}, |
185 | | - STATE: {FLAGS: {MANDATORY, STORE}}, |
186 | | - 'typekind': {MAPPING: { |
| 213 | + STATE: {FLAGS: {MANDATORY, STORE}}, |
| 214 | + TYPEKIND: {MAPPING: { |
187 | 215 | 'R4': 'ESMF_Typekind_R4', |
188 | 216 | 'R8': 'ESMF_Typekind_R8', |
189 | 217 | 'I4': 'ESMF_Typekind_I4', |
@@ -264,17 +292,27 @@ def emit_declare_pointers(specs, states=None): |
264 | 292 | """Emit pointer declarations from Iterable of spec instances.""" |
265 | 293 | # filter on state |
266 | 294 | 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 |
268 | 305 |
|
269 | 306 | def emit_declare_pointer(spec): |
270 | 307 | """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])) |
275 | 313 | # pointer variable |
276 | 314 | var = f'{spec[INTERNAL_NAME]}({DIMDELIM.join(DIMSTR*spec[RANK])})' |
277 | | - return ' :: '.join([decl, var]) |
| 315 | + return f'{ftypekind} :: {var}' |
278 | 316 |
|
279 | 317 | def emit_get_pointers(specs, states=None): |
280 | 318 | """Emit pointer get statements from an Iterable of spec instances.""" |
@@ -401,7 +439,7 @@ def get_from_values(keys, values, args): |
401 | 439 |
|
402 | 440 | def digest_spec(spec, options): |
403 | 441 | """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. |
405 | 443 | tuples = [(k, spec[k]) for k, v in spec.items() if k in options and spec[k]] |
406 | 444 | # Get the options corresponding to the spec keys. |
407 | 445 | spec_options = [options[k] for k, _ in tuples] |
@@ -530,7 +568,10 @@ def emit_values(specs, options): |
530 | 568 | # Emit all get_pointer calls and pointer declartions. |
531 | 569 | emitters = {DECLARE: emit_declare_pointers, GET: emit_get_pointers} |
532 | 570 | 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 |
534 | 575 | with open_file(component, args[key], key, 'pointer') as f: |
535 | 576 | f.writelines(add_newlines(emitted)) |
536 | 577 |
|
@@ -711,7 +752,7 @@ def inner(*args): |
711 | 752 | return inner |
712 | 753 |
|
713 | 754 | # Main Procedure (Added to facilitate testing.) |
714 | | -def main(): |
| 755 | +def main(logger): |
715 | 756 | exit_code = ERROR |
716 | 757 |
|
717 | 758 | # Process command line arguments |
@@ -746,6 +787,12 @@ def main(): |
746 | 787 | ############################################# |
747 | 788 |
|
748 | 789 | 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() |
750 | 797 | # FIN |
751 | 798 | sys.exit(SUCCESS) |
0 commit comments