|
155 | 155 | "r_h = Constant(5e3)\n", |
156 | 156 | "H = Constant(100.0)\n", |
157 | 157 | "expr = H * firedrake.max_value(0, 1 - inner(x, x) / r_h**2)\n", |
158 | | - "h = firedrake.Function(Q).interpolate(expr)\n", |
159 | | - "h_0 = h.copy(deepcopy=True)" |
| 158 | + "h_init = firedrake.Function(Q).interpolate(expr)" |
160 | 159 | ] |
161 | 160 | }, |
162 | 161 | { |
|
168 | 167 | "source": [ |
169 | 168 | "fig, ax = plt.subplots()\n", |
170 | 169 | "ax.set_aspect(\"equal\")\n", |
171 | | - "colors = firedrake.tripcolor(h, axes=ax)\n", |
| 170 | + "colors = firedrake.tripcolor(h_init, axes=ax)\n", |
172 | 171 | "fig.colorbar(colors);" |
173 | 172 | ] |
174 | 173 | }, |
|
187 | 186 | "metadata": {}, |
188 | 187 | "outputs": [], |
189 | 188 | "source": [ |
190 | | - "s = firedrake.Function(Q).interpolate(b + h)\n", |
| 189 | + "s = firedrake.Function(Q).interpolate(b + h_init)\n", |
191 | 190 | "a = firedrake.Function(Q).interpolate(smb(s))" |
192 | 191 | ] |
193 | 192 | }, |
|
227 | 226 | }, |
228 | 227 | { |
229 | 228 | "cell_type": "markdown", |
230 | | - "id": "bec1a763-ab01-4f63-ae93-d92f0ce0ef2a", |
| 229 | + "id": "922938b5-e240-4573-be3d-a6f6302951c2", |
231 | 230 | "metadata": {}, |
232 | 231 | "source": [ |
233 | | - "We'll use the shallow ice approximation, which diagnoses the velocity at a point in a purely local fashion using the thickness and surface slope, to initialize the ice velocity." |
| 232 | + "To proceed, we have to make function spaces to represent the membrane and basal stresses and create a variable that stores the velocity and stresses.\n", |
| 233 | + "Here we use piecewise constant finite elements for the membrane stresses.\n", |
| 234 | + "In general, if you use $CG(k)$ elements for the velocity, you need to use $DG(k - 1)$ elements for the stresses." |
234 | 235 | ] |
235 | 236 | }, |
236 | 237 | { |
|
242 | 243 | "source": [ |
243 | 244 | "V = firedrake.VectorFunctionSpace(mesh, cg1)\n", |
244 | 245 | "\n", |
245 | | - "u = firedrake.Function(V)\n", |
246 | | - "v = firedrake.TestFunction(V)\n", |
247 | | - "\n", |
248 | | - "ρ_I = Constant(ice_density)\n", |
249 | | - "g = Constant(gravity)\n", |
250 | | - "\n", |
251 | | - "n = Constant(glen_flow_law)\n", |
252 | | - "\n", |
253 | | - "P = ρ_I * g * h\n", |
254 | | - "S_n = inner(grad(s), grad(s))**((n - 1) / 2)\n", |
255 | | - "u_shear = -2 * A * P ** n / (n + 2) * h * S_n * grad(s)\n", |
256 | | - "F = inner(u - u_shear, v) * dx\n", |
257 | | - "\n", |
258 | | - "solver_params = {\"snes_type\": \"ksponly\", \"ksp_type\": \"gmres\"}\n", |
259 | | - "fc_params = {\"quadrature_degree\": 6}\n", |
260 | | - "params = {\"solver_parameters\": solver_params, \"form_compiler_parameters\": fc_params}\n", |
261 | | - "firedrake.solve(F == 0, u, **params)" |
262 | | - ] |
263 | | - }, |
264 | | - { |
265 | | - "cell_type": "code", |
266 | | - "execution_count": null, |
267 | | - "id": "5a32887c-dcd3-4aae-844e-1a6c70b183db", |
268 | | - "metadata": {}, |
269 | | - "outputs": [], |
270 | | - "source": [ |
271 | | - "fig, ax = plt.subplots()\n", |
272 | | - "ax.set_aspect(\"equal\")\n", |
273 | | - "colors = firedrake.tripcolor(u, axes=ax)\n", |
274 | | - "fig.colorbar(colors);" |
275 | | - ] |
276 | | - }, |
277 | | - { |
278 | | - "cell_type": "markdown", |
279 | | - "id": "9a900c91-a77f-4d7a-86e3-9c014512e3b9", |
280 | | - "metadata": {}, |
281 | | - "source": [ |
282 | | - "Now we'll get to the real modeling.\n", |
283 | | - "To proceed, we have to make function spaces to represent the membrane and basal stresses and create a variable that stores the velocity and stresses.\n", |
284 | | - "Here we use piecewise constant finite elements for the stresses.\n", |
285 | | - "In general, if you use $CG(k)$ elements for the velocity, you need to use $DG(k - 1)$ elements for the stresses." |
286 | | - ] |
287 | | - }, |
288 | | - { |
289 | | - "cell_type": "code", |
290 | | - "execution_count": null, |
291 | | - "id": "db935250-689e-4ca7-aee5-c5b0f212c4d4", |
292 | | - "metadata": {}, |
293 | | - "outputs": [], |
294 | | - "source": [ |
295 | 246 | "dg0 = firedrake.FiniteElement(\"DG\", \"triangle\", 0)\n", |
296 | 247 | "Σ = firedrake.TensorFunctionSpace(mesh, dg0, symmetry=True)\n", |
297 | | - "T = firedrake.VectorFunctionSpace(mesh, cg1)\n", |
298 | | - "Z = V * Σ * T\n", |
299 | | - "z = firedrake.Function(Z)\n", |
300 | | - "\n", |
301 | | - "z.sub(0).assign(u);" |
| 248 | + "Z = V * Σ * V * Q\n", |
| 249 | + "z = firedrake.Function(Z)" |
302 | 250 | ] |
303 | 251 | }, |
304 | 252 | { |
|
322 | 270 | "metadata": {}, |
323 | 271 | "outputs": [], |
324 | 272 | "source": [ |
| 273 | + "n = Constant(glen_flow_law)\n", |
| 274 | + "\n", |
325 | 275 | "τ_c = Constant(0.1)\n", |
326 | 276 | "ε_c = Constant(A * τ_c ** n)" |
327 | 277 | ] |
|
351 | 301 | "metadata": {}, |
352 | 302 | "outputs": [], |
353 | 303 | "source": [ |
| 304 | + "u, M, τ, h = firedrake.split(z)\n", |
| 305 | + "\n", |
354 | 306 | "K = h * A / (n + 2)\n", |
355 | 307 | "U_c = Constant(100.0)\n", |
356 | 308 | "u_c = K * τ_c ** n + U_c" |
|
378 | 330 | " \"sliding_coefficient\": u_c / τ_c,\n", |
379 | 331 | "}\n", |
380 | 332 | "\n", |
381 | | - "u, M, τ = firedrake.split(z)\n", |
382 | 333 | "fields = {\n", |
383 | 334 | " \"velocity\": u,\n", |
384 | 335 | " \"membrane_stress\": M,\n", |
385 | 336 | " \"basal_stress\": τ,\n", |
386 | 337 | " \"thickness\": h,\n", |
387 | | - " \"surface\": s,\n", |
| 338 | + " \"surface\": b + h,\n", |
388 | 339 | "}\n", |
389 | 340 | "\n", |
390 | | - "v, N, σ = firedrake.TestFunctions(Z)" |
| 341 | + "v, N, σ, η = firedrake.TestFunctions(Z)" |
391 | 342 | ] |
392 | 343 | }, |
393 | 344 | { |
|
441 | 392 | "from icepack2 import model\n", |
442 | 393 | "from icepack2.model.variational import momentum_balance, flow_law, friction_law\n", |
443 | 394 | "\n", |
444 | | - "F = (\n", |
| 395 | + "F_momentum = (\n", |
445 | 396 | " momentum_balance(**fields, test_function=v)\n", |
446 | 397 | " + firedrake.replace(flow_law(**fields, **glen_rheology, test_function=N), {h: H})\n", |
447 | 398 | " + α * firedrake.replace(flow_law(**fields, **linear_rheology, test_function=N), {h: H})\n", |
448 | 399 | " + friction_law(**fields, **glen_rheology, test_function=σ)\n", |
449 | 400 | " + α * friction_law(**fields, **linear_rheology, test_function=σ)\n", |
450 | 401 | ")\n", |
451 | 402 | "\n", |
| 403 | + "F_mass = (h - h_init) * η * dx\n", |
| 404 | + "\n", |
| 405 | + "F = F_momentum + F_mass\n", |
452 | 406 | "momentum_problem = firedrake.NonlinearVariationalProblem(F, z, **pparams)\n", |
453 | 407 | "momentum_solver = firedrake.NonlinearVariationalSolver(momentum_problem, **sparams)" |
454 | 408 | ] |
|
482 | 436 | "metadata": {}, |
483 | 437 | "outputs": [], |
484 | 438 | "source": [ |
485 | | - "u_init, M_init, τ_init = z.subfunctions\n", |
| 439 | + "u_init, M_init, τ_init, h_init = z.subfunctions\n", |
486 | 440 | "\n", |
487 | 441 | "fig, axes = plt.subplots()\n", |
488 | 442 | "axes.set_aspect(\"equal\")\n", |
|
526 | 480 | "Pack in the initial values of the velocity, membrane stress, and basal stress that we computed before." |
527 | 481 | ] |
528 | 482 | }, |
529 | | - { |
530 | | - "cell_type": "code", |
531 | | - "execution_count": null, |
532 | | - "id": "873be577-b14f-4f6a-bd69-fbe9a6cc2f34", |
533 | | - "metadata": {}, |
534 | | - "outputs": [], |
535 | | - "source": [ |
536 | | - "W = V * Σ * T * Q\n", |
537 | | - "w = firedrake.Function(W)\n", |
538 | | - "w.sub(0).assign(u_init)\n", |
539 | | - "w.sub(1).assign(M_init)\n", |
540 | | - "w.sub(2).assign(τ_init)\n", |
541 | | - "w.sub(3).assign(h);" |
542 | | - ] |
543 | | - }, |
544 | 483 | { |
545 | 484 | "cell_type": "markdown", |
546 | 485 | "id": "0573021d-eade-4e73-b8b1-563c56da95aa", |
|
556 | 495 | "metadata": {}, |
557 | 496 | "outputs": [], |
558 | 497 | "source": [ |
559 | | - "u, M, τ, h = firedrake.split(w)\n", |
560 | | - "v, N, σ, η = firedrake.TestFunctions(W)\n", |
561 | | - "\n", |
562 | | - "fields = {\n", |
563 | | - " \"velocity\": u,\n", |
564 | | - " \"membrane_stress\": M,\n", |
565 | | - " \"basal_stress\": τ,\n", |
566 | | - " \"thickness\": h,\n", |
567 | | - " \"surface\": b + h,\n", |
568 | | - "}\n", |
569 | | - "\n", |
570 | | - "F_momentum = (\n", |
571 | | - " momentum_balance(**fields, test_function=v)\n", |
572 | | - " + firedrake.replace(flow_law(**fields, **glen_rheology, test_function=N), {h: H})\n", |
573 | | - " + α * firedrake.replace(flow_law(**fields, **linear_rheology, test_function=N), {h: H})\n", |
574 | | - " + friction_law(**fields, **glen_rheology, test_function=σ)\n", |
575 | | - " + α * friction_law(**fields, **linear_rheology, test_function=σ)\n", |
576 | | - ")\n", |
577 | | - "\n", |
578 | 498 | "F_mass = model.mass_balance(thickness=h, velocity=u, accumulation=a, test_function=η)\n", |
579 | | - "\n", |
580 | 499 | "F = F_momentum + F_mass" |
581 | 500 | ] |
582 | 501 | }, |
|
591 | 510 | "t = Constant(0.0)\n", |
592 | 511 | "dt = Constant(1.0 / 6)\n", |
593 | 512 | "\n", |
594 | | - "lower = firedrake.Function(W)\n", |
595 | | - "upper = firedrake.Function(W)\n", |
| 513 | + "lower = firedrake.Function(Z)\n", |
| 514 | + "upper = firedrake.Function(Z)\n", |
596 | 515 | "lower.assign(-np.inf)\n", |
597 | 516 | "upper.assign(+np.inf)\n", |
598 | 517 | "lower.subfunctions[3].assign(0.0)\n", |
|
603 | 522 | " \"snes_monitor\": \":rainier-output-vi.log\",\n", |
604 | 523 | " \"snes_type\": \"vinewtonrsls\",\n", |
605 | 524 | " \"snes_max_it\": 200,\n", |
606 | | - " #\"snes_linesearch_type\": \"nleqerr\",\n", |
607 | 525 | " \"ksp_type\": \"gmres\",\n", |
608 | 526 | " \"pc_type\": \"lu\",\n", |
609 | 527 | " \"pc_factor_mat_solver_type\": \"mumps\",\n", |
610 | 528 | " },\n", |
611 | | - " \"form_compiler_parameters\": fc_params,\n", |
| 529 | + " \"form_compiler_parameters\": {\"quadrature_degree\": 6},\n", |
612 | 530 | " \"stage_type\": \"value\",\n", |
613 | 531 | " \"basis_type\": \"Bernstein\",\n", |
614 | 532 | " \"bounds\": bounds,\n", |
615 | 533 | "}\n", |
616 | 534 | "\n", |
617 | | - "solver = irksome.TimeStepper(F, tableau, t, dt, w, **bparams)" |
| 535 | + "solver = irksome.TimeStepper(F, tableau, t, dt, z, **bparams)" |
618 | 536 | ] |
619 | 537 | }, |
620 | 538 | { |
|
632 | 550 | "metadata": {}, |
633 | 551 | "outputs": [], |
634 | 552 | "source": [ |
635 | | - "us = [w.subfunctions[0].copy(deepcopy=True)]\n", |
636 | | - "hs = [w.subfunctions[3].copy(deepcopy=True)]\n", |
| 553 | + "us = [z.subfunctions[0].copy(deepcopy=True)]\n", |
| 554 | + "hs = [z.subfunctions[3].copy(deepcopy=True)]\n", |
637 | 555 | "\n", |
638 | 556 | "final_time = 500.0\n", |
639 | 557 | "num_steps = int(final_time / float(dt))\n", |
640 | 558 | "for step in trange(num_steps):\n", |
641 | 559 | " solver.advance()\n", |
642 | | - " h = w.subfunctions[3]\n", |
| 560 | + " h = z.subfunctions[3]\n", |
643 | 561 | " a.interpolate(smb(b + h))\n", |
644 | 562 | "\n", |
645 | | - " us.append(w.subfunctions[0].copy(deepcopy=True))\n", |
646 | | - " hs.append(w.subfunctions[3].copy(deepcopy=True))" |
| 563 | + " us.append(z.subfunctions[0].copy(deepcopy=True))\n", |
| 564 | + " hs.append(z.subfunctions[3].copy(deepcopy=True))" |
647 | 565 | ] |
648 | 566 | }, |
649 | 567 | { |
|
679 | 597 | "metadata": {}, |
680 | 598 | "outputs": [], |
681 | 599 | "source": [ |
682 | | - "u, M, τ, h = w.subfunctions\n", |
| 600 | + "u, M, τ, h = z.subfunctions\n", |
683 | 601 | "\n", |
684 | 602 | "fig, axes = plt.subplots()\n", |
685 | 603 | "axes.set_aspect(\"equal\")\n", |
|
0 commit comments