11import numpy as np
22import firedrake
33from firedrake import (
4- sqrt , exp , max_value , inner , as_vector , Constant , dx
4+ sqrt , exp , min_value , max_value , inner , as_vector , Constant , dx
55)
6+ from irksome import BackwardEuler , TimeStepper
67from icepack2 .model import mass_balance
78from icepack2 .model .variational import (
89 momentum_balance , flow_law , friction_law , calving_terminus
@@ -40,7 +41,7 @@ def mismip_bed_topography(x):
4041 return max_value (B_x + B_y , z_deep )
4142
4243
43- def form_momentum_balance (z , w , h , b , H , α , rheo1 , rheo3 ):
44+ def form_momentum_balance (z , w , h , s , H , α , rheo1 , rheo3 ):
4445 u , M , τ = z
4546 v , N , σ = w
4647
@@ -49,7 +50,7 @@ def form_momentum_balance(z, w, h, b, H, α, rheo1, rheo3):
4950 membrane_stress = M ,
5051 basal_stress = τ ,
5152 thickness = h ,
52- surface = b + h ,
53+ surface = s ,
5354 test_function = v ,
5455 )
5556
@@ -69,12 +70,17 @@ def form_momentum_balance(z, w, h, b, H, α, rheo1, rheo3):
6970 velocity = u , basal_stress = τ , ** rheo1 , test_function = σ
7071 )
7172
73+ F_terminus = calving_terminus (
74+ thickness = h , surface = s , test_function = v , outflow_ids = (2 ,)
75+ )
76+
7277 return (
7378 F_stress_balance
7479 + F_glen_law
7580 + F_linear_law
7681 + F_weertman_drag
7782 + F_viscous_drag
83+ + F_terminus
7884 )
7985
8086
@@ -136,14 +142,15 @@ def run_simulation(ny: int):
136142 }
137143
138144 z = firedrake .Function (Z )
145+ z .sub (3 ).assign (h_0 )
139146 u , M , τ , h = firedrake .split (z )
140147 s = max_value (b + h , (1 - ρ_I / ρ_W ) * h )
141148
142149 # TODO: Think very hard about the float mask
143150 p_I = ρ_I * g * h
144151 p_W = ρ_W * g * max_value (0 , - (s - h ))
145152 N = max_value (0 , p_I - p_W )
146- f = N / (2 * τ_c )
153+ f = min_value ( N / (2 * τ_c ), 1.0 )
147154
148155 fields = {
149156 "velocity" : u ,
@@ -154,9 +161,15 @@ def run_simulation(ny: int):
154161 "floating" : f ,
155162 }
156163
164+ inflow_bc = firedrake .DirichletBC (Z .sub (0 ), Constant ((0 , 0 )), [1 ])
165+ side_wall_bc = firedrake .DirichletBC (Z .sub (0 ), Constant ((0 , 0 )), [3 , 4 ])
166+ bcs = [inflow_bc , side_wall_bc ]
167+
157168 degree = 1
158169 qdegree = max (8 , degree ** glen_flow_law )
159- pparams = {"form_compiler_parameters" : {"quadrature_degree" : qdegree }}
170+ pparams = {
171+ "form_compiler_parameters" : {"quadrature_degree" : qdegree }
172+ }
160173
161174 sparams = {
162175 "solver_parameters" : {
@@ -176,10 +189,10 @@ def run_simulation(ny: int):
176189
177190 v , N , σ , η = firedrake .TestFunctions (Z )
178191
179- F_momentum = form_momentum_balance ((u , M , τ ), (v , N , σ ), h , b , H , α , rheo1 , rheo3 )
192+ F_momentum = form_momentum_balance ((u , M , τ ), (v , N , σ ), h , s , H , α , rheo1 , rheo3 )
180193 F_mass = (h - h_0 ) * η * dx
181194 F = F_momentum + F_mass
182- problem = firedrake .NonlinearVariationalProblem (F , z , ** pparams )
195+ problem = firedrake .NonlinearVariationalProblem (F , z , ** pparams , bcs = bcs )
183196 solver = firedrake .NonlinearVariationalSolver (problem , ** sparams )
184197
185198 num_continuation_steps = 5
@@ -188,6 +201,53 @@ def run_simulation(ny: int):
188201 m .assign ((1 - r ) + r * weertman_sliding_law )
189202 solver .solve ()
190203
204+ print ("Time-dependent solve" )
205+ F_mass = mass_balance (
206+ thickness = h ,
207+ velocity = u ,
208+ accumulation = a ,
209+ thickness_inflow = h_0 ,
210+ test_function = η ,
211+ )
212+
213+ t = Constant (0.0 )
214+ timestep = 1.0
215+ dt = Constant (timestep )
216+ F = F_momentum + F_mass
217+
218+ lower = firedrake .Function (Z )
219+ upper = firedrake .Function (Z )
220+ lower .assign (- np .inf )
221+ upper .assign (+ np .inf )
222+ lower .subfunctions [3 ].assign (0.0 )
223+
224+ params = {
225+ "solver_parameters" : {
226+ "snes_monitor" : None ,
227+ "snes_type" : "vinewtonrsls" ,
228+ "snes_max_it" : 200 ,
229+ "snes_linesearch_type" : "nleqerr" ,
230+ "ksp_type" : "gmres" ,
231+ "pc_type" : "lu" ,
232+ "pc_factor_mat_solver_type" : "mumps" ,
233+ },
234+ "stage_type" : "value" ,
235+ "basis_type" : "Bernstein" ,
236+ "bounds" : ("stage" , lower , upper ),
237+ }
238+ method = BackwardEuler ()
239+ solver = TimeStepper (F , method , t , dt , z , ** params , ** pparams , bcs = bcs )
240+
241+ final_time = 1.0
242+ num_steps = int (final_time / timestep )
243+ for step in range (num_steps ):
244+ solver .advance ()
245+
246+ u , M , τ , h = z .subfunctions
247+ firedrake .assemble ((h - h_0 ) * dx )
248+
249+ return z
250+
191251
192252def test_mismip ():
193253 run_simulation (ny = 20 )
0 commit comments