|
12 | 12 | "from numpy import pi as π\n", |
13 | 13 | "import matplotlib.pyplot as plt\n", |
14 | 14 | "import firedrake\n", |
15 | | - "from firedrake import inner, grad, dx, ds, exp, min_value, max_value, Constant, derivative\n", |
| 15 | + "from firedrake import inner, grad, dx, exp, min_value, max_value, Constant, derivative\n", |
16 | 16 | "import irksome\n", |
17 | 17 | "import icepack\n", |
18 | 18 | "from icepack2 import model" |
|
152 | 152 | "source": [ |
153 | 153 | "r_h = Constant(5e3)\n", |
154 | 154 | "H = Constant(100.0)\n", |
155 | | - "expr = H * firedrake.max_value(0, 1 - inner(x, x) / r_h**2)\n", |
| 155 | + "expr = H * max_value(0, 1 - inner(x, x) / r_h**2)\n", |
156 | 156 | "h = firedrake.Function(Q).interpolate(expr)\n", |
157 | 157 | "h_0 = h.copy(deepcopy=True)" |
158 | 158 | ] |
|
217 | 217 | "metadata": {}, |
218 | 218 | "outputs": [], |
219 | 219 | "source": [ |
220 | | - "from icepack2.constants import gravity as g, ice_density as ρ_I, glen_flow_law as n\n", |
| 220 | + "from icepack2.constants import gravity, ice_density, glen_flow_law\n", |
221 | 221 | "A = icepack.rate_factor(Constant(273.15))" |
222 | 222 | ] |
223 | 223 | }, |
|
241 | 241 | "u = firedrake.Function(V)\n", |
242 | 242 | "v = firedrake.TestFunction(V)\n", |
243 | 243 | "\n", |
| 244 | + "ρ_I = Constant(ice_density)\n", |
| 245 | + "g = Constant(gravity)\n", |
| 246 | + "n = Constant(glen_flow_law)\n", |
| 247 | + "\n", |
244 | 248 | "P = ρ_I * g * h\n", |
245 | 249 | "S_n = inner(grad(s), grad(s))**((n - 1) / 2)\n", |
246 | 250 | "u_shear = -2 * A * P ** n / (n + 2) * h * S_n * grad(s)\n", |
|
403 | 407 | "metadata": {}, |
404 | 408 | "outputs": [], |
405 | 409 | "source": [ |
406 | | - "h_min = Constant(1e-3)\n", |
| 410 | + "h_min = Constant(1e-5)\n", |
407 | 411 | "\n", |
408 | 412 | "rfields = {\n", |
409 | 413 | " \"velocity\": u,\n", |
410 | 414 | " \"membrane_stress\": M,\n", |
411 | 415 | " \"basal_stress\": τ,\n", |
412 | | - " \"thickness\": firedrake.max_value(h_min, h),\n", |
| 416 | + " \"thickness\": max_value(h_min, h),\n", |
413 | 417 | " \"surface\": s,\n", |
414 | 418 | "}\n", |
415 | 419 | "\n", |
416 | 420 | "L_r = sum(fn(**rfields, **rheology) for fn in fns)\n", |
417 | | - "F_r = firedrake.derivative(L_r, z)\n", |
418 | | - "J_r = firedrake.derivative(F_r, z)" |
419 | | - ] |
420 | | - }, |
421 | | - { |
422 | | - "cell_type": "markdown", |
423 | | - "id": "468d2245-b155-4ead-8ca1-c37c474d128f", |
424 | | - "metadata": {}, |
425 | | - "source": [ |
426 | | - "We'll also want to add a term to the linearization assuming a linear viscous flow law." |
427 | | - ] |
428 | | - }, |
429 | | - { |
430 | | - "cell_type": "code", |
431 | | - "execution_count": null, |
432 | | - "id": "37dba801-9394-4719-99d1-fdec7522f7a5", |
433 | | - "metadata": {}, |
434 | | - "outputs": [], |
435 | | - "source": [ |
436 | | - "v_c = firedrake.replace(u_c, {h: firedrake.max_value(h, h_min)})\n", |
437 | | - "linear_rheology = {\n", |
438 | | - " \"flow_law_exponent\": 1,\n", |
439 | | - " \"flow_law_coefficient\": ε_c / τ_c,\n", |
440 | | - " \"sliding_exponent\": 1,\n", |
441 | | - " \"sliding_coefficient\": v_c / τ_c,\n", |
442 | | - "}\n", |
443 | | - "\n", |
444 | | - "L_1 = sum(fn(**rfields, **linear_rheology) for fn in fns)\n", |
445 | | - "F_1 = firedrake.derivative(L_1, z)\n", |
446 | | - "J_1 = firedrake.derivative(F_1, z)" |
447 | | - ] |
448 | | - }, |
449 | | - { |
450 | | - "cell_type": "markdown", |
451 | | - "id": "39fbac26-12e1-408a-8aab-6c32e321edd5", |
452 | | - "metadata": {}, |
453 | | - "source": [ |
454 | | - "Finally, the linearization that we'll use for the nonlinear solver is a combination of the two (viscous and Glen)." |
455 | | - ] |
456 | | - }, |
457 | | - { |
458 | | - "cell_type": "code", |
459 | | - "execution_count": null, |
460 | | - "id": "3ad45f70-18a5-44f5-9d6f-2efd2a3c3e46", |
461 | | - "metadata": {}, |
462 | | - "outputs": [], |
463 | | - "source": [ |
464 | | - "λ = Constant(1e-3)\n", |
465 | | - "J = J_r + λ * J_1" |
| 421 | + "F_r = derivative(L_r, z)\n", |
| 422 | + "J_r = derivative(F_r, z)" |
466 | 423 | ] |
467 | 424 | }, |
468 | 425 | { |
|
481 | 438 | "outputs": [], |
482 | 439 | "source": [ |
483 | 440 | "degree = 1\n", |
484 | | - "qdegree = max(8, degree ** n)\n", |
| 441 | + "qdegree = max(8, degree ** glen_flow_law)\n", |
485 | 442 | "pparams = {\"form_compiler_parameters\": {\"quadrature_degree\": qdegree}}\n", |
486 | | - "momentum_problem = firedrake.NonlinearVariationalProblem(F, z, J=J, **pparams)" |
| 443 | + "momentum_problem = firedrake.NonlinearVariationalProblem(F, z, J=J_r, **pparams)" |
487 | 444 | ] |
488 | 445 | }, |
489 | 446 | { |
|
503 | 460 | "outputs": [], |
504 | 461 | "source": [ |
505 | 462 | "sparams = {\n", |
| 463 | + " \"snes_monitor\": \":rainier-output.txt\",\n", |
506 | 464 | " \"snes_type\": \"newtonls\",\n", |
507 | 465 | " \"snes_max_it\": 200,\n", |
508 | 466 | " \"snes_linesearch_type\": \"nleqerr\",\n", |
|
520 | 478 | "metadata": {}, |
521 | 479 | "outputs": [], |
522 | 480 | "source": [ |
523 | | - "momentum_solver.solve()" |
| 481 | + "num_continuation_steps = 5\n", |
| 482 | + "for exponent in np.linspace(1.0, 3.0, num_continuation_steps):\n", |
| 483 | + " n.assign(exponent)\n", |
| 484 | + " momentum_solver.solve()" |
524 | 485 | ] |
525 | 486 | }, |
526 | 487 | { |
|
705 | 666 | "from IPython.display import HTML\n", |
706 | 667 | "HTML(animation.to_html5_video())" |
707 | 668 | ] |
| 669 | + }, |
| 670 | + { |
| 671 | + "cell_type": "markdown", |
| 672 | + "id": "a1519ecf-2c80-4de1-9f54-33b861435322", |
| 673 | + "metadata": {}, |
| 674 | + "source": [ |
| 675 | + "Finally, let's check that the solver was working right." |
| 676 | + ] |
| 677 | + }, |
| 678 | + { |
| 679 | + "cell_type": "code", |
| 680 | + "execution_count": null, |
| 681 | + "id": "6a0ec125-564b-4457-bd47-71eb911e7a8b", |
| 682 | + "metadata": {}, |
| 683 | + "outputs": [], |
| 684 | + "source": [ |
| 685 | + "junk = \"SNES Function norm\"\n", |
| 686 | + "with open(\"rainier-output.txt\", \"r\") as log_file:\n", |
| 687 | + " raw_data = [\n", |
| 688 | + " line.replace(junk, \"\").strip().split()\n", |
| 689 | + " for line in log_file.readlines()\n", |
| 690 | + " ]\n", |
| 691 | + "\n", |
| 692 | + "convergence_log = [\n", |
| 693 | + " (int(iter_text), float(norm_text)) for iter_text, norm_text in raw_data\n", |
| 694 | + "]\n", |
| 695 | + "\n", |
| 696 | + "reduced_log = []\n", |
| 697 | + "current_entry = []\n", |
| 698 | + "for count, error in convergence_log:\n", |
| 699 | + " if count == 0:\n", |
| 700 | + " reduced_log.append(current_entry)\n", |
| 701 | + " current_entry = []\n", |
| 702 | + "\n", |
| 703 | + " current_entry.append(error)\n", |
| 704 | + "\n", |
| 705 | + "reduced_log.pop(0);" |
| 706 | + ] |
| 707 | + }, |
| 708 | + { |
| 709 | + "cell_type": "markdown", |
| 710 | + "id": "a4d62643-ae8f-4a5f-9a22-d45166505a45", |
| 711 | + "metadata": {}, |
| 712 | + "source": [ |
| 713 | + "First, we want to see that the number of Newton iterations was bounded.\n", |
| 714 | + "If it starts reaching above 20 then you're probably in trouble." |
| 715 | + ] |
| 716 | + }, |
| 717 | + { |
| 718 | + "cell_type": "code", |
| 719 | + "execution_count": null, |
| 720 | + "id": "1768b1cc-a969-4baf-9b09-4d0e83cdafbb", |
| 721 | + "metadata": {}, |
| 722 | + "outputs": [], |
| 723 | + "source": [ |
| 724 | + "fig, ax = plt.subplots()\n", |
| 725 | + "ax.set_ylim((0, 10))\n", |
| 726 | + "ax.set_xlabel(\"Time step\")\n", |
| 727 | + "ax.set_ylabel(\"#Newton steps\")\n", |
| 728 | + "ax.plot([len(entry) for entry in reduced_log]);" |
| 729 | + ] |
| 730 | + }, |
| 731 | + { |
| 732 | + "cell_type": "markdown", |
| 733 | + "id": "a0448417-72b3-4e5c-abba-1ad4a20f319c", |
| 734 | + "metadata": {}, |
| 735 | + "source": [ |
| 736 | + "Next, we'll have a look at the initial and final residual values.\n", |
| 737 | + "We used a convergence criterion where the iteration stops if the residual is reduced by more than something like $10^4$.\n", |
| 738 | + "It would be cause for concern if the final value of the residual were edging upward, but this isn't the case." |
| 739 | + ] |
| 740 | + }, |
| 741 | + { |
| 742 | + "cell_type": "code", |
| 743 | + "execution_count": null, |
| 744 | + "id": "eedac523-9bd0-4b48-8ba4-81d2622df72c", |
| 745 | + "metadata": {}, |
| 746 | + "outputs": [], |
| 747 | + "source": [ |
| 748 | + "fig, ax = plt.subplots()\n", |
| 749 | + "ax.set_yscale(\"log\")\n", |
| 750 | + "ax.set_xlabel(\"Time step\")\n", |
| 751 | + "ax.set_ylabel(\"Residual\")\n", |
| 752 | + "ax.plot([entry[0] for entry in reduced_log], label=\"Initial\")\n", |
| 753 | + "ax.plot([entry[-1] for entry in reduced_log], label=\"Final\")\n", |
| 754 | + "ax.legend(loc=\"upper right\");" |
| 755 | + ] |
708 | 756 | } |
709 | 757 | ], |
710 | 758 | "metadata": { |
|
0 commit comments