Skip to content

Commit 8af6379

Browse files
committed
Classes -> modules
1 parent 234357d commit 8af6379

File tree

6 files changed

+192
-181
lines changed

6 files changed

+192
-181
lines changed

src/icepack2/model.py

Lines changed: 0 additions & 166 deletions
This file was deleted.

src/icepack2/model/__init__.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import ufl
2+
from firedrake import (
3+
max_value, min_value, jump, inner, grad, dx, ds, dS, FacetNormal, Constant
4+
)
5+
from irksome import Dt
6+
from . import variational, minimization
7+
8+
9+
def mass_balance(**kwargs):
10+
r"""Return the mass balance equation"""
11+
field_names = ("thickness", "velocity", "accumulation", "test_function")
12+
h, u, a, φ = map(kwargs.get, field_names)
13+
h_inflow = kwargs.get("thickness_inflow", Constant(0.0))
14+
15+
cell_balance = (Dt(h) * φ - inner(h * u, grad(φ)) - a * φ) * dx
16+
17+
mesh = ufl.domain.extract_unique_domain(h)
18+
ν = FacetNormal(mesh)
19+
f = h * max_value(0, inner(u, ν))
20+
21+
outflow = f * φ * ds
22+
inflow = h_inflow * min_value(0, inner(u, ν)) * φ * ds
23+
boundary_balance = inflow + outflow
24+
25+
facet_balance = jump(f) * jump(φ) * dS
26+
27+
return cell_balance + facet_balance + boundary_balance

src/icepack2/model/minimization.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import ufl
2+
from firedrake import (
3+
Constant, inner, tr, sym, grad, div, dx, ds, dS, avg, jump, FacetNormal, min_value
4+
)
5+
from ..constants import ice_density as ρ_I, water_density as ρ_W, gravity as g
6+
7+
8+
def viscous_power(**kwargs):
9+
r"""Return the viscous power dissipation"""
10+
# Get all the dynamical fields
11+
field_names = ("membrane_stress", "thickness")
12+
M, h = map(kwargs.get, field_names)
13+
14+
# Get the parameters for the constitutive relation
15+
parameter_names = ("flow_law_coefficient", "flow_law_exponent")
16+
A, n = map(kwargs.get, parameter_names)
17+
18+
mesh = ufl.domain.extract_unique_domain(M)
19+
d = mesh.geometric_dimension()
20+
21+
M_2 = (inner(M, M) - tr(M) ** 2 / (d + 1)) / 2
22+
M_n = M_2 if float(n) == 1 else M_2 ** ((n + 1) / 2)
23+
return 2 * h * A / (n + 1) * M_n * dx
24+
25+
26+
def friction_power(**kwargs):
27+
r"""Return the frictional power dissipation"""
28+
τ = kwargs["basal_stress"]
29+
parameter_names = ("sliding_coefficient", "sliding_exponent")
30+
K, m = map(kwargs.get, parameter_names)
31+
τ_2 = inner(τ, τ)
32+
τ_m = τ_2 if float(m) == 1 else τ_2 ** ((m + 1) / 2)
33+
return K / (m + 1) * τ_m * dx
34+
35+
36+
def calving_terminus(**kwargs):
37+
r"""Return the power dissipation from the terminus boundary condition"""
38+
# Get all the dynamical fields and boundary conditions
39+
u, h, s = map(kwargs.get, ("velocity", "thickness", "surface"))
40+
outflow_ids = kwargs["outflow_ids"]
41+
42+
# Get the unit outward normal vector to the terminus
43+
mesh = ufl.domain.extract_unique_domain(u)
44+
ν = FacetNormal(mesh)
45+
46+
# Compute the forces per unit length at the terminus from the glacier
47+
# and from the ocean (assuming that sea level is at z = 0)
48+
f_I = 0.5 * ρ_I * g * h**2
49+
d = min_value(0, s - h)
50+
f_W = 0.5 * ρ_W * g * d**2
51+
52+
return (f_I - f_W) * inner(u, ν) * ds(outflow_ids)
53+
54+
55+
def momentum_balance(**kwargs):
56+
r"""Return the momentum balance constraint"""
57+
field_names = (
58+
"velocity", "membrane_stress", "basal_stress", "thickness", "surface"
59+
)
60+
u, M, τ, h, s = map(kwargs.get, field_names)
61+
f = kwargs.get("floating", Constant(1.0))
62+
ε = sym(grad(u))
63+
cell_balance = (-h * inner(M, ε) + inner(f * τ - ρ_I * g * h * grad(s), u)) * dx
64+
65+
mesh = ufl.domain.extract_unique_domain(u)
66+
ν = FacetNormal(mesh)
67+
facet_balance = ρ_I * g * avg(h) * inner(jump(s, ν), avg(u)) * dS
68+
69+
return cell_balance + facet_balance
70+
71+
72+
def ice_shelf_momentum_balance(**kwargs):
73+
r"""Return the momentum balance constraint for floating ice shelves
74+
75+
Floating ice shelves are simpler because there is no basal shear stress
76+
and we assume the ice is hydrostatic, in which case the surface
77+
elevation is proportional to the thickness.
78+
"""
79+
field_names = ("velocity", "membrane_stress", "thickness")
80+
u, M, h = map(kwargs.get, field_names)
81+
ε = sym(grad(u))
82+
83+
ρ = ρ_I * (1 - ρ_I / ρ_W)
84+
return (-h * inner(M, ε) + 0.5 * ρ * g * h**2 * div(u)) * dx

src/icepack2/model/variational.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import ufl
2+
from firedrake import (
3+
Constant, inner, tr, sym, grad, div, dx, ds, dS, avg, jump, FacetNormal, min_value
4+
)
5+
from ..constants import ice_density as ρ_I, water_density as ρ_W, gravity as g
6+
7+
8+
def flow_law(**kwargs):
9+
field_names = ("thickness", "membrane_stress", "velocity", "test_function")
10+
h, M, u, N = map(kwargs.get, field_names)
11+
A, n = map(kwargs.get, ("flow_law_coefficient", "flow_law_exponent"))
12+
13+
mesh = ufl.domain.extract_unique_domain(u)
14+
d = mesh.geometric_dimension()
15+
16+
ε = sym(grad(u))
17+
M_2 = (inner(M, M) - tr(M) ** 2 / (d + 1)) / 2
18+
M_n = Constant(1.0) if float(n) == 1 else M_2 ** ((n - 1) / 2)
19+
return h * (A * M_n * (inner(M, N) - tr(M) * tr(N) / (d + 1)) - inner(ε, N)) * dx
20+
21+
22+
def friction_law(**kwargs):
23+
τ, u, σ = map(kwargs.get, ("basal_stress", "velocity", "test_function"))
24+
K, m = map(kwargs.get, ("sliding_coefficient", "sliding_exponent"))
25+
τ_2 = inner(τ, τ)
26+
τ_m = Constant(1.0) if float(m) == 1 else τ_2 ** ((m - 1) / 2)
27+
return inner(K * τ_m * τ + u, σ) * dx
28+
29+
30+
def calving_terminus(**kwargs):
31+
h, s, v = map(kwargs.get, ("thickness", "surface", "test_function"))
32+
outflow_ids = kwargs["outflow_ids"]
33+
34+
mesh = ufl.domain.extract_unique_domain(v)
35+
ν = FacetNormal(mesh)
36+
37+
# Compute the forces per unit length at the terminus from the glacier
38+
# and from the ocean (assuming that sea level is at z = 0)
39+
f_I = 0.5 * ρ_I * g * h**2
40+
d = min_value(0, s - h)
41+
f_W = 0.5 * ρ_W * g * d**2
42+
43+
return (f_I - f_W) * inner(v, ν) * ds(outflow_ids)
44+
45+
46+
def momentum_balance(**kwargs):
47+
field_names = (
48+
"velocity",
49+
"membrane_stress",
50+
"basal_stress",
51+
"thickness",
52+
"surface",
53+
"test_function",
54+
)
55+
u, M, τ, h, s, v = map(kwargs.get, field_names)
56+
57+
ε = sym(grad(v))
58+
cell_balance = (-h * inner(M, ε) + inner(τ - ρ_I * g * h * grad(s), v)) * dx
59+
60+
mesh = ufl.domain.extract_unique_domain(u)
61+
ν = FacetNormal(mesh)
62+
facet_balance = ρ_I * g * avg(h) * inner(jump(s, ν), avg(v)) * dS
63+
64+
return cell_balance + facet_balance
65+
66+

test/mass_balance_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import firedrake
55
from firedrake import dx, inner, max_value, Constant
66
import irksome
7-
from icepack2.model import VariationalForm
7+
from icepack2 import model
88

99
@pytest.mark.parametrize("degree", [0, 1, 2])
1010
def test_convergence_rate(degree):
@@ -30,7 +30,7 @@ def test_convergence_rate(degree):
3030
w = x - c
3131
u = firedrake.as_vector((-w[1], w[0]))
3232

33-
problem = VariationalForm.mass_balance(
33+
problem = model.mass_balance(
3434
thickness=h,
3535
velocity=u,
3636
accumulation=Constant(0.0),

0 commit comments

Comments
 (0)