Skip to content

Commit 2f42e45

Browse files
committed
Merge branch 'development' into hplin/hb_diff
2 parents 39bbd60 + 77fa975 commit 2f42e45

22 files changed

+555
-454
lines changed

src/data/write_init_files.py

Lines changed: 67 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
'number_of_mpi_tasks'}
3434
# Variable input types
3535
_INPUT_TYPES = set(['in', 'inout'])
36+
_OUTPUT_TYPES = set(['out', 'inout'])
3637

3738
# Include files to insert in the module preamble
3839
_PHYS_VARS_PREAMBLE_INCS = ["cam_var_init_marks_decl.inc"]
@@ -131,7 +132,7 @@ def write_init_files(cap_database, ic_names, registry_constituents, vars_init_va
131132

132133
# Gather all the host model variables that are required by
133134
# any of the compiled CCPP physics suites.
134-
host_vars, constituent_set, retmsg = gather_ccpp_req_vars(cap_database, registry_constituents)
135+
in_vars, out_vars, constituent_set, retmsg = gather_ccpp_req_vars(cap_database, registry_constituents)
135136

136137
# Quit now if there are missing variables
137138
if retmsg:
@@ -173,13 +174,17 @@ def write_init_files(cap_database, ic_names, registry_constituents, vars_init_va
173174
outfile.include(filepath)
174175
# end for
175176

177+
all_req_vars = in_vars + out_vars
178+
# Remove duplicates but preserve order for testing
179+
unique_req_vars = list(OrderedDict.fromkeys(all_req_vars))
180+
176181
# Write public parameters:
177-
retvals = write_ic_params(outfile, host_vars, ic_names, registry_constituents)
182+
retvals = write_ic_params(outfile, unique_req_vars, ic_names, registry_constituents)
178183
ic_names, ic_max_len, stdname_max_len = retvals
179184

180185
# Write initial condition arrays:
181186
write_ic_arrays(outfile, ic_names, ic_max_len,
182-
stdname_max_len, host_vars, registry_constituents)
187+
stdname_max_len, unique_req_vars, registry_constituents)
183188

184189
# Add "contains" statement:
185190
outfile.end_module_header()
@@ -234,18 +239,19 @@ def write_init_files(cap_database, ic_names, registry_constituents, vars_init_va
234239
# Grab the host dictionary from the database
235240
host_dict = cap_database.host_model_dict()
236241

237-
# Collect imported host variables
238-
host_imports = collect_host_var_imports(host_vars, host_dict, constituent_set)
239-
242+
# Collect imported host variables for physics read
243+
host_imports = collect_host_var_imports(in_vars, host_dict, constituent_set)
240244
# Write physics_read_data subroutine:
241-
write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports,
245+
write_phys_read_subroutine(outfile, host_dict, in_vars, host_imports,
242246
phys_check_fname_str, constituent_set,
243247
vars_init_value)
244248

245249
outfile.blank_line()
246250

251+
# Collect imported host variables for physics check
252+
host_imports = collect_host_var_imports(out_vars, host_dict, constituent_set)
247253
# Write physics_check_data subroutine:
248-
write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports,
254+
write_phys_check_subroutine(outfile, host_dict, out_vars, host_imports,
249255
phys_check_fname_str, constituent_set)
250256

251257
# --------------------------------------
@@ -315,7 +321,8 @@ def gather_ccpp_req_vars(cap_database, registry_constituents):
315321

316322
# Dictionary of all 'in' and 'inout' suite variables.
317323
# Key is standard name, value is host-model or constituent variable
318-
req_vars = {}
324+
in_vars = {}
325+
out_vars = {}
319326
missing_vars = set()
320327
constituent_vars = set()
321328
retmsg = ""
@@ -330,22 +337,31 @@ def gather_ccpp_req_vars(cap_database, registry_constituents):
330337
intent = cvar.get_prop_value('intent')
331338
is_const = cvar.get_prop_value('advected') or cvar.get_prop_value('constituent')
332339
if ((intent in _INPUT_TYPES) and
333-
(stdname not in req_vars) and
340+
(stdname not in in_vars) and
334341
(stdname not in _EXCLUDED_STDNAMES)):
335342
if is_const:
336343
#Add variable to constituent set:
337344
constituent_vars.add(stdname)
338345
#Add variable to required variable list if it's not a registry constituent
339346
if stdname not in registry_constituents:
340-
req_vars[stdname] = cvar
347+
in_vars[stdname] = cvar
341348
# end if
342349
else:
343350
# We need to work with the host model version of this variable
344351
missing = _find_and_add_host_variable(stdname, host_dict,
345-
req_vars)
352+
in_vars)
346353
missing_vars.update(missing)
347354
# end if
348-
# end if (do not include output variables)
355+
# end if (only input variables)
356+
if ((intent in _OUTPUT_TYPES) and
357+
(stdname not in out_vars) and
358+
(stdname not in _EXCLUDED_STDNAMES)):
359+
if not is_const:
360+
missing = _find_and_add_host_variable(stdname, host_dict,
361+
out_vars)
362+
# do nothing with missing variables
363+
# end if
364+
# end if (only output variables)
349365
# end for (loop over call list)
350366
# end for (loop over phases)
351367

@@ -354,7 +370,7 @@ def gather_ccpp_req_vars(cap_database, registry_constituents):
354370
retmsg = f"Error: Missing required host variables: {mvlist}"
355371
# end if
356372
# Return the required variables as a list
357-
return list(req_vars.values()), constituent_vars, retmsg
373+
return list(in_vars.values()), list(out_vars.values()), constituent_vars, retmsg
358374

359375
##########################
360376
#FORTRAN WRITING FUNCTIONS
@@ -1178,8 +1194,6 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports,
11781194
outfile.write("end do", 2)
11791195
outfile.blank_line()
11801196

1181-
# start default case steps:
1182-
11831197
# End subroutine:
11841198
outfile.write("end subroutine physics_read_data", 1)
11851199

@@ -1240,8 +1254,8 @@ def write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports,
12401254
call_str += f"timestep, {var_locname}, '{var_stdname}', "
12411255
call_str += "min_difference, min_relative_value, is_first, diff_found)"
12421256
else:
1243-
call_str = f"call endrun('Cannot check status of {var_locname}'" + \
1244-
f"//', {reason}')"
1257+
# For check field, don't endrun
1258+
call_str = f"! do nothing - '{var_locname}' can't be checked against a file because {reason}"
12451259
# end if
12461260
# Add string to dictionary:
12471261
call_string_dict[call_string_key] = call_str
@@ -1376,7 +1390,7 @@ def write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports,
13761390
"that they can be read from input file if need be:", 3)
13771391
outfile.write("call ccpp_physics_suite_variables(suite_names" + \
13781392
"(suite_idx), ccpp_required_data, errmsg, errflg, " + \
1379-
"input_vars=.true., output_vars=.false.)", 4)
1393+
"input_vars=.false., output_vars=.true.)", 4)
13801394
outfile.blank_line()
13811395

13821396
# Loop over required variables:
@@ -1385,37 +1399,48 @@ def write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports,
13851399
outfile.write("do req_idx = 1, size(ccpp_required_data, 1)", 3)
13861400
outfile.blank_line()
13871401

1388-
# First check if the required variable is a constituent
1389-
outfile.comment("First check if the required variable is a constituent:", 4)
1390-
outfile.write("call const_get_index(ccpp_required_data(req_idx), constituent_idx, abort=.false., warning=.false.)", 4)
1391-
outfile.write("if (constituent_idx > -1) then", 4)
1392-
outfile.write("cycle", 5)
1393-
outfile.write("else", 4)
1394-
outfile.comment("The required variable is not a constituent. Check if the variable was read from a file", 5)
1395-
13961402
# Call input name search function:
1397-
outfile.comment("Find IC file input name array index for required variable:", 5)
1398-
outfile.write("call is_read_from_file(ccpp_required_data(req_idx), " + \
1399-
"is_read, stdnam_idx_out=name_idx)", 5)
1400-
outfile.write("if (.not. is_read) then", 5)
1401-
outfile.write("cycle", 6)
1402-
outfile.write("end if", 5)
1403+
outfile.comment("Find IC file input name array index for required variable:", 4)
1404+
outfile.write("name_idx = find_input_name_idx(ccpp_required_data(req_idx), .true., constituent_idx)", 4)
1405+
1406+
# Start select-case statement:
1407+
outfile.blank_line()
1408+
outfile.comment("Check for special index values:", 4)
1409+
outfile.write("select case (name_idx)", 4)
1410+
outfile.blank_line()
1411+
1412+
# Skip constituent variables:
1413+
outfile.write("case (const_idx)", 5)
1414+
outfile.blank_line()
1415+
outfile.comment("If variable is a constituent, then do nothing. We'll handle these later", 6)
1416+
outfile.blank_line()
1417+
1418+
# Generate error message if required variable isn't found:
1419+
outfile.write("case (no_exist_idx)", 5)
1420+
outfile.blank_line()
1421+
outfile.comment("If the index for an output variable was not found, then do nothing. We won't try to check these.", 6)
1422+
outfile.blank_line()
1423+
1424+
# start default case steps:
1425+
outfile.write("case default", 5)
1426+
outfile.blank_line()
14031427

14041428
# Generate "check_field" calls:
1405-
outfile.comment("Check variable vs input check file:", 5)
1429+
outfile.comment("Check variable vs input check file:", 6)
14061430
outfile.blank_line()
1407-
outfile.write("select case (trim(phys_var_stdnames(name_idx)))", 5)
1431+
outfile.write("select case (trim(phys_var_stdnames(name_idx)))", 6)
14081432
for case_call, read_call in call_string_dict.items():
1409-
outfile.write(case_call, 5)
1410-
outfile.write(read_call, 6)
1433+
outfile.write(case_call, 6)
1434+
outfile.write(read_call, 7)
14111435
outfile.blank_line()
1412-
outfile.write("end select !check variables", 5)
1413-
outfile.write("if (diff_found) then", 5)
1414-
outfile.write("overall_diff_found = .true.", 6)
1415-
outfile.write("end if", 5)
1416-
outfile.write("end if !check if constituent", 4)
1436+
outfile.write("end select !check variables", 6)
1437+
outfile.write("if (diff_found) then", 6)
1438+
outfile.write("overall_diff_found = .true.", 7)
1439+
outfile.write("end if", 6)
14171440

14181441
# End select case and required variables loop:
1442+
outfile.write("end select !special indices", 4)
1443+
outfile.blank_line()
14191444
outfile.write("end do !Suite-required variables", 3)
14201445
outfile.blank_line()
14211446

test/unit/python/sample_files/write_init_files/phys_vars_init_check_simple.F90

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,21 @@ module phys_vars_init_check_simple
3333
integer, public, parameter :: PARAM = 2
3434
integer, public, parameter :: READ_FROM_FILE = 3
3535
! Total number of physics-related variables:
36-
integer, public, parameter :: phys_var_num = 2
36+
integer, public, parameter :: phys_var_num = 4
3737
integer, public, parameter :: phys_const_num = 16
3838

3939
!Max length of physics-related variable standard names:
4040
integer, public, parameter :: std_name_len = 25
4141

4242
! Max length of input (IC) file variable names:
43-
integer, public, parameter :: ic_name_len = 5
43+
integer, public, parameter :: ic_name_len = 9
4444

4545
! Physics-related input variable standard names:
4646
character(len=25), public, protected :: phys_var_stdnames(phys_var_num) = (/ &
4747
'potential_temperature ', &
48-
'air_pressure_at_sea_level' /)
48+
'air_pressure_at_sea_level', &
49+
'tendency_of_peverwhee ', &
50+
'scalar_variable_llama ' /)
4951

5052
character(len=36), public, protected :: phys_const_stdnames(phys_const_num) = (/ &
5153
"ccpp_constituent_minimum_values ", &
@@ -65,17 +67,23 @@ module phys_vars_init_check_simple
6567
"suite_name ", &
6668
"suite_part " /)
6769
!Array storing all registered IC file input names for each variable:
68-
character(len=5), public, protected :: input_var_names(1, phys_var_num) = reshape((/ &
69-
'theta', &
70-
'slp ' /), (/1, phys_var_num/))
70+
character(len=9), public, protected :: input_var_names(1, phys_var_num) = reshape((/ &
71+
'theta ', &
72+
'slp ', &
73+
'ptend ', &
74+
'var_nodim' /), (/1, phys_var_num/))
7175

7276
! Array indicating whether or not variable is protected:
7377
logical, public, protected :: protected_vars(phys_var_num)= (/ &
78+
.false., &
79+
.false., &
7480
.false., &
7581
.false. /)
7682

7783
! Variable state (UNINITIALIZED, INTIIALIZED, PARAM or READ_FROM_FILE):
7884
integer, public, protected :: initialized_vars(phys_var_num)= (/ &
85+
UNINITIALIZED, &
86+
UNINITIALIZED, &
7987
UNINITIALIZED, &
8088
UNINITIALIZED /)
8189

test/unit/python/sample_files/write_init_files/physics_inputs_4D.F90

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference,
235235
use cam_pio_utils, only: cam_pio_openfile, cam_pio_closefile
236236
use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t
237237
use phys_vars_init_check_4D, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len
238-
use physics_types_4D, only: slp, theta
238+
use physics_types_4D, only: theta
239239

240240
! Dummy arguments
241241
character(len=SHR_KIND_CL), intent(in) :: file_name
@@ -304,37 +304,40 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference,
304304
do suite_idx = 1, size(suite_names, 1)
305305

306306
! Search for all needed CCPP input variables, so that they can be read from input file if need be:
307-
call ccpp_physics_suite_variables(suite_names(suite_idx), ccpp_required_data, errmsg, errflg, input_vars=.true., output_vars=.false.)
307+
call ccpp_physics_suite_variables(suite_names(suite_idx), ccpp_required_data, errmsg, errflg, input_vars=.false., output_vars=.true.)
308308

309309
! Loop over all required variables as specified by CCPP suite:
310310
do req_idx = 1, size(ccpp_required_data, 1)
311311

312-
! First check if the required variable is a constituent:
313-
call const_get_index(ccpp_required_data(req_idx), constituent_idx, abort=.false., warning=.false.)
314-
if (constituent_idx > -1) then
315-
cycle
316-
else
317-
! The required variable is not a constituent. Check if the variable was read from a file
318-
! Find IC file input name array index for required variable:
319-
call is_read_from_file(ccpp_required_data(req_idx), is_read, stdnam_idx_out=name_idx)
320-
if (.not. is_read) then
321-
cycle
322-
end if
323-
! Check variable vs input check file:
312+
! Find IC file input name array index for required variable:
313+
name_idx = find_input_name_idx(ccpp_required_data(req_idx), .true., constituent_idx)
324314

325-
select case (trim(phys_var_stdnames(name_idx)))
326-
case ('potential_temperature')
327-
call check_field(file, input_var_names(:,name_idx), 'lev', timestep, theta, 'potential_temperature', min_difference, &
328-
min_relative_value, is_first, diff_found)
315+
! Check for special index values:
316+
select case (name_idx)
329317

330-
case ('air_pressure_at_sea_level')
331-
call endrun('Cannot check status of slp'//', slp has unsupported dimension, timestep_for_physics.')
318+
case (const_idx)
319+
320+
! If variable is a constituent, then do nothing. We'll handle these later
321+
322+
case (no_exist_idx)
323+
324+
! If the index for an output variable was not found, then do nothing. We won't try to check these.
325+
326+
case default
327+
328+
! Check variable vs input check file:
329+
330+
select case (trim(phys_var_stdnames(name_idx)))
331+
case ('potential_temperature')
332+
call check_field(file, input_var_names(:,name_idx), 'lev', timestep, theta, 'potential_temperature', min_difference, &
333+
min_relative_value, is_first, diff_found)
334+
335+
end select !check variables
336+
if (diff_found) then
337+
overall_diff_found = .true.
338+
end if
339+
end select !special indices
332340

333-
end select !check variables
334-
if (diff_found) then
335-
overall_diff_found = .true.
336-
end if
337-
end if !check if constituent
338341
end do !Suite-required variables
339342

340343
! Deallocate required variables array for use in next suite:

0 commit comments

Comments
 (0)