Skip to content

Commit be5e369

Browse files
authored
Merge pull request #325 from jeremy-lilly/external-gravity-wave
Add new external gravity wave test case: We create a new ocean task for testing the temporal convergence rate of time-stepping schemes. The case is that of a simple external gravity wave on an aquaplant. The normal velocity is initialized to zero and the layer thickness is initialized as a Gaussian bump. The PR also implements a version of the task for local time-stepping schemes.
2 parents 5fb53b6 + 7e8524c commit be5e369

File tree

20 files changed

+1731
-2
lines changed

20 files changed

+1731
-2
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
(dev-ocean-external-gravity-wave)=
2+
3+
# external_gravity_wave
4+
5+
The {py:class}`polaris.tasks.ocean.external_gravity_wave.ExternalGravityWave`
6+
task provides a test case to evaluate the time-convergence of time-stepping
7+
schemes in the simplest possible model configuration.
8+
9+
Note that this is *not* a shallow water test case.
10+
While the standard, non-linear shallow water thickness equation
11+
has been left alone, all tendencies in the momentum equation have been turned
12+
off, save the pressure gradient term. The resulting equations are given by
13+
$$
14+
\begin{align}
15+
&\partial_t \mathbf{u} = -g \nabla h \\
16+
&\partial_t h + \nabla \cdot (h\mathbf{u}) = 0 \,.
17+
\end{align}
18+
$$
19+
20+
In particular, this task is used to test the convergence of local
21+
time-stepping schemes (`LTS` and `FB_LTS`) that employ a operator splitting
22+
in which tendency terms other than those above are advanced with
23+
a first-order error. As a result, this task helps to show that these local
24+
time-stepping schemes are achieving the correct theoretical order of
25+
convergence if said splitting was not used.
26+
27+
To calculate errors, the task runs the case once at a small time-step
28+
to generate a reference solution.
29+
30+
## framework
31+
32+
The config options for the `external_gravity_wave` tests are described in
33+
{ref}`ocean-external-gravity-wave` in the User's Guide.
34+
35+
### base_mesh
36+
37+
External gravity wave tasks use shared `base_mesh` steps for creating
38+
{ref}`dev-ocean-spherical-meshes` at a sequence of resolutions.
39+
40+
### init
41+
42+
The class {py:class}`polaris.tasks.ocean.external_graivty_wave.init.Init`
43+
defines a step for setting up the initial state.
44+
45+
### init_lts
46+
47+
The class
48+
{py:class}`polaris.tasks.ocean.external_graivty_wave.lts_regions.LTSRegions`
49+
descends from {py:class}`polaris.step`.
50+
This step labels the cells and edges of a mesh generated in an `init` step
51+
for use with an LTS method.
52+
53+
### forward
54+
55+
The class {py:class}`polaris.tasks.ocean.external_gravity_wave.forward.Forward`
56+
descends from
57+
{py:class}`polaris.ocean.convergence.spherical.SphericalConvergenceForward`,
58+
and defines a step for running MPAS-Ocean from an initial condition produced in
59+
an `init` step. See {ref}`dev-ocean-convergence` for some relevant
60+
discussion of the parent class.
61+
62+
Additionally, the class
63+
{py:class}`polaris.tasks.ocean.external_gravity_wave.forward.ReferenceForward`
64+
descends directly from {py:class}`polaris.ocean.model.OceanModelStep`.
65+
This is done to create a forward step to generate the reference solution
66+
independent of the rest of the convergence framework.
67+
68+
The time steps are determined from the resolution
69+
based on the `{time_integrator}_dt_per_km` config option in the `[convergence_forward]`
70+
section. Other model config options are taken from `forward.yaml`.
71+
72+
## analysis
73+
74+
The class
75+
{py:class}`polaris.tasks.ocean.external_graivty_wave.analysis.Analysis`
76+
descends from
77+
{py:class}`polaris.ocean.convergence.analysis.ConvergenceAnalysis` and
78+
defines a step for computing the error norm (L2) for results for each
79+
time-step against the reference solution, saving them in
80+
`convergence_layerThickness.csv` and `convergence_normalVelocity.csv`, and
81+
plotting them in `convergence_layerThickness.png` and
82+
`convergence_normalVelocity.png`.
83+

docs/developers_guide/ocean/tasks/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ baroclinic_channel
99
barotropic_gyre
1010
correlated_tracers_2d
1111
cosine_bell
12+
external_gravity_wave
1213
geostrophic
1314
divergent_2d
1415
ice_shelf_2d
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
(ocean-external-gravity-wave)=
2+
3+
# external gravity wave
4+
5+
The `external_graivty_wave_*_time_step/convergence_time` tasks implement a
6+
simple external gravity wave test case evaluate the time-convergence of
7+
time-stepping schemes in the simplest possible model configuration.
8+
9+
Note that this is *not* a shallow water test case.
10+
While the standard, non-linear shallow water thickness equation
11+
has been left alone, all tendencies in the momentum equation have been turned
12+
off, save the pressure gradient term. The resulting equations are given by
13+
$$
14+
\begin{align}
15+
&\partial_t \mathbf{u} = -g \nabla h \\
16+
&\partial_t h + \nabla \cdot (h\mathbf{u}) = 0 \,.
17+
\end{align}
18+
$$
19+
20+
In particular, this task is used to test the convergence of local
21+
time-stepping schemes (`LTS` and `FB_LTS`) that employ a operator splitting
22+
in which tendency terms other than those above are advanced with
23+
a first-order error. As a result, this task helps to show that these local
24+
time-stepping schemes are achieving the correct theoretical order of
25+
convergence is said splitting was not used.
26+
27+
To calculate errors, the task runs the case once at a small time-step
28+
to generate a reference solution. The result of the `analysis` step of each
29+
task is a plot like the following showing convergence
30+
as a function of the cell size and/or the time step:
31+
32+
```{image} images/external_gravity_wave_convergence.png
33+
:align: center
34+
:width: 500 px
35+
```
36+
37+
## supported models
38+
39+
These tasks currently only support MPAS-Ocean.
40+
41+
(ocean-external-gravity-wave-mesh)=
42+
## mesh
43+
44+
Two global mesh variants are tested, quasi-uniform (QU) and icosohydral. In
45+
addition, the tests can be set up to use either local or global time-stepping
46+
methods. Thus, there are 4 variants of the task:
47+
```
48+
ocean/spherical/icos/external_gravity_wave_global_time_step/convergence_time
49+
ocean/spherical/icos/external_gravity_wave_local_time_step/convergence_time
50+
ocean/spherical/qu/external_gravity_wave_global_time_step/convergence_time
51+
ocean/spherical/qu/external_gravity_wave_local_time_step/convergence_time
52+
```
53+
The default resolutions used in the task depends on the mesh type.
54+
55+
For the `icos` mesh type, the default is 60, as determined
56+
by the following config option. See {ref}`dev-ocean-convergence` for more
57+
details.
58+
59+
```cfg
60+
# config options for spherical convergence tests
61+
[spherical_convergence]
62+
63+
# The base resolution for the icosahedral mesh to which the refinement
64+
# factors are applied
65+
icos_base_resolution = 60.
66+
```
67+
68+
For the `qu` mesh type, it is 120 km as
69+
determined by the following config option:
70+
71+
```cfg
72+
# config options for spherical convergence tests
73+
[spherical_convergence]
74+
75+
# The base resolution for the quasi-uniform mesh to which the refinement
76+
# factors are applied
77+
qu_base_resolution = 120.
78+
79+
# a list of quasi-uniform mesh resolutions (km) to test
80+
qu_refinement_factors = 0.5, 0.75, 1., 1.25, 1.5, 1.75, 2.
81+
```
82+
83+
To alter the resolutions used in the convergence tasks, you will need to create
84+
your own config file (or add a `spherical_convergence` section to a config file
85+
if you're already using one). If you specify a different resolution
86+
before setting up `external_gravity_wave`, steps will be generated with
87+
the requested resolution (if you alter `icos_resolutions` or `qu_resolutions`
88+
in the task's config file in the work directory, nothing will happen).
89+
For `icos` meshes, make sure you use a resolution close to those listed in
90+
{ref}`dev-spherical-meshes`. Each resolution will be rounded to the nearest
91+
allowed icosahedral resolution.
92+
93+
The `base_mesh` steps are shared with other tasks so they are not housed in
94+
the `external_gravity_wave` work directory. Instead, they are in work
95+
directories like:
96+
97+
```
98+
ocean/spherical/icos/base_mesh/60km
99+
ocean/spherical/qu/base_mesh/60km
100+
```
101+
102+
(ocean-external-gravity-wave-vertical)=
103+
## vertical grid
104+
105+
For this task, only a single vertical level may be used. The bottom depth
106+
is constant and the results should be insensitive to the choice of
107+
`bottom_depth`.
108+
109+
```cfg
110+
# Options related to the vertical grid
111+
[vertical_grid]
112+
113+
# the type of vertical grid
114+
grid_type = uniform
115+
116+
# Number of vertical levels
117+
vert_levels = 1
118+
119+
# Depth of the bottom of the ocean
120+
bottom_depth = 1000.0
121+
122+
# The type of vertical coordinate (e.g. z-level, z-star)
123+
coord_type = z-level
124+
125+
# Whether to use "partial" or "full", or "None" to not alter the topography
126+
partial_cell_type = None
127+
128+
# The minimum fraction of a layer for partial cells
129+
min_pc_fraction = 0.1
130+
```
131+
132+
## initial conditions
133+
134+
The fluid velocity is initialized to zero, and the layer thickness is given as
135+
a simple Gaussian bump
136+
137+
$$
138+
h = e^{-100 \left( \left(\phi - \phi_0\right)^2 + \left(\theta - \theta_0\right)^2 \right)}
139+
$$
140+
141+
where $\phi$ is latitude, $\theta$ is longitude, $\phi_0 = 0$, and
142+
$\theta_0 = \pi / 2$. Here, $\phi_0$ and $\theta_0$ can be set by `lat_center`
143+
and `lon_center` as config options.
144+
145+
## forcing
146+
147+
N/A
148+
149+
(ocean-external-graivty-wave-time-step)=
150+
## time step and run duration
151+
152+
With any given time-stepping scheme, the time step for forward integration is
153+
determined by multiplying the resolution by a config option, `rk4_dt_per_km`,
154+
so that coarser meshes have longer time steps. You can alter this before setup
155+
(in a user config file) or before running the task (in the config file in
156+
the work directory).
157+
158+
```cfg
159+
# config options for convergence tests
160+
[convergence_forward]
161+
162+
# time integrator: {'split_explicit', 'RK4'}
163+
time_integrator = RK4
164+
165+
# RK4 time step per resolution (s/km), since dt is proportional to resolution
166+
rk4_dt_per_km = 3.0
167+
```
168+
169+
The `convergence_eval_time`, `run_duration` and `output_interval` are set to
170+
2 days:
171+
172+
```cfg
173+
# config options for convergence forward steps
174+
[convergence_forward]
175+
176+
# Run duration in hours
177+
run_duration = 48.
178+
179+
# Output interval in hours
180+
output_interval = ${convergence_forward:run_duration}
181+
```
182+
183+
## config options
184+
185+
The primary `external_graivty_wave` config options are:
186+
187+
```cfg
188+
# options for external gravity wave convergence test case
189+
[external_gravity_wave]
190+
191+
# the constant temperature of the domain
192+
temperature = 15.0
193+
194+
# the constant salinity of the domain
195+
salinity = 35.0
196+
197+
# the central latitude (rad) of the gaussian bump
198+
lat_center = 0.0
199+
200+
# the central longitude (rad) of the gaussian bump
201+
lon_center = 1.57079633
202+
```
203+
204+
Additionally, for the `global` and `local` time-stepping variants of this task,
205+
the user can configure the time-integrator used. For the `global` variant:
206+
207+
```cfg
208+
# config options for convergence forward steps
209+
[convergence_forward]
210+
211+
# time integrator
212+
# either: {'RK4'}
213+
# mpas-ocean: {'split_explicit'}
214+
# omega: {'Forward-Backward', 'RungeKutta2'}
215+
time_integrator = RK4
216+
```
217+
218+
For the `local` variant:
219+
220+
```cfg
221+
# config options for convergence forward steps
222+
[convergence_forward]
223+
224+
# local time integrator
225+
# mpas-ocean: {'LTS, FB_LTS'}
226+
# omega: None
227+
time_integrator = FB_LTS
228+
```
229+
230+
(ocean-external-graivty-wave-cores)=
231+
## cores
232+
233+
The target and minimum number of cores are determined by `goal_cells_per_core`
234+
and `max_cells_per_core` from the `ocean` section of the config file,
235+
respectively. This ensures that the number of cells per core is roughly
236+
constant across the different resolutions in the convergence study.
43.1 KB
Loading

docs/users_guide/ocean/tasks/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ baroclinic_channel
99
barotropic_gyre
1010
correlated_tracers_2d
1111
cosine_bell
12+
external_gravity_wave
1213
geostrophic
1314
divergent_2d
1415
ice_shelf_2d

polaris/ocean/convergence/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@ def get_timestep_for_task(config, refinement_factor, refinement='both'):
8585
if time_integrator == 'RK4':
8686
dt_per_km = section.getfloat('rk4_dt_per_km')
8787
btr_timestep = 0.0
88+
elif time_integrator == 'LTS':
89+
dt_per_km = section.getfloat('lts_dt_per_km')
90+
btr_timestep = 0.0
91+
elif time_integrator == 'FB_LTS':
92+
dt_per_km = section.getfloat('fblts_dt_per_km')
93+
btr_timestep = 0.0
8894
else:
8995
dt_per_km = section.getfloat('split_dt_per_km')
9096
btr_dt_per_km = section.getfloat('btr_dt_per_km')

polaris/ocean/convergence/analysis.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,12 @@ def plot_convergence(self, variable_name, title, zidx):
257257
error_title = error_dict[error_type]
258258

259259
ax = fig.add_subplot(111)
260-
ax.loglog(resolutions, order1, '--k', label='first order', alpha=0.3)
261-
ax.loglog(resolutions, order2, 'k', label='second order', alpha=0.3)
260+
ax.loglog(
261+
refinement_array, order1, '--k', label='first order', alpha=0.3
262+
)
263+
ax.loglog(
264+
refinement_array, order2, 'k', label='second order', alpha=0.3
265+
)
262266
ax.loglog(
263267
refinement_array,
264268
fit,

polaris/ocean/convergence/convergence.cfg

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ time_integrator = RK4
3333
# RK4 time step per resolution (s/km), since dt is proportional to resolution
3434
# if using convergence in time only, this is used for the largest resolution
3535
rk4_dt_per_km = 3.0
36+
#
37+
# LTS time step per resolution (s/km), since dt is proportional to resolution
38+
# if using convergence in time only, this is used for the largest resolution
39+
lts_dt_per_km = 3.0
40+
41+
# FB_LTS time step per resolution (s/km), since dt is proportional to resolution
42+
# if using convergence in time only, this is used for the largest resolution
43+
fblts_dt_per_km = 4.5
3644

3745
# split time step per resolution (s/km), since dt is proportional to resolution
3846
# if using convergence in time only, this is used for the largest resolution

polaris/suites/ocean/convergence.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ ocean/spherical/qu/cosine_bell/convergence_both
1515
cached: qu_base_mesh_120km qu_init_120km qu_base_mesh_150km qu_init_150km
1616
cached: qu_base_mesh_180km qu_init_180km qu_base_mesh_210km qu_init_210km
1717
cached: qu_base_mesh_240km qu_init_240km
18+
ocean/spherical/icos/external_gravity_wave/global_time_step/convergence_time
19+
cached: icos_base_mesh_60km icos_init_60km
20+
ocean/spherical/icos/external_gravity_wave/local_time_step/convergence_time
21+
cached: icos_base_mesh_60km icos_init_60km icos_init_lts_60km
22+
ocean/spherical/qu/external_gravity_wave/global_time_step/convergence_time
23+
cached: qu_base_mesh_120km qu_init_120km
24+
ocean/spherical/qu/external_gravity_wave/local_time_step/convergence_time
25+
cached: qu_base_mesh_120km qu_init_120km qu_init_lts_120km
1826
ocean/spherical/icos/geostrophic/convergence_both
1927
cached: icos_base_mesh_60km icos_init_60km icos_base_mesh_120km icos_init_120km
2028
cached: icos_base_mesh_240km icos_init_240km icos_base_mesh_480km icos_init_480km

0 commit comments

Comments
 (0)