Skip to content

Commit 340eb92

Browse files
Add rossby wave demo
*Currently disabled the coriolis source terms to debug an issue on mi210
1 parent e9ee865 commit 340eb92

9 files changed

+513
-12
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Planetary Rossby Wave
2+
This experiment is designed to show how a geostrophic monopole evolves on a $\beta$-plane.
3+
4+
## Configuration
5+
6+
### Equations
7+
8+
The equations solved are the linear shallow water equations, given by
9+
$$
10+
u_t - fv = -g \eta_x
11+
$$
12+
$$
13+
v_t + fu = -g \eta_y
14+
$$
15+
$$
16+
\eta_t + (Hu)_x + (Hv)_y = 0
17+
$$
18+
19+
where $\vec{u} = u \hat{x} + v \hat{y}$ is the barotropic velocity, $g$ is the acceleration of gravity, $H$ is a uniform resting fluid depth, and $\eta$ is the deviation of the fluid free surface relative to the resting fluid. In this model, the $x$ direction is similar to longitude and $y$ is similar to latitude.
20+
21+
A $\beta$-plane, in geophysical fluid dynamics, is an approximation that accounts for first order variability in the (vertical component of the) coriolis parameter with latitude,
22+
23+
$$
24+
f = f_0 + \beta y
25+
$$
26+
27+
The background variation in the planetary vorticity supports Rossby waves, which propagate "westward" with higher potential vorticity to the right of phase propagation.
28+
29+
### Domain Discretization
30+
In this problem, the domain is a square with $(x,y) \in [-500km, 500km]^2$. The model domain is divided into $10\times 10$ elements of uniform size. Within each element, the solution is approximated as a Lagrange interpolating polynomial of degree 7, using the Legendre-Gauss quadrature points as interpolating knots. To exchange momentum and mass fluxes between neighboring elements, we use a local upwind (Lax-Friedrich's) Riemann solver.
31+
32+
### Initial Condition
33+
The initial condition is defined by setting the free surface height to a Gaussian, centered at the origin, with a half width of 10 km and a height of 1 cm.
34+
$$
35+
\eta(t=0) = 0.01e^{ -( (x^2 + y^2 )/(2.0*10.0^{10}) )}
36+
$$
37+
38+
![Rossby Wave Initial Condition](./rossbywave_initialcondition.png){ align=center }
39+
40+
The initial velocity field is calculated by using the pressure gradient force and using geostrophic balance; in SELF, this is handled by the `LinearShallowWater % DiagnoseGeostrophicVelocity` type bound procedure after setting the initial free surface height.
41+
42+
### Boundary Conditions
43+
Radiation boundary conditions are applied by setting the external state to a motionless fluid with no free surface height variation ( $u=v=0, \eta = 0$). The model is integrated forward in time using Williamson's $3^{rd}$ order low storage Runge-Kutta, with a time step of $\Delta t = 0.5 s$.
44+
45+
### Physical Parameters
46+
The remaining parameters for the problem are as follows
47+
48+
* $g = 10 m s^{-2}$
49+
* $f_0 = 10^{-4} s^{-1}$
50+
* $\beta = 10^{-11} m^{-1} s^{-1}$
51+
* $H = 1000 m$
52+
53+
## Runtimes
54+
55+
To benchmark this example, we run the simulation for 10 days of simulation time, using a time-step of a half-second.
56+
The solution after 10 days looks like the image shown below.
57+
58+
![Rossby Wave Initial Condition](./rossbywave_day10.png){ align=center }
59+
60+
```
61+
$SELF_PREFIX/examples/LinearShallowWater_Rossbywave -dt 0.5 -tn 172800 -int "rk3"
62+
```
63+

examples/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,6 @@ add_fortran_tests (
6666
"linear_euler2d_planewave_reflection.f90"
6767
"linear_euler2d_planewave_propagation.f90"
6868
"linear_shallow_water2d_nonormalflow.f90"
69+
"linear_shallow_water2d_planetaryrossby_wave.f90"
6970
"linear_euler3d_spherical_soundwave_radiation.f90"
7071
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
! //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// !
2+
!
3+
! Maintainers : [email protected]
4+
! Official Repository : https://github.com/FluidNumerics/self/
5+
!
6+
! Copyright © 2024 Fluid Numerics LLC
7+
!
8+
! Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
9+
!
10+
! 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
11+
!
12+
! 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in
13+
! the documentation and/or other materials provided with the distribution.
14+
!
15+
! 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from
16+
! this software without specific prior written permission.
17+
!
18+
! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19+
! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20+
! HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21+
! LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22+
! THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23+
! THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24+
!
25+
! //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// !
26+
27+
program linear_shallow_water2d_rossbywave
28+
use self_data
29+
use self_LinearShallowWater2D
30+
use self_mesh_2d
31+
32+
implicit none
33+
character(SELF_INTEGRATOR_LENGTH),parameter :: integrator = 'rk3' ! Which integrator method
34+
integer,parameter :: controlDegree = 7 ! Degree of control polynomial
35+
integer,parameter :: targetDegree = 16 ! Degree of target polynomial
36+
real(prec),parameter :: dt = 0.5_prec ! Time-step size
37+
real(prec),parameter :: endtime = 1000.0_prec ! (s); 1-day
38+
real(prec),parameter :: f0 = 0.0_prec !10.0_prec**(-4) ! reference coriolis parameter (1/s)
39+
real(prec),parameter :: beta = 0.0_prec ! 10.0_prec**(-11) ! beta parameter (1/ms)
40+
real(prec),parameter :: iointerval = 10.0 ! Write files 10 times per day
41+
42+
real(prec) :: e0,ef ! Initial and final entropy
43+
type(LinearShallowWater2D) :: modelobj ! Shallow water model
44+
type(Lagrange),target :: interp ! Interpolant
45+
integer :: bcids(1:4) ! Boundary conditions for structured mesh
46+
type(Mesh2D),target :: mesh ! Mesh class
47+
type(SEMQuad),target :: geometry ! Geometry class
48+
49+
real(prec),parameter :: g = 10.0_prec ! Acceleration due to gravity
50+
real(prec),parameter :: H = 1000.0_prec ! Uniform resting depth
51+
real(prec),parameter :: dx = 10.0_prec**(5) ! grid spacing in x-direction (m)
52+
real(prec),parameter :: dy = 10.0_prec**(5) ! grid spacing in y-direction (m)
53+
integer,parameter :: ntx = 2 ! number of tiles in x-direction
54+
integer,parameter :: nty = 2 ! number of tiles in y-direction
55+
integer,parameter :: nxp = 5 ! number of element per tile in x-direction
56+
integer,parameter :: nyp = 5 ! number of element per tile in y-direction
57+
58+
! Set no normal flow boundary conditions
59+
bcids(1:4) = [SELF_BC_NONORMALFLOW, & ! South
60+
SELF_BC_NONORMALFLOW, & ! East
61+
SELF_BC_NONORMALFLOW, & ! North
62+
SELF_BC_NONORMALFLOW] ! West
63+
64+
! Create a uniform block mesh
65+
call mesh%StructuredMesh(nxp,nyp,ntx,nty,dx,dy,bcids)
66+
67+
! Create an interpolant
68+
call interp%Init(N=controlDegree, &
69+
controlNodeType=GAUSS, &
70+
M=targetDegree, &
71+
targetNodeType=UNIFORM)
72+
73+
! Generate geometry (metric terms) from the mesh elements
74+
call geometry%Init(interp,mesh%nElem)
75+
call geometry%GenerateFromMesh(mesh)
76+
77+
! Initialize the model
78+
call modelobj%Init(mesh,geometry)
79+
modelobj%prescribed_bcs_enabled = .false. ! Disables prescribed boundary condition block for gpu accelerated implementations
80+
modelobj%tecplot_enabled = .false. ! Disables tecplot output
81+
82+
! Set the resting surface height and gravity
83+
modelobj%H = H
84+
modelobj%g = g
85+
86+
! Set the initial conditions
87+
call modelobj%solution%SetEquation(1,'f = 0')
88+
call modelobj%solution%SetEquation(2,'f = 0')
89+
call modelobj%solution%SetEquation(3,'f = 0.01*exp( -( (x-500000.0)^2 + (y-500000.0)^2 )/(2.0*(10.0^10)) )')
90+
call modelobj%solution%SetInteriorFromEquation(geometry,0.0_prec)
91+
92+
! call modelobj%SetCoriolis(f0,beta)
93+
!call modelobj%DiagnoseGeostrophicVelocity()
94+
95+
call modelobj%WriteModel()
96+
call modelobj%IncrementIOCounter()
97+
98+
call modelobj%CalculateEntropy()
99+
call modelobj%ReportEntropy()
100+
call modelobj%ReportMetrics()
101+
e0 = modelobj%entropy
102+
103+
! Set the model's time integration method
104+
call modelobj%SetTimeIntegrator(integrator)
105+
106+
! forward step the model to `endtime` using a time step
107+
! of `dt` and outputing model data every `iointerval`
108+
call modelobj%ForwardStep(endtime,dt,iointerval)
109+
110+
ef = modelobj%entropy
111+
112+
print*,e0,ef
113+
if(abs(ef-e0) > epsilon(e0)) then
114+
print*,"Error: Final entropy greater than initial entropy! ",e0,ef
115+
stop 1
116+
endif
117+
118+
! Clean up
119+
call modelobj%free()
120+
call mesh%free()
121+
call geometry%free()
122+
call interp%free()
123+
124+
endprogram linear_shallow_water2d_rossbywave

examples/shallow_water_plot.py

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #
2+
#
3+
# Maintainers : [email protected]
4+
# Official Repository : https://github.com/FluidNumerics/self/
5+
#
6+
# Copyright © 2024 Fluid Numerics LLC
7+
#
8+
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
9+
#
10+
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
11+
#
12+
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in
13+
# the documentation and/or other materials provided with the distribution.
14+
#
15+
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from
16+
# this software without specific prior written permission.
17+
#
18+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20+
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21+
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23+
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24+
#
25+
# //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #
26+
#
27+
# NOTE #
28+
#
29+
# If you encounter the following error on debian/ubuntu:
30+
#
31+
# ```
32+
# libGL error: MESA-LOADER: failed to open swrast: /usr/lib/dri/swrast_dri.so: cannot open shared object file: No such file or directory (search paths /usr/lib/x86_64-linux-gnu/dri:\$${ORIGIN}/dri:/usr/lib/dri, suffix _dri)
33+
# libGL error: failed to load driver: swrast
34+
# 2024-10-18 01:47:34.339 ( 3.885s) [ 754DF00AD740]vtkXOpenGLRenderWindow.:651 ERR| vtkXOpenGLRenderWindow (0x3b03f80): Cannot create GLX context. Aborting.
35+
# ERROR:root:Cannot create GLX context. Aborting.
36+
# ```
37+
# See https://askubuntu.com/questions/1352158/libgl-error-failed-to-load-drivers-iris-and-swrast-in-ubuntu-20-04 for resolution
38+
39+
import numpy as np
40+
import matplotlib
41+
import pyself.model2d as model2d
42+
import pyvista as pv
43+
import glob
44+
import os
45+
import sys
46+
import subprocess
47+
48+
# Specify the directory you want to search in
49+
directory_path = "/home/joe/SELF/build/examples/"
50+
# output video name
51+
video_name = "rossbywave.mp4"
52+
53+
etamin = -1.0e-3
54+
etamax = 1.0e-3
55+
56+
colormap = matplotlib.colormaps['RdBu']
57+
58+
def get_sorted_files(pattern):
59+
files = glob.glob(pattern)
60+
files.sort(key=os.path.getmtime) # Sort by modification time
61+
return files
62+
63+
# Filter the list to include only .dat files
64+
pickup_files = get_sorted_files(f"{directory_path}/solution.*.h5")
65+
66+
# If you want to get the full path of each file
67+
pickup_files = [os.path.join(directory_path, f) for f in pickup_files]
68+
69+
model = model2d.model()
70+
pv.start_xvfb()
71+
72+
k = 0
73+
# Example usage of reading each file
74+
for pickup_file in pickup_files:
75+
print(pickup_file)
76+
if(k==0):
77+
model.load(pickup_file)
78+
pl = pv.Plotter(off_screen=True)
79+
pl.add_mesh(model.pvdata,
80+
scalars="eta",
81+
cmap=colormap,
82+
clim=[etamin,etamax])
83+
# pl.add_mesh(model.pvdata,
84+
# scalars="u",
85+
# cmap=colormap,
86+
# clim=[-1e-3, 0])
87+
pl.show(auto_close=False)
88+
pl.camera_position = 'xy'
89+
pl.open_movie(video_name)
90+
else:
91+
model.update_from_file(pickup_file)
92+
93+
pl.write_frame()
94+
k+=1
95+
96+
pl.close()
97+
98+
99+

pyself/geometry.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env python
22
#
33

4-
import self.lagrange as lagrange
4+
import pyself.lagrange as lagrange
55

66

77
# class semline:

pyself/model2d.py

+55
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,58 @@ def generate_pyvista(self):
136136
k+=1
137137

138138
print(self.pvdata)
139+
140+
def update_from_file(self, hdf5File):
141+
"""Loads in 2-D model from SELF model output"""
142+
import h5py
143+
import dask.array as da
144+
145+
f = h5py.File(hdf5File, 'r')
146+
147+
if 'controlgrid' in list(f.keys()):
148+
149+
controlgrid = f['controlgrid']
150+
for group_name in controlgrid.keys():
151+
152+
if( group_name == 'geometry' ):
153+
continue
154+
155+
group = controlgrid[group_name]
156+
# Create a list to hold data for this group
157+
group_data = getattr(self, group_name)
158+
print(f"Loading {group_name} group")
159+
160+
for k in group.keys():
161+
k_decoded = k.encode('utf-8').decode('utf-8')
162+
if k == 'metadata':
163+
continue
164+
else:
165+
print(f"Loading {k_decoded} field")
166+
# Load the actual data
167+
d = group[k]
168+
N = d.shape[2]
169+
170+
# Find index for this field
171+
i = 0
172+
for sol in group_data:
173+
if sol['name'] == k_decoded:
174+
break
175+
else:
176+
i += 1
177+
178+
group_data[i]['data'] = da.from_array(d, chunks=(self.geom.daskChunkSize, N, N))
179+
180+
# # Load fields into pvdata
181+
k = 0
182+
for attr in self.__dict__:
183+
if not attr in ['pvdata','varnames','varunits','geom']:
184+
controlgroup = getattr(self, attr)
185+
for var in controlgroup:
186+
self.pvdata.point_data.set_array(var['data'].flatten(),var['name'])
187+
k+=1
188+
189+
else:
190+
print(f"Error: /controlgrid group not found in {hdf5File}.")
191+
return 1
192+
193+
return 0

0 commit comments

Comments
 (0)