Skip to content

Commit 455003c

Browse files
peverwheeCourtney Peverley
andauthored
Add new register phase (#319)
Tag name (required for release branches): Originator(s): peverwhee Description (include the issue title, and the keyword ['closes', 'fixes', 'resolves'] followed by the issue number): 1. Adds call to new CCPP register phase brought in with framework PR [#582](NCAR/ccpp-framework#582) 2. Uses the full error message returned from the exception handled when xmllint is called (updated in framework PR [#586](NCAR/ccpp-framework#586)) 3. Adds `inverse_exner_function_wrt_surface_pressure` as possible input variable name for exner for backwards compatibility with old converted snapshots closes #215 (add optional register phase) closes #286 (Improve error message returned by XML linter) Describe any changes made to build system: None Describe any changes made to the namelist: None List any changes to the defaults for the input datasets (e.g. boundary datasets): None List all files eliminated and why: None List all files added and what they do: None List all existing files that have been modified, and describe the changes: (Helpful git command: `git diff --name-status development...<your_branch_name>`) M .gitmodules - brings in new CCPP framework tag M src/control/cam_comp.F90 M src/physics/utils/phys_comp.F90 - Adds call to new CCPP register phase in the generated cap M src/data/generate_registry_data.py - Uses full error message returned from xmllint M src/data/registry.xml - add backwards-compatible exner name If there are new failures (compared to the `test/existing-test-failures.txt` file), have them OK'd by the gatekeeper, note them here, and add them to the file. If there are baseline differences, include the test and the reason for the diff. What is the nature of the change? Roundoff? derecho/intel/aux_sima: all pass derecho/gnu/aux_sima: all pass If this changes climate describe any run(s) done to evaluate the new climate in enough detail that it(they) could be reproduced: N/A CAM-SIMA date used for the baseline comparison tests if different than latest: --------- Co-authored-by: Courtney Peverley <[email protected]>
1 parent e69640a commit 455003c

File tree

8 files changed

+168
-29
lines changed

8 files changed

+168
-29
lines changed

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[submodule "ccpp-framework"]
22
path = ccpp_framework
33
url = https://github.com/NCAR/ccpp-framework
4-
fxtag = 2024-07-19-dev
4+
fxtag = 2024-10-31-dev
55
fxrequired = AlwaysRequired
66
fxDONOTUSEurl = https://github.com/NCAR/ccpp-framework
77
[submodule "history"]

ccpp_framework

Submodule ccpp_framework updated 46 files

src/control/cam_comp.F90

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ subroutine cam_init(caseid, ctitle, model_doi_url, &
8686
use cam_initfiles, only: cam_initfiles_open
8787
use dyn_grid, only: model_grid_init
8888
use phys_comp, only: phys_init
89+
use phys_comp, only: phys_register
8990
use dyn_comp, only: dyn_init
9091
! use cam_restart, only: cam_read_restart
9192
use camsrfexch, only: hub2atm_alloc, atm2hub_alloc
@@ -186,6 +187,10 @@ subroutine cam_init(caseid, ctitle, model_doi_url, &
186187
! Open initial or restart file, and topo file if specified.
187188
call cam_initfiles_open()
188189

190+
! Call CCPP physics register phase (must happen before
191+
! cam_register_constituents)
192+
call phys_register()
193+
189194
! Initialize constituent information
190195
! This will set the total number of constituents and the
191196
! number of advected constituents.

src/data/generate_registry_data.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1783,16 +1783,7 @@ def gen_registry(registry_file, dycore, outdir, indent,
17831783
logger, schema_path=schema_dir,
17841784
error_on_noxmllint=error_on_no_validate)
17851785
except CCPPError as ccpperr:
1786-
cemsg = f"{ccpperr}".split('\n', maxsplit=1)[0]
1787-
if cemsg[0:12] == 'Execution of':
1788-
xstart = cemsg.find("'")
1789-
if xstart >= 0:
1790-
xend = cemsg[xstart + 1:].find("'") + xstart + 1
1791-
emsg += '\n' + cemsg[xstart + 1:xend]
1792-
# end if (else, just keep original message)
1793-
elif cemsg[0:18] == 'validate_xml_file:':
1794-
emsg += "\n" + cemsg
1795-
# end if
1786+
emsg += f"\n{ccpperr}"
17961787
file_ok = False
17971788
# end try
17981789
if not file_ok:

src/data/registry.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@
154154
allocatable="pointer">
155155
<long_name>inverse exner function w.r.t. surface pressure (ps/p)^(R/cp)</long_name>
156156
<dimensions>horizontal_dimension vertical_layer_dimension</dimensions>
157-
<ic_file_input_names>exner state_exner</ic_file_input_names>
157+
<ic_file_input_names>exner state_exner inverse_exner_function_wrt_surface_pressure</ic_file_input_names>
158158
</variable>
159159
<variable local_name="zm"
160160
standard_name="geopotential_height_wrt_surface"

src/physics/utils/phys_comp.F90

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module phys_comp
1010
private
1111

1212
public :: phys_readnl
13+
public :: phys_register
1314
public :: phys_init
1415
public :: phys_timestep_init
1516
public :: phys_run1
@@ -129,26 +130,14 @@ subroutine phys_readnl(nlfilename)
129130

130131
end subroutine phys_readnl
131132

132-
subroutine phys_init()
133-
use cam_abortutils, only: endrun
134-
use physics_grid, only: columns_on_task
135-
use vert_coord, only: pver, pverp
136-
use cam_thermo, only: cam_thermo_init
137-
use physics_types, only: allocate_physics_types_fields
138-
use cam_ccpp_cap, only: cam_ccpp_physics_initialize
133+
subroutine phys_register()
134+
use cam_ccpp_cap, only: cam_ccpp_physics_register
139135
use cam_ccpp_cap, only: ccpp_physics_suite_part_list
136+
use cam_abortutils, only: endrun
140137

141138
! Local variables
142139
integer :: i_group
143140

144-
call cam_thermo_init(columns_on_task, pver, pverp)
145-
146-
call allocate_physics_types_fields(columns_on_task, pver, pverp, &
147-
set_init_val_in=.true., reallocate_in=.false.)
148-
call cam_ccpp_physics_initialize(phys_suite_name)
149-
if (errcode /= 0) then
150-
call endrun('cam_ccpp_physics_initialize: '//trim(errmsg))
151-
end if
152141
call ccpp_physics_suite_part_list(phys_suite_name, suite_parts, &
153142
errmsg, errcode)
154143
if (errcode /= 0) then
@@ -158,11 +147,35 @@ subroutine phys_init()
158147
! Confirm that the suite parts are as expected
159148
do i_group = 1, size(suite_parts)
160149
if (.not. any(suite_parts(i_group) == suite_parts_expect)) then
161-
write(errmsg, *) 'phys_init: SDF suite groups MUST be ', &
150+
write(errmsg, *) 'phys_register: SDF suite groups MUST be ', &
162151
'ONLY `physics_before_coupler` and/or `physics_after_coupler`'
163152
call endrun(errmsg)
164153
end if
165154
end do
155+
! Call CCPP register phase
156+
call cam_ccpp_physics_register(phys_suite_name)
157+
if (errcode /= 0) then
158+
call endrun('cam_ccpp_physics_register: '//trim(errmsg))
159+
end if
160+
161+
end subroutine phys_register
162+
163+
subroutine phys_init()
164+
use cam_abortutils, only: endrun
165+
use physics_grid, only: columns_on_task
166+
use vert_coord, only: pver, pverp
167+
use cam_thermo, only: cam_thermo_init
168+
use physics_types, only: allocate_physics_types_fields
169+
use cam_ccpp_cap, only: cam_ccpp_physics_initialize
170+
171+
call cam_thermo_init(columns_on_task, pver, pverp)
172+
173+
call allocate_physics_types_fields(columns_on_task, pver, pverp, &
174+
set_init_val_in=.true., reallocate_in=.false.)
175+
call cam_ccpp_physics_initialize(phys_suite_name)
176+
if (errcode /= 0) then
177+
call endrun('cam_ccpp_physics_initialize: '//trim(errmsg))
178+
end if
166179

167180
end subroutine phys_init
168181

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<registry name="cam_registry" version="1.0">
4+
<file name="physics_types_complete" type="module">
5+
<use module="ccpp_kinds" reference="kind_phys"/>
6+
<use module="physconst" reference="rair"/>
7+
<use module="physconst" reference="cpair"/>
8+
<variable local_name="ncol" standard_name="horizontal_dimension"
9+
units="count" type="integer" access="protected">
10+
<long_name>Number of horizontal columns</long_name>
11+
<initial_value>0</initial_value>
12+
</variable>
13+
<variable local_name="pver" standard_name="vertical_layer_dimension"
14+
units="count" type="integer" access="protected">
15+
<long_name>Number of vertical layers</long_name>
16+
<initial_value>0</initial_value>
17+
</variable>
18+
<variable local_name="ix_qv"
19+
standard_name="index_of_water_vapor_specific_humidity"
20+
units="count" type="integer">
21+
<initial_value>1</initial_value>
22+
</variable>
23+
<variable local_name="ix_cld_liq"
24+
standard_name="index_of_cloud_liquid_water_mixing_ratio_of_moist_air"
25+
units="count" type="integer">
26+
<initial_value>2</initial_value>
27+
</variable>
28+
<variable local_name="latitude" standard_name="latitude"
29+
units="radians" type="real" kind="kind_phys"
30+
allocatable="pointer" access="protected">
31+
<dimensions>horizontal_dimension</dimensions>
32+
<ic_file_input_name>lat</ic_file_input_name>
33+
</variable>
34+
<variable local_name="longitude" standard_name="longitude"
35+
units="radians" type="real" kind="kind_phys"
36+
allocatable="pointer" access="protected">
37+
<dimensions>horizontal_dimension</dimensions>
38+
<ic_file_input_names>lon</ic_file_input_names>
39+
</variable>
40+
<variable local_name="u" standard_name="x_wind"
41+
units="m s-1" type="real" kind="kind_phys"
42+
allocatable="pointer" access="protected">
43+
<dimensions>horizontal_dimension vertical_layer_dimension</dimensions>
44+
<ic_file_input_names>u_wind</ic_file_input_names>
45+
</variable>
46+
<variable local_name="v" standard_name="y_wind"
47+
units="m s-1" type="real" kind="kind_phys"
48+
allocatable="pointer" access="protected">
49+
<dimensions>horizontal_dimension vertical_layer_dimension</dimensions>
50+
<ic_file_input_names>v_wind</ic_file_input_names>
51+
</variable>
52+
<variable local_name="param_val_var"
53+
standard_name="made_up_param_variable"
54+
units="count" type="integer" allocatable="parameter">
55+
<initial_value>42</initial_value>
56+
</variable>
57+
<variable local_name="standard_var"
58+
standard_name="standard_non_ddt_variable"
59+
units="K" type="real" phys_timestep_init_zero="true">
60+
<ic_file_input_names>stand_var</ic_file_input_names>
61+
</variable>
62+
<variable local_name="cappav"
63+
standard_name="composition_dependent_ratio_of_dry_air_gas_constant_to_specific_heat_at_constant_pressure"
64+
units="1" type="real" kind="kind_phys"
65+
allocatable="allocatable">
66+
<long_name>Composition-dependent ratio of dry air gas constant to specific heat at constant pressure</long_name>
67+
<dimensions>horizontal_dimension vertical_layer_dimension</dimensions>
68+
<initial_value>1 + rair/cpair - rair * 2</initial_value>
69+
</variable>
70+
<array local_name="q" standard_name="constituent_mixing_ratio"
71+
units="kg kg-1"
72+
type="real" kind="kind_phys"
73+
allocatable="pointer">
74+
<dimensions>horizontal_dimension vertical_layer_dimension
75+
number_of_constituents</dimensions>
76+
<element standard_name="water_vapor_specific_humidity"
77+
index_name="index_of_water_vapor_specific_humidity"
78+
index_pos="number_of_constituents">
79+
<ic_file_input_names>Q Q_snapshot</ic_file_input_names>
80+
</element>
81+
<element standard_name="cloud_liquid_water_mixing_ratio_of_moist_air"
82+
index_name="index_of_cloud_liquid_water_mixing_ratio_of_moist_air"
83+
index_pos="number_of_constituents">
84+
<ic_file_input_names>CLDLIQ CLDLIQ_snapshot</ic_file_input_names>
85+
</element>
86+
</array>
87+
<ddt type="physics_base" bindC="true">
88+
<data>horizontal_dimension</data>
89+
<data>vertical_layer_dimension</data>
90+
</ddt>
91+
<ddt type="model_wind">
92+
<data>x_wind</data>
93+
<data>y_wind</data>
94+
</ddt>
95+
<variable local_name="wind" standard_name="model_wind"
96+
units="None" type="model_wind" />
97+
<ddt type="physics_state" extends="physics_base">
98+
<data>latitude</data>
99+
<data>longitude</data>
100+
<data>model_wind</data>
101+
<data>constituent_mixing_ratio</data>
102+
</ddt>
103+
<variable local_name="phys_state"
104+
standard_name="physics_state_due_to_dynamics"
105+
units="None" type="physics_state" phys_timestep_init_zero="true">
106+
<long_name>Physics state variables updated by dynamical core</long_name>
107+
</variable>
108+
</file>
109+
<metadata_file>$SRCROOT/test/unit/sample_files/ref_pres.meta</metadata_file>
110+
</registry>

test/unit/test_registry.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
from generate_registry_data import gen_registry
4343
from generate_registry_data import metadata_file_to_files, TypeRegistry
4444
from framework_env import CCPPFrameworkEnv
45+
from parse_source import CCPPError
4546
# pylint: enable=wrong-import-position
4647

4748
###############################################################################
@@ -116,6 +117,25 @@ def test_good_simple_registry(self):
116117
self.assertTrue(filecmp.cmp(out_source, in_source, shallow=False),
117118
msg=amsg)
118119

120+
def test_bad_registry_xml(self):
121+
"""Test that the full error messages from xmllint is returned"""
122+
# Setup test
123+
filename = os.path.join(_SAMPLE_FILES_DIR, "reg_bad_xml.xml")
124+
out_name = "physics_types_bad"
125+
# Try to generate the registry
126+
with self.assertRaises(CCPPError) as cerr:
127+
retcode, files, _ = gen_registry(filename, 'se', _TMP_DIR, 2,
128+
_SRC_MOD_DIR, _CAM_ROOT,
129+
loglevel=logging.ERROR,
130+
error_on_no_validate=True)
131+
# end with
132+
expected_error = "reg_bad_xml.xml:32: element ic_file_input_name: Schemas validity error : Element 'ic_file_input_name': This element is not expected. Expected is one of ( initial_value, ic_file_input_names )."
133+
split_exception = str(cerr.exception).split('\n')
134+
amsg = f"Test failure: exception raised is {len(split_exception)} lines long and is expected to be 4"
135+
self.assertEqual(len(split_exception), 4, msg=amsg)
136+
# Check that the full xmllint message was returned
137+
self.assertTrue(split_exception[2].endswith(expected_error))
138+
119139
def test_good_ddt_registry(self):
120140
"""Test code and metadata generation from a good registry with a DDT.
121141
Check that generate_registry_data.py generates good

0 commit comments

Comments
 (0)