|
| 1 | +Shape optimization |
| 2 | +================== |
| 3 | + |
| 4 | +Shape optimization is about modifying the shape of a domain so that an |
| 5 | +objective function is minimized. In this demo, we consider an objective |
| 6 | +function constrained to a boundary value problem and implement a simple |
| 7 | +mesh-moving shape optimization strategy using Firedrake and pyadjoint. This |
| 8 | +tutorial was contributed by ` Alberto Paganini < mailto:[email protected]>`__ |
| 9 | +and was written during the `ccp-dcm hackaton |
| 10 | +<https://ccp-dcm.github.io/exeter_hackathon>`__ at Dartington Hall. |
| 11 | + |
| 12 | +Let |
| 13 | + |
| 14 | +.. math:: |
| 15 | +
|
| 16 | + J(\Omega) = \int_\Omega \big(u(\mathbf{x}) - u_t(\mathbf{x})\big)^2 \,\mathrm{d}\mathbf{x}\,. |
| 17 | +
|
| 18 | +where :math:`u:\mathbb{R}^2\to\mathbb{R}` is the solution to the scalar |
| 19 | +boundary value problem |
| 20 | + |
| 21 | +.. math:: |
| 22 | +
|
| 23 | + -\Delta u = 4 \quad \text{in }\Omega\,, \qquad u = 0 \quad \text{on } \partial\Omega |
| 24 | +
|
| 25 | +
|
| 26 | +and :math:`u_t:\mathbb{R}^2\to\mathbb{R}` is a target function. In particular, |
| 27 | +we consider |
| 28 | + |
| 29 | +.. math:: |
| 30 | +
|
| 31 | + u_t(x,y) = 1.21 - (x - 0.5)^2 - (y - 0.5)^2\,. |
| 32 | +
|
| 33 | +Beside the empty set, the domain that minimizes :math:`J(\Omega)` is a disc of |
| 34 | +radius :math:`1.1` centered at :math:`(0.5,0.5)`. |
| 35 | + |
| 36 | +We can now proceed to set up the problem. We import firedrake and pyadjoint and |
| 37 | +choose an initial guess (in this case, a unit disc centred at the origin):: |
| 38 | + |
| 39 | + from firedrake import * |
| 40 | + from firedrake.adjoint import * |
| 41 | + mesh = UnitDiskMesh(refinement_level=3) |
| 42 | + |
| 43 | +Then, we start annotating and turn the mesh coordinates into a control variable:: |
| 44 | + |
| 45 | + continue_annotation() |
| 46 | + Q = mesh.coordinates.function_space() |
| 47 | + dT = Function(Q) |
| 48 | + mesh.coordinates.assign(mesh.coordinates + dT) |
| 49 | + |
| 50 | +We can now implement the target function:: |
| 51 | + |
| 52 | + x, y = SpatialCoordinate(mesh) |
| 53 | + u_t = Constant(1.21) - (x - Constant(0.5))**2 - (y - Constant(0.5))**2 |
| 54 | + |
| 55 | +solve the weak form of the boundary value problem:: |
| 56 | + |
| 57 | + V = FunctionSpace(mesh, "CG", 1) |
| 58 | + u = Function(V, name='state') |
| 59 | + v = TestFunction(V) |
| 60 | + F = (dot(grad(u), grad(v)) - 4 * v) * dx |
| 61 | + bcs = DirichletBC(V, Constant(0.), "on_boundary") |
| 62 | + solve(F == 0, u, bcs=bcs) |
| 63 | + |
| 64 | +and evaluate the objective function:: |
| 65 | + |
| 66 | + J = assemble((u - u_t)**2*dx) |
| 67 | + |
| 68 | +We now turn the objective function into a reduced function so that pyadjoint |
| 69 | +(and UFL shape differentiation capability) can automatically compute shape |
| 70 | +gradients, that is, directions of steepest ascent:: |
| 71 | + |
| 72 | + Jred = ReducedFunctional(J, Control(dT)) |
| 73 | + stop_annotating() |
| 74 | + |
| 75 | +We now have all the ingredients to implement a basic steepest descent shape |
| 76 | +optimization algorithm with fixed step size.:: |
| 77 | + |
| 78 | + File = VTKFile("shape_iterates.pvd") |
| 79 | + for ii in range(30): |
| 80 | + print("J(ii =", ii, ") =", Jred(dT)) |
| 81 | + File.write(mesh.coordinates) |
| 82 | + |
| 83 | + # compute the gradient (steepest ascent) |
| 84 | + opts = {"riesz_representation": "H1"} |
| 85 | + gradJ = Jred.derivative(options=opts) |
| 86 | + |
| 87 | + # update domain |
| 88 | + dT -= 0.2*gradJ |
| 89 | + |
| 90 | + File.write(mesh.coordinates) |
| 91 | + print("J(final) =", Jred(dT)) |
| 92 | + |
| 93 | +<video width="640" height="360" controls loop autoplay muted> |
| 94 | + <source src="shape_optimization.avi" type="video/avi"> |
| 95 | + Your browser does not support the video tag. |
| 96 | +</video> |
| 97 | + |
| 98 | +**Remark:** mesh-moving shape optimization can lead to mesh tangling, which |
| 99 | +invalidates finite element computations. For faster and more robust shape |
| 100 | +optimization, we recommend using Firedrake's shape optimization toolbox |
| 101 | +`Fireshape <https://github.com/fireshape/fireshape>`__. |
| 102 | + |
| 103 | +A python script version of this demo can be found :demo:`here <shape_optimization.py>`. |
0 commit comments