Shape Optimization with a Poisson Problem#
Problem Formulation#
In this demo, we investigate the basics of cashocs for shape optimization problems. As a model problem, we investigate the following one from Etling, Herzog, Loayza, Wachsmuth - First and Second Order Shape Optimization Based on Restricted Mesh Deformations
For the initial domain, we use the unit disc \(\Omega = \{ x \in \mathbb{R}^2 \,\mid\, \lvert\lvert x \rvert\rvert_2 < 1 \}\) and the right-hand side \(f\) is given by
Implementation#
The complete python code can be found in the file demo_shape_poisson.py
,
and the corresponding config can be found in config.ini
.
Initialization#
We start the problem by using a wildcard import for FEniCS, and by importing cashocs
from fenics import *
import cashocs
As for the case of optimal control problems, we can specify the verbosity of cashocs with the line
cashocs.set_log_level(cashocs.LogLevel.INFO)
which is documented at cashocs.set_log_level()
(cf. Distributed Control of a Poisson Problem).
Similarly to the optimal control case, we also require config files for shape
optimization problems in cashocs. A detailed discussion of the config files
for shape optimization is given in Documentation of the Config Files for Shape Optimization Problems.
We read the config file with the load_config
command
config = cashocs.load_config("./config.ini")
Next, we have to define the mesh. We load the mesh (which was previously generated
with Gmsh and converted to xdmf with cashocs.convert()
mesh, subdomains, boundaries, dx, ds, dS = cashocs.import_mesh("./mesh/mesh.xdmf")
Note
In config.ini
,
in the section ShapeGradient, there is
the line
[ShapeGradient]
shape_bdry_def = [1]
which specifies that the boundary marked with 1
is deformable. For our
example this is exactly what we want, as this means that the entire boundary
is variable, due to the fact that the entire boundary is marked by 1
in the
Gmsh file. For a detailed documentation we refer to the corresponding documentation of the ShapeGradient section.
After having defined the initial geometry, we define a
fenics.FunctionSpace
consisting of piecewise linear Lagrange elements via
V = FunctionSpace(mesh, "CG", 1)
u = Function(V)
p = Function(V)
This also defines our state variable \(u\) as u
, and the adjoint state \(p\) is
given by p
.
Note
As remarked in Distributed Control of a Poisson Problem, in classical FEniCS syntax we would use a
fenics.TrialFunction
for u
and a fenics.TestFunction
for p
. However, for cashocs this must not be the case. Instead, the state
and adjoint variables have to be fenics.Function
objects.
The right-hand side of the PDE constraint is then defined as
x = SpatialCoordinate(mesh)
f = 2.5 * pow(x[0] + 0.4 - pow(x[1], 2), 2) + pow(x[0], 2) + pow(x[1], 2) - 1
which allows us to define the weak form of the state equation via
e = inner(grad(u), grad(p)) * dx - f * p * dx
bcs = DirichletBC(V, Constant(0), boundaries, 1)
The optimization problem and its solution#
We are now almost done, the only thing left to do is to define the cost functional
J = cashocs.IntegralFunctional(u * dx)
and the shape optimization problem
sop = cashocs.ShapeOptimizationProblem(e, bcs, J, u, p, boundaries, config=config)
This can then be solved in complete analogy to Distributed Control of a Poisson Problem with
the sop.solve()
command
sop.solve()
We visualize the result with the following code
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 5))
ax_mesh = plt.subplot(1, 2, 1)
fig_mesh = plot(mesh)
plt.title("Discretization of the optimized geometry")
ax_u = plt.subplot(1, 2, 2)
ax_u.set_xlim(ax_mesh.get_xlim())
ax_u.set_ylim(ax_mesh.get_ylim())
fig_u = plot(u)
plt.colorbar(fig_u, fraction=0.046, pad=0.04)
plt.title("State variable u")
plt.tight_layout()
# plt.savefig('./img_shape_poisson.png', dpi=150, bbox_inches='tight')
and the result should look like this
Note
As in Distributed Control of a Poisson Problem we can specify some keyword
arguments for the solve
command.
If none are given, then the settings from the config file are used, but if
some are given, they override the parameters specified
in the config file. In particular, these arguments are
algorithm
: Specifies which solution algorithm shall be used.
rtol
: The relative tolerance for the optimization algorithm.
atol
: The absolute tolerance for the optimization algorithm.
max_iter
: The maximum amount of iterations that can be carried out.
The possible choices for these parameters are discussed in detail in
Section OptimizationRoutine and the documentation of the
solve
method.
As before, it is not strictly necessary to supply config files to cashocs, but
it is very strongly recommended to do so. In case one does not supply a config
file, one has to at least specify the solution algorithm in the call to
the solve
method.