-
Notifications
You must be signed in to change notification settings - Fork 1
/
fofonoff_qg.py
88 lines (68 loc) · 2.81 KB
/
fofonoff_qg.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
from firedrake import *
import numpy as np
#OPERATORS
gradperp = lambda i: as_vector((-i.dx(1),i.dx(0)))
# Geometry
Lx = 1. # Zonal length
Ly = 1. # Meridonal length
n0 = 20 # Spatial resolution
mesh = RectangleMesh(n0, n0, Lx, Ly, reorder=None)
# Function and Vector Spaces
Vcg = FunctionSpace(mesh,"CG",3) # CG elements for Streamfunction
Vdg = FunctionSpace(mesh,"DG",1) # DG elements for Potential Vorticity (PV)
Vcdg = VectorFunctionSpace(mesh,"DG",2) # DG elements for velocity
# Boundary Conditions
bc = DirichletBC(Vcg, 0.0, (1, 2, 3, 4))
# Physical parameters and Winds
beta = Constant("1.0") # Beta parameter
F = Constant("1.0") # Burger number
r = Constant("0.3") # Bottom drag
tau = Constant("0.00001") # Wind Forcing
Fwinds = Function(Vcg).interpolate(Expression("-tau*cos(pi*(x[1]-0.5))", tau=tau))
# Test and Trial Functions
phi = TestFunction(Vcg)
psi = TrialFunction(Vcg)
# Solution Functions
psi_lin = Function(Vcg, name="Linear Streamfunction")
psi_non = Function(Vcg, name="Nonlinear Streamfunction")
# Define Weak Form
a = -r*inner(grad(phi), grad(psi))*dx - F*phi*psi*dx + beta*phi*psi.dx(0)*dx
L = Fwinds*phi*dx
# Set up Elliptic inverter for Linear Problem
linear_problem = LinearVariationalProblem(a, L, psi_lin, bcs=bc)
linear_solver = LinearVariationalSolver(linear_problem,
solver_parameters={
'ksp_type':'preonly',
'pc_type':'lu'
})
# Solve the linear problem
linear_solver.solve()
# Plot Solution
#p = plot(psi_lin)
#p.show()
# Use linear solution as a good guess
psi_non.assign(psi_lin)
# Define Weak Form
G = -r*inner(grad(phi), grad(psi_non))*dx - F*phi*psi_non*dx + beta*phi*psi_non.dx(0)*dx \
- inner(grad(phi),gradperp(psi_non))*div(grad(psi_non))*dx \
- Fwinds*phi*dx
# Set up Elliptic inverter
nonlinear_problem = NonlinearVariationalProblem(G, psi_non, bcs=bc)
nonlinear_solver = NonlinearVariationalSolver(nonlinear_problem,
solver_parameters={
'snes_type': 'newtonls',
'ksp_type':'preonly',
'pc_type':'lu'
})
# solve for streamfunction
nonlinear_solver.solve()
# Plot Solution
p = plot(psi_non)
p.show()
"""
# Potential Energy
print potential_energy
# Output to a file
outfile = File("outputQG.pvd")
outfile.write(psi_soln)
"""