|
2 | 2 | "cells": [ |
3 | 3 | { |
4 | 4 | "cell_type": "markdown", |
5 | | - "id": "4535be91", |
| 5 | + "id": "0", |
6 | 6 | "metadata": {}, |
7 | 7 | "source": [ |
8 | 8 | "# Adaptive mesh refinement with NetGen and DOLFINx\n", |
|
18 | 18 | }, |
19 | 19 | { |
20 | 20 | "cell_type": "markdown", |
21 | | - "id": "b0282fe2", |
| 21 | + "id": "1", |
22 | 22 | "metadata": {}, |
23 | 23 | "source": [ |
24 | 24 | "In this tutorial, we will consider an adaptive mesh refinement method, applied to\n", |
|
31 | 31 | { |
32 | 32 | "cell_type": "code", |
33 | 33 | "execution_count": null, |
34 | | - "id": "32fe6a58", |
| 34 | + "id": "2", |
35 | 35 | "metadata": {}, |
36 | 36 | "outputs": [], |
37 | 37 | "source": [ |
|
50 | 50 | }, |
51 | 51 | { |
52 | 52 | "cell_type": "markdown", |
53 | | - "id": "4782ba3b", |
| 53 | + "id": "3", |
54 | 54 | "metadata": {}, |
55 | 55 | "source": [ |
56 | 56 | "## Generating a higher-order mesh with NetGen\n", |
|
60 | 60 | { |
61 | 61 | "cell_type": "code", |
62 | 62 | "execution_count": null, |
63 | | - "id": "d6046434", |
| 63 | + "id": "4", |
64 | 64 | "metadata": {}, |
65 | 65 | "outputs": [], |
66 | 66 | "source": [ |
|
80 | 80 | }, |
81 | 81 | { |
82 | 82 | "cell_type": "markdown", |
83 | | - "id": "e041abef", |
| 83 | + "id": "5", |
84 | 84 | "metadata": {}, |
85 | 85 | "source": [ |
86 | 86 | "## Loading a mesh into DOLFINx\n", |
|
92 | 92 | { |
93 | 93 | "cell_type": "code", |
94 | 94 | "execution_count": null, |
95 | | - "id": "fc64bf64", |
| 95 | + "id": "6", |
96 | 96 | "metadata": {}, |
97 | 97 | "outputs": [], |
98 | 98 | "source": [ |
|
101 | 101 | }, |
102 | 102 | { |
103 | 103 | "cell_type": "markdown", |
104 | | - "id": "67cded8b", |
| 104 | + "id": "7", |
105 | 105 | "metadata": {}, |
106 | 106 | "source": [ |
107 | 107 | "Next, we generate the mesh with the function :py:func:`ngsPETSc.utils.fenicsx.GeometricModel.model_to_mesh`.\n", |
|
112 | 112 | { |
113 | 113 | "cell_type": "code", |
114 | 114 | "execution_count": null, |
115 | | - "id": "dbae564a", |
| 115 | + "id": "8", |
116 | 116 | "metadata": {}, |
117 | 117 | "outputs": [], |
118 | 118 | "source": [ |
|
121 | 121 | }, |
122 | 122 | { |
123 | 123 | "cell_type": "markdown", |
124 | | - "id": "f90ca932", |
| 124 | + "id": "9", |
125 | 125 | "metadata": {}, |
126 | 126 | "source": [ |
127 | 127 | "We use pyvista to visualize the mesh." |
|
130 | 130 | { |
131 | 131 | "cell_type": "code", |
132 | 132 | "execution_count": null, |
133 | | - "id": "34407248", |
| 133 | + "id": "10", |
134 | 134 | "metadata": { |
135 | 135 | "tags": [ |
136 | 136 | "hide-input" |
|
154 | 154 | }, |
155 | 155 | { |
156 | 156 | "cell_type": "markdown", |
157 | | - "id": "6a18b03f", |
| 157 | + "id": "11", |
158 | 158 | "metadata": {}, |
159 | 159 | "source": [ |
160 | 160 | "We have read in any cell and facet markers that have been defined in the NetGen model,\n", |
|
166 | 166 | { |
167 | 167 | "cell_type": "code", |
168 | 168 | "execution_count": null, |
169 | | - "id": "adc50da0", |
| 169 | + "id": "12", |
170 | 170 | "metadata": {}, |
171 | 171 | "outputs": [], |
172 | 172 | "source": [ |
|
176 | 176 | }, |
177 | 177 | { |
178 | 178 | "cell_type": "markdown", |
179 | | - "id": "0a3449b0", |
| 179 | + "id": "13", |
180 | 180 | "metadata": {}, |
181 | 181 | "source": [ |
182 | 182 | "Again, we visualize the curved mesh with pyvista." |
|
185 | 185 | { |
186 | 186 | "cell_type": "code", |
187 | 187 | "execution_count": null, |
188 | | - "id": "1eb97f0f", |
| 188 | + "id": "14", |
189 | 189 | "metadata": { |
190 | 190 | "tags": [ |
191 | 191 | "hide-input" |
|
206 | 206 | }, |
207 | 207 | { |
208 | 208 | "cell_type": "markdown", |
209 | | - "id": "7613cc7f", |
| 209 | + "id": "15", |
210 | 210 | "metadata": {}, |
211 | 211 | "source": [ |
212 | 212 | "## Solving the eigenvalue problem\n", |
|
224 | 224 | }, |
225 | 225 | { |
226 | 226 | "cell_type": "markdown", |
227 | | - "id": "717f48a2", |
| 227 | + "id": "16", |
228 | 228 | "metadata": { |
229 | 229 | "lines_to_next_cell": 2 |
230 | 230 | }, |
|
236 | 236 | { |
237 | 237 | "cell_type": "code", |
238 | 238 | "execution_count": null, |
239 | | - "id": "d59bc925", |
| 239 | + "id": "17", |
240 | 240 | "metadata": { |
241 | 241 | "lines_to_next_cell": 2 |
242 | 242 | }, |
|
310 | 310 | }, |
311 | 311 | { |
312 | 312 | "cell_type": "markdown", |
313 | | - "id": "1c251b79", |
| 313 | + "id": "18", |
314 | 314 | "metadata": { |
315 | 315 | "lines_to_next_cell": 2 |
316 | 316 | }, |
317 | 317 | "source": [ |
318 | 318 | "## Error-indicator\n", |
319 | 319 | "In this example, we will use an error-indicator $\\eta$ to decide what cells should be refined.\n", |
320 | | - "Specifically, the estimator is:\n", |
| 320 | + "Specifically, the estimator $\\eta$ is defined as:\n", |
321 | 321 | "\n", |
322 | 322 | "\\begin{align*}\n", |
323 | | - " \\eta = \\sum_{K\\in \\mathcal{T}_h(\\Omega)}\\left(h^2\\int_K \\vert \\lambda u_h + \\Delta u_h\\vert^2~\\mathrm{d}x\\right)\n", |
| 323 | + " \\eta^2 = \\sum_{K\\in \\mathcal{T}_h(\\Omega)}\\left(h^2\\int_K \\vert \\lambda u_h + \\Delta u_h\\vert^2~\\mathrm{d}x\\right)\n", |
324 | 324 | "+ \\sum_{E\\in\\mathcal{F}_i}\\frac{h}{2} \\vert [\\nabla \\cdot \\mathbf{n}_E ]\\vert^2~\\mathrm{d}s\n", |
325 | 325 | "\\end{align*}\n", |
326 | 326 | "\n", |
|
330 | 330 | { |
331 | 331 | "cell_type": "code", |
332 | 332 | "execution_count": null, |
333 | | - "id": "95f75bd8", |
| 333 | + "id": "19", |
334 | 334 | "metadata": {}, |
335 | 335 | "outputs": [], |
336 | 336 | "source": [ |
337 | 337 | "def mark_cells(uh_r: dolfinx.fem.Function, lam: float):\n", |
338 | 338 | " mesh = uh_r.function_space.mesh\n", |
339 | 339 | " W = dolfinx.fem.functionspace(mesh, (\"DG\", 0))\n", |
340 | 340 | " w = ufl.TestFunction(W)\n", |
341 | | - " eta = dolfinx.fem.Function(W)\n", |
| 341 | + " eta_squared = dolfinx.fem.Function(W)\n", |
342 | 342 | " f = dolfinx.fem.Constant(mesh, 1.0)\n", |
343 | 343 | " h = dolfinx.fem.Function(W)\n", |
344 | 344 | " h.x.array[:] = mesh.h(mesh.topology.dim, np.arange(len(h.x.array), dtype=np.int32))\n", |
|
349 | 349 | " + ufl.inner(h(\"+\") / 2 * ufl.jump(ufl.grad(uh_r), n) ** 2, w(\"+\")) * ufl.dS\n", |
350 | 350 | " + ufl.inner(h(\"-\") / 2 * ufl.jump(ufl.grad(uh_r), n) ** 2, w(\"-\")) * ufl.dS\n", |
351 | 351 | " )\n", |
352 | | - " dolfinx.fem.petsc.assemble_vector(eta.x.petsc_vec, dolfinx.fem.form(G))\n", |
353 | | - " sqrt_eta = dolfinx.fem.Function(W)\n", |
354 | | - " sqrt_eta.x.array[:] = np.sqrt(eta.x.array[:])\n", |
| 352 | + " dolfinx.fem.petsc.assemble_vector(eta_squared.x.petsc_vec, dolfinx.fem.form(G))\n", |
| 353 | + " eta = dolfinx.fem.Function(W)\n", |
| 354 | + " eta.x.array[:] = np.sqrt(eta_squared.x.array[:])\n", |
355 | 355 | "\n", |
356 | | - " sqrt_eta_max = sqrt_eta.x.petsc_vec.max()[1]\n", |
| 356 | + " eta_max = eta.x.petsc_vec.max()[1]\n", |
357 | 357 | "\n", |
358 | 358 | " theta = 0.5\n", |
359 | | - " should_refine = ufl.conditional(ufl.gt(sqrt_eta, theta * sqrt_eta_max), 1, 0)\n", |
| 359 | + " should_refine = ufl.conditional(ufl.gt(eta, theta * eta_max), 1, 0)\n", |
360 | 360 | " markers = dolfinx.fem.Function(W)\n", |
361 | 361 | " ip = W.element.interpolation_points\n", |
362 | 362 | " if Version(dolfinx.__version__) < Version(\"0.10.0\"):\n", |
|
367 | 367 | }, |
368 | 368 | { |
369 | 369 | "cell_type": "markdown", |
370 | | - "id": "d9243490", |
| 370 | + "id": "20", |
371 | 371 | "metadata": {}, |
372 | 372 | "source": [ |
373 | 373 | "## Running the adaptive refinement algorithm\n", |
|
376 | 376 | }, |
377 | 377 | { |
378 | 378 | "cell_type": "markdown", |
379 | | - "id": "ab8f6701", |
| 379 | + "id": "21", |
380 | 380 | "metadata": {}, |
381 | 381 | "source": [ |
382 | 382 | "We will track the progress of the adaptive mesh refinement as a GIF." |
|
385 | 385 | { |
386 | 386 | "cell_type": "code", |
387 | 387 | "execution_count": null, |
388 | | - "id": "293b959a", |
| 388 | + "id": "22", |
389 | 389 | "metadata": {}, |
390 | 390 | "outputs": [], |
391 | 391 | "source": [ |
|
395 | 395 | }, |
396 | 396 | { |
397 | 397 | "cell_type": "markdown", |
398 | | - "id": "5fe0ac8b", |
| 398 | + "id": "23", |
399 | 399 | "metadata": { |
400 | 400 | "lines_to_next_cell": 2 |
401 | 401 | }, |
|
407 | 407 | { |
408 | 408 | "cell_type": "code", |
409 | 409 | "execution_count": null, |
410 | | - "id": "969aaaa5", |
| 410 | + "id": "24", |
411 | 411 | "metadata": { |
412 | 412 | "tags": [ |
413 | 413 | "hide-input" |
|
444 | 444 | }, |
445 | 445 | { |
446 | 446 | "cell_type": "markdown", |
447 | | - "id": "d798464c", |
| 447 | + "id": "25", |
448 | 448 | "metadata": {}, |
449 | 449 | "source": [ |
450 | 450 | "We set some parameters for checking convergence of the algorithm, and provide the exact eigenvalue\n", |
|
460 | 460 | { |
461 | 461 | "cell_type": "code", |
462 | 462 | "execution_count": null, |
463 | | - "id": "ebd3fef7", |
| 463 | + "id": "26", |
464 | 464 | "metadata": { |
465 | 465 | "tags": [ |
466 | 466 | "scroll-output" |
|
492 | 492 | }, |
493 | 493 | { |
494 | 494 | "cell_type": "markdown", |
495 | | - "id": "5bac3843", |
| 495 | + "id": "27", |
496 | 496 | "metadata": {}, |
497 | 497 | "source": [ |
498 | 498 | "<img src=\"./amr.gif\" alt=\"gif\" class=\"bg-primary mb-1\" width=\"800px\">" |
|
0 commit comments