20
20
from metavar import CCPP_LOOP_VAR_STDNAMES
21
21
from fortran_tools import FortranWriter
22
22
from parse_tools import CCPPError
23
- from parse_tools import ParseObject , ParseSource , ParseContext
23
+ from parse_tools import ParseObject , ParseSource , ParseContext , ParseSyntaxError
24
24
25
25
###############################################################################
26
26
_HEADER = "cap for {host_model} calls to CCPP API"
@@ -284,6 +284,7 @@ def add_constituent_vars(cap, host_model, suite_list, run_env):
284
284
vert_layer_dim = "vertical_layer_dimension"
285
285
vert_interface_dim = "vertical_interface_dimension"
286
286
array_layer = "vars_layer"
287
+ tend_layer = "vars_layer_tend"
287
288
# Table preamble (leave off ccpp-table-properties header)
288
289
ddt_mdata = [
289
290
#"[ccpp-table-properties]",
@@ -300,6 +301,9 @@ def add_constituent_vars(cap, host_model, suite_list, run_env):
300
301
" type = real" , " kind = kind_phys" ]
301
302
# Add entries for each constituent (once per standard name)
302
303
const_stdnames = set ()
304
+ tend_stdnames = set ()
305
+ const_vars = set ()
306
+ tend_vars = set ()
303
307
for suite in suite_list :
304
308
if run_env .verbose :
305
309
lmsg = "Adding constituents from {} to {}"
@@ -308,12 +312,13 @@ def add_constituent_vars(cap, host_model, suite_list, run_env):
308
312
scdict = suite .constituent_dictionary ()
309
313
for cvar in scdict .variable_list ():
310
314
std_name = cvar .get_prop_value ('standard_name' )
311
- if std_name not in const_stdnames :
315
+ if std_name not in const_stdnames and std_name not in tend_stdnames :
312
316
# Add a metadata entry for this constituent
313
317
# Check dimensions and figure vertical dimension
314
318
# Currently, we only support variables with first dimension,
315
319
# horizontal_dimension, and second (optional) dimension,
316
320
# vertical_layer_dimension or vertical_interface_dimension
321
+ is_tend_var = 'tendency_of' in std_name
317
322
dims = cvar .get_dimensions ()
318
323
if (len (dims ) < 1 ) or (len (dims ) > 2 ):
319
324
emsg = "Unsupported constituent dimensions, '{}'"
@@ -329,7 +334,11 @@ def add_constituent_vars(cap, host_model, suite_list, run_env):
329
334
if len (dims ) > 1 :
330
335
vdim = dims [1 ].split (':' )[- 1 ]
331
336
if vdim == vert_layer_dim :
332
- cvar_array_name = array_layer
337
+ if is_tend_var :
338
+ cvar_array_name = tend_layer
339
+ else :
340
+ cvar_array_name = array_layer
341
+ # end if
333
342
else :
334
343
emsg = "Unsupported vertical constituent dimension, "
335
344
emsg += "'{}', must be '{}' or '{}'"
@@ -340,8 +349,13 @@ def add_constituent_vars(cap, host_model, suite_list, run_env):
340
349
emsg = f"Unsupported 2-D variable, '{ std_name } '"
341
350
raise CCPPError (emsg )
342
351
# end if
343
- # First, create an index variable for <cvar>
344
- ind_std_name = "index_of_{}" .format (std_name )
352
+ # Create an index variable for <cvar>
353
+ if is_tend_var :
354
+ const_std_name = std_name .split ("tendency_of_" )[1 ]
355
+ else :
356
+ const_std_name = std_name
357
+ # end if
358
+ ind_std_name = f"index_of_{ const_std_name } "
345
359
loc_name = f"{ cvar_array_name } (:,:,{ ind_std_name } )"
346
360
ddt_mdata .append (f"[ { loc_name } ]" )
347
361
ddt_mdata .append (f" standard_name = { std_name } " )
@@ -352,10 +366,44 @@ def add_constituent_vars(cap, host_model, suite_list, run_env):
352
366
vtype = cvar .get_prop_value ('type' )
353
367
vkind = cvar .get_prop_value ('kind' )
354
368
ddt_mdata .append (f" type = { vtype } | kind = { vkind } " )
355
- const_stdnames .add (std_name )
369
+ if is_tend_var :
370
+ tend_vars .add (cvar )
371
+ tend_stdnames .add (std_name )
372
+ else :
373
+ const_vars .add (cvar )
374
+ const_stdnames .add (std_name )
375
+ # end if
376
+
356
377
# end if
357
378
# end for
358
379
# end for
380
+ # Check that all tendency variables are valid
381
+ for tendency_variable in tend_vars :
382
+ tend_stdname = tendency_variable .get_prop_value ('standard_name' )
383
+ tend_const_name = tend_stdname .split ('tendency_of_' )[1 ]
384
+ found = False
385
+ # Find the corresponding constituent variable
386
+ for const_variable in const_vars :
387
+ const_stdname = const_variable .get_prop_value ('standard_name' )
388
+ if const_stdname == tend_const_name :
389
+ found = True
390
+ compat = tendency_variable .compatible (const_variable , run_env , is_tend = True )
391
+ if not compat :
392
+ errstr = f"Tendency variable, '{ tend_stdname } '"
393
+ errstr += f", incompatible with associated state variable '{ tend_const_name } '"
394
+ errstr += f". Reason: '{ compat .incompat_reason } '"
395
+ raise ParseSyntaxError (errstr , token = tend_stdname ,
396
+ context = tendency_variable .context )
397
+ # end if
398
+ # end if
399
+ # end for
400
+ if not found :
401
+ # error because we couldn't find the associated constituent
402
+ errstr = f"No associated state variable for tendency variable, '{ tend_stdname } '"
403
+ raise ParseSyntaxError (errstr , token = tend_stdname ,
404
+ context = tendency_variable .context )
405
+ # end if
406
+ # end for
359
407
# Parse this table using a fake filename
360
408
parse_obj = ParseObject (f"{ host_model .name } _constituent_mod.meta" ,
361
409
ddt_mdata )
0 commit comments