Release 1.4.2 SebastianBlauth

171
cashocs Release 1.5.3 Sebastian Blauth Feb 01, 2022

Transcript of Release 1.4.2 SebastianBlauth

Page 1: Release 1.4.2 SebastianBlauth

cashocsRelease 1.5.3

Sebastian Blauth

Feb 01, 2022

Page 2: Release 1.4.2 SebastianBlauth
Page 3: Release 1.4.2 SebastianBlauth

CONTENTS:

1 Installation 3

2 Getting Started 5

3 Tutorial 7

4 API Reference 103

5 Contributing Guidelines 147

6 Code of Conduct 149

7 Change Log 151

8 Citing 155

9 License 157

10 Contact / About 159

11 Indices and tables 161

Python Module Index 163

Index 165

i

Page 4: Release 1.4.2 SebastianBlauth

ii

Page 5: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

CONTENTS: 1

Page 6: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

2 CONTENTS:

Page 7: Release 1.4.2 SebastianBlauth

CHAPTER

ONE

INSTALLATION

1.1 Via conda-forge

cashocs is available via the anaconda package manager, and you can install it with

conda install -c conda-forge cashocs

Alternatively, you might want to create a new, clean conda environment with the command

conda create -n <ENV_NAME> -c conda-forge cashocs

where <ENV_NAME> is the desired name of the new environment.

Note: Gmsh is now (starting with release 1.3.2) automatically installed with anaconda.

1.2 Manual Installation

• First, install FEniCS, version 2019.1. Note, that FEniCS should be compiled with PETSc and petsc4py.

• Then, install meshio, with a h5py version that matches the HDF5 version used in FEniCS, and matplotlib. Theversion of meshio should be at least 4, but for compatibility it is recommended to use meshio 4.4.

• You might also want to install Gmsh, version 4.8. cashocs does not necessarily need this to work properly, but itis required for the remeshing functionality.

Note: If you are having trouble with using the conversion tool cashocs-convert from the command line, then you mostlikely encountered a problem with hdf5 and h5py. This can (hopefully) be resolved by following the suggestions fromthis thread, i.e., you should try to install meshio using the command

pip3 install meshio[all] --no-binary=h5py

• You can install cashocs via the PYPI:

pip3 install cashocs

You can install the newest (development) version of cashocs with:

3

Page 8: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

pip3 install git+https://github.com/sblauth/cashocs.git

• To get the latest (development) version of cashocs, clone this repository with git and install it with pip

git clone https://github.com/sblauth/cashocs.gitcd cashocspip3 install .

Note: To verify that the installation was successful, run the tests for cashocs with

python3 -m pytest

or simply

pytest

from the source / repository root directory. Note, that it might take some time to perform all of these tests for the veryfirst time, as FEniCS compiles the necessary code. However, on subsequent iterations the compiled code is retrievedfrom a cache, so that the tests are singificantly faster.

4 Chapter 1. Installation

Page 9: Release 1.4.2 SebastianBlauth

CHAPTER

TWO

GETTING STARTED

As newcomer to cashocs, we recommend the paper Blauth, cashocs: A Computational, Adjoint-Based Shape Opti-mization and Optimal Control Software, which gives an overview over cashocs and its capabilities. Moreover, for acomprehensive description of cashocs, we refer to its tutorial.

In the following, we briefly showcase how cashocs can be used to solve a distributed optimal control problem with aPoisson equation as PDE constaint.

Since cashocs is based on FEniCS, most of the user input consists of definining the objects (such as the state system andcost functional) via UFL forms. If one has a functioning code for the forward problem and the evaluation of the costfunctional, the necessary modifications to optimize the problem in cashocs are minimal. Consider, e.g., the followingoptimization problem

min 𝐽(𝑦, 𝑢) =1

2

∫Ω

(𝑦 − 𝑦𝑑)2 d𝑥 +

𝛼

2

∫Ω

𝑢2 d𝑥

subject to

−∆𝑦 = 𝑢 in Ω,

𝑦 = 0 on Γ.

Note, that the problem is treated in detail in the corresponding cashocs tutorial.

For our purposes, we assume that a mesh for this problem is defined and that a suitable function space is chosen. Thiscan, e.g., be achieved via

from fenics import *import cashocs

config = cashocs.load_config('path_to_config')mesh, subdomains, boundaries, dx, ds, dS = cashocs.regular_mesh(25)V = FunctionSpace(mesh, 'CG', 1)

The config object, which is created from a .ini file, is used to determine the parameters for the optimization algorithms.This is where the user can finely tune the behavior of the algorithms.

To define the state problem, we then define a state variable y, an adjoint variable p and a control variable u, and writethe PDE as a weak form

y = Function(V)p = Function(V)u = Function(V)e = inner(grad(y), grad(p)) - u*p*dxbcs = cashocs.create_dirichlet_bcs(V, Constant(0), boundaries, [1,2,3,4])

Finally, we define the cost functional and the optimization problem

5

Page 10: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

y_d = Expression('sin(2*pi * x[0] * sin(2*pi*x[1]))', degree=1)alpha = 1e-6J = 1/2*(y - y_d) * (y - y_d) * dx + alpha/2*u*u*dxopt_problem = cashocs.OptimalControlProblem(e, bcs, J, y, u, p, config)opt_problem.solve()

The only major difference between cashocs and FEniCS code is that one has to use fenics.Function objects forstates and adjoints, and that fenics.TrialFunction and fenics.TestFunction are not needed to define the stateequation. Other than that, the syntax would also be valid with FEniCS, at least for this problem.

For a detailed discussion of the features of cashocs and its usage we refer to the cashocs tutorial.

6 Chapter 2. Getting Started

Page 11: Release 1.4.2 SebastianBlauth

CHAPTER

THREE

TUTORIAL

Welcome to the cashocs tutorial. In the following, we present several example programs that showcase how cashocscan be used to solve optimal control and shape optimization problems.

Note, that we assume that you are (at least somewhat) familiar with PDE constrained optimization and FEniCS. For aintroduction to these topics, we can recommend the textbooks

• Optimal Control and general PDE constrained optimization

– Hinze, Ulbrich, Ulbrich, and Pinnau, Optimization with PDE Constraints

– Tröltzsch, Optimal Control of Partial Differential Equations

• Shape Optimization

– Delfour and Zolesio, Shapes and Geometries

– Sokolowski and Zolesio, Introduction to Shape Optimization

• FEniCS

– Logg, Mardal, and Wells, Automated Solution of Differential Equations by the Finite Element Method

– The FEniCS demos

However, we will also provide links to either the underlying theory of PDE constrained optimization or to the relevantdocumentation of FEniCS in this tutorial.

Note, that an overview over cashocs and its capabilities can be found in Blauth, cashocs: A Computational, Adjoint-Based Shape Optimization and Optimal Control Software.

3.1 Optimal Control Problems

In this part of the tutorial, we investigate how optimal control problems can be treated with cashocs.

3.1.1 Distributed Control of a Poisson Problem

7

Page 12: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Problem Formulation

In this demo we investigate the basics of cashocs for optimal control problems. To do so, we investigate the “motherproblem” of PDE constrained optimization, i.e.,

min 𝐽(𝑦, 𝑢) =1

2

∫Ω

(𝑦 − 𝑦𝑑)2 d𝑥 +

𝛼

2

∫Ω

𝑢2 d𝑥

subject to

−∆𝑦 = 𝑢 in Ω,

𝑦 = 0 on Γ.

(see, e.g., Tröltzsch, Optimal Control of Partial Differential Equations or Hinze, Pinnau, Ulbrich, and Ulbrich, Opti-mization with PDE constraints).

For this first example, we do not consider control constraints, but search for an optimal control u in the entire space𝐿2(Ω), for the sake of simplicitiy. For the domain under consideration, we use the unit square Ω = (0, 1)2, since thisis built into cashocs.

In the following, we will describe how to solve this problem using cashocs. Moreover, we also detail alternative /equivalent FEniCS code which could be used to define the problem instead.

Implementation

The complete python code can be found in the file demo_poisson.py, and the corresponding config can be found inconfig.ini.

Initialization

We begin by importing FEniCS and cashocs. For the sake of better readability we use a wildcard import for FEniCS

from fenics import *import cashocs

Afterwards, we can specify the so-called log level of cashocs. This is done in the line

cashocs.set_log_level(cashocs.LogLevel.INFO)

Hint: There are a total of five levels of verbosity, given by cashocs.LogLevel.DEBUG, cashocs.LogLevel.INFO,cashocs.LogLevel.WARNING, cashocs.LogLevel.ERROR, and cashocs.LogLevel.CRITICAL. The default valueis INFO, which would also be selected if the cashocs.set_log_level() method would not have been called.

Next, we have to load the config file which loads the user’s input parameters into the script. For a detailed documenta-tion of the config files and the parameters within, we refer to Documentation of the Config Files for Optimal ControlProblems. Note, that the corresponding file is config.ini . The config is then loaded via

config = cashocs.load_config('./config.ini')

Hint: An alternative way of loading the config file would be to load the config file manually, via

import configparserconfig = configparser.ConfigParser()config.read('path_to_config_file')

8 Chapter 3. Tutorial

Page 13: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

which is equivalent for optimal control problems, but does not work for shape optimization problems. Hence, theformer method is to be preferred.

Next up, we have to define the state equation. This mostly works with usual FEniCS syntax. In cashocs, we can quicklygenerate meshes for squares and cubes, as well as import meshes generated by GMSH, for more complex geometries.In this example we take a built-in unit square as example. This is generated via

mesh, subdomains, boundaries, dx, ds, dS = cashocs.regular_mesh(50)

The input for regular_mesh determines the number of elements that are placed along each axis of the square. Note, thatthe mesh could be further manipulated with additional, optional arguments, and we refer to regular_mesh for moreinfos. Note, that the subdomains object is a (empty) MeshFunction, and that boundaries is a MeshFunction thatcontains markers for the following boundaries

• The left side of the square is marked by 1

• The right side is marked by 2

• The bottom is marked by 3

• The top is marked by 4,

as defined in regular_mesh .

With the geometry defined, we create a function space with the classical FEniCS syntax

V = FunctionSpace(mesh, 'CG', 1)

which creates a function space of continuous, linear Lagrange elements.

Definition of the state equation

To describe the state system in cashocs, we use (almost) standard FEniCS syntax, and the differences will be highlightedin the following. First, we define a fenics.Function y that models our state variable 𝑦, and a fenics.Function pthat models the corresponding adjoint variable 𝑝 via

y = Function(V)p = Function(V)

Next up, we analogously define the control variable as fenics.Function u

u = Function(V)

This enables us to define the weak form of the state equation, which is tested not with a fenics.TestFunction butwith the adjoint variable p via the classical FEniCS / UFL syntax

e = inner(grad(y), grad(p))*dx - u*p*dx

Note: For the clasical definition of this weak form with FEniCS one would write the following code

y = TrialFunction(V)p = TestFunction(V)u = Function(V)a = inner(grad(y), grad(p))*dxL = u*p*dx

3.1. Optimal Control Problems 9

Page 14: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

as this is a linear problem. However, to have greater flexibility we have to treat the problems as being potentiallynonlinear. In this case, the classical FEniCS formulation for this as nonlinear problem would be

y = Function(V)p = TestFunction(V)u = Function(V)F = inner(grad(y), grad(p))*dx -u*p*dx

which could then be solved via the fenics.solve() interface. This formulation, which comes more naturally fornonlinear variational problems (see the FEniCS examples) is closer to the one in cashocs. However, for the use withcashocs, the state variable y must not be a fenics.TrialFunction, and the adjoint variable p must not be a fenics.TestFunction. They have to be defined as regular fenics.Function objects, otherwise the code will not workproperly.

After defining the weak form of the state equation, we now specify the corresponding (homogeneous) Dirichlet bound-ary conditions via

bcs = cashocs.create_dirichlet_bcs(V, Constant(0), boundaries, [1,2,3,4])

This creates Dirichlet boundary conditions with value 0 at the boundaries 1,2,3, and 4, i.e., everywhere.

Hint: Classically, these boundary conditions could also be defined via

def boundary(x, on_bdry):return on_boundarybc = DirichletBC(V, Constant(0), boundary)

which would yield a single DirichletBC object, instead of the list returned by create_dirichlet_bcs. Any of themany methods for defining the boundary conditions works here, as long as it is valid input for the fenics.solve()function.

With the above description, we see that defining the state system for cashocs is nearly identical to defining it withFEniCS, the only major difference lies in the definition of the state and adjoint variables as fenics.Function objects,instead of fenics.TrialFunction and fenics.TestFunction.

Definition of the cost functional

Now, we have to define the optimal control problem which we do by first specifying the cost functional. To do so, wedefine the desired state 𝑦𝑑 as an fenics.Expression y_d, i.e.,

y_d = Expression('sin(2*pi*x[0])*sin(2*pi*x[1])', degree=1)

Alternatively, y_d could also be a fenics.Function or any other object that is usable in an UFL form (e.g. generatedwith fenics.SpatialCoordinate()).

Then, we define the regularization parameter 𝛼 and the tracking-type cost functional via the commands

alpha = 1e-6J = Constant(0.5)*(y - y_d)*(y - y_d)*dx + Constant(0.5*alpha)*u*u*dx

The cost functional has to be a UFL form, which returns a scalar value when evaluated with the assemble commandfrom FEniCS. These definitions are also classical in the sense that they would have to be performed in this (or a similar)way in FEniCS when one would want to evaluate the (reduced) cost functional, so that we have only very little overhead.

10 Chapter 3. Tutorial

Page 15: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Definition of the optimization problem and its solution

Finally, we set up an OptimalControlProblem ocp and then directly solve it with the the method ocp.solve()

ocp = cashocs.OptimalControlProblem(e, bcs, J, y, u, p, config)ocp.solve()

Hint: Note, that the solve command without any additional keyword arguments leads to cashocs using the settingsdefined in the config file. However, there are some options that can be directly set with keyword arguments for thesolve call. These 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.

Hence, we could also use the command

ocp.solve('lbfgs', 1e-3, 0.0, 100)

to solve the optimization problem with the L-BFGS method, a relative tolerance of 1e-3, no absolute tolerance, and amaximum of 100 iterations.

The possible values for these arguments are the same as the corresponding ones in the config file. This just allows forsome shortcuts, e.g., when one wants to quickly use a different solver.

Note, that it is not strictly necessary to supply config files in cashocs. In this case, the user has to follow the aboveexample and specify at least the solution algorithm via the solve method. However, it is very strongly recommendedto use config files with cashocs as they allow a detailed tuning of its behavior.

Finally, we visualize the results using matplotlib and the following code

import matplotlib.pyplot as pltplt.figure(figsize=(16,9))

plt.subplot(1, 3, 1)fig = plot(u)plt.colorbar(fig, fraction=0.046, pad=0.04)plt.title('Control variable u')

plt.subplot(1,3,2)fig = plot(y)plt.colorbar(fig, fraction=0.046, pad=0.04)plt.title('State variable y')

plt.subplot(1,3,3)fig = plot(interpolate(y_d, V))plt.colorbar(fig, fraction=0.046, pad=0.04)plt.title('Desired state y_d')

plt.tight_layout()

The output should look like this

3.1. Optimal Control Problems 11

Page 16: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

3.1.2 Documentation of the Config Files for Optimal Control Problems

Let us take a look at how the config files are structured for optimal control problems. The corresponding config file isconfig.ini.

First of all, the config is divided into the sections: Mesh, StateSystem, OptimizationRoutine, AlgoLBFGS, AlgoCG,AlgoTNM, and Output. These manage the settings for the mesh, the state equation of the optimization problem, thesolution algorithms, and the output, respectively. Note, that the structure of such config files is explained in-depth inthe documentation of the configparser module. In particular, the order of the entries in each section is arbitrary.

Moreover, we remark that cashocs has a default behavior for almost all of these parameters, which is triggered whenthey are NOT specified in the config file, and we will discuss this behavior for each parameter in this tutorial. Asummary of all parameters as well as their default values can be found at the end of this page.

Section Mesh

The mesh section consists, for optimal control problems, only of a path to the .xdmf version of the mesh file

mesh_file = ../mesh/mesh.xdmf

This section is completely optional and can be used when importing meshes generated with GMSH. Note, that thissection can become more populated and useful for shape optimization problems, as detailed in the description of theirconfig files. To convert a .msh file to the .xdmf format, you can use the command line tool cashocs-convert.

Section StateSystem

The state system section is used to detail how the state and adjoint systems are solved. This includes settings for adamped Newton method and a Picard iteration.

In the following, we go over each parameter in detail. First, we have

is_linear = True

This is a boolean parameter which indicates, whether the state system is linear. This is used to speed up some compu-tations. Note, that the program will always work when this is set to False, as it treats the linear problem in a nonlinearfashion and the corresponding solver converges in one iteration. However, using is_linear = True on a nonlinearstate system throws an error related to FEniCS. The default value for this parameter is False.

The next parameter is defined via

newton_rtol = 1e-11

12 Chapter 3. Tutorial

Page 17: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

This parameter determines the relative tolerance for the Newton solver that is used to solve a nonlinear state system.Subsequently, we can also define the absolute tolerance for the Newton solver via

newton_atol = 1e-13

Note, that the default values are newton_rtol = 1e-11 and newton_atol = 1e-13.

The parameter newton_iter, which is defined via

newton_iter = 50

controls how many iterations the Newton method is allowed to make before it terminates. This defaults to 50.

Moreover, we have the boolean newton_damped

newton_damped = True

which determines whether a damping should be used (in case this is True) or not (otherwise). This parameter defaultsto True if nothing is given.

Additionally, we have the boolean parameter newton_inexact, defined via

newton_inexact = False

which sets up an inexact Newton method for solving nonlinear problems in case this is True. The default is False.

The parameter

newton_verbose = False

is used to make the Newton solver’s output verbose. This is disabled by default. This concludes the settings for Newton’smethod.

Next up, we have the parameters controlling the Picard iteration. First, we have

picard_iteration = False

This is another boolean flag, used to determine, whether the state system shall be solved using a Picard iteration (if thisis True) or not (if this is False). For a single state equation (i.e. one single state variable) both options are equivalent.The difference is only active when considering a coupled system with multiple state variables that is coupled. Thedefault value for this parameter is False.

The tolerances for the Picard iteration are defined via

picard_rtol = 1e-10picard_atol = 1e-12

The first parameter determines the relative tolerance used for the Picard iteration, in case it is enabled, and the secondone determines the absolute tolerance. Their default value are given by picard_rtol = 1e-10 and picard_atol= 1e-12.

The maximum number of iterations of the method can be set via

picard_iter = 10

and the default value for this parameter is picard_iter = 50.

The parmater picard_verbose enables verbose output of the convergence of the Picard iteration, and is set as follows

3.1. Optimal Control Problems 13

Page 18: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

picard_verbose = False

Its default value is False.

Section OptimizationRoutine

The following section is used to specify general parameters for the solution algorithm, which can be customized here.The first parameter determines the choice of the particular algorithm, via

algorithm = lbfgs

The possible choices are given by

• gd or gradient_descent : a gradient descent method

• cg, conjugate_gradient, ncg, nonlinear_cg : nonlinear CG methods

• lbfgs or bfgs : limited memory BFGS method

• newton : a truncated Newton method

Note, that there is no default value, so that this always has to be specified by the user.

The next line of the config file is given by

rtol = 1e-4

This parameter determines the relative tolerance for the solution algorithm. In the case where no control constraints arepresent, this uses the “classical” norm of the gradient of the cost functional as measure. In case there are box constraintspresent, it uses the stationarity measure (see Kelley, Iterative Methods for Optimization as measure. Analogously, wealso have the line

atol = 0.0

This determines the absolute tolerance for the solution algorithm. The default tolerances for the optimization algorithmare given by rtol = 1e-3 and atol = 0.0.

Next up, we have

maximum_iterations = 100

This parameter determines the maximum number of iterations carried out by the solution algorithm before it is termi-nated. It defaults to maximum_iterations = 100.

The initial step size for the Armijo line search can be set via

initial_stepsize = 1.0

This can have an important effect on performance of the gradient descent and nonlinear cg methods, as they do notinclude a built-in scaling of the step size. The default value is initial_stepsize = 1.0.

The next paramter, epsilon_armijo, is defined as follows

epsilon_armijo = 1e-4

This paramter describes the parameter used in the Armijo rule to determine sufficient decrease, via

𝐽(𝑢 + 𝑡𝑑) ≤ 𝐽(𝑢) + 𝜀𝑡 ⟨𝑔, 𝑑⟩

14 Chapter 3. Tutorial

Page 19: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

where u is the current optimization variable, d is the search direction, t is the step size, and g is the current gradient.Note, that 𝜀 corresponds to the parameter epsilon_armijo. A value of 1e-4 is recommended and commonly used(see Nocedal and Wright, Numerical Optimization), so that we use epsilon_armijo = 1e-4 as default value.

In the following line, the parameter beta_armijo is defined

beta_armijo = 2

This parameter determines the factor by the which the step size is decreased if the Armijo condition is not satisfied,i.e., we get 𝑡 = 𝑡

𝛽 beta` corresponds to beta_armijo. The default value for this parameter is beta_armijo = 2.0.

Finally, we have the parameter soft_exit, which is defined as

soft_exit = False

This parameter determines, whether we get a hard (False) or soft (True) exit of the optimization routine in case itdoes not converge. In case of a hard exit an Exception is raised and the script does not complete. However, it can bebeneficial to still have the subsequent code be processed, which happens in case soft_exit = True. Note, however,that in this case the returned results are NOT optimal, as defined by the user input parameters. Hence, the default valueis soft_exit = False.

The following sections describe parameters that belong to the certain solution algorithms.

Section AlgoLBFGS

For the L-BFGS method we have the following parameters. First, we have bfgs_memory_size, which is set via

bfgs_memory_size = 2

and determines the size of the memory of the L-BFGS method. E.g., the command above specifies that informationof the previous two iterations shall be used. The case bfgs_memory_size = 0 yields the classical gradient descentmethod, whereas bfgs_memory_size > maximum_iterations gives rise to the classical BFGS method with un-limited memory. The default behavior is bfgs_memory_size = 5.

Second, we have the parameter use_bfgs_scaling, that is set via

use_bfgs_scaling = True

This determines, whether one should use a scaling of the initial Hessian approximation (see Nocedal and Wright,Numerical Optimization). This is usually very beneficial and should be kept enabled, which it is by default.

Section AlgoCG

The parameter

cg_method = PR

determines which of the nonlinear cg methods shall be used. Available are

• FR : the Fletcher-Reeves method

• PR : the Polak-Ribiere method

• HS : the Hestenes-Stiefel method

• DY : the Dai-Yuan method

• HZ : the Hager-Zhang method

3.1. Optimal Control Problems 15

Page 20: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

The default value for this parameter is cg_method = FR.

After the definition of the particular cg method, we now have parameters determining restart strategies for these method.First up, we have the line

cg_periodic_restart = False

This parameter determines, whether the CG method should be restarted with a gradient step periodically, which canlead to faster convergence. The amount of iterations between restarts is then determined by

cg_periodic_its = 5

In this example, the NCG method is restarted after 5 iterations. The default behavior is given bycg_periodic_restart = False and cg_periodic_its = 10. This means, if neither of the parameters is speci-fied, no periodic restarting takes place. If, however, only cg_periodic_restart = True is set, the default numberof iterations before a restart will be cg_periodic_its = 10, unless cg_periodic_its is defined, too.

Another possibility to restart NCG methods is based on a relative criterion (see Nocedal and Wright, Numerical Opti-mization, Chapter 5.2). This is enabled via the boolean flag

cg_relative_restart = False

and the corresponding relative tolerance (which should lie in (0, 1)) is determined via

cg_restart_tol = 0.5

Note, that this relative restart reinitializes the iteration with a gradient step in case subsequent gradients arenot “sufficiently” orthogonal anymore. The default behavior is given by cg_relative_restart = False andcg_restart_tol = 0.25.

Section AlgoTNM

The parameters for the truncated Newton method are determined in the following.

First up, we have

inner_newton = cg

which determines the Krylov method for the solution of the Newton problem. Should be one of

• cg : A linear conjugate gradient method

• cr : A conjugate residual method

Note, that these Krylov solvers are streamlined for symmetric linear operators, which the Hessian is (should be alsopositive definite for a minimizer so that the conjugate gradient method should yield good results when initialized nottoo far from the optimum). The conjugate residual does not require positive definiteness of the operator, so that it mightperform slightly better when the initial guess is further away from the optimum. The default value is inner_newton= cr.

Then, we have the following line

inner_newton_rtol = 1e-15

This determines the relative tolerance of the iterative Krylov solver for the Hessian problem. This is set toinner_newton_rtol = 1e-15 by default.

Moreover, we can also specify the absolute tolerance for the iterative solver for the Hessian problem, with the line

16 Chapter 3. Tutorial

Page 21: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

inner_newton_atol = 1e-15

analogously to the relative tolerance above.

In the final line, the paramter max_it_inner_newton is defined via

max_it_inner_newton = 50

This parameter determines how many iterations of the Krylov solver are performed before the inner iteration is ter-minated. Note, that the approximate solution of the Hessian problem is used after max_it_inner_newton iterationsregardless of whether this is converged or not. This defaults to max_it_inner_newton = 50.

Section Output

This section determines the behavior of cashocs regarding output, both in the terminal and w.r.t. output files. The firstline of this section reads

verbose = True

The parameter verbose determines, whether the solution algorithm generates a verbose output in the console, usefulfor monitoring its convergence. This is set to verbose = True by default.

Next up, we define the parameter save_results

save_results = True

If this parameter is set to True, the history of the optimization is saved in a .json file located in the same folder as theoptimization script. This is very useful for postprocessing the results. This defaults to save_results = True.

Moreover, we define the parameter save_txt

save_txt = True

This saves the output of the optimization, which is usually shown in the terminal, to a .txt file, which is human-readable.

We define the parameter save_pvd in the line

save_pvd = False

If save_pvd is set to True, the state variables are saved to .pvd files in a folder named “pvd”, located in the samedirectory as the optimization script. These can be visualized with Paraview. This parameter defaults to save_pvd =False.

The next parameter is save_pvd_adjoint, which is given in the line

save_pvd_adjoint = False

Analogously to the previous parameter, if save_pvd_adjoint is True, the adjoint variables are saved to .pvd files.The default value is save_pvd_adjoint = False.

The next parameter is given by save_pvd_gradient, which is given in the line

save_pvd_gradient = False

This boolean flag ensures that a paraview with the computed gradients is saved in result_dir/pvd. The main purposeof this is for debugging.

3.1. Optimal Control Problems 17

Page 22: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Finally, we can specify in which directory the results should be stored with the parameter result_dir, which is givenin this config file by

result_dir = ./results

The path given there can be either relative or absolute. In this example, the working directory of the python script ischosen.

Moreover, we have the parameter time_suffix, which adds a suffix to the result directory based on the current time.It is controlled by the line

time_suffix = False

Summary

Finally, an overview over all parameters and their default values can be found in the following.

[Mesh]

Parameter Default value Remarksmesh_file optional, see import_mesh

[StateSystem]

Parameter Default value Remarksis_linear False using True gives an error for nonlinear problemsnewton_rtol 1e-11 relative tolerance for Newton’s methodnewton_atol 1e-13 absolute tolerance for Newton’s methodnewton_iter 50 maximum iterations for Newton’s methodnewton_damped True if True, damping is enablednewton_inexact False if True, an inexact Newton’s method is usednewton_verbose False True enables verbose output of Newton’s methodpicard_iteration False True enables Picard iteration; only has an effect for multiple variablespicard_rtol 1e-10 relative tolerance for Picard iterationpicard_atol 1e-12 absolute tolerance for Picard iterationpicard_iter 50 maximum iterations for Picard iterationpicard_verbose False True enables verbose output of Picard iteration

18 Chapter 3. Tutorial

Page 23: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

[OptimizationRoutine]

Parameter Defaultvalue

Remarks

algorithm has to be specified by the user; see solvertol 1e-3 relative tolerance for the optimization algorithmatol 0.0 absolute tolerance for the optimization algorithmmaximum itera-tions

100 maximum iterations for the optimization algorithm

initial_stepsize 1.0 initial stepsize for the first iteration in the Armijo ruleepsilon_armijo 1e-4beta_armijo 2.0soft_exit False if True, the optimization algorithm does not raise an exception if it did not

converge

[AlgoLBFGS]

Parameter Defaultvalue

Remarks

bfgs_memory_size 5 memory size of the L-BFGS methoduse_bfgs_scaling True if True, uses a scaled identity mapping as initial guess for the inverse Hessian

[AlgoCG]

Parameter Defaultvalue

Remarks

cg_method FR specifies which nonlinear CG method is usedcg_periodic_restart False if True, enables periodic restart of NCG methodcg_periodic_its 10 specifies, after how many iterations the NCG method is restarted, if applica-

blecg_relative_restart False if True, enables restart of NCG method based on a relative criterioncg_restart_tol 0.25 the tolerance of the relative restart criterion, if applicable

[AlgoTNM]

Parameter Default value Remarksinner_newton cr inner iterative solver for the truncated Newton methodinner_newton_rtol 1e-15 relative tolerance for the inner iterative solverinner_newton_atol 0.0 absolute tolerance for the inner iterative solvermax_it_inner_newton 50 maximum iterations for the inner iterative solver

3.1. Optimal Control Problems 19

Page 24: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

[Output]

Parameter Defaultvalue

Remarks

verbose True if True, the history of the optimization is printed to the consolesave_results True if True, the history of the optimization is saved to a .json filesave_txt True if True, the history of the optimization is saved to a human readable .txt filesave_pvd False if True, the history of the state variables over the optimization is saved in .pvd

filessave_pvd_adjoint False if True, the history of the adjoint variables over the optimization is saved in

.pvd filessave_pvd_gradient False if True, the history of the gradient(s) over the optimization is saved in .pvd

filesresult_dir ./ path to the directory, where the output should be placedtime_suffix False Boolean flag, which adds a suffix to result_dir based on the current time

This concludes the documentation of the config files for optimal control problems. For the corresponding documenta-tion for shape optimization problems, see Documentation of the Config Files for Shape Optimization Problems.

3.1.3 Control Constraints

Problem Formulation

In this demo, we take a deeper look at how control constraints can be treated in cashocs. To do so, we investigate thesame problem as in Distributed Control of a Poisson Problem, but now with the addition of box constraints for thecontrol variable. This problem reads

min 𝐽(𝑦, 𝑢) =1

2

∫Ω

(𝑦 − 𝑦𝑑)2 d𝑥 +

𝛼

2

∫Ω

𝑢2 d𝑥

subject to

⎧⎪⎨⎪⎩−∆𝑦 = 𝑢 in Ω,

𝑦 = 0 on Γ,

𝑢𝑎 ≤ 𝑢 ≤ 𝑢𝑏 in Ω

(see, e.g., Tröltzsch, Optimal Control of Partial Differential Equations or Hinze, Pinnau, Ulbrich, and Ulbrich, Opti-mization with PDE constraints.

Here, the functions 𝑢𝑎 and 𝑢𝑏 are𝐿∞(Ω) functions. As before, we consider as domain the unit square, i.e., Ω = (0, 1)2.

Implementation

The complete python code can be found in the file demo_box_constraints.py, and the corresponding config can befound in config.ini.

20 Chapter 3. Tutorial

Page 25: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Initialization

The beginning of the script is completely identical to the one of previous example, so we only restate the correspondingcode in the following

from fenics import *import cashocs

config = cashocs.load_config('./config.ini')

mesh, subdomains, boundaries, dx, ds, dS = cashocs.regular_mesh(50)V = FunctionSpace(mesh, 'CG', 1)

y = Function(V)p = Function(V)u = Function(V)

e = inner(grad(y), grad(p))*dx - u*p*dx

bcs = cashocs.create_dirichlet_bcs(V, Constant(0), boundaries, [1,2,3,4])

y_d = Expression('sin(2*pi*x[0])*sin(2*pi*x[1])', degree=1)alpha = 1e-6J = Constant(0.5)*(y - y_d)*(y - y_d)*dx + Constant(0.5*alpha)*u*u*dx

Definition of the control constraints

Here, we have nearly everything at hand to define the optimal control problem, the only missing ingredient are the boxconstraints, which we define now. For the purposes of this example, we consider a linear (in the x-direction) corridorfor these constraints, as it highlights the capabilities of cashocs. Hence, we define the lower and upper bounds via

u_a = interpolate(Expression('50*(x[0]-1)', degree=1), V)u_b = interpolate(Expression('50*x[0]', degree=1), V)

which just corresponds to two functions, generated from fenics.Expression objects via fenics.interpolate().These are then put into the list cc, which models the control constraints, i.e.,

cc = [u_a, u_b]

Note: As an alternative way of specifying the box constraints, one can also use regular float or int objects, in case thatthey are constant. For example, the constraint that we only want to consider positive value for u, i.e., 0 ≤ 𝑢 ≤ +∞ canbe realized via

u_a = 0u_b = float('inf')cc = [u_a, u_b]

and completely analogous with float('-inf') for no constraint on the lower bound. Moreover, note that the specifi-cation of using either constant float values and fenics.Function objects can be mixed arbitrarily, so that one can,e.g., specify a constant value for the upper boundary and use a fenics.Function on the lower one.

3.1. Optimal Control Problems 21

Page 26: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Setup of the optimization problem and its solution

Now, we can set up the optimal control problem as we did before, using the additional keyword argumentcontrol_constraints into which we put the list cc, and then solve it via the ocp.solve() method

ocp = cashocs.OptimalControlProblem(e, bcs, J, y, u, p, config, control_constraints=cc)ocp.solve()

To check that the box constraints are actually satisfied by our solution, we perform an assertion

import numpy as npassert np.alltrue(u_a.vector()[:] <= u.vector()[:]) and np.alltrue(u.vector()[:] <= u_b.→˓vector()[:])

which shows that they are indeed satisfied. The visualization is carried out analogously to before, and should yield thefollowing result

3.1.4 Neumann Boundary Control

Problem Formulation

In this demo we investigate an optimal control problem with a Neumann type boundary control. This problem reads

min 𝐽(𝑦, 𝑢) =1

2

∫Ω

(𝑦 − 𝑦𝑑)2 d𝑥 +

𝛼

2

∫Γ

𝑢2 d𝑠

subject to

−∆𝑦 + 𝑦 = 0 in Ω,

𝑛 · ∇𝑦 = 𝑢 on Γ.

(see, e.g., Tröltzsch, Optimal Control of Partial Differential Equations or Hinze, Pinnau, Ulbrich, and Ulbrich, Opti-mization with PDE constraints. Note, that we cannot use a simple Poisson equation as constraint since this would notbe compatible with the boundary conditions (i.e. not well-posed).

22 Chapter 3. Tutorial

Page 27: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Implementation

The complete python code can be found in the file demo_neumann_control.py, and the corresponding config can befound in config.ini.

Initialization

Initially, the code is again identical to the previous ones (see Distributed Control of a Poisson Problem and ControlConstraints), i.e., we have

from fenics import *import cashocs

config = cashocs.load_config('./config.ini')mesh, subdomains, boundaries, dx, ds, dS = cashocs.regular_mesh(50)V = FunctionSpace(mesh, 'CG', 1)

y = Function(V)p = Function(V)u = Function(V)

Definition of the state equation

Now, the definition of the state problem obviously differs from the previous two examples, and we use

e = inner(grad(y), grad(p))*dx + y*p*dx - u*p*ds

which directly puts the Neumann boundary condition into the weak form. For this problem, we do not have Dirichletboundary conditions, so that we use

bcs = None

Hint: Alternatively, we could have also used a empty list, i.e.,

bcs = []

Definition of the cost functional

The definition of the cost functional is nearly identical to before, only the integration measure for the regularizationterm changes, so that we have

y_d = Expression('sin(2*pi*x[0])*sin(2*pi*x[1])', degree=1)alpha = 1e-6J = Constant(0.5)*(y - y_d)*(y - y_d)*dx + Constant(0.5*alpha)*u*u*ds

As the default Hilbert space for a control is 𝐿2(Ω), we now also have to change this, to accommodate for the fact thatthe control variable u now lies in the space 𝐿2(Γ), i.e., it is only defined on the boundary. This is done by defining thescalar product of the corresponding Hilbert space, which we do with

3.1. Optimal Control Problems 23

Page 28: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

scalar_product = TrialFunction(V)*TestFunction(V)*ds

The scalar_product always has to be a symmetric, coercive and continuous bilinear form, so that it induces an actualscalar product on the corresponding space.

Note: This means, that we could also define an alternative scalar product for Distributed Control of a Poisson Problem,using the space 𝐻1(Ω) instead of 𝐿2(Ω) with the following

scalar_product = inner(grad(TrialFunction(V)), grad(TestFunction(V)))*dx +→˓TrialFunction(V)*TestFunction(V)*dx

This allows a great amount of flexibility in the choice of the control space.

Setup of the optimization problem and its solution

With this, we can now define the optimal control problem with the additional keyword argumentriesz_scalar_products and solve it with the ocp.solve() command

ocp = cashocs.OptimalControlProblem(e, bcs, J, y, u, p, config, riesz_scalar_→˓products=scalar_product)ocp.solve()

Hence, in order to treat boundary control problems, the corresponding weak forms have to be modified accordingly,and one has to adapt the scalar products used to determine the gradients.

The resulting visualization of the result looks as follows

3.1.5 Using Multiple Variables and PDEs

24 Chapter 3. Tutorial

Page 29: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Problem Formulation

In this demo we show how cashocs can be used to treat multiple state equations as constraint. Additionally, this alsohighlights how the case of multiple controls can be treated. As model example, we consider the following problem

min 𝐽((𝑦, 𝑧), (𝑢, 𝑣)) =1

2

∫Ω

(𝑦 − 𝑦𝑑) d𝑥 +1

2

∫Ω

(𝑧 − 𝑧𝑑) d𝑥 +𝛼

2

∫Ω

𝑢2 d𝑥 +𝛽

2

∫Ω

𝑣2 d𝑥

subject to

⎧⎪⎪⎪⎨⎪⎪⎪⎩−∆𝑦 = 𝑢 in Ω,

𝑦 = 0 on Γ,

−∆𝑧 − 𝑦 = 𝑣 in Ω,

𝑧 = 0 on Γ.

For the sake of simplicity, we restrict this investigation to homogeneous boundary conditions as well as to a verysimple one way coupling. More complex problems (using e.g. Neumann control or more difficult couplings) arestraightforward to implement.

In contrast to the previous examples, in the case where we have multiple state equations, which are either decoupledor only one-way coupled, the corresponding state equations are solved one after the other so that every input related tothe state and adjoint variables has to be put into a ordered list, so that they can be treated properly, as is explained inthe following.

Implementation

The complete python code can be found in the file demo_multiple_variables.py, and the corresponding configcan be found in config.ini.

Initialization

The initial setup is identical to the previous cases (see, Distributed Control of a Poisson Problem), where we again use

from fenics import *import cashocs

config = cashocs.load_config('config.ini')mesh, subdomains, boundaries, dx, ds, dS = cashocs.regular_mesh(50)V = FunctionSpace(mesh, 'CG', 1)

which defines the geometry and the function space.

Defintion of the Functions

We now first define the state equation corresponding to the state 𝑦. This is done in analogy to Distributed Control of aPoisson Problem

y = Function(V)p = Function(V)u = Function(V)e_y = inner(grad(y), grad(p)) * dx - u * p * dxbcs_y = cashocs.create_dirichlet_bcs(V, Constant(0), boundaries, [1, 2, 3, 4])

3.1. Optimal Control Problems 25

Page 30: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Similarly to before, p is the adjoint state corresponding to y.

Next, we define the second state equation (which is for the state 𝑧) via

z = Function(V)q = Function(V)v = Function(V)e_z = inner(grad(z), grad(q)) * dx - (y + v) * q * dxbcs_z = cashocs.create_dirichlet_bcs(V, Constant(0), boundaries, [1, 2, 3, 4])

Here, q is the adjoint state corresponding to z.

In order to treat this one-way coupled with cashocs, we now have to specify what the state, adjoint, and control variablesare. This is done by putting the corresponding fenics.Function objects into ordered lists

states = [y, z]adjoints = [p, q]controls = [u, v]

To define the corresponding state system, the state equations and Dirichlet boundary conditions also have to be put intoan ordered list, i.e.,

e = [e_y, e_z]bcs_list = [bcs_y, bcs_z]

Note: It is important, that the ordering of the state and adjoint variables, as well as the state equations and boundaryconditions is in the same way. This means, that e[i] is the state equation for state[i], which is supplemented withDirichlet boundary conditions defined in bcs_list[i], and has a corresponding adjoint state adjoints[i], for alli. In analogy, the same holds true for the control variables, the scalar product of the control space, and the controlconstraints, i.e., controls[j], riesz_scalar_products[j], and control_constraints[j] all have to belongto the same control variable.

Note, that the control variables are completely independent of the state and adjoint ones, so that the relative orderingbetween these objects does not matter.

Defintion of the state system

Now, we can define the PDE constraints corresponding to y and z, which read in FEniCS syntax

e_y = inner(grad(y), grad(p))*dx - u*p*dxe_z = inner(grad(z), grad(q))*dx - (y + v)*q*dx

Again, the state equations have to be gathered into a list, where the order has to be in analogy to the list y, i.e.,

e = [e_y, e_z]

Finally, the boundary conditions for both states are homogeneous Dirichlet conditions, which we generate via

bcs1 = cashocs.create_dirichlet_bcs(V, Constant(0), boundaries, [1, 2, 3, 4])bcs2 = cashocs.create_dirichlet_bcs(V, Constant(0), boundaries, [1, 2, 3, 4])

bcs_list = [bcs1, bcs2]

and who are also put into a joint list bcs_list.

26 Chapter 3. Tutorial

Page 31: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Defintion of the cost functional and optimization problem

For the optimization problem we now define the cost functional via

y_d = Expression('sin(2*pi*x[0])*sin(2*pi*x[1])', degree=1)z_d = Expression('sin(4*pi*x[0])*sin(4*pi*x[1])', degree=1)alpha = 1e-6beta = 1e-4J = Constant(0.5)*(y - y_d)*(y - y_d)*dx + Constant(0.5)*(z - z_d)*(z - z_d)*dx \

+ Constant(0.5*alpha)*u*u*dx + Constant(0.5*beta)*v*v*dx

This setup is sufficient to now define the optimal control problem and solve it, via

optimization_problem = cashocs.OptimalControlProblem(e, bcs_list, J, states, controls,→˓adjoints, config)optimization_problem.solve()

The result should look like this

Note: Note, that the error between 𝑧 and 𝑧𝑑 is significantly larger that the error between 𝑦 and 𝑦𝑑. This is due to thefact that we use a different regularization parameter for the controls 𝑢 and 𝑣. For the former, which only acts on 𝑦, wehave a regularization parameter of alpha = 1e-6, and for the latter we have beta = 1e-4. Hence, 𝑣 is penalizedhigher for being large, so that also 𝑧 is (significantly) smaller than 𝑧𝑑.

Hint: Note, that for the case that we consider control constraints (see Control Constraints) or different Hilbert spaces,e.g., for boundary control (see Neumann Boundary Control), the corresponding control constraints have also to be putinto a joint list, i.e.,

3.1. Optimal Control Problems 27

Page 32: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

cc_u = [u_a, u_b]cc_v = [v_a, v_b]cc = [cc_u, cc_v]

and the corresponding scalar products have to be treated analogously, i.e.,

scalar_product_u = TrialFunction(V)*TestFunction(V)*dxscalar_product_v = TrialFunction(V)*TestFunction(V)*dxscalar_products = [scalar_product_u, scalar_produt_v]

In summary, to treat multiple (control or state) variables, the corresponding objects simply have to placed into orderedlists which are then passed to the OptimalControlProblem instead of the “single” objects as in the previous examples.Note, that each individual object of these lists is allowed to be from a different function space, and hence, this enablesdifferent discretizations of state and adjoint systems.

3.1.6 Coupled Problems - Monolithic Approach

Problem Formulation

In this demo we show how cashocs can be used with a coupled PDE constraint. For this demo, we consider a monolithicapproach, whereas we investigate an approach based on a Picard iteration in Coupled Problems - Picard Iteration.

As model example, we consider the following problem

min 𝐽((𝑦, 𝑧), (𝑢, 𝑣)) =1

2

∫Ω

(𝑦 − 𝑦𝑑)2 d𝑥 +

1

2

∫Ω

(𝑧 − 𝑧𝑑)2 d𝑥 +

𝛼

2

∫Ω

𝑢2 d𝑥 +𝛽

2

∫Ω

𝑣2 d𝑥

subject to

⎧⎪⎪⎪⎨⎪⎪⎪⎩−∆𝑦 + 𝑧 = 𝑢 in Ω,

𝑦 = 0 on Γ,

−∆𝑧 + 𝑦 = 𝑣 in Ω,

𝑧 = 0 on Γ.

In constrast to Using Multiple Variables and PDEs, the system is now two-way coupled. To solve it, we employ a mixedfinite element method in this demo.

Implementation

The complete python code can be found in the file demo_monolithic_problems.py, and the corresponding configcan be found in config.ini.

Initialization and variable definitions

The initialization for this example works as before, i.e., we use

from fenics import *import cashocs

config = cashocs.load_config('config.ini')mesh, subdomains, boundaries, dx, ds, dS = cashocs.regular_mesh(50)

28 Chapter 3. Tutorial

Page 33: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

For the mixed finite element method we have to define a fenics.MixedFunctionSpace, via

elem_1 = FiniteElement('CG', mesh.ufl_cell(), 1)elem_2 = FiniteElement('CG', mesh.ufl_cell(), 1)V = FunctionSpace(mesh, MixedElement([elem_1, elem_2]))

The control variables get their own fenics.FunctionSpace

U = FunctionSpace(mesh, 'CG', 1)

Then, the state and adjoint variables state and adjoint are defined

state = Function(V)adjoint = Function(V)

As these are part of a fenics.MixedFunctionSpace, we can access their individual components by

y, z = split(state)p, q = split(adjoint)

Similarly to Using Multiple Variables and PDEs, p is the adjoint state corresponding to y, and q is the one correspondingto z.

We then define the control variables as

u = Function(U)v = Function(U)controls = [u, v]

Note, that we directly put the control variables u and v into a list controls, which implies that u is the first componentof the control variable, and v the second one.

Hint: An alternative way of specifying the controls would be to reuse the mixed function space and use

controls = Function(V)u, v = split(controls)

Allthough this formulation is slightly different (it uses a fenics.Function for the controls, and not a list) the de-facto behavior of both methods is completely identical, just the interpretation is slightly different (since the individualcomponents of the V fenics.FunctionSpace are also CG1 functions).

Definition of the mixed weak form

Next, we define the mixed weak form. To do so, we first define the first equation and its Dirichlet boundary conditions

e_y = inner(grad(y), grad(p))*dx + z*p*dx - u*p*dxbcs_y = cashocs.create_dirichlet_bcs(V.sub(0), Constant(0), boundaries, [1, 2, 3, 4])

and, in analogy, the second state equation

e_z = inner(grad(z), grad(q))*dx + y*q*dx - v*q*dxbcs_z = cashocs.create_dirichlet_bcs(V.sub(1), Constant(0), boundaries, [1, 2, 3, 4])

To arrive at the mixed weak form of the entire syste, we have to add the state equations and Dirichlet boundary conditions

3.1. Optimal Control Problems 29

Page 34: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

e = e_y + e_zbcs = bcs_y + bcs_z

Note, that we can only have one state equation as we also have only a single state variable state, and the number ofstate variables and state equations has to coincide, and the same is true for the boundary conditions, where also just asingle list is required.

Defintion of the optimization problem

The cost functional can be specified in analogy to the one of Using Multiple Variables and PDEs

y_d = Expression('sin(2*pi*x[0])*sin(2*pi*x[1])', degree=1)z_d = Expression('sin(4*pi*x[0])*sin(4*pi*x[1])', degree=1)alpha = 1e-6beta = 1e-6J = Constant(0.5)*(y - y_d)*(y - y_d)*dx + Constant(0.5)*(z - z_d)*(z - z_d)*dx \

+ Constant(0.5*alpha)*u*u*dx + Constant(0.5*beta)*v*v*dx

Finally, we can set up the optimization problem and solve it

optimization_problem = cashocs.OptimalControlProblem(e, bcs, J, state, controls, adjoint,→˓ config)optimization_problem.solve()

The result should look like this

30 Chapter 3. Tutorial

Page 35: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

3.1.7 Coupled Problems - Picard Iteration

Problem Formulation

In this demo we show how cashocs can be used with a coupled PDE constraint. For this, we consider a iterativeapproach, whereas we investigated a monolithic approach in Coupled Problems - Monolithic Approach.

As model example, we consider the following problem

min 𝐽((𝑦, 𝑧), (𝑢, 𝑣)) =1

2

∫Ω

(𝑦 − 𝑦𝑑)2 d𝑥 +

1

2

∫Ω

(𝑧 − 𝑧𝑑)2 d𝑥 +

𝛼

2

∫Ω

𝑢2 d𝑥 +𝛽

2

∫Ω

𝑣2 d𝑥

subject to

⎧⎪⎪⎪⎨⎪⎪⎪⎩−∆𝑦 + 𝑧 = 𝑢 in Ω,

𝑦 = 0 on Γ,

−∆𝑧 + 𝑦 = 𝑣 in Ω,

𝑧 = 0 on Γ.

Again, the system is two-way coupled. To solve it, we now employ a Picard iteration. Therefore, the two PDEs aresolved subsequently, where the variables are frozen in between: At the beginning the first PDE is solved for 𝑦, with 𝑧being fixed. Afterwards, the second PDE is solved for 𝑧 with 𝑦 fixed. This is then repeated until convergence is reached.

Note: There is, however, no a-priori guarantee that the Picard iteration converges for a particular problem, unless acareful analysis is carried out by the user. Still, it is an important tool, which also often works well in practice.

Implementation

The complete python code can be found in the file demo_picard_iteration.py, and the corresponding config canbe found in config.ini.

Initialization

The setup is as in Distributed Control of a Poisson Problem

from fenics import *import cashocs

config = cashocs.load_config('config.ini')mesh, subdomains, boundaries, dx, ds, dS = cashocs.regular_mesh(50)V = FunctionSpace(mesh, 'CG', 1)

However, compared to the previous examples, there is a major change in the config file. As we want to use the Picarditeration as solver for the state PDEs, we now specify

picard_iteration = True

see config.ini.

3.1. Optimal Control Problems 31

Page 36: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Definition of the state system

The definition of the state system follows the same ideas as introduced in Using Multiple Variables and PDEs:We define both state equations through their components, and then gather them in lists, which are passed to theOptimalControlProblem . The state and adjoint variables are defined via

y = Function(V)p = Function(V)z = Function(V)q = Function(V)

The control variables are defined as

u = Function(V)v = Function(V)

Next, we define the state system, using the weak forms from Coupled Problems - Monolithic Approach

e_y = inner(grad(y), grad(p))*dx + z*p*dx - u*p*dxbcs_y = cashocs.create_dirichlet_bcs(V, Constant(0), boundaries, [1, 2, 3, 4])

e_z = inner(grad(z), grad(q))*dx + y*q*dx - v*q*dxbcs_z = cashocs.create_dirichlet_bcs(V, Constant(0), boundaries, [1, 2, 3, 4])

Finally, we use the same procedure as in Using Multiple Variables and PDEs, and put everything into (ordered) lists

states = [y, z] adjoints = [p, q] controls = [u, v]

e = [e_y, e_z] bcs = [bcs_y, bcs_z]

Definition of the optimization problem

The cost functional is defined as in Coupled Problems - Monolithic Approach, the only difference is that y and z noware fenics.Function objects, whereas they were generated with the fenics.split() command previously

y_d = Expression('sin(2*pi*x[0])*sin(2*pi*x[1])', degree=1)z_d = Expression('sin(4*pi*x[0])*sin(4*pi*x[1])', degree=1)alpha = 1e-6beta = 1e-6J = Constant(0.5)*(y - y_d)*(y - y_d)*dx + Constant(0.5)*(z - z_d)*(z - z_d)*dx \

+ Constant(0.5*alpha)*u*u*dx + Constant(0.5*beta)*v*v*dx

Finally, we set up the optimization problem and solve it

optimization_problem = cashocs.OptimalControlProblem(e, bcs, J, states, controls,→˓adjoints, config)optimization_problem.solve()

The result should look like this

32 Chapter 3. Tutorial

Page 37: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Note: Comparing the output (especially in the early iterations) between the monlithic and Picard apporach we observethat both methods yield essentially the same results (up to machine precision). This validates the Picard approach.

However, one should note that for this example, the Picard approach takes significantly longer to compute the optimizer.This is due to the fact that the individual PDEs have to be solved several times, whereas in the monolithic approach thestate system is (slightly) larger, but has to be solved less often. However, the monolithic approach needs significantlymore memory, so that the Picard iteration becomes feasible for very large problems. Further, the convergence propertiesof the Picard iteration are better, so that it may converge even when the monolithic approach fails.

3.1.8 Distributed Control of a Stokes Problem

Problem Formulation

In this demo we investigate how cashocs can be used to treat a different kind of PDE constraint, in particular, weinvestigate a Stokes problem. The optimization problem reads as follows

min 𝐽(𝑢, 𝑐) =1

2

∫Ω

|𝑢− 𝑢𝑑|2 d𝑥 +𝛼

2

∫Ω

|𝑐|2 d𝑥

subject to

⎧⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎩

−∆𝑢 + ∇𝑝 = 𝑐 in Ω,

div(𝑢) = 0 in Ω,

𝑢 = 𝑢dir on Γdir,

𝑢 = 0 on Γno slip,

𝑝 = 0 at 𝑥pres.

In contrast to the other demos, here we denote by 𝑢 the velocity of a fluid and by 𝑝 its pressure, which are the twostate variables. The control is now denoted by c and acts as a volume source for the system. The tracking type cost

3.1. Optimal Control Problems 33

Page 38: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

functional again aims at getting the velocity u close to some desired velocity 𝑢𝑑.

For this example, the geometry is again given by Ω = (0, 1)2, and we take a look at the setting of the well knownlid driven cavity benchmark here. In particular, the boundary conditions are classical no slip boundary conditions atthe left, right, and bottom sides of the square. On the top (or the lid), a velocity 𝑢dir is prescribed, pointing into thepositive x-direction. Note, that since this problem has Dirichlet conditions on the entire boundary, the pressure is onlydetermined up to a constant, and hence we have to specify another condition to ensure uniqueness. For this demo wechoose another Dirichlet condition, specifying the value of the pressure at a single point in the domain. Alternatively,we could have also required that, e.g., the integral of the velocity 𝑢 over Ω vanishes (the implementation would thenonly be slightly longer, but not as intuitive). An example of how to treat such an additional constraint in FEniCS andcashocs can be found in Inverse Problem in Electric Impedance Tomography.

Implementation

The complete python code can be found in the file demo_stokes.py, and the corresponding config can be found inconfig.ini.

Initialization

The initialization is the same as in Distributed Control of a Poisson Problem, i.e.,

from fenics import *import cashocs

config = cashocs.load_config('./config.ini')mesh, subdomains, boundaries, dx, ds, dS = cashocs.regular_mesh(30)

For the solution of the Stokes (and adjoint Stokes) system, which have a saddle point structure, we have to choose LBBstable elements or a suitable stabilization, see e.g. Ern and Guermond, Theory and Practice of Finite Elements. Forthis demo, we use the classical Taylor-Hood elements of piecewise quadratic Lagrange elements for the velocity, andpiecewise linear ones for the pressure, which are LBB-stable. These are defined as

v_elem = VectorElement('CG', mesh.ufl_cell(), 2)p_elem = FiniteElement('CG', mesh.ufl_cell(), 1)V = FunctionSpace(mesh, MixedElement([v_elem, p_elem]))U = VectorFunctionSpace(mesh, 'CG', 1)

Moreover, we have defined the control space U as fenics.FunctionSpace with piecewise linear Lagrange elements.

Next, we set up the corresponding function objects, as follows

up = Function(V)u, p = split(up)vq = Function(V)v, q = split(vq)c = Function(U)

Here, up plays the role of the state variable, having components u and p, which are extracted using the fenics.split() command. The adjoint state vq is structured in exactly the same fashion. See Coupled Problems - MonolithicApproach for more details. Similarly to there, v will play the role of the adjoint velocity, and q the one of the adjointpressure.

Next up is the definition of the Stokes system. This can be done via

34 Chapter 3. Tutorial

Page 39: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

e = inner(grad(u), grad(v))*dx - p*div(v)*dx - q*div(u)*dx - inner(c, v)*dx

Note: Note, that we have chosen to consider the incompressibility condition with a negative sign. This is used to makesure that the resulting system is symmetric (but indefinite) which can simplify its solution. Using the positive sign forthe divergence constraint would instead lead to a non-symmetric but positive-definite system.

The boundary conditions for this system can be defined as follows

def pressure_point(x, on_boundary):return on_boundary and near(x[0], 0) and near(x[1], 0)

no_slip_bcs = cashocs.create_dirichlet_bcs(V.sub(0), Constant((0,0)), boundaries, [1,2,→˓3])lid_velocity = Expression(('4*x[0]*(1-x[0])', '0.0'), degree=2)bc_lid = DirichletBC(V.sub(0), lid_velocity, boundaries, 4)bc_pressure = DirichletBC(V.sub(1), Constant(0), pressure_point, method='pointwise')bcs = no_slip_bcs + [bc_lid, bc_pressure]

Here, we first define the point 𝑥pres, where the pressure is set to 0. Afterwards, we use the cashocs functioncreate_dirichlet_bcs to quickly create the no slip conditions at the left, right, and bottom of the cavity. Next,we define the Dirichlet velocity 𝑢dir for the lid of the cavity as a fenics.Expression, and create a correspondingboundary condition. Finally, the Dirichlet condition for the pressure is defined. Note, that in order to make this work,one has to specify the keyword argument method='pointwise'.

Defintion of the optimization problem

The definition of the optimization problem is in complete analogy to the previous ones we considered. The onlydifference is the fact that we now have to use fenics.inner() to multiply the vector valued functions u, u_d and c

alpha = 1e-5u_d = Expression(('sqrt(pow(x[0], 2) + pow(x[1], 2))*cos(2*pi*x[1])', '-sqrt(pow(x[0],→˓2) + pow(x[1], 2))*sin(2*pi*x[0])'), degree=2)J = Constant(0.5)*inner(u - u_d, u - u_d)*dx + Constant(0.5*alpha)*inner(c, c)*dx

As in Coupled Problems - Monolithic Approach, we then set up the optimization problem ocp and solve it with thecommand ocp.solve()

ocp = cashocs.OptimalControlProblem(e, bcs, J, up, c, vq, config)ocp.solve()

For post processing, we then create deep copies of the single components of the state and the adjoint variables with

u, p = up.split(True)v, q = vq.split(True)

The result should look like this

3.1. Optimal Control Problems 35

Page 40: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

3.1.9 Distributed Control for Time Dependent Problems

Problem Formulation

In this demo we take a look at how time dependent problems can be treated with cashocs. To do so, we investigatea problem with a heat equation as PDE constraint, which was considered in Blauth, Optimal Control and AsymptoticAnalysis of the Cattaneo Model. It reads

min 𝐽(𝑦, 𝑢) =1

2

∫ 𝑇

0

∫Ω

(𝑦 − 𝑦𝑑)2 d𝑥 d𝑡 +

𝛼

2

∫ 𝑇

0

∫Ω

𝑢2 d𝑥 d𝑡

subject to

⎧⎪⎨⎪⎩𝜕𝑡𝑦 − ∆𝑦 = 𝑢 in (0, 𝑇 ) × Ω,

𝑦 = 0 on (0, 𝑇 ) × Γ,

𝑦(0, ·) = 𝑦(0) in Ω.

Since FEniCS does not have any direct built-in support for time dependent problems, we first have to perform a semi-discretization of the PDE system in the temporal component (e.g. via finite differences), and then solve the resultingsequence of PDEs.

In particular, for the use with cashocs, we have to create not a single weak form and fenics.Function, that can bere-used, like one would in classical FEniCS programs, but we have to create the corresponding objects a-priori for eachtime step.

For the domain of this problem, we once again consider the space time cylinder given by (0, 𝑇 )×Ω = (0, 1)× (0, 1)2.And for the initial condition we use 𝑦(0) = 0.

Temporal discretization

For the temporal discretization, we use the implicit Euler scheme as this is unconditionally stable for the parabolic heatequation. This means, we discretize the interval [0, 𝑇 ] by a grid with nodes 𝑡𝑘, 𝑘 = 0, . . . , 𝑛, with 𝑡0 := 0 and 𝑡𝑛 :=𝑇 . Then, we approximate the time derivative 𝜕𝑡𝑦(𝑡𝑘+1) at some time 𝑡𝑘+1 by the backward difference

𝜕𝑡𝑦(𝑡𝑘+1) ≈ 𝑦(𝑡𝑘+1) − 𝑦(𝑡𝑘)

∆𝑡,

where ∆𝑡 = 𝑡𝑘+1 − 𝑡𝑘, and thus get the sequence of PDEs

𝑦𝑘+1 − 𝑦𝑘∆𝑡

− ∆𝑦𝑘+1 = 𝑢𝑘+1 in Ω for 𝑘 = 0, . . . , 𝑛− 1,

𝑦𝑘+1 = 0 on Γ for 𝑘 = 0, . . . , 𝑛− 1,

36 Chapter 3. Tutorial

Page 41: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Note, that 𝑦𝑘 ≈ 𝑦(𝑡𝑘), and 𝑢𝑘 ≈ 𝑢(𝑡𝑘) are approximations of the continuous functions. The initial condition isincluded via

𝑦0 = 𝑦(0)

Moreover, for the cost functionals, we can discretize the temporal integrals using a rectangle rule. This means weapproximate the cost functional via

𝐽(𝑦, 𝑢) ≈ 1

2

𝑛−1∑𝑘=0

∆𝑡

(∫Ω

(𝑦𝑘+1 − (𝑦𝑑)𝑘+1)2 d𝑥 + 𝛼

∫Ω

𝑢2𝑘+1 d𝑥

).

Here, (𝑦𝑑)𝑘 is an approximation of the desired state at time 𝑡𝑘.

Let us now investigate how to solve this problem with cashocs.

Implementation

The complete python code can be found in the file demo_heat_equation.py, and the corresponding config can befound in config.ini.

Initialization

This section is the same as for all previous problems and is done via

from fenics import *import cashocsimport numpy as np

config = cashocs.load_config('config.ini')mesh, subdomains, boundaries, dx, ds, dS = cashocs.regular_mesh(20)V = FunctionSpace(mesh, 'CG', 1)

Next up, we specify the temporal discretization via

dt = 1 / 10t_start = dtt_end = 1.0t_array = np.linspace(t_start, t_end, int(1/dt))

Here, t_array is a numpy array containing all time steps. Note, that we do not include t=0 in the array. This is dueto the fact, that the initial condition is prescribed and fixed. Due to the fact that we discretize the equation temporally,we do not only get a single fenics.Function describing our state and control, but one fenics.Function for eachtime step. Hence, we initialize these (together with the adjoint states) directly in lists

states = [Function(V) for i in range(len(t_array))]controls = [Function(V) for i in range(len(t_array))]adjoints = [Function(V) for i in range(len(t_array))]

Note, that states[k] corresponds to 𝑦𝑘+1 since indices start at 0 in most programming languages (as it is the case inpython).

As the boundary conditions are not time dependent, we can initialize them now, and repeat them in a list, since theyare the same for every state

3.1. Optimal Control Problems 37

Page 42: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

bcs = cashocs.create_dirichlet_bcs(V, Constant(0), boundaries, [1,2,3,4])bcs_list = [bcs for i in range(len(t_array))]

To define the sequence of PDEs, we will use a loop over all time steps. But before we can do that, we first initializeempty lists for the state equations, the approximations of the desired state, and the summands of the cost functional

y_d = []e = []J_list = []

Definition of the optimization problem

For the desired state, we define it with the help of a fenics.Expression, that is dependent on an additional parameterwhich models the time

alpha = 1e-5y_d_expr = Expression('exp(-20*(pow(x[0] - 0.5 - 0.25*cos(2*pi*t), 2) + pow(x[1] - 0.5 -→˓0.25*sin(2*pi*t), 2)))', degree=1, t=0.0)

Next, we have the following for loop, which we describe in detail after stating it here

for k in range(len(t_array)):t = t_array[k]y_d_expr.t = t

y = states[k]if k == 0:

y_prev = Function(V)else:

y_prev = states[k - 1]p = adjoints[k]u = controls[k]

state_eq = Constant(1/dt)*(y - y_prev)*p*dx + inner(grad(y), grad(p))*dx - u*p*dx

e.append(state_eq)y_d.append(interpolate(y_d_expr, V))

J_list.append(Constant(0.5*dt) * (y - y_d[k]) * (y - y_d[k]) * dx + Constant(0.5 *→˓dt * alpha) * u * u * dx)

Note: At the beginning, the ‘current’ time t is determined from t_array, and the expression for the desired state isupdated to reflect the current time. The line

y = states[k]

sets the object y to 𝑦𝑘+1. For the backward difference in the implicit Euler method, we also need 𝑦𝑘 which we defineby the if condition

if k == 0:y_prev = Function(V)

(continues on next page)

38 Chapter 3. Tutorial

Page 43: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

(continued from previous page)

else:y_prev = states[k - 1]

which ensures that 𝑦0 = 0, which corresponds to the initial condition 𝑦(0) = 0. Hence, y_prev indeed corresponds to𝑦𝑘. Moreover, we get the current control and adjoint state via

p = adjoints[k]u = controls[k]

This allow us to define the state equation at time t as

state_eq = Constant(1/dt)*(y - y_prev)*p*dx + inner(grad(y), grad(p))*dx - u*p*dx

This is then appended to the list of state constraints

e.append(state_eq)

Further, we also put the current desired state into the respective list, i.e.,

y_d.append(interpolate(y_d_expr, V))

Finally, we can define the k-th summand of the cost functional via

J_list.append(Constant(0.5*dt) * (y - y_d[k]) * (y - y_d[k]) * dx + Constant(0.5 * dt *→˓alpha) * u * u * dx)

and directly append this to the cost functional list.

To sum up over all elements of this list, cashocs includes the function cashocs.utils.summation(), which we call

J = cashocs.utils.summation(J_list)

Finally, we can define an optimal control problem as before, and solve it as in the previous demos (see, e.g., DistributedControl of a Poisson Problem)

ocp = cashocs.OptimalControlProblem(e, bcs_list, J, states, controls, adjoints, config)ocp.solve()

For a postprocessing, which visualizes the resulting optimal control and optimal state, the following lines are added atthe end

u_file = File('./visualization/u.pvd')y_file = File('./visualization/y.pvd')temp_u = Function(V)temp_y = Function(V)

for k in range(len(t_array)):t = t_array[k]

temp_u.vector()[:] = controls[k].vector()[:]u_file << temp_u, t

temp_y.vector()[:] = states[k].vector()[:]y_file << temp_y, t

3.1. Optimal Control Problems 39

Page 44: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

which saves the result in the directory ./visualization/ as paraview .pvd files.

3.1.10 Optimal Control with Nonlinear PDE Constraints

Problem Formulation

In this demo, we take a look at the case of nonlinear PDE constraints for optimization problems. As a model problem,we consider

min 𝐽(𝑦, 𝑢) =1

2

∫Ω

(𝑦 − 𝑦𝑑)2 d𝑥 +

𝛼

2

∫Ω

𝑢2 d𝑥

subject to

−∆𝑦 + 𝑐𝑦3 = 𝑢 in Ω,

𝑦 = 0 on Γ.

As this problem has a nonlinear PDE as state constraint, we have to modify the config file slightly. In particular, in theSection StateSystem we have to write

is_linear = False

Note, that is_linear = False works for any problem, as linear equations are just a special case of nonlinear ones,and the corresponding nonlinear solver converges in a single iteration for these. However, in the opposite case, FEniCSwill raise an error, so that an actually nonlinear equation cannot be solved using is_linear = True. Also, we brieflyrecall from Documentation of the Config Files for Optimal Control Problems, that the default behavior is is_linear= False, so that this is not an issue.

Implementation

The complete python code can be found in the file demo_nonlinear_pdes.py, and the corresponding config can befound in config.ini.

Initialization

Thanks to the high level interface for implementing weak formulations, this problem is tackled almost as easily as theone in Distributed Control of a Poisson Problem. In particular, the entire initialization, up to the definition of the weakform of the PDE constraint, is identical, and we have

from fenics import *import cashocs

config = cashocs.load_config('config.ini')mesh, subdomains, boundaries, dx, ds, dS = cashocs.regular_mesh(25)V = FunctionSpace(mesh, 'CG', 1)

y = Function(V)p = Function(V)u = Function(V)

For the definition of the state constraints, we use essentially the same syntax as we would use for the problem in FEniCS,i.e., we write

40 Chapter 3. Tutorial

Page 45: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

c = Constant(1e2)e = inner(grad(y), grad(p))*dx + c*pow(y, 3)*p*dx - u*p*dx

Note: In particular, the only difference between the cashocs implementation of this weak form and the FEniCS oneis that, as before, we use fenics.Function objects for both the state and adjoint variables, whereas we would usefenics.Function objects for the state, and fenics.TestFunction for the adjoint variable, which would actuallyplay the role of the test function. Other than that, the syntax is, again, identical to the one of FEniCS.

Finally, the boundary conditions are defined as before

bcs = cashocs.create_dirichlet_bcs(V, Constant(0), boundaries, [1, 2, 3, 4])

Solution of the optimization problem

To define and solve the optimization problem, we now proceed exactly as in Distributed Control of a Poisson Problem,and use

y_d = Expression('sin(2*pi*x[0])*sin(2*pi*x[1])', degree=1)alpha = 1e-6J = Constant(0.5)*(y - y_d)*(y - y_d)*dx + Constant(0.5*alpha)*u*u*dx

ocp = cashocs.OptimalControlProblem(e, bcs, J, y, u, p, config)ocp.solve()

The results looks like this

3.1.11 Dirichlet Boundary Control

Problem Formulation

In this demo, we investigate how Dirichlet boundary control is possible with cashocs. To do this, we have to employthe so-called Nitsche method, which we briefly recall in the following. Our model problem for this example is givenby

min 𝐽(𝑦, 𝑢) =1

2

∫Ω

(𝑦 − 𝑦𝑑)2 d𝑥 +

𝛼

2

∫Γ

𝑢2 d𝑠

subject to

−∆𝑦 = 0 in Ω,

𝑦 = 𝑢 on Γ.

3.1. Optimal Control Problems 41

Page 46: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

In contrast to our previous problems, the control now enters the problem via a Dirichlet boundary condition. However,we cannot apply these via a fenics.DirichletBC, because for cashocs to work properly, the controls, states, and ad-joints are only allowed to appear in UFL forms. Nitsche’s Method circumvents this problem by imposing the boundaryconditions in the weak form directly. Let us first briefly recall this method.

Nitsche’s method

Consider the Laplace problem

−∆𝑦 = 0 in Ω,

𝑦 = 𝑢 on Γ.

We can derive a weak form for this equation in 𝐻1(Ω) (not 𝐻10 (Ω)) by multiplying the equation by a test function

𝑝 ∈ 𝐻1(Ω) and applying the divergence theorem∫Ω

−∆𝑦𝑝 d𝑥 =

∫Ω

∇𝑦 · ∇𝑝 d𝑥−∫Γ

(∇𝑦 · 𝑛)𝑝 d𝑠.

This weak form is the starting point for Nitsche’s method. First of all, observe that this weak form is not symmetricanymore. To restore symmetry of the problem, we can use the Dirichlet boundary condition and “add a zero” by adding∫Γ∇𝑝 · 𝑛(𝑦 − 𝑢) d𝑠. This gives the weak form∫

Ω

∇𝑦 · ∇𝑝 d𝑥−∫Γ

(∇𝑦 · 𝑛)𝑝 d𝑠−∫Γ

(∇𝑝 · 𝑛)𝑦 d𝑠 =

∫Γ

(∇𝑝 · 𝑛)𝑢 d𝑠.

However, one can show that this weak form is not coercive. Hence, Nitsche’s method adds another zero to this weakform, namely

∫Γ𝜂(𝑦−𝑢)𝑝 d𝑠, which yields the coercivity of the problem if 𝜂 is sufficiently large. Hence, we consider

the following weak form∫Ω

∇𝑦 · ∇𝑝 d𝑥−∫Γ

(∇𝑦 · 𝑛)𝑝 d𝑠−∫Γ

(∇𝑝 · 𝑛)𝑦 d𝑠 + 𝜂

∫Γ

𝑦𝑝 d𝑠 =

∫Γ

(∇𝑝 · 𝑛)𝑢 d𝑠 + 𝜂

∫Γ

𝑢𝑝 d𝑠,

and this is the form we implement for this problem.

For a detailed introduction to Nitsche’s method, we refer to Assous and Michaeli, A numerical method for handlingboundary and transmission conditions in some linear partial differential equations.

Note: To ensure convergence of the method when the mesh is refined, the parameter 𝜂 is scaled in dependence withthe mesh size. In particular, we use a scaling of the form

𝜂 =𝜂

ℎ,

where ℎ is the diameter of the current mesh element.

Implementation

The complete python code can be found in the file demo_dirichlet_control.py, and the corresponding config canbe found in config.ini.

42 Chapter 3. Tutorial

Page 47: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Initialization

The beginning of the program is nearly the same as for Distributed Control of a Poisson Problem

from fenics import *import cashocsimport numpy as np

config = cashocs.load_config('config.ini')mesh, subdomains, boundaries, dx, ds, dS = cashocs.regular_mesh(25)n = FacetNormal(mesh)h = MaxCellEdgeLength(mesh)V = FunctionSpace(mesh, 'CG', 1)

y = Function(V)p = Function(V)u = Function(V)

The only difference is, that we now also define n, which is the outer unit normal vector on Γ, and h, which is themaximum length of an edge of the respective finite element (during assemly).

Then, we define the Dirichlet boundary conditions, which are enforced strongly. As we use Nitsche’s method to imple-ment the boundary conditions on the entire boundary, there are no strongly enforced ones left, and we define

bcs = []

Hint: Alternatively, we could have also written

bcs = None

which yields exactly the same result, i.e., no strongly enforced Dirichlet boundary conditions.

Definition of the PDE and optimization problem via Nitsche’s method

Afterwards, we implement the weak form using Nitsche’s method, as described above, which is given by the codesegment

eta = Constant(1e4)e = inner(grad(y), grad(p))*dx - inner(grad(y), n)*p*ds - inner(grad(p), n)*(y - u)*ds +→˓eta/h*(y - u)*p*ds - Constant(1)*p*dx

Finally, we can define the optimization problem similarly to Neumann Boundary Control

y_d = Expression('sin(2*pi*x[0])*sin(2*pi*x[1])', degree=1)alpha = 1e-4J = Constant(0.5)*(y - y_d)*(y - y_d)*dx + Constant(0.5*alpha)*u*u*ds

As for Neumann Boundary Control, we have to define a scalar product on 𝐿2(Γ) to get meaningful results (as thecontrol is only defined on the boundary), which we do with

3.1. Optimal Control Problems 43

Page 48: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

scalar_product = TrialFunction(V)*TestFunction(V)*ds

Solution of the optimization problem

The optimal control problem is solved with the usual syntax

ocp = cashocs.OptimalControlProblem(e, bcs, J, y, u, p, config, riesz_scalar_→˓products=scalar_product)ocp.solve()

The result should look like this

Note: In the end, we validate whether the boundary conditions are applied correctly using this approach. Therefore,we first compute the indices of all DOF’s that lie on the boundary via

bcs = cashocs.create_dirichlet_bcs(V, 1, boundaries, [1,2,3,4])bdry_idx = Function(V)[bc.apply(bdry_idx.vector()) for bc in bcs]mask = np.where(bdry_idx.vector()[:] == 1)[0]

Then, we restrict both y and u to the boundary by

y_bdry = Function(V)u_bdry = Function(V)y_bdry.vector()[mask] = y.vector()[mask]u_bdry.vector()[mask] = u.vector()[mask]

Finally, we compute the relative errors in the 𝐿∞(Γ) and 𝐿2(Γ) norms and print the result

error_inf = np.max(np.abs(y_bdry.vector()[:] - u_bdry.vector()[:])) / np.max(np.abs(u_→˓bdry.vector()[:])) * 100error_l2 = np.sqrt(assemble((y - u)*(y - u)*ds)) / np.sqrt(assemble(u*u*ds)) * 100

print('Error regarding the (weak) imposition of the boundary values')print('Error L^\infty: ' + format(error_inf, '.3e') + ' %')print('Error L^2: ' + format(error_l2, '.3e') + ' %')

We see, that with eta = 1e4 we get a relative error of under 5e-3 % in the 𝐿∞(Ω) norm, and under 5e-4 in the 𝐿2(Ω)norm, which is sufficient for applications.

44 Chapter 3. Tutorial

Page 49: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

3.1.12 Iterative Solvers for State and Adjoint Systems

Problem Formulation

cashocs is also capable of using iterative solvers through the linear algebra backend PETSc. In this demo we showhow this can be used. For the sake of simplicitiy, we consider the same setting as in Distributed Control of a PoissonProblem, i.e.

min 𝐽(𝑦, 𝑢) =1

2

∫Ω

(𝑦 − 𝑦𝑑)2 d𝑥 +

𝛼

2

∫Ω

𝑢2 d𝑥

subject to

−∆𝑦 = 𝑢 in Ω,

𝑦 = 0 on Γ.

(see, e.g., Tröltzsch, Optimal Control of Partial Differential Equations or Hinze, Pinnau, Ulbrich, and Ulbrich, Opti-mization with PDE constraints.

It is well-known, that the state problem, when discretized using a classical, conforming Ritz-Galerkin method, givesrise to a linear system with a symmetric and positive definite Matrix. We use these properties in this demo by solvingthe state system with the conjugate gradient method. Moreover, the adjoint system is also a Poisson problem withright-hand side 𝑦 − 𝑦𝑑, and so also gives rise to a symmetric and positive definite system, for which we also employiterative solvers.

Implementation

The complete python code can be found in the file demo_iterative_solvers.py, and the corresponding config canbe found in config.ini.

Initialization

The initialization works exactly as in Distributed Control of a Poisson Problem

from fenics import *import cashocs

config = cashocs.load_config('config.ini')mesh, subdomains, boundaries, dx, ds, dS = cashocs.regular_mesh(50)V = FunctionSpace(mesh, 'CG', 1)

y = Function(V)p = Function(V)u = Function(V)

e = inner(grad(y), grad(p))*dx - u*p*dxbcs = cashocs.create_dirichlet_bcs(V, Constant(0), boundaries, [1, 2, 3, 4])

3.1. Optimal Control Problems 45

Page 50: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Definition of the iterative solvers

The options for the state and adjoint systems are defined as follows. For the state system we have

ksp_options = [['ksp_type', 'cg'],['pc_type', 'hypre'],['pc_hypre_type', 'boomeramg'],['ksp_rtol', 1e-10],['ksp_atol', 1e-13],['ksp_max_it', 100],

]

This is a list of lists, where the inner ones have either 1 or 2 entries, which correspond to the command line options forPETSc. For a detailed documentation of the possibilities, we refer to the PETSc documentation. Of particular interestare the pages for the Krylov solvers and Preconditioners. The relevant options for the command line are describedunder “Options Database Keys”.

Note: For example, the first command

['ksp_type', 'cg'],

can be found in KSPSetType, and the corresponding options are shown under KSPTYPE. Here, we see that the aboveline corresponds to using the conjugate gradient method as krylov solver. The following two lines

['pc_type', 'hypre'],['pc_hypre_type', 'boomeramg'],

specify that we use the algebraic multigrid preconditioner BOOMERAMG from HYPRE. This is documented in PC-SetType, PCTYPE, and PCHYPRETYPE. Finally, the last three lines

['ksp_rtol', '1e-10'],['ksp_atol', '1e-13'],['ksp_max_it', 100],

specify that we use a relative tolerance of 1e-10, an absolute one of 1e-13, and at most 100 iterations for each solve ofthe linear system, cf. KSPSetTolerances.

Coming from the first optimize, then discretize view point, it is not required that the adjoint system should be solvedexactly the same as the state system. This is why we can also define PETSc options for the adjoint system, which wedo with

adjoint_ksp_options = [['ksp_type', 'minres'],['pc_type', 'icc'],['pc_factor_levels', 0],['ksp_rtol', 1e-6],['ksp_atol', 1e-15],

]

As can be seen, we now use a completely different solver, namely MINRES (the minimal residual method) with an ICC(incomplete Cholesky factorization) preconditioner with zero levels of fill, i.e., it uses the sparsity pattern of the systemmatrix. Finally, the tolerances for the adjoint solver can also be rather different from the ones of the state system, as isshown here.

46 Chapter 3. Tutorial

Page 51: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Hint: To verify that the options indeed are used, one can supply the option

['ksp_view'],

which shows the detailed settings of the solvers, and also

['ksp_monitor_true_residual'],

which prints the residual of the method over its iterations.

For multiple state and adjoint systems, one can proceed analogously to Using Multiple Variables and PDEs, and onehas to create a such a list of options for each component, and then put them into an additional list.

With these definitions, we can now proceed as in Distributed Control of a Poisson Problem and solve the optimizationproblem with

y_d = Expression('sin(2*pi*x[0])*sin(2*pi*x[1])', degree=1)alpha = 1e-6J = Constant(0.5)*(y - y_d)*(y - y_d)*dx + Constant(0.5*alpha)*u*u*dx

ocp = cashocs.OptimalControlProblem(e, bcs, J, y, u, p, config, ksp_options=ksp_options,→˓adjoint_ksp_options=adjoint_ksp_options)ocp.solve()

Note: Note, that if the ksp_options and adjoint_ksp_options are not passed to the OptimalControlProblemor None, which is the default value of these keyword parameters, then the direct solver MUMPS is used. Moreover, ifone wants to use identical options for state and adjoint systems, then only the ksp_options have to be passed. Thisis because of the fact that adjoint_ksp_options always mirrors the ksp_options in case that the input is None foradjoint_ksp_options.

The result of the optimization looks very much like that of Distributed Control of a Poisson Problem

3.1. Optimal Control Problems 47

Page 52: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

3.1.13 Optimal Control with State Constraints

Problem Formulation

In this demo we investigate how state constraints can be handled in cashocs. Thanks to the high level interface forsolving (control-constrained) optimal control problems, the state constrained case can be treated (approximately) usinga Moreau-Yosida regularization, which we show in the following. As model problem, we consider the following one

min 𝐽(𝑦, 𝑢) =1

2

∫Ω

(𝑦 − 𝑦𝑑)2 d𝑥 +

𝛼

2

∫Ω

𝑢2 d𝑥

subject to

⎧⎪⎨⎪⎩−∆𝑦 = 𝑢 in Ω,

𝑦 = 0 on Γ,

𝑦 ≤ 𝑦 in Ω,

see, e.g., Hinze, Pinnau, Ulbrich, and Ulbrich, Optimization with PDE constraints.

Moreau-Yosida regularization

Instead of solving this problem directly, the Moreau-Yosida regularization instead solves a sequence of problems with-out state constraints which are of the form

min 𝐽𝛾(𝑦, 𝑢) =1

2

∫Ω

(𝑦 − 𝑦𝑑)2 d𝑥 +

𝛼

2

∫Ω

𝑢2 d𝑥 +1

2𝛾

∫Ω

|max (0, + 𝛾(𝑦 − 𝑦))|2 d𝑥

for 𝛾 → +∞. We employ a simple homotopy method, and solve the problem for one value of 𝛾, and then use thissolution as initial guess for the next higher value of 𝛾. As initial guess we use the solution of the unconstrained problem.For a detailed discussion of the Moreau-Yosida regularization, we refer the reader to, e.g., Hinze, Pinnau, Ulbrich, andUlbrich, Optimization with PDE constraints.

Implementation

The complete python code can be found in the file demo_state_constraints.py, and the corresponding config canbe found in config.ini.

The initial guess for the homotopy

As mentioned earlier, we first solve the unconstrained problem to get an initial guess for the homotopy method. This isdone in complete analogy to Distributed Control of a Poisson Problem

from fenics import *import cashocsimport numpy as npfrom ufl import Max

config = cashocs.load_config('config.ini')mesh, subdomains, boundaries, dx, ds, dS = cashocs.regular_mesh(25)V = FunctionSpace(mesh, 'CG', 1)

y = Function(V)p = Function(V)

(continues on next page)

48 Chapter 3. Tutorial

Page 53: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

(continued from previous page)

u = Function(V)

e = inner(grad(y), grad(p))*dx - u*p*dxbcs = cashocs.create_dirichlet_bcs(V, Constant(0), boundaries, [1, 2, 3, 4])

y_d = Expression('sin(2*pi*x[0]*x[1])', degree=1)alpha = 1e-3J_init = Constant(0.5)*(y - y_d)*(y - y_d)*dx + Constant(0.5*alpha)*u*u*dxocp_init = cashocs.OptimalControlProblem(e, bcs, J_init, y, u, p, config)ocp_init.solve()

Note: Cashocs automatically updates the user input during the runtime of the optimization algorithm. Hence, afterthe ocp_init.solve() command has returned, the solution is already stored in u.

The regularized problems

For the homotopy method with the Moreau-Yosida regularization, we first define the upper bound for the state 𝑦 andselect a sequence of values for 𝛾 via

y_bar = 1e-1gammas = [pow(10, i) for i in np.arange(1, 9, 3)]

Solving the regularized problems is then as simple as writing a for loop

for gamma in gammas:

J = J_init + cashocs.moreau_yosida_regularization(y, gamma, dx, upper_treshold=y_bar

)

ocp_gamma = cashocs.OptimalControlProblem(e, bcs, J, y, u, p, config)ocp_gamma.solve()

Here, we use a for loop, define the new cost functional (with the new value of 𝛾), set up the optimal control problemand solve it, as previously.

Hint: Note, that we could have also defined y_bar as a fenics.Function or fenics.Expression, and the methodwould have worked exactly the same, the corresponding object just has to be a valid input for an UFL form.

Note: We could have also defined the Moreau-Yosida regularization of the inequality constraint directly, with thefollowing code

J = (J_init+ Constant(1 / (2 * gamma)) * pow(Max(0, Constant(gamma) * (y - y_bar)), 2) * dx

)

3.1. Optimal Control Problems 49

Page 54: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

However, this is directly implemented in cashocs.moreau_yosida_regularization(), which is why we use thisfunction in the demo.

Validation of the method

Finally, we perform a post processing to see whether the state constraint is (approximately) satisfied. Therefore, wecompute the maximum value of y, and compute the relative error between this and y_bar

y_max = np.max(y.vector()[:])error = abs(y_max - y_bar) / abs(y_bar) * 100print('Maximum value of y: ' + str(y_max))print('Relative error between y_max and y_bar: ' + str(error) + ' %')

As the error is about 0.01 %, we observe that the regularization indeed works as expected, and this tolerance is suffi-ciently low for practical applications.

The visualization of the solution looks as follows

3.1.14 Sparse Control

In this demo, we investigate a possibility for obtaining sparse optimal controls. To do so, we use a sparsity promoting𝐿1 regularization. Hence, our model problem for this demo is given by

min 𝐽(𝑦, 𝑢) =1

2

∫Ω

(𝑦 − 𝑦𝑑)2 d𝑥 +

𝛼

2

∫Ω

|𝑢| d𝑥

subject to

−∆𝑦 = 𝑢 in Ω,

𝑦 = 0 on Γ.

This is basically the same problem as in Distributed Control of a Poisson Problem, but the regularization is now notthe 𝐿2 norm squared, but just the 𝐿1 norm.

50 Chapter 3. Tutorial

Page 55: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Implementation

The complete python code can be found in the file demo_sparse_control.py, and the corresponding config can befound in config.ini.

The implementation of this problem is completely analogous to the one of Distributed Control of a Poisson Problem,the only difference is the definition of the cost functional. We state the entire code in the following. The only differencebetween this implementation and the one of Distributed Control of a Poisson Problem is in line 18, and is highlightedhere.

1 from fenics import *2 import cashocs3

4

5 config = cashocs.load_config('config.ini')6 mesh, subdomains, boundaries, dx, ds, dS = cashocs.regular_mesh(25)7 V = FunctionSpace(mesh, 'CG', 1)8

9 y = Function(V)10 p = Function(V)11 u = Function(V)12

13 e = inner(grad(y), grad(p))*dx - u*p*dx14 bcs = cashocs.create_dirichlet_bcs(V, Constant(0), boundaries, [1, 2, 3, 4])15

16 y_d = Expression('sin(2*pi*x[0])*sin(2*pi*x[1])', degree=1)17 alpha = 1e-418 J = Constant(0.5)*(y - y_d)*(y - y_d)*dx + Constant(0.5*alpha)*abs(u)*dx19

20 ocp = cashocs.OptimalControlProblem(e, bcs, J, y, u, p, config)21 ocp.solve()

Note, that for the regularization term we now do not use Constant(0.5*alpha)*u*u*dx, which corresponds to the𝐿2(Ω) norm squared, but rather

Constant(0.5*alpha)*abs(u)*dx

which corresponds to the 𝐿1(Ω) norm. Other than that, the code is identical. The visualization of the code also shows,that we have indeed a sparse control

Note: The oscillations in between the peaks for the control variable u are just numerical noise, which comes from the

3.1. Optimal Control Problems 51

Page 56: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

discretization error.

3.1.15 Tracking of the Cost Functional for Optimal Control Problems

Problem Formulation

In this demo we investigate cashocs functionality of tracking scalar-type terms such as cost functional values and otherquanitites, which typically arise after integration. For this, we investigate the problem

min 𝐽(𝑦, 𝑢) =1

2

∫Ω

𝑦2 d𝑥− 𝐶𝑑𝑒𝑠

2subject to

−∆𝑦 = 𝑢 in Ω,

𝑦 = 0 on Γ.

For this example, we do not consider control constraints, but search for an optimal control u in the entire space 𝐿2(Ω),for the sake of simplicitiy. For the domain under consideration, we use the unit square Ω = (0, 1)2, since this is builtinto cashocs.

In the following, we will describe how to solve this problem using cashocs. Moreover, we also detail alternative /equivalent FEniCS code which could be used to define the problem instead.

Implementation

The complete python code can be found in the file demo_scalar_control_tracking.py, and the correspondingconfig can be found in config.ini.

The state problem

The difference to Distributed Control of a Poisson Problem is that the cost functional does now track the value of the 𝐿2

norm of 𝑦 against a desired value of 𝐶𝑑𝑒𝑠, and not the state 𝑦 itself. Other than that, the corresponding PDE constraintand its setup are completely analogous to Distributed Control of a Poisson Problem

from fenics import *

import cashocs

cashocs.set_log_level(cashocs.LogLevel.INFO)config = cashocs.load_config('config.ini')mesh, subdomains, boundaries, dx, ds, dS = cashocs.regular_mesh(25)V = FunctionSpace(mesh, 'CG', 1)

y = Function(V)p = Function(V)u = Function(V)u.vector()[:] = 1.0

e = inner(grad(y), grad(p))*dx - u*p*dx

bcs = cashocs.create_dirichlet_bcs(V, Constant(0), boundaries, [1, 2, 3, 4])

52 Chapter 3. Tutorial

Page 57: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Definition of the scalar tracking type cost functional

Next, we define the cost functional. To do this in cashocs, we first have to set the usual cost functional to 0 by writingthe line

J = Constant(0)*dx

This ensures that only the other terms will be active

Note: In case J is not defined as Constant(0)*dx but, e.g., like in Distributed Control of a Poisson Problem, theterms will be added on top of each other.

To define the desired tracking type functional, note that cashocs implements the functional for the following kind ofcost functionals

𝐽𝑣𝑜𝑙(𝑦, 𝑢) =1

2

∫Ω

𝑓(𝑦, 𝑢) d𝑥− 𝐶𝑑𝑒𝑠

2𝐽𝑠𝑢𝑟𝑓(𝑦, 𝑢) =

1

2

∫Γ

𝑔(𝑦, 𝑢) d𝑠−𝐷𝑑𝑒𝑠

2Of course, also integrals over interior boundaries could be considered, or integrals over only a subset of Ω or Γ. Touniquely define these cost functionals, we only need to define the integrands, i.e.,

𝑓(𝑦, 𝑢) and 𝑔(𝑦, 𝑢)

as well as the goals of the tracking type functionals, i.e.,

𝐶𝑑𝑒𝑠 and 𝐷𝑑𝑒𝑠.

We do this by defining a python dictionary, which includes these terms with the keywords 'integrand' and'tracking_goal'. For our model problem, the integrand is given by 𝑦2 d𝑥, which is defined in FEniCS via theline

integrand = y*y*dx

For the desired value of the (squared) norm of 𝑦 we use the value 1.0, i.e., we define

tracking_goal = 1.0

This is then put into a dictionary as follows

J_tracking = 'integrand' : integrand, 'tracking_goal' : tracking_goal

Note: We could also prescribe a list of multiple dicts of this type. In this case, each of the corresponding trackingtype terms will be added up.

Note: The factor in front of the quadratic term can also be adapted, by using the keyword weight in the integrand andsupplying the desired factor. Note, that the default factor is 0.5, and that each weight defined in the dictionary will bemultiplied by this value.

Finally, we can set up our new optimization problem as we already know, but we now use the keyword argument

3.1. Optimal Control Problems 53

Page 58: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

scalar_tracking_forms = J_tracking

to specify the correct cost functional for our problem. As usual, this is then solved with the solve method of theoptimization problem.

Finally, we visualize the results using matplotlib and the following code

import matplotlib.pyplot as pltplt.figure(figsize=(10,5))

plt.subplot(1, 2, 1)fig = plot(u)plt.colorbar(fig, fraction=0.046, pad=0.04)plt.title('Control variable u')

plt.subplot(1,2,2)fig = plot(y)plt.colorbar(fig, fraction=0.046, pad=0.04)plt.title('State variable y')

plt.tight_layout()

The output should look like this

54 Chapter 3. Tutorial

Page 59: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

3.2 Shape Optimization Problems

In this part of the tutorial, we investigate how shape optimization problems can be treated with cashocs.

3.2.1 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 investigatethe following one from Etling, Herzog, Loayza, Wachsmuth, First and Second Order Shape Optimization Based onRestricted Mesh Deformations

minΩ

𝐽(𝑢,Ω) =

∫Ω

𝑢 d𝑥

subject to

−∆𝑢 = 𝑓 in Ω,

𝑢 = 0 on Γ.

For the initial domain, we use the unit disc Ω = 𝑥 ∈ R2 | ||𝑥||2 < 1, and the right-hand side 𝑓 is given by

𝑓(𝑥) = 2.5(𝑥1 + 0.4 − 𝑥2

2

)2+ 𝑥2

1 + 𝑥22 − 1.

Implementation

The complete python code can be found in the file demo_shape_poisson.py, and the corresponding config can befound 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. Adetailed discussion of the config files for shape optimization is given in Documentation of the Config Files for ShapeOptimization Problems. We read the config file with the load_config command

config = cashocs.load_config('./config.ini')

Next, we have to define the mesh. As the above problem is posed on the unit disc initially, we define this via FEniCScommands (cashocs only has rectangular meshes built in). This is done via the following code

meshlevel = 10degree = 1dim = 2mesh = UnitDiscMesh.create(MPI.comm_world, meshlevel, degree, dim)

3.2. Shape Optimization Problems 55

Page 60: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Next up, we define the fenics.Measure objects, which we need to define the problem. For the volume measure, wecan simply invoke

dx = Measure('dx', mesh)

However, for the surface measure, we need to mark the boundary. This is required since cashocs distinguishes betweenthree types of boundaries: The deformable boundary, the fixed boundary, and boundaries that can only be deformedperpendicular to a certain coordinate axis (see the relevant documentation of the config files). Here, we investigate thecase of a completely deformable boundary, which makes things rather easy. We mark this boundary with the marker 1with the following piece of code

boundary = CompiledSubDomain('on_boundary')boundaries = MeshFunction('size_t', mesh, dim=1)boundary.mark(boundaries, 1)ds = Measure('ds', mesh, subdomain_data=boundaries)

Note: In config.ini, in the section ShapeGradient, there is the line

shape_bdry_def = [1]

which specifies that the boundary marked with 1 is deformable. For our example this is exactly what we want, as thismeans that the entire boundary is variable, due to the previous commands. For a detailed documentation we refer tothe corresponding documentation of the ShapeGradient section.

Note, that all of the alternative ways of marking subdomains or boundaries with numbers, as explained in Langtangenand Logg, Solving PDEs in Python also work here. If it is valid for FEniCS, it is also for cashocs.

After having defined the initial geometry, we define a fenics.FunctionSpace consisting of piecewise linear La-grange elements via

V = FunctionSpace(mesh, 'CG', 1)u = Function(V)p = Function(V)

This also defines our state variable 𝑢 as u, and the adjoint state 𝑝 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*dxbcs = DirichletBC(V, Constant(0), boundaries, 1)

56 Chapter 3. Tutorial

Page 61: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

The optimization problem and its solution

We are now almost done, the only thing left to do is to define the cost functional

J = u*dx

and the shape optimization problem

sop = cashocs.ShapeOptimizationProblem(e, bcs, J, u, p, boundaries, config)

This can then be solved in complete analogy to Distributed Control of a Poisson Problem with the sop.solve()command

sop.solve()

The result of the optimization looks like this

Note: As in Distributed Control of a Poisson Problem we can specify some keyword arguments for the solve com-mand. If none are given, then the settings from the config file are used, but if some are given, they override theparameters 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 documentationof 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. Incase one does not supply a config file, one has to at least specify the solution algorithm in the call to the solve method.

3.2. Shape Optimization Problems 57

Page 62: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

3.2.2 Documentation of the Config Files for Shape Optimization Problems

Let us take a detailed look at the config files for shape optimization problems and discusss the corresponding param-eters. The corresponding config file used for this discussion is config.ini, which is the config file used for ShapeOptimization with a Poisson Problem.

For shape optimization problems, the config file is a lot larger compared to the config files for optimal control. However,several important parameters are shared between both types of optimization problems.

A general config file for shape optimization has the following sections Mesh, StateSystem, OptimizationRoutine, Al-goLBFGS, AlgoCG, ShapeGradient, Regularization, MeshQuality and Output. We go over these sections and eachparameter in them in the following.

As in Documentation of the Config Files for Optimal Control Problems, we refer to the documentation of the config-parser module for a detailed description of how these config files can be structured. Moreover, we remark that cashocshas a default behavior for almost all of these parameters, which is triggered when they are NOT specified in the configfile, and we will discuss this behavior for each parameter in this tutorial. For a summary over all parameters and theirdefault values look at the end of this page.

Section Mesh

The mesh section is, in contrast to the corresponding one for optimal control problems, more important and also hasmore parameters. However, its primary importance is for remeshing, which we cover in Remeshing with cashocs.

As first parameter, we have

mesh_file = ./mesh/mesh.xdmf

This specifies a path to a .xdmf file containing the discretized geometry. For all purposes, cashocs assumes that this.xdmf file was generated via conversion from a GMSH file using the command line command cashocs-convert.

Note, that the corresponding files for the boundaries and subdomains are generated automatically withcashocs-convert, and they will also be read by import_mesh if they are present.

The second parameter in the Mesh section, gmsh_file, is defined via

gmsh_file = ./mesh/mesh.msh

This defines the path to the GMSH .msh file which was used to create the .xdmf file specified in mesh_file. As before,this parameter is only relevant for remeshing purposes, and not needed otherwise.

The next parameter is geo_file, which is the final file we need for remeshing ( and only there). It is also given by apath to a file, in this case to the GMSH .geo file used to generate the gmsh_file. It is specified, .e.g., as

geo_file = ./mesh/mesh.geo

Note: For a detailed discussion of how to use these parameters we refer to Remeshing with cashocs.

Next up is a boolean flag that is used to indicate whether remeshing shall be performed

remesh = False

As the remeshing feature is experimental, we do advise to always try without remeshing. Note, that by default this flagis set to False so that remeshing is disabled.

Finally, we have the boolean flag show_gmsh_output, specified via

58 Chapter 3. Tutorial

Page 63: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

show_gmsh_output = False

This is used to toggle on / off the terminal output of GMSH when it performs a remeshing operation. This can behelpful for debugging purposes. By default, this is set to False.

As stated throughout the Mesh section, these parameters are optional most of the time, and are only really requiredfor remeshing. You can safely leave them out of your config file, and you should not need them, unless you want toperform remeshing.

Section StateSystem

The StateSystem section is in complete analogy to the corresponding one for optimal control problems. For the sakeof completeness, we briefly recall the parameters here, anyway.

The first parameter is is_linear, and can be set as

is_linear = True

This is a boolean flag that indicates whether the state system is linear or not. The default value for this parameter isFalse, as every linear problem can also be interpreted as a nonlinear one.

The next parameters are used to define the tolerances of the Newton solver, in case a nonlinear state system has to besolved

newton_rtol = 1e-11newton_atol = 1e-13

Here, newton_rtol sets the relative, and newton_atol the absolute tolerance for Newton’s method. Their defaultvalues are newton_rtol = 1e-11 and newton_atol = 1e-13.

The next parameter for the Newton iteration is the maximum number of iterations it is allowed to perform before theiteration is cancelled. This is controlled via

newton_iter = 50

which defaults to newton_iter = 50.

The parameter newton_damped, which is set via

newton_damped = True

is a boolean flag, indicating whether a damping strategy should be performed for the Newton method, or whether theclassical Newton-Raphson iteration shall be used. This defaults to True, but for some problems it might be beneficial(and faster) to not use damping.

Additionally, we have the boolean parameter newton_inexact, defined via

newton_inexact = False

which sets up an inexact Newton method for solving nonlinear problems in case this is True. The default is False.

Next, we have the parameter

newton_verbose = False

This is used to toggle the verbose output of the Newton method for the state system. By default this is set to False sothat there is not too much noise in the terminal.

3.2. Shape Optimization Problems 59

Page 64: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

The upcoming parameters are used to define the behavior of a Picard iteration, that may be used if we have multiplevariables.

Note: For a detailed discussion of how to use the Picard iteration to solve a coupled state system, we refer to CoupledProblems - Picard Iteration. Note, that this demo is written for optimal control problems, but the definition of the statesystem can be transferred analogously to shape optimization problems, too.

First, we have a boolean flag, set via

picard_iteration = False

which determines whether the Picard iteration is enabled or not. This defaults to picard_iteration = False, so thatthe Picard solver is disabled by default. The following two parameters determine, analogously to above, the tolerancesfor the Picard iteration

picard_rtol = 1e-10picard_atol = 1e-12

The default values for these parameters are picard_rtol = 1e-10 and picard_atol = 1e-12. Moreover, notethat the tolerances of the Newton solver are adjusted automatically in case a Picard iteration is performedm, so that aninexact Picard iteration is used.

The maximum amout of iterations for the Picard iteration are set with

picard_iter = 10

The default value for this is given by picard_iter = 50.

Finally, we can enable verbose output of the Picard iteration with the following boolean flag

picard_verbose = False

which is set to False by default.

Section OptimizationRoutine

The section OptimizationRoutine also closely resembles the one for optimal control problems. Again, we will take abrief look at all parameters here

The first parameter that can be controlled via the config file is algorithm, which is set via

algorithm = lbfgs

There are three possible choices for this parameter for shape optimization problems, namely

• gd or gradient_descent : A gradient descent method

• cg, conjugate_gradient, ncg, nonlinear_cg : Nonlinear CG methods

• lbfgs or bfgs : limited memory BFGS method.

Thereafter, we specify the tolerances for the optimization algorithm with the parameters

rtol = 5e-3atol = 0.0

60 Chapter 3. Tutorial

Page 65: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Again, rtol denotes the relative, and atol the absolute tolerance, and the defaults for these parameters are given byrtol = 1e-3, and atol = 0.0.

The next parameter is used to control the maximum number of iterations performed by the optimization algorithm. Itis set via

maximum_iterations = 50

and defaults to maximum_iterations = 100.

Next up, we have the initial guess for the step size, which can be determined via

initial_stepsize = 1.0

The default behavior is given by initial_stepsize = 1.0.

The upcoming parameters are used for the Armijo rule

epsilon_armijo = 1e-4beta_armijo = 2

They are used to verify that the condition

𝐽((𝐼 + 𝑡𝒱)Ω) ≤ 𝐽(Ω) + 𝜀Armijo 𝑡 𝑑𝐽(Ω)[𝒱]

holds, and if this is not satisfied, the stepsize is updated via 𝑡 = 𝑡𝛽Armijo

. As default values for these parameters we useepsilon_armijo = 1e-4 as well as beta_armijo = 2.

The following parameter, soft_exit, is a boolean flag which determines how the optimization algorithm is terminatedin case it does not converge. If soft_exit = True, then an error message is printed, but code after the solve callof the optimization problem will still be executed. However, when soft_exit = False, cashocs raises an exceptionand terminates. This is set via

soft_exit = False

and is set to False by default.

Section AlgoLBFGS

Next, we discuss the parameters relevant for the limited memory BFGS method. For details regarding this method, werefer to Schulz, Siebenborn, and Welker, Efficient PDE Constrained Shape Optimization Based on Steklov-Poincaré-Type Metrics, where the methods are introduced.

The first parameter, bfgs_memory_size, determines how large the storage of the BFGS method is. It is set via

bfgs_memory_size = 3

Usually, a higher storage leads to a better Hessian approximation, and thus to faster convergence. However, thisalso leads to an increased memory usage. Typically, values below 5 already work very well. The default isbfgs_memory_size = 5.

The other parameter for the BFGS method is

use_bfgs_scaling = True

This determines, whether one should use a scaling of the initial Hessian approximation (see Nocedal and Wright,Numerical Optimization). This is usually very beneficial and should be kept enabled (which is the default).

3.2. Shape Optimization Problems 61

Page 66: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Section AlgoCG

The following parameters are used to define the behavior of the nonlinear conjugate gradient methods for shape opti-mization. For more details on this, we refer to the preprint Blauth, Nonlinear Conjugate Gradient Methods for PDEConstrained Shape Optimization Based on Steklov-Poincaré-Type Metrics.

First, we define which nonlinear CG method is used by

cg_method = DY

Available options are

• FR : The Fletcher-Reeves method

• PR : The Polak-Ribiere method

• HS : The Hestenes-Stiefel method

• DY : The Dai-Yuan method

• HZ : The Hager-Zhang method

The default value is cg_method = FR. As for optimal control problems, the subsequent parameters are used to definethe restart behavior of the nonlinear CG methods. First, we have

cg_periodic_restart = False

This boolean flag en- or disables that the NCG methods are restarted after a fixed amount of iterations, which is specifiedvia

cg_periodic_its = 5

i.e., if cg_periodic_restart = True and cg_periodic_its = n, then the NCG method is restarted every n iter-ations. The default behavior is given by cg_periodic_restart = False and cg_periodic_its = 10.

Alternatively, there also exists a relative restart criterion (see Nocedal and Wright, Numerical Optimization), whichcan be enabled via the boolean flag cg_relative_restart, which is defined in the line

cg_relative_restart = False

and the corresponding restart tolerance is set in

cg_restart_tol = 0.5

Note, that cg_restart_tol should be in (0, 1). If two subsequent gradients generated by the nonlinear CG methodare not “sufficiently orthogonal”, the method is restarted with a gradient step. The default behavior is given bycg_relative_restart = False and cg_restart_tol = 0.25.

Section ShapeGradient

After we have specified the behavior of the solution algorithm, this section is used to specify parameters relevant to thecomputation of the shape gradient. Note, that by shape gradient we refer to the following object.

Let 𝒮 ⊂ Ω | Ω ⊂ R𝑑 be a subset of the power set of R𝑑. Let 𝐽 be a shape differentiable functional 𝐽 : 𝒮 → R withshape derivative 𝑑𝐽(Ω)[𝒱]. Moreover, let 𝑎 : 𝐻 ×𝐻 → R be a symmetric, continuous, and coercive bilinear form onthe Hilbert space 𝐻 . Then, the shape gradient 𝒢 of 𝐽 (w.r.t. 𝑎) is defined as the solution of the problem

Find 𝒢 ∈ 𝐻 such that𝑎(𝒢,𝒱) = 𝑑𝐽(Ω)[𝒱].

62 Chapter 3. Tutorial

Page 67: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

For PDE constrained shape optimization, it is common to use a bilinear form based on the linear elasticity equations,which enables smooth mesh deformations. This bilinear form is given as follows, in a general form, that is also imple-mented in cashocs

𝑎 : 𝐻 ×𝐻; 𝑎(𝒲,𝒱) =

∫Ω

2𝜇 (𝜀(𝒲) : 𝜀(𝒱)) + 𝜆 (div(𝒲)div(𝒱)) + 𝛿 (𝑉 ·𝑊 ) d𝑥,

where 𝐻 is some suitable subspace of 𝐻1(Ω)𝑑 and 𝜀(𝒱) = 12 (𝐷𝒱 + 𝐷𝒱⊤) is the symmetric part of the Jacobian.

The subspace property is needed to include certain geometrical constraints of the shape optimization problem, whichfix certain boundaries, into the shape gradient. For a detailed description of this setting we refer to the preprint Blauth,Nonlinear Conjugate Gradient Methods for PDE Constrained Shape Optimization Based on Steklov-Poincaré-TypeMetrics. Moreover, we note that for the second Lamé parameter 𝜇, cashocs implements an idea from Schulz andSiebenborn, Computational Comparison of Surface Metric for PDE Constrained Shape Optimization: There, it isproposed to compute 𝜇 as the solution of the Laplace problem

−∆𝜇 = 0 in Ω,

𝜇 = 𝜇def on Γdef,

𝜇 = 𝜇fix on Γfix.

This allows to give the deformable and fixed boundaries a different stiffness, which is then smoothly extended into theinterior of the domain. Moreover, they propose to use the solution of this Laplace equation directly for 2D problems,and to use √𝜇 for 3D problems.

Moreover, let us take a look at the possible types of boundaries that can be used with cashocs. In principle, thereexist two types: deformable and fixed boundaries. On fixed boundaries, we impose homogeneous Dirichlet boundaryconditions for the shape gradient, so that these are not moved under the corresponding deformation. In cashocs, wedefine what boundaries are fixed and deformable via their markers, which are either defined in the corresponding pythonscript, or in the GMSH file, if such a mesh is imported.

The config file for Shape Optimization with a Poisson Problem defines the deformable boundaries with the command

shape_bdry_def = [1]

Note: Remember, that in Shape Optimization with a Poisson Problem, we defined boundaries with the commands

boundary = CompiledSubDomain('on_boundary')boundaries = MeshFunction('size_t', mesh, dim=1)boundary.mark(boundaries, 1)

Hence, we see that the marker 1 corresponds to the entire boundary, so that this is set to being deformable through theconfig.

As we do not have a fixed boundary for this problem, the corresponding list for the fixed boundaries is empty

shape_bdry_fix = []

Note, that cashocs also gives you the possibility of defining partially constrainted boundaries, where only one axialcomponent is fixed, whereas the other two are not. These are defined in

shape_bdry_fix_x = []shape_bdry_fix_y = []shape_bdry_fix_z = []

For these, we have that shape_bdry_fix_x is a list of all markers whose corresponding boundaries should not bedeformable in x-direction, but can be deformed in the y- and z-directions. Of course you can constrain a boundary tobe only variable in a single direction by adding the markers to the remaining lists.

3.2. Shape Optimization Problems 63

Page 68: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

The next parameter is specified via

use_pull_back = True

This parameter is used to determine, whether the material derivative should be computed for objects that are not stateor adjoint variables. This is enabled by default.

Warning: This parameter should always be set to True, otherwise the shape derivative might be wrong. Onlydisable it when you are sure what you are doing.

Furthermore, note that the material derivative computation is only correct, as long as no differential operators acton objects that are not state or adjoint variables. However, this should only be a minor restriction and not relevantfor almost all problems.

Note: See Inverse Problem in Electric Impedance Tomography for a case, where we use use_pull_back = False.

The next parameters determine the coefficients of the bilinear form 𝑎. First, we have the first Lamé parameter 𝜆, whichis set via

lambda_lame = 1.428571428571429

The default value for this is lambda_lame = 0.0.

Next, we specify the damping parameter 𝛿 with the line

damping_factor = 0.2

The default for this is damping_factor = 0.0.

Note: As the default value for the damping factor is damping_factor = 0.0, this should be set to a positive value incase the entire boundary of a problem is deformable. Otherwise, the Riesz identification problem for the shape gradientis not well-posed.

Finally, we define the values for 𝜇def and 𝜇fix via

mu_fix = 0.35714285714285715mu_def = 0.35714285714285715

The default behavior is given by mu_fix = 1.0 and mu_def = 1.0.

The parameter use_sqrt_mu is a boolean flag, which switches between using 𝜇 and √𝜇 as the stiffness for the linear

elasticity equations, as discussed above. This is set via

use_sqrt_mu = False

and the default value is use_sqrt_mu = False.

The next line in the config file is

inhomogeneous = False

This determines, whether an inhomogeneous linear elasticity equation is used to project the shape gradient. This scalesthe parameters 𝜇, 𝜆 and 𝛿 by 1

vol , where vol is the volume of the current element (during assembly). This means, that

64 Chapter 3. Tutorial

Page 69: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

smaller elements get a higher stiffness, so that the deformation takes place in the larger elements, which can handlelarger deformations without reducing their quality too much. For more details on this approach, we refer to the paperBlauth, Leithäuser, and Pinnau, Model Hierarchy for the Shape Optimization of a Microchannel Cooling System.

Moreover, the parameter

update_inhomogeneous = False

can be used to update the local mesh size after each mesh deformation, in case this is True, so that elements whichbecome smaller also obtain a higher stiffness and vice versa. The default is False.

There is also a different possibility to define the stiffness parameter 𝜇 using cashocs, namely to define 𝜇 in terms ofhow close a point of the computational domain is to a boundary. In the following we will explain this alternative wayof defining 𝜇. To do so, we must first set the boolean parameter

use_distance_mu = True

which enables this formulation and deactivates the previous one. Note that by default, the value of use_distance_muis False. Next, we have the parameters dist_min, dist_max, mu_min and mu_max. These do the following: If thedistance to the boundary is smaller than dist_min, the value of 𝜇 is set to mu_min, and if the distance to the boundaryis larger than dist_max, 𝜇 is set to mu_max. If the distance to the boundary is between dist_min and dist_max, thevalue of 𝜇 is interpolated between mu_min and mu_max. The type of this interpolation is determined by the parameter

smooth_mu = True

If this parameter is set to True, then a smooth, cubic polynomial is used to interplate between mu_min and mu_max,which yields a continuously differentiable 𝜇. If this is set to False, then a linear interpolation is used, which onlyyields a continuous 𝜇. The default for this parameter is False.

Finally, we can specify which boundaries we want to incorporate when computing the distance. To do so, we canspecify a list of indices which contain the boundary markers in the parameter

boundaries_dist = [1,2,3]

This means, that only boundaries marked with 1, 2, and 3 are considered for computing the distance, and all others areignored. The default behavior is that all (outer) boundaries are considered.

There is also another possibility to compute the shape gradient in cashocs, namely using the 𝑝-Laplacian, as proposedby Müller, Kühl, Siebenborn, Deckelnick, Hinze, and Rung. In order to do so, we have the following line

use_p_laplacian = False

If this is set to True, the 𝑝-Laplacian is used to compute the shape gradient, as explained in Shape Optimization withthe p-Laplacian. However, by default this is disabled. The value of 𝑝 which is then used is defined in the next line

p_laplacian_power = 6

which defaults to 2, whenever the parameter is not defined. The higher 𝑝 is chosen, the better the numerical are expectedto be, but the numerical solution of the problem becomes more involved.

Finally, there is the possibility to use a stabilized weak form for the 𝑝-Laplacian operator, where the stabilizationparameter can be defined in the line

p_laplacian_stabilization = 0.0

The default value of this parameter is 0.0. Note, that the parameter should be chosen comparatively small, i.e., signif-icantly smaller than 1.0.

3.2. Shape Optimization Problems 65

Page 70: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Furthermore, we have the parameter fixed_dimensions, which enables us to restrict the shape gradient to specificdimensions. It is set via

fixed_dimensions = []

In case fixed_dimensions == [], there is no restriction on the shape gradient. However, if fixed_dimensions== [i]``, then the i-th component of the shape gradient is set to 0, so that we have no deformation in the i-th coordinatedirection. For example, if fixed_dimensions == [0, 2], we only have a deformation in the y-component of themesh. The default is fixed_dimensions = [].

Section Regularization

In this section, the parameters for shape regularizations are specified. For a detailed discussion of their usage, we referto Regularization for Shape Optimization Problems.

First, we have the parameters factor_volume and target_volume. These are set via the lines

factor_volume = 0.0target_volume = 3.14

They are used to implement the (target) volume regularization term

𝜇vol

2

(∫Ω

1 d𝑥− voldes

)2

Here, 𝜇vol is specified via factor_volume, and voldes is the target volume, specified via target_volume. The defaultbehavior is factor_volume = 0.0 and target_volume = 0.0, so that we do not have a volume regularization.

The next line, i.e.,

use_initial_volume = True

determines the boolean flag use_initial_volume. If this is set to True, then not the value given in target_volumeis used, but instead the volume of the initial geometry is used for voldes.

For the next two types of regularization, namely the (target) surface and (target) barycenter regularization, the syntaxfor specifying the parameters is completely analogous. For the (target) surface regularization we have

factor_surface = 0.0target_surface = 1.0

These parameter are used to implement the regularization term

𝜇surf

2

(∫Γ

1 d𝑠− surfdes

)2

Here, 𝜇surf is determined via factor_surface, and surfdes is determined via target_surface. The default valuesare given by factor_surface = 0.0 and target_surface = 0.0.

As for the volume regularization, the parameter

use_initial_surface = True

determines whether the target surface area is specified via target_surface or if the surface area of the initial geometryshould be used instead. The default behavior is given by use_initial_surface = False.

Next, we have the curvature regularization, which is controlled by the parameter

66 Chapter 3. Tutorial

Page 71: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

factor_curvature = 0.0

This is used to determine the size of 𝜇curv in the regularization term

𝜇curv

2

∫Γ

𝜅2 d𝑠,

where 𝜅 denotes the mean curvature. This regularization term can be used to generate more smooth boundaries and toprevent kinks from occurring.

Finally, we have the (target) barycenter regularization. This is specified via the parameters

factor_barycenter = 0.0target_barycenter = [0.0, 0.0, 0.0]

and implements the term

𝜇bary

2

1

vol(Ω)

∫Ω

𝑥 d𝑥− barydes

2The default behavior is given by factor_barycenter = 0.0 and target_barycenter = [0,0,0], so that we donot have a barycenter regularization.

The flag

use_initial_barycenter = True

again determines, whether barydes is determined via target_barycenter or if the barycenter of the initial geometryshould be used instead. The default behavior is given by use_initial_barycenter = False.

Hint: The object target_barycenter has to be a list. For 2D problems it is also sufficient, if the list only has twoentries, for the 𝑥 and 𝑦 barycenters.

Section MeshQuality

This section details the parameters that influence the quality of the computational mesh. First, we have the lines

volume_change = infangle_change = inf

These parameters are used to specify how much the volume and the angles, respectively, of the mesh elements areallowed to change in a single transformation. In particular, they implement the following criteria (see Etling, Herzog,Loayza, Wachsmuth, First and Second Order Shape Optimization Based on Restricted Mesh Deformations)

1

𝛼≤ det (id + 𝐷𝒱) ≤ 𝛼

||𝐷𝒱||𝐹 ≤ 𝛽.

Here, 𝛼 corresponds to volume_change and 𝛽 corresponds to angle_change, and 𝒱 is the deformation. The defaultbehavior is given by volume_change = inf and angle_change = inf, so that no restrictions are posed. Note,that, e.g., Etling, Herzog, Loayza, Wachsmuth, First and Second Order Shape Optimization Based on Restricted MeshDeformations use the values volume_change = 2.0 and angle_change = 0.3.

The next two parameters are given by

3.2. Shape Optimization Problems 67

Page 72: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

tol_lower = 0.0tol_upper = 1e-15

These parameters specify a kind of interval for the mesh quality. In particular, we have the following situation (notethat the mesh quality is always an element in [0, 1]):

• If the mesh quality is in [tol upper, 1], the mesh is assumed to be “good”, so that finite element solutions ofthe corresponding PDEs are sensible and not influenced by the mesh quality or discretization artifacts.

• If the mesh quality is in [tol lower, tol upper], a kind of breaking point is reached. Here, it is assumed thatthe mesh is sufficiently good so that the solution of the state system is still possible. However, a mesh whosequality is in this interval should not be used anymore to compute the solution of the adjoint system or to computethe shape gradient, as the quality is too poor for this purpose. Usually, this means that the algorithm is terminated,unless remeshing is enabled. In the latter case, remeshing is performed.

• If the mesh quality is in the interval [0, tol lower], the mesh quality is assumed to be so poor, that even thesolution of the state system is not possible anymore. In practice, this can only happen during the Armijo linesearch. Thanks to our previous considerations, we also know that the mesh, that is to be deformed, has at least aquality of tol_lupper, so that this quality might be reached again, if the step size is just decreased sufficientlyoften. This way, it is ensured that the state system is only solved when the mesh quality is larger than tol_lower,so that the corresponding cost functional value is reasonable.

The default behavior is given by tol_lower = 0.0 and tol_upper = 1e-15, so that there are basically no require-ments on the mesh quality.

Finally, the upcoming two parameters specify how exactly the mesh quality is measured. The first one is

measure = condition_number

and determines one of the four mesh quality criteria, as defined in MeshQuality. Available options are

• skewness

• maximum_angle

• radius_ratios

• condition_number

(see MeshQuality for a detailed description). The default value is given by measure = skewness.

Finally, the parameter type determines, whether the minimum quality over all elements (type = min) or the averagequality over all elements (type = avg) shall be used. This is set via

type = min

and defaults to type = min.

Section Output

In this section, the parameters for the output of the algorithm, either in the terminal or as files, are specified. First, wehave the parameter verbose. This is used to toggle the output of the optimization algorithm. It defaults to True andis controlled via

verbose = True

The parameter save_results is a boolean flag, which determines whether a history of the optimization algorithm,including cost functional value, gradient norm, accepted step sizes, and mesh quality, shall be saved to a .json file. Thisdefaults to True, and can be set with

68 Chapter 3. Tutorial

Page 73: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

save_results = False

Moreover, we define the parameter save_txt

save_txt = False

This saves the output of the optimization, which is usually shown in the terminal, to a .txt file, which is human-readable.

The next line in the config file is

save_pvd = False

Here, the parameter save_pvd is set. This is a boolean flag, which can be set to True to enable that cashocs generates.pvd files for the state variables for each iteration the optimization algorithm performs. These are great for visualizingthe steps done by the optimization algorithm, but also need some disc space, so that they are disabled by default. Note,that for visualizing these files, you need Paraview.

The next parameter, save_pvd_adjoint works analogously, and is given in the line

save_pvd_adjoint = False

If this is set to True, cashocs generates .pvd files for the adjoint variables in each iteration of the optimization algorithm.Its main purpose is for debugging.

The next parameter is given by save_pvd_gradient, which is given in the line

save_pvd_gradient = False

This boolean flag ensures that a paraview with the computed shape gradient is saved in result_dir/pvd. The mainpurpose of this is for debugging.

Moreover, we also have the parameter save_mesh that is set via

save_mesh = False

This is used to save the optimized geometry to a GMSH file. The default behavior is given by save_mesh = False.Note, that this is only possible if the input mesh was already generated by GMSH, and specified in the Mesh section ofthe config file. For any other meshes, the underlying mesh is also saved in the .pvd files, so that you can at least alwaysvisualize the optimized geometry.

In the end, we also have, like for optimal control problems, a parameter that specifies where the output is placed, againnamed result_dir, which is given in the config file in the line

result_dir = ./results

As before, this is either a relative or absolute path to the directory where the results should be placed.

Moreover, we have the parameter time_suffix, which adds a suffix to the result directory based on the current time.It is controlled by the line

time_suffix = False

3.2. Shape Optimization Problems 69

Page 74: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Summary

Finally, an overview over all parameters and their default values can be found in the following.

[Mesh]

Parameters Default value Remarksmesh_file Only needed for remeshinggmsh_file Only needed for remeshinggeo_file Only needed for remeshingremesh False if True, remeshing is enabled; this feature is experimental, use with careshow_gmsh_output False if True, shows the output of GMSH during remeshing in the console

[StateSystem]

Parameter Default value Remarksis_linear False using True gives an error for nonlinear problemsnewton_rtol 1e-11 relative tolerance for Newton’s methodnewton_atol 1e-13 absolute tolerance for Newton’s methodnewton_iter 50 maximum iterations for Newton’s methodnewton_damped True if True, damping is enablednewton_inexact False if True, an inexact Newton’s method is usednewton_verbose False True enables verbose output of Newton’s methodpicard_iteration False True enables Picard iteration; only has an effect for multiple variablespicard_rtol 1e-10 relative tolerance for Picard iterationpicard_atol 1e-12 absolute tolerance for Picard iterationpicard_iter 50 maximum iterations for Picard iterationpicard_verbose False True enables verbose output of Picard iteration

[OptimizationRoutine]

Parameter Defaultvalue

Remarks

algorithm has to be specified by the user; see solvertol 1e-3 relative tolerance for the optimization algorithmatol 0.0 absolute tolerance for the optimization algorithmmaximum itera-tions

100 maximum iterations for the optimization algorithm

initial_stepsize 1.0 initial stepsize for the first iteration in the Armijo ruleepsilon_armijo 1e-4beta_armijo 2.0soft_exit False if True, the optimization algorithm does not raise an exception if it did not

converge

70 Chapter 3. Tutorial

Page 75: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

[AlgoLBFGS]

Parameter Defaultvalue

Remarks

bfgs_memory_size 5 memory size of the L-BFGS methoduse_bfgs_scaling True if True, uses a scaled identity mapping as initial guess for the inverse Hessian

[AlgoCG]

Parameter Defaultvalue

Remarks

cg_method FR specifies which nonlinear CG method is usedcg_periodic_restart False if True, enables periodic restart of NCG methodcg_periodic_its 10 specifies, after how many iterations the NCG method is restarted, if applica-

blecg_relative_restart False if True, enables restart of NCG method based on a relative criterioncg_restart_tol 0.25 the tolerance of the relative restart criterion, if applicable

3.2. Shape Optimization Problems 71

Page 76: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

[ShapeGradient]

Parameter Defaultvalue

Remarks

shape_bdry_def [] list of indices for the deformable boundariesshape_bdry_fix [] list of indices for the fixed boundariesshape_bdry_fix_x [] list of indices for boundaries with fixed x valuesshape_bdry_fix_y [] list of indices for boundaries with fixed y valuesshape_bdry_fix_z [] list of indices for boundaries with fixed z valuesuse_pull_back True if False, shape derivative might be wrong; no pull-back for the material derivative

is performed; only use with cautionlambda_lame 0.0 value of the first Lamé parameter for the elasticity equationsdamping_factor 0.0 value of the damping parameter for the elasticity equationsmu_def 1.0 value of the second Lamé parameter on the deformable boundariesmu_fix 1.0 value of the second Lamé parameter on the fixed boundariesuse_sqrt_mu False if True, uses the square root of the computed mu_lame; might be good for 3D

problemsinhomogeneous False if True, uses inhomogeneous elasticity equations, weighted by the local mesh sizeup-date_inhomogeneous

False if True and inhomogeneous=True, then the weighting with the local mesh sizeis updated as the mesh is deformed.

use_distance_mu False if True, the value of the second Lamé parameter is computed via the distance tothe boundary

dist_min 1.0 Specifies the distance to the boundary, until which 𝜇 is given by mu_mindist_max 1.0 Specifies the distance to the boundary, until which 𝜇 is given by mu_maxmu_min 1.0 The value of 𝜇 for a boundary distance smaller than dist_minmu_max 1.0 The value of 𝜇 for a boundary distance larger than dist_maxboundaries_dist [] The indices of the boundaries, which shall be used to compute the distance, []

means that all boundaries are consideredsmooth_mu False If false, a linear (continuous) interpolation between mu_min and mu_max is used,

otherwise a cubic 𝐶1 interpolant is useduse_p_laplacian False If True, then the 𝑝-Laplacian is used to compute the shape gradientp_laplacian_power 2 The parameter 𝑝 of the 𝑝-Laplacianp_laplacian_stabilization0.0 The stabilization parameter for the 𝑝-Laplacian problem. No stabilization is used

when this is 0.0.

72 Chapter 3. Tutorial

Page 77: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

[Regularization]

Parameter Default value Remarksfactor_volume 0.0 value of the regularization parameter for volume regularization; needs to

be non-negativetarget_volume 0.0 prescribed volume for the volume regularizationuse_initial_volume False if True uses the volume of the initial geometry as prescribed volumefactor_surface 0.0 value of the regularization parameter for surface regularization; needs to be

non-negativetarget_surface 0.0 prescribed surface for the surface regularizationuse_initial_surface False if True uses the surface area of the initial geometry as prescribed surfacefactor_curvature 0.0 value of the regularization parameter for curvature regularization; needs to

be non-negativefactor_barycenter 0.0 value of the regularization parameter for barycenter regularization; needs

to be non-negativetarget_barycenter [0.0, 0.0,

0.0]prescribed barycenter for the barycenter regularization

use_initial_barycenterFalse if True uses the barycenter of the initial geometry as prescribed barycenter

[MeshQuality]

Pa-rame-ter

De-faultvalue

Remarks

vol-ume_change

inf determines by what factor the volume of a cell is allowed to change within a single deformation

an-gle_change

inf determines how much the angles of a cell are allowed to change within a single deformation

tol_lower 0.0 if the mesh quality is lower than this tolerance, the state system is not solved for the Armijo rule,instead step size is decreased

tol_upper1e-15 if the mesh quality is between tol_lower and tol_upper, the state system will still be solvedfor the Armijo rule. If the accepted step yields a quality lower than this, algorithm is terminated(or remeshing is initiated)

mea-sure

skewnessdetermines which quality measure is used

type min determines if minimal or average quality is considered

3.2. Shape Optimization Problems 73

Page 78: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

[Output]

Parameter Defaultvalue

Remarks

verbose True if True, the history of the optimization is printed to the consolesave_results True if True, the history of the optimization is saved to a .json filesave_txt True if True, the history of the optimization is saved to a human readable .txt filesave_pvd False if True, the history of the state variables over the optimization is saved in .pvd

filessave_pvd_adjoint False if True, the history of the adjoint variables over the optimization is saved in

.pvd filessave_pvd_gradient False if True, the history of the shape gradient over the optimization is saved in .pvd

filessave_mesh False if True, saves the mesh for the optimized geometry; only available for GMSH

inputresult_dir ./results path to the directory, where the output should be placedtime_suffix False Boolean flag, which adds a suffix to result_dir based on the current time

3.2.3 Regularization for Shape Optimization Problems

Problem Formulation

In this demo, we investigate how we can use regularizations for shape optimization problems in cashocs. For ourmodel problem, we use one similar to the one in Shape Optimization with a Poisson Problem, but which has additionalregularization terms, i.e.,

minΩ

𝐽(𝑢,Ω) =

∫Ω

𝑢 d𝑥 + 𝛼vol

∫Ω

1 d𝑥 + 𝛼surf

∫Γ

1 d𝑠

+𝜇vol

2

(∫Ω

1 d𝑥− voldes

)2

+𝜇surf

2

(∫Γ

1 d𝑠− surfdes

)2

+𝜇curv

2

∫Γ

𝜅2 d𝑠

subject to

−∆𝑢 = 𝑓 in Ω,

𝑢 = 0 on Γ.

Here, 𝜅 is the mean curvature. For the initial domain, we use the unit disc Ω = 𝑥 ∈ R2 | ||𝑥||2 < 1, and theright-hand side 𝑓 is given by

𝑓(𝑥) = 2.5(𝑥1 + 0.4 − 𝑥2

2

)2+ 𝑥2

1 + 𝑥22 − 1,

as in Shape Optimization with a Poisson Problem.

74 Chapter 3. Tutorial

Page 79: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Implementation

The complete python code can be found in the file demo_regularization.py, and the corresponding config can befound in config.ini.

Initialization

The initial code, including the defition of the PDE constraint, is identical to Shape Optimization with a Poisson Problem,and uses the following code

from fenics import *import cashocs

config = cashocs.load_config('./config.ini')

meshlevel = 15degree = 1dim = 2mesh = UnitDiscMesh.create(MPI.comm_world, meshlevel, degree, dim)dx = Measure('dx', mesh)boundary = CompiledSubDomain('on_boundary')boundaries = MeshFunction('size_t', mesh, dim=1)boundary.mark(boundaries, 1)ds = Measure('ds', mesh, subdomain_data=boundaries)

V = FunctionSpace(mesh, 'CG', 1)u = Function(V)p = Function(V)

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

e = inner(grad(u), grad(p))*dx - f*p*dxbcs = DirichletBC(V, Constant(0), boundaries, 1)

Cost functional and regularization

The only difference to Shape Optimization with a Poisson Problem comes now, in the definition of the cost functionalwhich includes the additional regularization terms.

Note: cashocs cannot treat the last two regularization terms directly by a user implementation. Instead, these regular-ization terms can be realized by setting the appropriate parameters in the config files, see the Section Regularization.

The first three summands of the cost functional can then be defined as

alpha_vol = 1e-1alpha_surf = 1e-1

J = u*dx + Constant(alpha_vol)*dx + Constant(alpha_surf)*ds

3.2. Shape Optimization Problems 75

Page 80: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

The remaining two parts are specified via config.ini, where the following lines are relevant

[Regularization]factor_volume = 1.0target_volume = 1.5use_initial_volume = Falsefactor_surface = 1.0target_surface = 4.5use_initial_surface = Falsefactor_curvature = 1e-4

This sets the factor 𝜇vol to 1.0, voldes to 1.5, 𝜇surf to 1.0, surfdes to 4.5, and 𝜇curv to 1e-4. Note, thatuse_initial_volume and use_initial_surface have to be set to False, otherwise the corresponding quanti-ties of the initial geometry would be used instead of the ones prescribed in the config file. The resulting regularizationterms are then treated by cashocs, but are, except for these definitions in the config file, invisible for the user.

Finally, we solve the problem as in Shape Optimization with a Poisson Problem with the lines

sop = cashocs.ShapeOptimizationProblem(e, bcs, J, u, p, boundaries, config)sop.solve()

The results should look like this

3.2.4 Inverse Problem in Electric Impedance Tomography

Problem Formulation

For this demo, we investigate an inverse problem in the setting of electric impedance tomography. It is based on the oneused in the preprint Blauth, Nonlinear Conjugate Gradient Methods for PDE Constrained Shape Optimization Based

76 Chapter 3. Tutorial

Page 81: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

on Steklov-Poincaré-Type Metrics. The problem reads

minΩ

𝐽(𝑢,Ω) =

𝑀∑𝑖=1

𝜈𝑖2

∫𝜕𝐷

(𝑢𝑖 −𝑚𝑖)2 d𝑠

subject to

⎧⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎩

−𝜅in∆𝑢in𝑖 = 0 in Ω,

−𝜅out∆𝑢out𝑖 = 0 in 𝐷 ∖ Ω,

𝜅out𝜕𝑛𝑢out𝑖 = 𝑓𝑖 on 𝜕𝐷,

𝑢out𝑖 = 𝑢in

𝑖 on Γ,

𝜅out𝜕𝑛in𝑢out𝑖 = 𝜅in𝜕𝑛in𝑢in

𝑖 on Γ,∫𝜕𝐷

𝑢out𝑖 d𝑠 = 0.

The setting is as follows. We have an object Ω that is located inside another one, 𝐷 ∖ Ω. Our goal is to identify theshape of the interior from measurements of the electric potential, denoted by 𝑢, on the outer boundary of 𝐷, to whichwe have access. In particular, we consider the case of having several measurements at our disposal, as indicated bythe index 𝑖. The PDE constraint now models the electric potential in experiment 𝑖, namely 𝑢𝑖, which results from anapplication of the electric current 𝑓𝑖 on the outer boundary 𝜕𝐷. Our goal of identifying the interior body Ω is modeledby the tracking type cost functional, which measures the 𝐿2(Γ) distance between the simulated electric potential 𝑢𝑖

and the measured one, 𝑚𝑖. In particular, note that the outer boundaries, i.e. 𝜕𝐷 are fixed, and only the internalboundary Γ = 𝜕Ω is deformable. For a detailed description of this problem as well as its physical interpretation, werefer to the preprint Blauth, Nonlinear Conjugate Gradient Methods for PDE Constrained Shape Optimization Basedon Steklov-Poincaré-Type Metrics.

For our demo, we use as domain the unit square 𝐷 = (0, 1)2, and the initial geometry of Ω is a square inside 𝐷. Weconsider the case of three measurements, so that 𝑀 = 3, given by

𝑓1 = 1 on Γ𝑙 ∪ Γ𝑟 and 𝑓1 = −1 on Γ𝑡 ∪ Γ𝑏,

𝑓2 = 1 on Γ𝑙 ∪ Γ𝑡 and 𝑓2 = −1 on Γ𝑟 ∪ Γ𝑏,

𝑓3 = 1 on Γ𝑙 ∪ Γ𝑏 and 𝑓3 = −1 on Γ𝑟 ∪ Γ𝑡,

where Γ𝑙,Γ𝑟,Γ𝑡,Γ𝑏 are the left, right, top, and bottom sides of the unit square.

Implementation

The complete python code can be found in the file demo_inverse_tomography.py, and the corresponding configcan be found in config.ini.

Initialization and generation of synthetic measurements

We start our code by importing FEniCS and cashocs

from fenics import *import cashocs

Next, we directly define the sample values of 𝜅in and 𝜅out since these are needed later on

kappa_out = 1e0kappa_in = 1e1

In the next part, we generate synthetic measurements, which correspond to 𝑚𝑖. To do this, we define a functiongenerate_measurements() as follows

3.2. Shape Optimization Problems 77

Page 82: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

def generate_measurements():mesh, subdomains, boundaries, dx, ds, dS = cashocs.import_mesh('./mesh/reference.xdmf

→˓')

cg_elem = FiniteElement('CG', mesh.ufl_cell(), 1)r_elem = FiniteElement('R', mesh.ufl_cell(), 0)V = FunctionSpace(mesh, MixedElement([cg_elem, r_elem]))

u, c = TrialFunctions(V)v, d = TestFunctions(V)

a = kappa_out*inner(grad(u), grad(v))*dx(1) + kappa_in*inner(grad(u), grad(v))*dx(2)→˓+ u*d*ds + v*c*ds

L1 = Constant(1)*v*(ds(3) + ds(4)) + Constant(-1)*v*(ds(1) + ds(2))L2 = Constant(1)*v*(ds(3) + ds(2)) + Constant(-1)*v*(ds(1) + ds(4))L3 = Constant(1)*v*(ds(3) + ds(1)) + Constant(-1)*v*(ds(2) + ds(4))

meas1 = Function(V)meas2 = Function(V)meas3 = Function(V)solve(a==L1, meas1)solve(a==L2, meas2)solve(a==L3, meas3)

m1, _ = meas1.split(True)m2, _ = meas2.split(True)m3, _ = meas3.split(True)

return [m1, m2, m3]

Note: The code executed in generate_measurements() is used to solve the state problem on a reference domain,given by the mesh ./mesh/reference.xdmf. This mesh has the domain Ω as a circle in the center of the unit square.To distinguish between these two, we note that 𝐷 ∖ Ω has the index / marker 1 and that Ω has the index / marker 2 inthe corresponding GMSH file, which is then imported into subdomains.

Note, that we have to use a mixed finite element method to incorporate the integral constraint on the electric potential.The second component of the corresponding fenics.FunctionSpace V is just a scalar, one-dimensional, real element.The actual PDE constraint is then given by the part

kappa_out*inner(grad(u), grad(v))*dx(1) + kappa_in*inner(grad(u), grad(v))*dx(2)

and the integral constraint is realized with the saddle point formulation

u*d*ds + v*c*ds

The right hand sides L1, L2, and L3 are just given by the Neumann boundary conditions as specified above.

Finally, these PDEs are then solved via the fenics.solve() command, and then only the actual solution of the PDE(and not the Lagrange multiplier for the integral constraint) is returned.

As usual, we load the config into cashocs with the line

78 Chapter 3. Tutorial

Page 83: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

config = cashocs.load_config('./config.ini')

Afterwards, we import the mesh into cashocs

mesh, subdomains, boundaries, dx, ds, dS = cashocs.import_mesh('./mesh/mesh.xdmf')

Next, we define the fenics.FunctionSpace object, which consists of CG1 elements together with a scalar, realelement, which acts as a Lagrange multiplier for the integral constraint

cg_elem = FiniteElement('CG', mesh.ufl_cell(), 1)r_elem = FiniteElement('R', mesh.ufl_cell(), 0)V = FunctionSpace(mesh, MixedElement([cg_elem, r_elem]))

Next, we compute the synthetic measurements via

measurements = generate_measurements()

The PDE constraint

Let us now investigate how the PDE constraint is defined. As we have a mixed finite element problem due to the integralconstraint, we proceed similarly to Coupled Problems - Monolithic Approach and define the first state equation withthe following lines

uc1 = Function(V)u1, c1 = split(uc1)pd1 = Function(V)p1, d1 = split(pd1)e1 = kappa_out*inner(grad(u1), grad(p1))*dx(1) + kappa_in*inner(grad(u1),→˓grad(p1))*dx(2) + u1*d1*ds + p1*c1*ds \

- Constant(1)*p1*(ds(3) + ds(4)) - Constant(-1)*p1*(ds(1) + ds(2))

The remaining two experiments are defined completely analogously:

uc2 = Function(V)u2, c2 = split(uc2)pd2 = Function(V)p2, d2 = split(pd2)e2 = kappa_out*inner(grad(u2), grad(p2))*dx(1) + kappa_in*inner(grad(u2),→˓grad(p2))*dx(2) + u2*d2*ds + p2*c2*ds \

- Constant(1)*p2*(ds(3) + ds(2)) - Constant(-1)*p2*(ds(1) + ds(4))

uc3 = Function(V)u3, c3 = split(uc3)pd3 = Function(V)p3, d3 = split(pd3)e3 = kappa_out*inner(grad(u3), grad(p3))*dx(1) + kappa_in*inner(grad(u3),→˓grad(p3))*dx(2) + u3*d3*ds + p3*c3*ds \

- Constant(1)*p3*(ds(3) + ds(1)) - Constant(-1)*p3*(ds(2) + ds(4))

Finally, we group together the state equations as well as the state and adjoint variables to (ordered) lists, as in UsingMultiple Variables and PDEs

3.2. Shape Optimization Problems 79

Page 84: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

e = [e1, e2, e3]u = [uc1, uc2, uc3]p = [pd1, pd2, pd3]

Since the problem only has Neumann boundary conditions, we use

bcs = None

the specify this.

The shape optimization problem

The cost functional is then defined by first creating the individual summands, and then summing them up:

J1 = Constant(0.5)*pow(u1 - measurements[0], 2)*dsJ2 = Constant(0.5)*pow(u2 - measurements[1], 2)*dsJ3 = Constant(0.5)*pow(u3 - measurements[2], 2)*ds

J = J1 + J2 + J3

where we use a coefficient of 𝜈𝑖 = 1 for all cases.

Before we can define the shape optimization properly, we have to take a look at the config file to specify which bound-aries are fixed, and which are deformable. There, we have the following lines

[ShapeGradient]shape_bdry_def = []shape_bdry_fix = [1, 2, 3, 4]

Note, that the boundaries 1, 2, 3, 4 are the sides of the unit square, as defined in the .geo file for the geometry(located in the ./mesh/ directory), and they are fixed due to the problem definition (recall that 𝜕𝐷 is fixed). However,at the first glance it seems that there is no deformable boundary. This is, however, wrong. In fact, there is still aninternal boundary, namely Γ, which is not specified here, and which is, thus, deformable (this is the default behavior).

Warning: As stated in Documentation of the Config Files for Shape Optimization Problems, we have to use theconfig file setting

use_pull_back = False

This is due to the fact that the measurements are defined / computed on a different mesh / geometry than the remain-ing objects, and FEniCS is not able to do some computations in this case. However, note that the cost functionalis posed on 𝜕𝐷 only, which is fixed anyway. Hence, the deformation field vanishes there, and the correspondingdiffeomorphism, which maps between the deformed and original domain, is just the identity mapping. In particular,no material derivatives are needed for the measurements, which is why it is safe to disable use_pull_back for thisparticular problem.

The shape optimization problem can now be created as in Shape Optimization with a Poisson Problem and can besolved as easily, with the commands

sop = cashocs.ShapeOptimizationProblem(e, bcs, J, u, p, boundaries, config)sop.solve()

The results should look like this

80 Chapter 3. Tutorial

Page 85: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

and we observe that we are indeed able to identify the shape of the circle which was used to create the measurements.

3.2.5 Optimization of an Obstacle in Stokes Flow

Problem Formulation

For this tutorial, we investigate a problem similarly to the ones considered in, e.g., Blauth, Nonlinear Conjugate Gra-dient Methods for PDE Constrained Shape Optimization Based on Steklov-Poincaré-Type Metrics and Schulz andSiebenborn, Computational Comparison of Surface Metric for PDE Constrained Shape Optimization, which reads:

minΩ

𝐽(𝑢,Ω) =

∫Ωflow

𝐷𝑢 : 𝐷𝑢 d𝑥

subject to

⎧⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎩

−∆𝑢 + ∇𝑝 = 0 in Ω,

div(𝑢) = 0 in Ω,

𝑢 = 𝑢in on Γin,

𝑢 = 0 on Γwall ∪ Γobs,

𝜕𝑛𝑢− 𝑝𝑛 = 0 on Γout.

Here, we have an inflow boundary condition on the inlet Γin, a no-slip boundary condition on the wall boundary Γwall

as well as the obstacle boundary Γobs, and a do-nothing condition on the outlet Γout.

This problem is supplemented with the geometrical constraints

vol(Ω) =

∫Ω

1 d𝑥 =

∫Ω0

1 d𝑥 = vol(Ω0),

bary(Ω) =1

vol(Ω)

∫Ω

𝑥 d𝑥 =1

vol(Ω0)

∫Ω0

𝑥 d𝑥 = bary(Ω0),

where Ω0 denotes the initial geometry. This models that both the volume and the barycenter of the geometry shouldremain fixed during the optimization. To treat this problem with cashocs, we regularize the constraints in the sense of aquadratic penalty function. See the corresponding section in the documentation of the config files for shape optimization

3.2. Shape Optimization Problems 81

Page 86: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

as well as Regularization for Shape Optimization Problems. In particular, the regularized problem reads

minΩ

𝐽(𝑢,Ω) =

∫Ωflow

𝐷𝑢 : 𝐷𝑢 d𝑥 +𝜇vol

2

(∫Ω

1 d𝑥− vol(Ω0)

)2

+𝜇bary

2

1

vol(Ω)

∫Ω

𝑥 d𝑥− bary(Ω0)

2

subject to

⎧⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎩

−∆𝑢 + ∇𝑝 = 0 in Ω,

div(𝑢) = 0 in Ω,

𝑢 = 𝑢in on Γin,

𝑢 = 0 on Γwall ∪ Γobs,

𝜕𝑛𝑢− 𝑝𝑛 = 0 on Γout.

where we have no additional geometrical constraints. However, the parameters 𝜇vol and 𝜇bary have to be sufficientlylarge, so that the regularized constraints are satisfied approximately.

Note, that the domain Ω denotes the domain of the obstacle, but that the cost functional involves an integral over the flowdomain Ωflow. Therefore, we switch our point of view and optimize the geometry of the flow instead (which of courseincludes the optimization of the “hole” generated by the obstacle). In particular, only the boundary of the obstacle Γobs

is deformable, all remaining boundaries are fixed. Hence, it is equivalent to pose the geometrical constraints on Ω andΩflow, so that we can work completely with the flow domain.

As (initial) domain, we consider the rectangle (−2, 2)× (−3, 3) without a circle centered in the origin with radius 0.5.The correspondig geometry is created with GMSH, and can be found in the ./mesh/ directory.

Implementation

The complete python code can be found in the file demo_shape_stokes.py, and the corresponding config can befound in config.ini.

Initialization

As for the previous tutorial problems, we start by importing FEniCS and cashocs:

config = cashocs.load_config('./config.ini')

Afterwards we import the (initial) geometry with the import_mesh command

mesh, subdomains, boundaries, dx, ds, dS = cashocs.import_mesh('./mesh/mesh.xdmf')

Note: As defined in ./mesh/mesh.geo, we have the following boundaries

• The inlet boundary Γin, which has index 1

• The wall boundary Γwall, which have index 2

• The outlet boundary Γout, which has index 3

• The boundary of the obstacle Γobs, which has index 4

To include the fact that only the obstacle boundary, with index 4, is deformable, we have the following lines in theconfig file

82 Chapter 3. Tutorial

Page 87: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

[ShapeGradient]shape_bdry_def = [4]shape_bdry_fix = [1,2,3]

which ensures that only Γobs is deformable.

State system

The definition of the state system is analogous to the one we considered in Distributed Control of a Stokes Problem.Here, we, too, use LBB stable Taylor-Hood elements, which are defined as

v_elem = VectorElement('CG', mesh.ufl_cell(), 2)p_elem = FiniteElement('CG', mesh.ufl_cell(), 1)V = FunctionSpace(mesh, MixedElement([v_elem, p_elem]))

For the weak form of the PDE, we have the same code as in Distributed Control of a Stokes Problem

up = Function(V)u, p = split(up)vq = Function(V)v, q = split(vq)

e = inner(grad(u), grad(v))*dx - p*div(v)*dx - q*div(u)*dx

The Dirichlet boundary conditions are slightly different, though. For the inlet velocity 𝑢in we use a parabolic profile

u_in = Expression(('-1.0/4.0*(x[1] - 2.0)*(x[1] + 2.0)', '0.0'), degree=2)bc_in = DirichletBC(V.sub(0), u_in, boundaries, 1)

The wall and obstacle boundaries get a no-slip boundary condition, each, with the line

bc_no_slip = cashocs.create_dirichlet_bcs(V.sub(0), Constant((0,0)), boundaries, [2,4])

Finally, all Dirichlet boundary conditions are gathered into the list bcs

bcs = [bc_in] + bc_no_slip

Note: The outflow boundary condition is of Neumann type and already included in the weak form of the problem.

Cost functional and optimization problem

The cost functional is easily defined with the line

J = inner(grad(u), grad(u))*dx

Note: The additional regularization terms are defined similarly to Regularization for Shape Optimization Problems.In the config file, we have the following (relevant) lines:

3.2. Shape Optimization Problems 83

Page 88: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

[Regularization]factor_volume = 1e4use_initial_volume = Truefactor_barycenter = 1e5use_initial_barycenter = True

This ensures that we use 𝜇vol = 1𝑒4 and 𝜇bary = 1𝑒5, which are comparatively large parameters, so that thegeometrical constraints are satisfied with high accuracy. Moreover, the boolean flags use_initial_volume anduse_initial_barycenter, which are both set to True, ensure that we actually use the volume and barycenter ofthe initial geometry.

Finally, we solve the shape optimization problem as previously with the commands

sop = cashocs.ShapeOptimizationProblem(e, bcs, J, up, vq, boundaries, config)sop.solve()

Note: For the definition of the shape gradient, we use the same parameters for the linear elasticity equations as inBlauth, Nonlinear Conjugate Gradient Methods for PDE Constrained Shape Optimization Based on Steklov-Poincaré-Type Metrics and Schulz and Siebenborn, Computational Comparison of Surface Metric for PDE Constrained ShapeOptimization. These are defined in the config file in the ShapeGradient section

lambda_lame = 0.0damping_factor = 0.0mu_fix = 1mu_def = 5e2

so that we use a rather high stiffness for the elements at the deformable boundary, which is also discretized finely, anda rather low stiffness for the fixed boundaries.

Note: This demo might take a little longer than the others, depending on the machine it is run on. This is normal, andcaused by the finer discretization of the geometry compared to the previous problems.

The results should look like this

84 Chapter 3. Tutorial

Page 89: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

3.2.6 Remeshing with cashocs

Problem Formulation

In this tutorial, we take a close look at how remeshing works in cashocs. To keep this discussion simple, we take a lookat the model problem already investigated in Shape Optimization with a Poisson Problem, i.e.,

minΩ

𝐽(𝑢,Ω) =

∫Ω

𝑢 d𝑥

subject to

−∆𝑢 = 𝑓 in Ω,

𝑢 = 0 on Γ.

As before, we use the unit disc Ω = 𝑥 ∈ R2 | ||𝑥||2 < 1, as initial geometry, and the right-hand side 𝑓 is given by

𝑓(𝑥) = 2.5(𝑥1 + 0.4 − 𝑥2

2

)2+ 𝑥2

1 + 𝑥22 − 1.

Implementation

The complete python code can be found in the file demo_remeshing.py, and the corresponding config can be foundin config.ini. The corresponding mesh files are ./mesh/mesh.geo and ./mesh/mesh.msh.

Pre-Processing with GMSH

Before we can start with the actual cashocs implementation of remeshing, we have to take a closer look at how we candefine a geometry with GMSH. For this, .geo files are used.

Hint: A detailed documentation and tutorials regarding the generation of geometries and meshes with GMSH can befound here.

The file ./mesh/mesh.geo describes our geometry.

Important: Any user defined variables that should be also kept for the remeshing, such as the characteristic lengths,must be lower case, so that cashocs can distinguish them from the other GMSH commands. Any user defined variablestarting with an upper case letter is not considered for the .geo file created for remeshing and will, thus, probably causean error.

In our case of the .geo file, the characteristic length is defined as lc, and this is used to specify the (local) size of thediscretization via so-called size fields. Note, that this variable is indeed taken into consideration for the remeshing asit starts with a lower case letter.

The resulting mesh file was created over the command line with the command

gmsh ./mesh/mesh.geo -o ./mesh/mesh.msh -2

Note: For the purpose of this tutorial it is recommended to leave the ./mesh/mesh.msh file as it is. In particular,carrying out the above command will overwrite the file and is, thus, not recommended. The command just highlights,how one would / could use GMSH to define their own geometries and meshes for cashocs or FEniCS.

The resulting file is ./mesh/mesh.msh. This .msh file can be converted to the .xdmf format by using cashocs-convertas follows:

3.2. Shape Optimization Problems 85

Page 90: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

cashocs-convert ./mesh/mesh.msh ./mesh/mesh.xdmf

from the command line.

Hint: As the cashocs-convert merely converts the .msh file to .xdmf, the user may very well use this command.

To ensure that cashocs also finds these files, we have to specify them in the file config.ini. For this, we have thefollowing lines

[Mesh]mesh_file = ./mesh/mesh.xdmfgmsh_file = ./mesh/mesh.mshgeo_file = ./mesh/mesh.georemesh = Trueshow_gmsh_output = True

With this, we have specified the paths to the mesh files and also enabled the remeshing as well as the verbose output ofGMSH to the terminal, as explained in the corresponding documentation of the config files.

Note: Note, that the paths given in the config file can be either absolute or relative. In the latter case, they have to berelative to the location of the cashocs script which is used to solve the problem.

With this, we can now focus on the implementation in python.

Initialization

The program starts as Shape Optimization with a Poisson Problem, with the following lines

from fenics import *import cashocs

config = cashocs.load_config('./config.ini')

with which we import FEniCS and cashocs, and read the config file. The mesh and all other related objects are createdwith the command

mesh, subdomains, boundaries, dx, ds, dS = cashocs.import_mesh(config)

Note, that in contrast to Shape Optimization with a Poisson Problem, we cannot use a built-in mesh for this tutorialsince remeshing is only available for meshes generated by GMSH.

Important: It is important to note that we have to pass the config as argument to import_mesh . The alternativesyntax

mesh, subdomains, boundaries, dx, ds, dS = cashocs.import_mesh(./mesh/mesh.xdmf)

is NOT equivalent for remeshing, even though the definition in the config file points to the same object, where thecorresponding line reads

86 Chapter 3. Tutorial

Page 91: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

mesh_file = ./mesh/mesh.xdmf

Definition of the state system

The definition of the state system is now completely analogous to the one in Shape Optimization with a Poisson Problem.Here, we just repeat the code for the sake of completeness

V = FunctionSpace(mesh, 'CG', 1)u = Function(V)p = Function(V)

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

e = inner(grad(u), grad(p))*dx - f*p*dxbcs = DirichletBC(V, Constant(0), boundaries, 1)

The shape optimization problem

The definition of the ShapeOptimizationProblem as well as its solution is now also completely analogous to ShapeOptimization with a Poisson Problem, and is done with the lines

J = u*dx

sop = cashocs.ShapeOptimizationProblem(e, bcs, J, u, p, boundaries, config)sop.solve()

The results should look like the one of Shape Optimization with a Poisson Problem:

3.2. Shape Optimization Problems 87

Page 92: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Note: The example for remeshing is somewhat artificial, as the problem does not actually need remeshing. Therefore,the tolerances used in the config file, i.e.,

tol_lower = 0.1tol_upper = 0.25

are comparatively large. However, this problem still shows all relevant aspects of remeshing in cashocs and can, thus,be transferred to “harder” problems that require remeshing.

3.2.7 Custom Scalar Products for Shape Gradient Computation

Problem Formulation

In this demo, we show how to supply a custom bilinear form for the computation of the shape gradient with cashocs.For the sake of simplicity, we again consider our model problem from Shape Optimization with a Poisson Problem,given by

minΩ

𝐽(𝑢,Ω) =

∫Ω

𝑢 d𝑥

subject to

−∆𝑢 = 𝑓 in Ω,

𝑢 = 0 on Γ.

For the initial domain, we use the unit disc Ω = 𝑥 ∈ R2 | ||𝑥||2 < 1, and the right-hand side 𝑓 is given by

𝑓(𝑥) = 2.5(𝑥1 + 0.4 − 𝑥2

2

)2+ 𝑥2

1 + 𝑥22 − 1.

Implementation

The complete python code can be found in the file demo_custom_scalar_product.py, and the corresponding configcan be found in config.ini.

Initialization

The demo program closely follows the one from Shape Optimization with a Poisson Problem, so that up to the definitionof the ShapeOptimizationProblem , the code is identical to the one in Shape Optimization with a Poisson Problem,and given by

from fenics import *import cashocs

config = cashocs.load_config('./config.ini')

meshlevel = 15degree = 1dim = 2mesh = UnitDiscMesh.create(MPI.comm_world, meshlevel, degree, dim)dx = Measure('dx', mesh)boundary = CompiledSubDomain('on_boundary')

(continues on next page)

88 Chapter 3. Tutorial

Page 93: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

(continued from previous page)

boundaries = MeshFunction('size_t', mesh, dim=1)boundary.mark(boundaries, 1)ds = Measure('ds', mesh, subdomain_data=boundaries)

V = FunctionSpace(mesh, 'CG', 1)u = Function(V)p = Function(V)

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

e = inner(grad(u), grad(p))*dx - f*p*dxbcs = DirichletBC(V, Constant(0), boundaries, 1)

J = u*dx

Definition of the scalar product

To define the scalar product that shall be used for the shape optimization, we can proceed analogously to NeumannBoundary Control and define the corresponding bilinear form in FEniCS. However, note that one has to use a fenics.VectorFunctionSpace with piecewise linear Lagrange elements, i.e., one has to define the corresponding functionspace as

VCG = VectorFunctionSpace(mesh, 'CG', 1)

With this, we can now define the bilinear form as follows

shape_scalar_product = inner((grad(TrialFunction(VCG))), (grad(TestFunction(VCG))))*dx +→˓inner(TrialFunction(VCG), TestFunction(VCG))*dx

Note: Note, that we cannot use the formulation

shape_scalar_product = inner((grad(TrialFunction(VCG))), (grad(TestFunction(VCG))))*dx

as this would not yield a coercive bilinear form for this problem. This is due to the fact that the entire boundary of Ωis variable. Hence, we actually need this second term.

Finally, we can set up the ShapeOptimizationProblem and solve it with the lines

sop = cashocs.ShapeOptimizationProblem(e, bcs, J, u, p, boundaries, config, shape_scalar_→˓product=shape_scalar_product)sop.solve()

The result of the optimization looks like this

3.2. Shape Optimization Problems 89

Page 94: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

3.2.8 Scaling of the Cost Functional

Problem Formulation

In this demo, we take a look at how cashocs can be used to scale cost functionals, which is particularly useful in caseone uses multiple terms to define the cost functional and wants to weight them appropriately, e.g., if there are multiplecompeting objectives. This demo investigates this problem by considering a slightly modified version of the modelshape optimization problem from Shape Optimization with a Poisson Problem, i.e.,

minΩ

𝐽(𝑢,Ω) = 𝛼

∫Ω

𝑢 d𝑥 + 𝛽

∫Ω

1 d𝑥

subject to

−∆𝑢 = 𝑓 in Ω,

𝑢 = 0 on Γ.

For the initial domain, we use the unit disc Ω = 𝑥 ∈ R2 | ||𝑥||2 < 1, and the right-hand side 𝑓 is given by

𝑓(𝑥) = 2.5(𝑥1 + 0.4 − 𝑥2

2

)2+ 𝑥2

1 + 𝑥22 − 1.

Our goal is to choose the parameters 𝛼 and 𝛽 in such a way that the magnitude of the second term is twice as big as thevalue of the first term for the initial geometry.

Implementation

The complete python code can be found in the file demo_scaling.py, and the corresponding config can be found inconfig.ini.

90 Chapter 3. Tutorial

Page 95: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Initialization

The definition of the PDE constraint is completely identical to the one described in Shape Optimization with a PoissonProblem, which we recall here for the sake of completeness

from fenics import *import cashocs

config = cashocs.load_config('./config.ini')

meshlevel = 15degree = 1dim = 2mesh = UnitDiscMesh.create(MPI.comm_world, meshlevel, degree, dim)dx = Measure('dx', mesh)boundary = CompiledSubDomain('on_boundary')boundaries = MeshFunction('size_t', mesh, dim=1)boundary.mark(boundaries, 1)ds = Measure('ds', mesh, subdomain_data=boundaries)

V = FunctionSpace(mesh, 'CG', 1)u = Function(V)p = Function(V)

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

e = inner(grad(u), grad(p))*dx - f*p*dxbcs = DirichletBC(V, Constant(0), boundaries, 1)

Definition of the Cost Functional

Our goal is to choose 𝛼 and 𝛽 in such a way that 𝛼

∫Ω0

𝑢 d𝑥

= 𝐶1,𝛽

∫Ω0

1 d𝑥

= 𝐶2,

where Ω0 is the intial geometry. Here, we choose the value 𝐶1 = 1 and 𝐶2 = 2 without loss of generality. Thiswould then achieve our goal of having the second term (a volume regularization) being twice as large as the first termin magnitude.

To implement this in cashocs, we do not specify a single UFL form for the cost functional as in all previous demos,instead we supply a list of UFL forms into which we put every single term of the cost functional. These are then scaledautomatically by cashocs and then added to obtain the actual cost functional.

Hence, let us first define the individual terms of the cost functional we consider, and place them into a list

J_1 = u*dxJ_2 = Constant(1)*dxJ_list = [J_1, J_2]

3.2. Shape Optimization Problems 91

Page 96: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Afterwards, we have to create a second list which includes the values that the terms of J_list should have on theinitial geometry

desired_weights = [1, 2]

Finally, these are supplied to the shape optimization problem as follows: J_list is passed instead of the usualcost_functional_form parameter, and desired_weights enters the optimization problem as keyword argumentof the same name, i.e.,

sop = cashocs.ShapeOptimizationProblem(e, bcs, J_list, u, p, boundaries, config, desired_→˓weights=desired_weights)sop.solve()

Note: Since the first term of the cost functional, i.e.,∫Ω𝑢 d𝑥, is negative, the intial function value for our choice of

scaling is −1 + 2 = 1.

Note: If the keyword argument desired_weights is not given or None, this is equivalent to not using the scalingdescribed above, i.e., one could also just pass J = J_1 + J_2 as cost_functional_form.

Note: If a cost functional is close to zero for the initial domain, the scaling is disabled for this term, and instead therespective term is just multiplied by the corresponding factor in desired_weights. cashocs issues an info messagein this case.

Note: The scaling of the cost functional works completely analogous for optimal control problems: There, one alsohas to supply a list of the individual terms of the cost functional and use the keyword argument desired_weights inorder to define and supply the desired magnitude of the terms for the initial iteration.

The result of the optimization looks like this

92 Chapter 3. Tutorial

Page 97: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

3.2.9 Computing the Shape Stiffness via Distance to the Boundaries

Problem Formulation

We are solving the same problem as in Optimization of an Obstacle in Stokes Flow, but now use a different approach forcomputing the stiffness of the shape gradient. Recall, that the corresponding (regularized) shape optimization problemis given by

minΩ

𝐽(𝑢,Ω) =

∫Ωflow

𝐷𝑢 : 𝐷𝑢 d𝑥 +𝜇vol

2

(∫Ω

1 d𝑥− vol(Ω0)

)2

+𝜇bary

2

1

vol(Ω)

∫Ω

𝑥 d𝑥− bary(Ω0)

2

subject to

⎧⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎩

−∆𝑢 + ∇𝑝 = 0 in Ω,

div(𝑢) = 0 in Ω,

𝑢 = 𝑢in on Γin,

𝑢 = 0 on Γwall ∪ Γobs,

𝜕𝑛𝑢− 𝑝𝑛 = 0 on Γout.

For a background on the stiffness of the shape gradient, we refer to Section ShapeGradient, where it is defined as theparameter 𝜇 used in the computation of the shape gradient. Note, that the distance computation is done via an eikonalequation, hence the name of the demo.

3.2. Shape Optimization Problems 93

Page 98: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Implementation

The complete python code can be found in the file demo_eikonal_stiffness.py, and the corresponding config canbe found in config.ini.

Changes in the config file

In order to compute the stiffness𝜇 based on the distance to selected boundaries, we only have to change the configurationfile we are using, the python code for solving the shape optimization problem with cashocs stays exactly as it was inOptimization of an Obstacle in Stokes Flow.

To use the stiffness computation based on the distance to the boundary, we add the following lines to the config file

use_distance_mu = Truedist_min = 0.05dist_max = 1.25mu_min = 5e2mu_max = 1.0smooth_mu = falseboundaries_dist = [4]

The first line

use_distance_mu = True

ensures that the stiffness will be computed based on the distance to the boundary.

The next four lines then specify the behavior of this computation. In particular, we have the following behavior for 𝜇

𝜇 =

𝜇min if 𝛿 ≤ 𝛿min,

𝜇max if 𝛿 ≥ 𝛿max

where 𝛿 denotes the distance to the boundary and 𝛿min and 𝛿max correspond to dist_min and dist_max, respectively.

The values in-between are given by interpolation. Either a linear, continuous interpolation is used, or a smooth 𝐶1

interpolation given by a third order polynomial. These can be selected with the option

smooth_mu = false

where smooth_mu = True uses the third order polynomial, and smooth_mu = False uses the linear function.

Finally, the line

boundaries_dist = [4]

specifies, which boundaries are considered for the distance computation. These are again specified using the boundarymarkers, as it was previously explained in Section ShapeGradient.

The results should look like this

94 Chapter 3. Tutorial

Page 99: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

3.2.10 Shape Optimization with the p-Laplacian

Problem Formulation

In this demo, we take a look at yet another possibility to compute the shape gradient and to use this method for solvingshape optimization problems. Here, we investigate the approach of Müller, Kühl, Siebenborn, Deckelnick, Hinze, andRung and use the 𝑝-Laplacian in order to compute the shape gradient. As a model problem, we consider the followingone, as in Shape Optimization with a Poisson Problem:

minΩ

𝐽(𝑢,Ω) =

∫Ω

𝑢 d𝑥

subject to

−∆𝑢 = 𝑓 in Ω,

𝑢 = 0 on Γ.

For the initial domain, we use the unit disc Ω = 𝑥 ∈ R2 | ||𝑥||2 < 1, and the right-hand side 𝑓 is given by

𝑓(𝑥) = 2.5(𝑥1 + 0.4 − 𝑥2

2

)2+ 𝑥2

1 + 𝑥22 − 1.

Implementation

The complete python code can be found in the file demo_p_laplacian.py, and the corresponding config can be foundin config.ini.

Source Code

The python source code for this example is completely identical to the one in Shape Optimization with a PoissonProblem, so we do not cover this here again. The only changes occur in the configuration file, which we cover below.

Configuration File

All the relevant changes appear in the ShapeGradient Section of the config file, where we now add the following threelines

use_p_laplacian = Truep_laplacian_power = 10p_laplacian_stabilization = 0.0

Here, use_p_laplacian is a boolean flag which indicates that we want to override the default behavior and use the 𝑝Laplacian to compute the shape gradient instead of linear elasticity. In particular, this means that we solve the followingequation to determine the shape gradient 𝒢

Find 𝒢 such that∫Ω

𝜇 (∇𝒢 : ∇𝒢)𝑝−22 ∇𝒢 : ∇𝒱 + 𝛿𝒢 · 𝒱 d𝑥 = 𝑑𝐽(Ω)[𝒱]

for all 𝒱.

Here, 𝑑𝐽(Ω)[𝒱] is the shape derivative. The parameter 𝑝 is defined via the config file parameter p_laplacian_power,and is 10 for this example. Finally, it is possible to use a stabilized formulation of the 𝑝-Laplacian equation shown above,where the stabilization parameter is determined via the config line parameter p_laplacian_stabilization, whichshould be small (e.g. in the order of 1e-3). Moreover, 𝜇 is the stiffness parameter, which can be specified via theconfig file parameters mu_def and mu_fixed and works as usually (cf. Shape Optimization with a Poisson Problem:).

3.2. Shape Optimization Problems 95

Page 100: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Finally, we have added the possibility to use the damping parameter 𝛿, which is specified via the config file parameterdamping_factor, also in the Section ShapeGradient.

Note: Note, that the 𝑝-Laplace methods are only meant to work with the gradient descent method. Other methods,such as BFGS or NCG methods, might be able to work on certain problems, but you might encounter strange behaviorof the methods.

Finally, we show the result of the optimization, which looks similar to the one obtained in Shape Optimization with aPoisson Problem:

3.3 Using cashocs Exclusively as a Solver

Here, we showcase that one can use cashocs optimization routines without its automatic derivation of adjoint systemsand (shape) derivatives, where the user can choose to supply these forms themselves.

3.3.1 cashocs as Solver for Optimal Control Problems

Problem Formulation

As a model problem we again consider the one from Distributed Control of a Poisson Problem, but now we do notuse cashocs to compute the adjoint equation and derivative of the (reduced) cost functional, but supply these termsourselves. The optimization problem is given by

min 𝐽(𝑦, 𝑢) =1

2

∫Ω

(𝑦 − 𝑦𝑑)2 d𝑥 +

𝛼

2

∫Ω

𝑢2 d𝑥

subject to

−∆𝑦 = 𝑢 in Ω,

𝑦 = 0 on Γ.

(see, e.g., Tröltzsch, Optimal Control of Partial Differential Equations or Hinze, Pinnau, Ulbrich, and Ulbrich, Opti-mization with PDE constraints).

96 Chapter 3. Tutorial

Page 101: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

For the numerical solution of this problem we consider exactly the same setting as in Distributed Control of a PoissonProblem, and most of the code will be identical to this.

Implementation

The complete python code can be found in the file demo_control_solver.py, and the corresponding config can befound in config.ini.

Recapitulation of Distributed Control of a Poisson Problem

For using cashocs exclusively as solver, the procedure is very similar to regularly using it, with a few additions afterdefining the optimization problem. In particular, up to the initialization of the optimization problem, our code is exactlythe same as in Distributed Control of a Poisson Problem, i.e., we use

from fenics import *import cashocs

config = cashocs.create_config('config.ini')mesh, subdomains, boundaries, dx, ds, dS = cashocs.regular_mesh(25)V = FunctionSpace(mesh, 'CG', 1)

y = Function(V)p = Function(V)u = Function(V)

e = inner(grad(y), grad(p))*dx - u*p*dx

bcs = cashocs.create_dirichlet_bcs(V, Constant(0), boundaries, [1, 2, 3, 4])

y_d = Expression('sin(2*pi*x[0])*sin(2*pi*x[1])', degree=1)alpha = 1e-6J = Constant(0.5)*(y - y_d)*(y - y_d)*dx + Constant(0.5*alpha)*u*u*dx

ocp = cashocs.OptimalControlProblem(e, bcs, J, y, u, p, config)

Supplying Custom Adjoint Systems and Derivatives

When using cashocs as a solver, the user can specify their custom weak forms of the adjoint system and of the derivativeof the reduced cost functional. For our optimization problem, the adjoint equation is given by

−∆𝑝 = 𝑦 − 𝑦𝑑 in Ω,

𝑝 = 0 on Γ,

and the derivative of the cost functional is then given by

𝑑𝐽(𝑢)[ℎ] =

∫Ω

(𝛼𝑢 + 𝑝)ℎ d𝑥

Note: For a detailed derivation and discussion of these objects we refer to Tröltzsch, Optimal Control of PartialDifferential Equations or Hinze, Pinnau, Ulbrich, and Ulbrich, Optimization with PDE constraints.

3.3. Using cashocs Exclusively as a Solver 97

Page 102: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

To specify that cashocs should use these equations instead of the automatically computed ones, we have the followingcode. First, we specify the derivative of the reduced cost functional via

dJ = Constant(alpha)*u*TestFunction(V)*dx + p*TestFunction(V)*dx

Afterwards, the weak form for the adjoint system is given by

adjoint_form = inner(grad(p), grad(TestFunction(V)))*dx - (y - y_d)*TestFunction(V)*dxadjoint_bcs = bcs

where we can “recycle” the homogeneous Dirichlet boundary conditions used for the state problem.

For both objects, one has to define them as a single UFL form for cashocs, as with the state system and cost func-tional. In particular, the adjoint weak form has to be in the form of a nonlinear variational problem, so that fenics.solve(adjoint_form == 0, p, adjoint_bcs) could be used to solve it. In particular, both forms have to includefenics.TestFunction objects from the control space and adjoint space, respectively, and must not contain fenics.TrialFunction objects.

These objects are then supplied to the OptimalControlProblem via

ocp.supply_custom_forms(dJ, adjoint_form, adjoint_bcs)

Note: One can also specify either the adjoint system or the derivative of the cost functional, using the methodssupply_adjoint_forms or supply_derivatives. However, this is potentially dangerous, due to the following.The adjoint system is a linear system, and there is no fixed convention for the sign of the adjoint state. Hence, supplying,e.g., only the adjoint system, might not be compatible with the derivative of the cost functional which cashocs computes.In effect, the sign is specified by the choice of adding or subtracting the PDE constraint from the cost functional for thedefinition of a Lagrangian function, which is used to determine the adjoint system and derivative. cashocs internallyuses the convention that the PDE constraint is added, so that, internally, it computes not the adjoint state 𝑝 as definedby the equations given above, but −𝑝 instead. Hence, it is recommended to either specify all respective quantities withthe supply_custom_forms method.

Finally, we can use the solve method to solve the problem with the line

ocp.solve()

as in Distributed Control of a Poisson Problem. The results are, of course, identical to Distributed Control of a PoissonProblem and look as follows

Note: In case we have multiple state equations as in Using Multiple Variables and PDEs, one has to supply orderedlists of adjoint equations and boundary conditions, analogously to the usual procedure for cashocs.

98 Chapter 3. Tutorial

Page 103: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

In the case of multiple control variables, the derivatives of the reduced cost functional w.r.t. each of these have to bespecified, again using an ordered list.

3.3.2 cashocs as Solver for Shape Optimization Problems

Problem Formulation

Let us now investigate how cashocs can be used exclusively as a solver for shape optimization problems. The procedureis very similar to the one discussed in cashocs as Solver for Optimal Control Problems, but with some minor variationstailored to shape optimization.

As a model shape optimization problem we consider the same as in Shape Optimization with a Poisson Problem, i.e.,

minΩ

𝐽(𝑢,Ω) =

∫Ω

𝑢 d𝑥

subject to

−∆𝑢 = 𝑓 in Ω,

𝑢 = 0 on Γ.

For the initial domain, we use the unit disc Ω = 𝑥 ∈ R2 | ||𝑥||2 < 1, and the right-hand side 𝑓 is given by

𝑓(𝑥) = 2.5(𝑥1 + 0.4 − 𝑥2

2

)2+ 𝑥2

1 + 𝑥22 − 1.

Implementation

The complete python code can be found in the file demo_shape_solver.py, and the corresponding config can befound in config.ini.

Recapitulation of Shape Optimization with a Poisson Problem

Analogously to cashocs as Solver for Optimal Control Problems, the code we use in case cashocs is treated as a solveronly is identical to the one of Shape Optimization with a Poisson Problem up to the definition of the optimizationproblem. For the sake of completeness we recall the corresponding code in the following

from fenics import *import cashocs

config = cashocs.create_config('./config.ini')

meshlevel = 15degree = 1dim = 2mesh = UnitDiscMesh.create(MPI.comm_world, meshlevel, degree, dim)dx = Measure('dx', mesh)boundary = CompiledSubDomain('on_boundary')boundaries = MeshFunction('size_t', mesh, dim=1)boundary.mark(boundaries, 1)ds = Measure('ds', mesh, subdomain_data=boundaries)

V = FunctionSpace(mesh, 'CG', 1)(continues on next page)

3.3. Using cashocs Exclusively as a Solver 99

Page 104: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

(continued from previous page)

u = Function(V)p = Function(V)

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

e = inner(grad(u), grad(p))*dx - f*p*dxbcs = DirichletBC(V, Constant(0), boundaries, 1)

J = u*dx

sop = cashocs.ShapeOptimizationProblem(e, bcs, J, u, p, boundaries, config)

Supplying Custom Adjoint Systems and Shape Derivatives

Now, our goal is to use custom UFL forms for the adjoint system and shape derivative. Note, that the adjoint systemfor the considered optimization problem is given by

−∆𝑝 = 1 in Ω,

𝑝 = 0 on Γ,

and the corresponding shape derivative is given by

𝑑𝐽(Ω)[𝒱] =

∫Ω

div (𝒱)𝑢 d𝑥 +

∫Ω

((div(𝒱)𝐼 − 2𝜀(𝒱))∇𝑢) · ∇𝑝 d𝑥 +

∫Ω

div (𝑓𝒱) 𝑝 d𝑥,

where 𝜀(𝒱) is the symmetric part of the gradient of 𝒱 given by 𝜀(𝒱) = 12

(𝐷𝒱 + 𝐷𝒱⊤). For details, we refer the

reader to, e.g., Delfour and Zolesio, Shapes and Geometries.

To supply these weak forms to cashocs, we can use the following code. For the shape derivative, we write

vector_field = sop.get_vector_field()dJ = div(vector_field)*u*dx - inner((div(vector_field)*Identity(2) - 2*sym(grad(vector_→˓field)))*grad(u), grad(p))*dx + div(f*vector_field)*p*dx

Note, that we have to call the get_vector_field method which returns the UFL object corresponding to 𝒱 and whichis to be used at its place.

Hint: Alternatively, one could define the variable vector_field as follows:

space = VectorFunctionSpace(mesh, 'CG', 1)vector_field = TestFunction(space)

which would yield identical results. However, the shorthand via the get_vector_field is more convenient, as onedoes not have to remember to define the correct function space first.

For the adjoint system, the procedure is exactly the same as in cashocs as Solver for Optimal Control Problems and wehave the following code

adjoint_form = inner(grad(p), grad(TestFunction(V)))*dx - TestFunction(V)*dxadjoint_bcs = bcs

100 Chapter 3. Tutorial

Page 105: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Again, the format is analogous to the format of the state system, but now we have to specify a fenics.TestFunctionobject for the adjoint equation.

Finally, the weak forms are supplied to cashocs with the line

sop.supply_custom_forms(dJ, adjoint_form, adjoint_bcs)

and the optimization problem is solved with

sop.solve()

Note: One can also specify either the adjoint system or the shape derivative of the cost functional, using the methodssupply_adjoint_forms or supply_derivatives. However, this is potentially dangerous, due to the following. Theadjoint system is a linear system, and there is no fixed convention for the sign of the adjoint state. Hence, supplying, e.g.,only the adjoint system, might not be compatible with the derivative of the cost functional which cashocs computes. Ineffect, the sign is specified by the choice of adding or subtracting the PDE constraint from the cost functional for thedefinition of a Lagrangian function, which is used to determine the adjoint system and derivative. cashocs internallyuses the convention that the PDE constraint is added, so that, internally, it computes not the adjoint state 𝑝 as definedby the equations given above, but −𝑝 instead. Hence, it is recommended to either specify all respective quantities withthe supply_custom_forms method.

The result is, of course, completely identical to the one of Shape Optimization with a Poisson Problem and looks asfollows

Note: In case multiple state equations are used, the corresponding adjoint systems also have to be specified as orderedlists, just as explained for optimal control problems in Using Multiple Variables and PDEs.

Note: We recommend that you start with the introductory demos for optimal control problems, i.e., Distributed Controlof a Poisson Problem and Documentation of the Config Files for Optimal Control Problems, as these demonstrate thebasic ideas of cashocs. Additionally, they are a bit simpler than the introductory tutorials for shape optimization prob-lems, i.e., Shape Optimization with a Poisson Problem and Documentation of the Config Files for Shape Optimization

3.3. Using cashocs Exclusively as a Solver 101

Page 106: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Problems.

Moreover, we note that some of cashocs functionality is explained only for optimal control, but not for shape opti-mization problems. This includes the contents of Coupled Problems - Picard Iteration, Distributed Control for TimeDependent Problems, Iterative Solvers for State and Adjoint Systems, Optimal Control with State Constraints. However,the corresponding functionalities only deal with either the definition of the state system, its (numerical) solution, or thedefinition of suitable cost functionals. Therefore, they are straightforward to adapt to the case of shape optimization.

On the contrary, the possibility to scale individual terms of a cost functional is only explained in Scaling of the CostFunctional for shape optimization problems, but works completely analogous for optimal control problems.

102 Chapter 3. Tutorial

Page 107: Release 1.4.2 SebastianBlauth

CHAPTER

FOUR

API REFERENCE

cashocs is a shape optimization and optimal control software for python.

cashocs is based on the finite element package FEniCS and uses its high-level unified form language UFL to treatgeneral PDE constrained optimization problems, in particular, shape optimization and optimal control problems.

The documentation for cashocs can be found here.

Here, we detail the (public) API of cashocs.

For a more hands-on approach, we recommend the tutorial, which shows many examples from PDE constrained opti-mization that can be efficiently solved with cashocs.

4.1 PDE Constrained Optimization Problems

If you are using cashocs to solve PDE constrained optimization problems, you should use the following two classes,for either optimal control or shape optimization problems.

4.1.1 OptimalControlProblem

class cashocs.OptimalControlProblem(state_forms, bcs_list, cost_functional_form, states, controls, adjoints,config=None, riesz_scalar_products=None,control_constraints=None, initial_guess=None, ksp_options=None,adjoint_ksp_options=None, scalar_tracking_forms=None,min_max_terms=None, desired_weights=None)

Bases: cashocs._optimization.optimization_problem.OptimizationProblem

Implements an optimal control problem.

This class is used to define an optimal control problem, and also to solve it subsequently. For a detailed docu-mentation, see the examples in the tutorial. For easier input, when considering single (state or control) variables,these do not have to be wrapped into a list. Note, that in the case of multiple variables these have to be groupedinto ordered lists, where state_forms, bcs_list, states, adjoints have to have the same order (i.e. [y1, y2] and[p1, p2], where p1 is the adjoint of y1 and so on.

Parameters

• state_forms (Union[ufl.Form, List[ufl.Form]]) – The weak form of the stateequation (user implemented). Can be either a single UFL form, or a (ordered) list of UFLforms.

103

Page 108: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

• bcs_list (Union[fenics.DirichletBC, List[fenics.DirichletBC],List[List[fenics.DirichletBC]]]) – The list of fenics.DirichletBC ob-jects describing Dirichlet (essential) boundary conditions. If this is None, then no Dirichletboundary conditions are imposed.

• cost_functional_form (Union[ufl.Form, List[ufl.Form]]) – UFL form of thecost functional. Can also be a list of summands of the cost functional

• states (Union[fenics.Function, List[fenics.Function]]) – The state vari-able(s), can either be a fenics.Function, or a list of these.

• controls (Union[fenics.Function, List[fenics.Function]]) – The control vari-able(s), can either be a fenics.Function, or a list of these.

• adjoints (Union[fenics.Function, List[fenics.Function]]) – The adjoint vari-able(s), can either be a fenics.Function, or a (ordered) list of these.

• config (Optional[configparser.ConfigParser]) – The config file for the problem,generated via cashocs.create_config(). Alternatively, this can also be None, in whichcase the default configurations are used, except for the optimization algorithm. This has thento be specified in the solve method. The default is None.

• riesz_scalar_products (Optional[Union[ufl.Form, List[ufl.Form]]]) – Thescalar products of the control space. Can either be None, a single UFL form, or a (ordered)list of UFL forms. If None, the 𝐿2(Ω) product is used (default is None).

• control_constraints (Optional[List[List[Union[float, fenics.Function]]]]) – Box constraints posed on the control, None means that there arenone (default is None). The (inner) lists should contain two elements of the form [u_a,u_b], where u_a is the lower, and u_b the upper bound.

• initial_guess (Optional[List[fenics.Function]]) – List of functions that act asinitial guess for the state variables, should be valid input for fenics.assign(). Defaultsto None, which means a zero initial guess.

• ksp_options (Optional[List[List[List[str]]]]) – A list of strings correspondingto command line options for PETSc, used to solve the state systems. If this is None, then thedirect solver mumps is used (default is None).

• adjoint_ksp_options (Optional[List[List[List[str]]]]) – A list of strings cor-responding to command line options for PETSc, used to solve the adjoint systems. If this isNone, then the same options as for the state systems are used (default is None).

• scalar_tracking_forms (Optional[Union[Dict, List[Dict]]]) – A list of dic-tionaries that define scalar tracking type cost functionals, where an integral value shouldbe brought to a desired value. Each dict needs to have the keys 'integrand' and'tracking_goal'. Default is None, i.e., no scalar tracking terms are considered.

• min_max_terms (Optional[List[Dict]]) – Additional terms for the cost functional, notto be used directly.

• desired_weights (Optional[List[float]]) – A list of values for scaling the cost func-tional terms. If this is supplied, the cost functional has to be given as list of summands. Theindividual terms are then scaled, so that term i has the magnitude of desired_weights[i] forthe initial iteration. In case that desired_weights is None, no scaling is performed. Defaultis None.

Return type OptimalControlProblem

104 Chapter 4. API Reference

Page 109: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Examples

Examples how to use this class can be found in the tutorial.

compute_adjoint_variables()Solves the adjoint system.

This can be used for debugging purposes and solver validation. Updates / overwrites the user input for theadjoint variables. The solve of the corresponding state system needed to determine the adjoints is carriedout automatically.

Return type None

compute_gradient()Solves the Riesz problem to determine the gradient.

This can be used for debugging, or code validation. The necessary solutions of the state and adjoint systemsare carried out automatically.

Returns A list consisting of the (components) of the gradient.

Return type List[fenics.Function]

compute_state_variables()Solves the state system.

This can be used for debugging purposes and to validate the solver. Updates and overwrites the user inputfor the state variables.

Return type None

gradient_test(u=None, h=None, rng=None)Performs a Taylor test to verify correctness of the computed gradient.

Parameters

• u (Optional[List[fenics.Function]]) – The point, at which the gradient shall beverified. If this is None, then the current controls of the optimization problem are used.Default is None.

• h (Optional[List[fenics.Function]]) – The direction(s) for the directional(Gateaux) derivative. If this is None, one random direction is chosen. Default is None.

• rng (Optional[numpy.random.RandomState]) – A numpy random state for calculat-ing a random direction.

Returns The convergence order from the Taylor test. If this is (approximately) 2 or larger, every-thing works as expected.

Return type float

inject_post_hook(function)Changes the a-posteriori hook of the OptimizationProblem to function.

Parameters function (Callable) – A custom function without arguments, which will becalled after the computation of the gradient(s)

Return type None

inject_pre_hook(function)Changes the a-priori hook of the OptimizationProblem to function.

Parameters function (Callable) – A custom function without arguments, which will becalled before each solve of the state system

4.1. PDE Constrained Optimization Problems 105

Page 110: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Return type None

inject_pre_post_hook(pre_function, post_function)Changes the a-priori (pre) and a-posteriori (post) hook

Parameters

• pre_function (Callable) – A function without arguments, which is to be called beforeeach solve of the state system

• post_function (Callable) – A function without arguments, which is to be called aftereach computation of the (shape) gradient

Return type None

solve(algorithm=None, rtol=None, atol=None, max_iter=None)Solves the optimization problem by the method specified in the config file.

Updates / overwrites states, controls, and adjoints according to the optimization method, i.e., the user-inputfenics.Function() objects.

Parameters

• algorithm (Optional[typing_extensions.Literal[gradient_descent, gd,conjugate_gradient, nonlinear_cg, ncg, lbfgs, bfgs, newton]]) – Selectsthe optimization algorithm. Valid choices are 'gradient_descent' or 'gd' for agradient descent method, 'conjugate_gradient', 'nonlinear_cg', 'ncg' or 'cg'for nonlinear conjugate gradient methods, 'lbfgs' or 'bfgs' for limited memory BFGSmethods, and 'newton' for a truncated Newton method. This overwrites the valuespecified in the config file. If this is None, then the value in the config file is used. Defaultis None.

• rtol (Optional[float]) – The relative tolerance used for the termination criterion.Overwrites the value specified in the config file. If this is None, the value from the configfile is taken. Default is None.

• atol (Optional[float]) – The absolute tolerance used for the termination criterion.Overwrites the value specified in the config file. If this is None, the value from the configfile is taken. Default is None.

• max_iter (Optional[int]) – The maximum number of iterations the optimization al-gorithm can carry out before it is terminated. Overwrites the value specified in the configfile. If this is None, the value from the config file is taken. Default is None.

Return type None

Notes

If either rtol or atol are specified as arguments to the solve call, the termination criterion changes to:

• a purely relative one (if only rtol is specified), i.e.,

||∇𝐽(𝑢𝑘)|| ≤ rtol||∇𝐽(𝑢0)||.

• a purely absolute one (if only atol is specified), i.e.,

||∇𝐽(𝑢𝐾)|| ≤ atol.

• a combined one if both rtol and atol are specified, i.e.,

||∇𝐽(𝑢𝑘)|| ≤ atol + rtol||∇𝐽(𝑢0)||

106 Chapter 4. API Reference

Page 111: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

supply_adjoint_forms(adjoint_forms, adjoint_bcs_list)Overwrites the computed weak forms of the adjoint system.

This allows the user to specify their own weak forms of the problems and to use cashocs merely as a solverfor solving the optimization problems.

Parameters

• adjoint_forms (Union[ufl.Form, List[ufl.Form]]) – The UFL forms of the ad-joint system(s).

• adjoint_bcs_list (Union[fenics.DirichletBC, List[fenics.DirichletBC], List[List[fenics.DirichletBC]]]) – The list of Dirichletboundary conditions for the adjoint system(s).

Return type None

supply_custom_forms(derivatives, adjoint_forms, adjoint_bcs_list)Overrides both adjoint system and derivatives with user input.

This allows the user to specify both the derivatives of the reduced cost functional and the correspondingadjoint system, and allows them to use cashocs as a solver.

Parameters

• derivatives (Union[ufl.Form, List[ufl.Form]]) – The derivatives of the re-duced (!) cost functional w.r.t. the control variables.

• adjoint_forms (Union[ufl.Form, List[ufl.Form]]) – The UFL forms of the ad-joint system(s).

• adjoint_bcs_list (Union[fenics.DirichletBC, List[fenics.DirichletBC], List[List[fenics.DirichletBC]]]) – The list of Dirichletboundary conditions for the adjoint system(s).

Return type None

supply_derivatives(derivatives)Overwrites the derivatives of the reduced cost functional w.r.t. controls.

This allows users to implement their own derivatives and use cashocs as a solver library only.

Parameters

• derivatives (Union[ufl.Form, List[ufl.Form]]) – The derivatives of the re-duced (!) cost functional w.r.t.

• variables. (the control) –

Return type None

4.1.2 ShapeOptimizationProblem

class cashocs.ShapeOptimizationProblem(state_forms, bcs_list, cost_functional_form, states, adjoints,boundaries, config=None, shape_scalar_product=None,initial_guess=None, ksp_options=None,adjoint_ksp_options=None, scalar_tracking_forms=None,min_max_terms=None, desired_weights=None)

Bases: cashocs._optimization.optimization_problem.OptimizationProblem

A shape optimization problem.

4.1. PDE Constrained Optimization Problems 107

Page 112: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

This class is used to define a shape optimization problem, and to solve it subsequently. For a detailed documenta-tion, we refer to the tutorial. For easier input, when consider single (state or control) variables, these do not haveto be wrapped into a list. Note, that in the case of multiple variables these have to be grouped into ordered lists,where state_forms, bcs_list, states, adjoints have to have the same order (i.e. [y1, y2] and [p1,p2], where p1 is the adjoint of y1 and so on).

Parameters

• state_forms (Union[ufl.Form, List[ufl.Form]]) – The weak form of the stateequation (user implemented). Can be either a single UFL form, or a (ordered) list of UFLforms.

• bcs_list (Union[fenics.DirichletBC, List[fenics.DirichletBC],List[List[fenics.DirichletBC]], None]) – The list of fenics.DirichletBCobjects describing Dirichlet (essential) boundary conditions. If this is None, then noDirichlet boundary conditions are imposed.

• cost_functional_form (Union[ufl.Form, List[ufl.Form]]) – UFL form of thecost functional. Can also be a list of summands of the cost functional

• states (Union[fenics.Function, List[fenics.Function]]) – The state vari-able(s), can either be a fenics.Function, or a list of these.

• adjoints (Union[fenics.Function, List[fenics.Function]]) – The adjoint vari-able(s), can either be a fenics.Function, or a (ordered) list of these.

• boundaries (fenics.MeshFunction) – A fenics.MeshFunction that indicates theboundary markers.

• config (Optional[configparser.ConfigParser]) – The config file for the problem,generated via cashocs.create_config(). Alternatively, this can also be None, in whichcase the default configurations are used, except for the optimization algorithm. This has thento be specified in the solve method. The default is None.

• shape_scalar_product (Optional[ufl.Form]) – The bilinear form for computing theshape gradient (or gradient deformation). This has to use fenics.TrialFunction andfenics.TestFunction objects to define the weak form, which have to be in a fenics.VectorFunctionSpace of continuous, linear Lagrange finite elements. Moreover, this formis required to be symmetric.

• initial_guess (Optional[List[fenics.Function]]) – List of functions that act asinitial guess for the state variables, should be valid input for fenics.assign(). Defaultsto None, which means a zero initial guess.

• ksp_options (Optional[List[List[List[str]]]]) – A list of strings correspondingto command line options for PETSc, used to solve the state systems. If this is None, then thedirect solver mumps is used (default is None).

• adjoint_ksp_options (Optional[List[List[List[str]]]]) – A list of strings cor-responding to command line options for PETSc, used to solve the adjoint systems. If this isNone, then the same options as for the state systems are used (default is None).

• scalar_tracking_forms (Optional[Dict]) – A list of dictionaries that define scalartracking type cost functionals, where an integral value should be brought to a desired value.Each dict needs to have the keys 'integrand' and 'tracking_goal'. Default is None,i.e., no scalar tracking terms are considered.

• min_max_terms (Optional[Dict]) – Additional terms for the cost functional, not to beused directly.

108 Chapter 4. API Reference

Page 113: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

• desired_weights (Optional[List[float]]) – A list of values for scaling the cost func-tional terms. If this is supplied, the cost functional has to be given as list of summands. Theindividual terms are then scaled, so that term i has the magnitude of desired_weights[i] forthe initial iteration. In case that desired_weights is None, no scaling is performed. Defaultis None.

Return type ShapeOptimizationProblem

compute_adjoint_variables()Solves the adjoint system.

This can be used for debugging purposes and solver validation. Updates / overwrites the user input for theadjoint variables. The solve of the corresponding state system needed to determine the adjoints is carriedout automatically.

Return type None

compute_shape_gradient()Solves the Riesz problem to determine the shape gradient.

This can be used for debugging, or code validation. The necessary solutions of the state and adjoint systemsare carried out automatically.

Returns A list containing the shape gradient.

Return type List[fenics.Function]

compute_state_variables()Solves the state system.

This can be used for debugging purposes and to validate the solver. Updates and overwrites the user inputfor the state variables.

Return type None

get_vector_field()Returns the TestFunction for defining shape derivatives.

Returns The TestFunction object.

Return type dolfin.function.argument.Argument

gradient_test(h=None, rng=None)Performs a Taylor test to verify that the computed shape gradient is correct.

Parameters

• h (Optional[fenics.Function]) – The direction used to compute the directionalderivative. If this is None, then a random direction is used (default is None).

• rng (Optional[numpy.random.RandomState]) – A numpy random state for calculat-ing a random direction

Returns The convergence order from the Taylor test. If this is (approximately) 2 or larger, every-thing works as expected.

Return type float

inject_post_hook(function)Changes the a-posteriori hook of the OptimizationProblem to function.

Parameters function (Callable) – A custom function without arguments, which will becalled after the computation of the gradient(s)

Return type None

4.1. PDE Constrained Optimization Problems 109

Page 114: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

inject_pre_hook(function)Changes the a-priori hook of the OptimizationProblem to function.

Parameters function (Callable) – A custom function without arguments, which will becalled before each solve of the state system

Return type None

inject_pre_post_hook(pre_function, post_function)Changes the a-priori (pre) and a-posteriori (post) hook

Parameters

• pre_function (Callable) – A function without arguments, which is to be called beforeeach solve of the state system

• post_function (Callable) – A function without arguments, which is to be called aftereach computation of the (shape) gradient

Return type None

solve(algorithm=None, rtol=None, atol=None, max_iter=None)Solves the optimization problem by the method specified in the config file.

Parameters

• algorithm (Optional[typing_extensions.Literal[gradient_descent, gd,conjugate_gradient, nonlinear_cg, ncg, lbfgs, bfgs]]) – Selects the op-timization algorithm. Valid choices are 'gradient_descent' or 'gd' for a gradientdescent method, 'conjugate_gradient', 'nonlinear_cg', 'ncg' or 'cg' fornonlinear conjugate gradient methods, and 'lbfgs' or 'bfgs' for limited memoryBFGS methods. This overwrites the value specified in the config file. If this is None, thenthe value in the config file is used. Default is None.

• rtol (Optional[float]) – The relative tolerance used for the termination criterion.Overwrites the value specified in the config file. If this is None, the value from the configfile is taken. Default is None.

• atol (Optional[float]) – The absolute tolerance used for the termination criterion.Overwrites the value specified in the config file. If this is None, the value from the configfile is taken. Default is None.

• max_iter (Optional[int]) – The maximum number of iterations the optimization al-gorithm can carry out before it is terminated. Overwrites the value specified in the configfile. If this is None, the value from the config file is taken. Default is None.

Return type None

Notes

If either rtol or atol are specified as arguments to the solve call, the termination criterion changes to:

• a purely relative one (if only rtol is specified), i.e.,

||∇𝐽(𝑢𝑘)|| ≤ rtol||∇𝐽(𝑢0)||.

• a purely absolute one (if only atol is specified), i.e.,

||∇𝐽(𝑢𝐾)|| ≤ atol.

• a combined one if both rtol and atol are specified, i.e.,

||∇𝐽(𝑢𝑘)|| ≤ atol + rtol||∇𝐽(𝑢0)||

110 Chapter 4. API Reference

Page 115: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

supply_adjoint_forms(adjoint_forms, adjoint_bcs_list)Overwrites the computed weak forms of the adjoint system.

This allows the user to specify their own weak forms of the problems and to use cashocs merely as a solverfor solving the optimization problems.

Parameters

• adjoint_forms (Union[ufl.Form, List[ufl.Form]]) – The UFL forms of the ad-joint system(s).

• adjoint_bcs_list (Union[fenics.DirichletBC, List[fenics.DirichletBC], List[List[fenics.DirichletBC]]]) – The list of Dirichletboundary conditions for the adjoint system(s).

Return type None

supply_custom_forms(shape_derivative, adjoint_forms, adjoint_bcs_list)Overrides both adjoint system and shape derivative with user input.

This allows the user to specify both the shape_derivative of the reduced cost functional and the correspond-ing adjoint system, and allows them to use cashocs as a solver.

Parameters

• shape_derivative (ufl.Form) – The shape derivative of the reduced (!) cost functional.

• adjoint_forms (Union[ufl.Form, List[ufl.Form]]) – The UFL forms of the ad-joint system(s).

• adjoint_bcs_list (Union[fenics.DirichletBC, List[fenics.DirichletBC], List[List[fenics.DirichletBC]]]) – The list of Dirichletboundary conditions for the adjoint system(s).

Return type None

supply_shape_derivative(shape_derivative)Overrides the shape derivative of the reduced cost functional.

This allows users to implement their own shape derivative and use cashocs as a solver library only.

Parameters shape_derivative (ufl.Form) – The shape_derivative of the reduced cost func-tional.

Return type None

4.2 Additionally constrained problems

4.2.1 ConstrainedOptimalControlProblem

class cashocs.ConstrainedOptimalControlProblem(state_forms, bcs_list, cost_functional_form, states,controls, adjoints, constraint_list, config=None,riesz_scalar_products=None,control_constraints=None, initial_guess=None,ksp_options=None, adjoint_ksp_options=None,scalar_tracking_forms=None)

Bases: cashocs._constraints.constrained_problems.ConstrainedOptimizationProblem

An optimal control problem with additional (in-)equality constraints.

Parameters

4.2. Additionally constrained problems 111

Page 116: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

• state_forms (Union[ufl.Form, List[ufl.Form]]) – The weak form of the stateequation (user implemented). Can be either a single UFL form, or a (ordered) list of UFLforms.

• bcs_list (Union[fenics.DirichletBC, List[fenics.DirichletBC],List[List[fenics.DirichletBC]]]) – The list of fenics.DirichletBC ob-jects describing Dirichlet (essential) boundary conditions. If this is None, then no Dirichletboundary conditions are imposed.

• cost_functional_form (Union[ufl.Form, List[ufl.Form]]) – UFL form of thecost functional. Can also be a list of summands of the cost functional

• states (Union[fenics.Function, List[fenics.Function]]) – The state vari-able(s), can either be a fenics.Function, or a list of these.

• controls (Union[fenics.Function, List[fenics.Function]]) – The control vari-able(s), can either be a fenics.Function, or a list of these.

• adjoints (Union[fenics.Function, List[fenics.Function]]) – The adjoint vari-able(s), can either be a fenics.Function, or a (ordered) list of these.

• constraint_list (Union[constraints.EqualityConstraint, constraints.InequalityConstraint, List[Union[constraints.EqualityConstraint,constraints.InequalityConstraint]]]) – (A list of) additional equality andinequality constraints for the problem.

• config (Optional[configparser.ConfigParser]) – The config file for the problem,generated via cashocs.create_config(). Alternatively, this can also be None, in whichcase the default configurations are used, except for the optimization algorithm. This has thento be specified in the solve method. The default is None.

• riesz_scalar_products (Optional[Union[ufl.Form, List[ufl.Form]]]) – Thescalar products of the control space. Can either be None, a single UFL form, or a (ordered)list of UFL forms. If None, the 𝐿2(Ω) product is used (default is None).

• control_constraints (Optional[List[List[Union[float, fenics.Function]]]]) – Box constraints posed on the control, None means that there arenone (default is None). The (inner) lists should contain two elements of the form [u_a,u_b], where u_a is the lower, and u_b the upper bound.

• initial_guess (Optional[List[fenics.Function]]) – List of functions that act asinitial guess for the state variables, should be valid input for fenics.assign(). Defaultsto None, which means a zero initial guess.

• ksp_options (Optional[List[List[List[str]]]]) – A list of strings correspondingto command line options for PETSc, used to solve the state systems. If this is None, then thedirect solver mumps is used (default is None).

• adjoint_ksp_options (Optional[List[List[List[str]]]]) – A list of strings cor-responding to command line options for PETSc, used to solve the adjoint systems. If this isNone, then the same options as for the state systems are used (default is None).

• scalar_tracking_forms (Optional[Union[Dict, List[Dict]]]) – A list of dic-tionaries that define scalar tracking type cost functionals, where an integral value shouldbe brought to a desired value. Each dict needs to have the keys 'integrand' and'tracking_goal'. Default is None, i.e., no scalar tracking terms are considered.

Return type None

inject_post_hook(function)Changes the a-posteriori hook of the OptimizationProblem.

112 Chapter 4. API Reference

Page 117: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Parameters function (Callable) – A custom function without arguments, which will becalled after the computation of the gradient(s)

Return type None

inject_pre_hook(function)Changes the a-priori hook of the OptimizationProblem.

Parameters function (Callable) – A custom function without arguments, which will becalled before each solve of the state system

Return type None

inject_pre_post_hook(pre_function, post_function)Changes the a-priori (pre) and a-posteriori (post) hook of the problem.

Parameters

• pre_function (Callable) – A function without arguments, which is to be called beforeeach solve of the state system

• post_function (Callable) – A function without arguments, which is to be called aftereach computation of the (shape) gradient

Return type None

solve(method='Augmented Lagrangian', tol=0.01, max_iter=25, inner_rtol=None, inner_atol=None,constraint_tol=None, mu_0=None, lambda_0=None)

Solves the constrained optimization problem.

Parameters

• method (typing_extensions.Literal[Augmented Lagrangian, AL,Quadratic Penalty, QP]) – The solution algorithm, either an augmented Lagrangianmethod (“Augmented Lagrangian”, “AL”) or quadratic penalty method (“QuadraticPenalty”, “QP”)

• tol (float) – An overall tolerance to be used in the algorithm. This will set the relativetolerance for the inner optimization problems to tol. Default is 1e-2.

• max_iter (int) – Maximum number of iterations for the outer solver. Default is 25.

• inner_rtol (Optional[float]) – Relative tolerance for the inner problem. Default isNone,

• used. (so that inner_rtol = tol is) –

• inner_atol (Optional[float]) – Absolute tolerance for the inner problem. Default isNone, so that inner_atol = tol/10 is used.

• constraint_tol (Optional[float]) – The tolerance for the constraint violation, whichis desired. If this is None (default), then this is specified as tol/10.

• mu_0 (Optional[float]) – Initial value of the penalty parameter. Default is None, whichmeans that mu_0 = 1 is used.

• lambda_0 (Optional[List[float]]) – Initial guess for the Lagrange multipliers. De-fault is None, which corresponds to a zero guess.

Return type None

total_constraint_violation()Computes the total constraint violation.

Returns The 2-norm of the total constraint violation.

4.2. Additionally constrained problems 113

Page 118: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Return type float

4.2.2 ConstrainedShapeOptimizationProblem

class cashocs.ConstrainedShapeOptimizationProblem(state_forms, bcs_list, cost_functional_form, states,adjoints, boundaries, constraint_list, config=None,shape_scalar_product=None, initial_guess=None,ksp_options=None, adjoint_ksp_options=None,scalar_tracking_forms=None)

Bases: cashocs._constraints.constrained_problems.ConstrainedOptimizationProblem

A shape optimization problem with additional (in-)equality constraints.

Parameters

• state_forms (Union[ufl.Form, List[ufl.Form]]) – The weak form of the stateequation (user implemented). Can be either a single UFL form, or a (ordered) list of UFLforms.

• bcs_list (Union[fenics.DirichletBC, List[fenics.DirichletBC],List[List[fenics.DirichletBC]], None]) – The list of fenics.DirichletBCobjects describing Dirichlet (essential) boundary conditions. If this is None, then noDirichlet boundary conditions are imposed.

• cost_functional_form (Union[ufl.Form, List[ufl.Form]]) – UFL form of thecost functional. Can also be a list of summands of the cost functional

• states (Union[fenics.Function, List[fenics.Function]]) – The state vari-able(s), can either be a fenics.Function, or a list of these.

• adjoints (Union[fenics.Function, List[fenics.Function]]) – The adjoint vari-able(s), can either be a fenics.Function, or a (ordered) list of these.

• boundaries (fenics.MeshFunction) – A fenics.MeshFunction that indicates theboundary markers.

• constraint_list (Union[constraints.EqualityConstraint, constraints.InequalityConstraint, List[constraints.EqualityConstraint,constraints.InequalityConstraint]]) – (A list of) additional equality and in-equality constraints for the problem.

• config (Optional[configparser.ConfigParser]) – The config file for the problem,generated via cashocs.create_config(). Alternatively, this can also be None, in whichcase the default configurations are used, except for the optimization algorithm. This has thento be specified in the solve method. The default is None.

• shape_scalar_product (Optional[ufl.Form]) – The bilinear form for computing theshape gradient (or gradient deformation). This has to use fenics.TrialFunction andfenics.TestFunction objects to define the weak form, which have to be in a fenics.VectorFunctionSpace of continuous, linear Lagrange finite elements. Moreover, this formis required to be symmetric.

• initial_guess (Optional[List[fenics.Function]]) – List of functions that act asinitial guess for the state variables, should be valid input for fenics.assign(). Defaultsto None, which means a zero initial guess.

• ksp_options (Optional[List[List[List[str]]]]) – A list of strings correspondingto command line options for PETSc, used to solve the state systems. If this is None, then thedirect solver mumps is used (default is None).

114 Chapter 4. API Reference

Page 119: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

• adjoint_ksp_options (Optional[List[List[List[str]]]]) – A list of strings cor-responding to command line options for PETSc, used to solve the adjoint systems. If this isNone, then the same options as for the state systems are used (default is None).

• scalar_tracking_forms (Optional[Dict]) – A list of dictionaries that define scalartracking type cost functionals, where an integral value should be brought to a desired value.Each dict needs to have the keys 'integrand' and 'tracking_goal'. Default is None,i.e., no scalar tracking terms are considered.

Return type None

inject_post_hook(function)Changes the a-posteriori hook of the OptimizationProblem.

Parameters function (Callable) – A custom function without arguments, which will becalled after the computation of the gradient(s)

Return type None

inject_pre_hook(function)Changes the a-priori hook of the OptimizationProblem.

Parameters function (Callable) – A custom function without arguments, which will becalled before each solve of the state system

Return type None

inject_pre_post_hook(pre_function, post_function)Changes the a-priori (pre) and a-posteriori (post) hook of the problem.

Parameters

• pre_function (Callable) – A function without arguments, which is to be called beforeeach solve of the state system

• post_function (Callable) – A function without arguments, which is to be called aftereach computation of the (shape) gradient

Return type None

solve(method='Augmented Lagrangian', tol=0.01, max_iter=25, inner_rtol=None, inner_atol=None,constraint_tol=None, mu_0=None, lambda_0=None)

Solves the constrained optimization problem.

Parameters

• method (typing_extensions.Literal[Augmented Lagrangian, AL,Quadratic Penalty, QP]) – The solution algorithm, either an augmented Lagrangianmethod (“Augmented Lagrangian”, “AL”) or quadratic penalty method (“QuadraticPenalty”, “QP”)

• tol (float) – An overall tolerance to be used in the algorithm. This will set the relativetolerance for the inner optimization problems to tol. Default is 1e-2.

• max_iter (int) – Maximum number of iterations for the outer solver. Default is 25.

• inner_rtol (Optional[float]) – Relative tolerance for the inner problem. Default isNone,

• used. (so that inner_rtol = tol is) –

• inner_atol (Optional[float]) – Absolute tolerance for the inner problem. Default isNone, so that inner_atol = tol/10 is used.

4.2. Additionally constrained problems 115

Page 120: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

• constraint_tol (Optional[float]) – The tolerance for the constraint violation, whichis desired. If this is None (default), then this is specified as tol/10.

• mu_0 (Optional[float]) – Initial value of the penalty parameter. Default is None, whichmeans that mu_0 = 1 is used.

• lambda_0 (Optional[List[float]]) – Initial guess for the Lagrange multipliers. De-fault is None, which corresponds to a zero guess.

Return type None

total_constraint_violation()Computes the total constraint violation.

Returns The 2-norm of the total constraint violation.

Return type float

4.2.3 EqualityConstraint

class cashocs.EqualityConstraint(variable_function, target, measure=None)Bases: cashocs._constraints.constraints.Constraint

Models an (additional) equality constraint.

Parameters

• variable_function (Union[ufl.Form, ufl.core.expr.Expr]) – Either a ufl Form(when we have a scalar / integral constraint) or an ufl expression (when we have a pointwiseconstraint), which models the part that is to be constrained.

• target (float) – The target (rhs) of the equality constraint.

• measure (Optional[fenics.Measure]) – A measure indicating where a pointwise con-straint should be satisfied.

Return type None

constraint_violation()Computes the constraint violation for the problem.

Returns The computed violation

Return type float

4.2.4 InequalityConstraint

class cashocs.InequalityConstraint(variable_function, lower_bound=None, upper_bound=None,measure=None)

Bases: cashocs._constraints.constraints.Constraint

Models an (additional) inequality constraint.

Parameters

• variable_function (Union[ufl.Form, ufl.core.expr.Expr]) – Either a ufl Form(when we have a scalar / integral constraint) or an ufl expression (when we have a pointwiseconstraint), which models the part that is to be constrained

• lower_bound (Optional[Union[float, fenics.Function]]) – The lower bound forthe inequality constraint

116 Chapter 4. API Reference

Page 121: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

• upper_bound (Optional[Union[float, fenics.Function]]) – The upper bound forthe inequality constraint

• measure (Optional[fenics.Measure]) – A measure indicating where a pointwise con-straint should be satisfied.

Return type None

constraint_violation()Computes the constraint violation for the problem.

Returns The computed violation

Return type float

4.3 Command Line Interface

For the command line interface of cashocs, we have a mesh conversion tool which converts GMSH .msh files to .xdmfones, which can be read with the import mesh functionality. It’s usage is detailed in the following.

4.3.1 cashocs-convert

Convert GMSH to XDMF.

usage: cashocs-convert [-h] infile outfile

Positional Arguments

infile GMSH file to be converted, has to end in .msh

outfile XDMF file to which the mesh shall be converted, has to end in .xdmf

4.4 MeshQuality

class cashocs.MeshQualityA class used to compute the quality of a mesh.

This class implements either a skewness quality measure, one based on the maximum angle of the elements, orone based on the radius ratios. All quality measures have values in [0, 1], where 1 corresponds to the reference(optimal) element, and 0 corresponds to degenerate elements.

4.3. Command Line Interface 117

Page 122: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Examples

This class can be directly used, without any instantiation, as shown here

import cashocs

mesh, _, _, _, _, _ = cashocs.regular_mesh(10)

min_skew = cashocs.MeshQuality.min_skewness(mesh)avg_skew = cashocs.MeshQuality.avg_skewness(mesh)

min_angle = cashocs.MeshQuality.min_maximum_angle(mesh)avg_angle = cashocs.MeshQuality.avg_maximum_angle(mesh)

min_rad = cashocs.MeshQuality.min_radius_ratios(mesh)avg_rad = cashocs.MeshQuality.avg_radius_ratios(mesh)

min_cond = cashocs.MeshQuality.min_condition_number(mesh)avg_cond = cashocs.MeshQuality.avg_condition_number(mesh)

This works analogously for any mesh compatible with FEniCS.

Return type None

static avg_condition_number(mesh)Computes quality based on the condition number of the reference mapping.

This quality criterion uses the condition number (in the Frobenius norm) of the (linear) mapping from theelements of the mesh to the reference element. Computes the average of the condition number over allelements.

Parameters mesh – The mesh, whose quality shall be computed.

Returns The average mesh quality based on the condition number.

classmethod avg_maximum_angle(mesh)Computes the average quality measure based on the largest angle.

This measures the relative distance of a triangle’s angles or a tetrahedron’s dihedral angles to the corre-sponding optimal angle. The optimal angle is defined as the angle an equilateral (and thus equiangular)element has. This is defined as

1 − max

(𝛼− 𝛼*

𝜋 − 𝛼* , 0

),

where 𝛼 is the corresponding (dihedral) angle of the element and 𝛼* is the corresponding (dihedral) angleof the reference element. To compute the quality measure, the average of this expression over all elementsand all of their (dihedral) angles is computed.

Parameters mesh (fenics.Mesh ) – The mesh, whose quality shall be computed.

Returns The average quality, based on the maximum angle measure.

Return type float

static avg_radius_ratios(mesh)Computes the average radius ratio of the mesh.

This measures the ratio of the element’s inradius to it’s circumradius, normalized by the geometric dimen-sion. This is computed via

𝑑𝑟

𝑅,

118 Chapter 4. API Reference

Page 123: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

where 𝑑 is the spatial dimension, 𝑟 is the inradius, and 𝑅 is the circumradius. To compute the (global)quality measure, the average of this expression over all elements is returned.

Parameters mesh (fenics.Mesh ) – The mesh, whose quality shall be computed.

Returns The average radius ratio of the mesh.

Return type float

classmethod avg_skewness(mesh)Computes the average skewness of the mesh.

This measure the relative distance of a triangle’s angles or a tetrahedron’s dihedral angles to the correspond-ing optimal angle. The optimal angle is defined as the angle an equilateral, and thus equiangular, elementhas. The skewness lies in [0, 1], where 1 corresponds to the case of an optimal (equilateral) element, and0 corresponds to a degenerate element. The skewness corresponding to some (dihedral) angle 𝛼 is definedas

1 − max

(𝛼− 𝛼*

𝜋 − 𝛼*,𝛼* − 𝛼

𝛼* − 0

),

where 𝛼* is the corresponding angle of the reference element. To compute the quality measure, the averageof this expression over all elements and all of their (dihedral) angles is computed.

Parameters mesh (fenics.Mesh ) – The mesh, whose quality shall be computed.

Returns The average skewness of the mesh.

Return type float

static min_condition_number(mesh)Computes quality based on the condition number of the reference mapping.

This quality criterion uses the condition number (in the Frobenius norm) of the (linear) mapping from theelements of the mesh to the reference element. Computes the minimum of the condition number over allelements.

Parameters mesh (fenics.Mesh ) – The mesh, whose quality shall be computed.

Returns The minimal condition number quality measure.

Return type float

classmethod min_maximum_angle(mesh)Computes the minimal quality measure based on the largest angle.

This measures the relative distance of a triangle’s angles or a tetrahedron’s dihedral angles to the corre-sponding optimal angle. The optimal angle is defined as the angle an equilateral (and thus equiangular)element has. This is defined as

1 − max

(𝛼− 𝛼*

𝜋 − 𝛼* , 0

),

where 𝛼 is the corresponding (dihedral) angle of the element and 𝛼* is the corresponding (dihedral) angleof the reference element. To compute the quality measure, the minimum of this expression over all elementsand all of their (dihedral) angles is computed.

Parameters mesh (fenics.Mesh ) – The mesh, whose quality shall be computed.

Returns The minimum value of the maximum angle quality measure.

Return type float

4.4. MeshQuality 119

Page 124: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

static min_radius_ratios(mesh)Computes the minimal radius ratio of the mesh.

This measures the ratio of the element’s inradius to it’s circumradius, normalized by the geometric dimen-sion. This is computed via

𝑑𝑟

𝑅,

where 𝑑 is the spatial dimension, 𝑟 is the inradius, and 𝑅 is the circumradius. To compute the (global)quality measure, the minimum of this expression over all elements is returned.

Parameters mesh (fenics.Mesh ) – The mesh, whose quality shall be computed.

Returns The minimal radius ratio of the mesh.

Return type float

classmethod min_skewness(mesh)Computes the minimal skewness of the mesh.

This measure the relative distance of a triangle’s angles or a tetrahedron’s dihedral angles to the correspond-ing optimal angle. The optimal angle is defined as the angle an equilateral, and thus equiangular, elementhas. The skewness lies in [0, 1], where 1 corresponds to the case of an optimal (equilateral) element, and0 corresponds to a degenerate element. The skewness corresponding to some (dihedral) angle 𝛼 is definedas

1 − max

(𝛼− 𝛼*

𝜋 − 𝛼*,𝛼* − 𝛼

𝛼* − 0

),

where 𝛼* is the corresponding angle of the reference element. To compute the quality measure, the mini-mum of this expression over all elements and all of their (dihedral) angles is computed.

Parameters mesh (fenics.Mesh ) – The mesh whose quality shall be computed.

Returns The minimum skewness of the mesh.

Return type float

4.5 DeformationHandler

class cashocs.DeformationHandler(mesh)A class, which implements mesh deformations.

The deformations can be due to a deformation vector field or a (piecewise) update of the mesh coordinates.

Parameters mesh (fenics.Mesh ) – The fenics mesh which is to be deformed.

Return type None

assign_coordinates(coordinates)Assigns coordinates to self.mesh.

Parameters coordinates (numpy.ndarray) – Array of mesh coordinates, which you want toassign.

Returns True if the assignment was possible, False if not.

Return type bool

coordinate_to_dof(coordinate_deformation)Converts a coordinate deformation to a deformation vector field (dof based).

120 Chapter 4. API Reference

Page 125: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Parameters coordinate_deformation (numpy.ndarray) – The deformation for the mesh co-ordinates.

Returns The deformation vector field.

Return type fenics.Function

dof_to_coordinate(dof_deformation)Converts a deformation vector field to a coordinate based deformation.

Parameters dof_deformation (fenics.Function) – The deformation vector field.

Returns The array which can be used to deform the mesh coordinates.

Return type numpy.ndarray

move_mesh(transformation, validated_a_priori=False)Transforms the mesh by perturbation of identity.

Moves the mesh according to the deformation given by

id + 𝒱(𝑥),

where 𝒱 is the transformation. This represents the perturbation of identity.

Parameters

• transformation (Union[fenics.Function, numpy.ndarray]) – The transforma-tion for the mesh, a vector CG1 Function.

• validated_a_priori (bool) – A boolean flag, which indicates whether an a-priori checkhas already been performed before moving the mesh. Default is False

Returns True if the mesh movement was successful, False otherwise.

Return type bool

revert_transformation()Reverts the previous mesh transformation.

This is used when the mesh quality for the resulting deformed mesh is not sufficient, or when the solutionalgorithm terminates, e.g., due to lack of sufficient decrease in the Armijo rule

Return type None

4.6 Functions

The functions which are directly available in cashocs are taken from the sub-modules geometry,nonlinear_solvers, and utils. These are functions that are likely to be used often, so that they are di-rectly callable via cashocs.function for any of the functions shown below. Note, that they are repeated in the APIreference for their respective sub-modules.

4.6. Functions 121

Page 126: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

4.6.1 import_mesh

cashocs.import_mesh(input_arg)Imports a mesh file for use with cashocs / FEniCS.

This function imports a mesh file that was generated by GMSH and converted to .xdmf with the command linefunction cashocs-convert. If there are Physical quantities specified in the GMSH file, these are imported to thesubdomains and boundaries output of this function and can also be directly accessed via the measures, e.g., withdx(1), ds(1), etc.

Parameters input_arg (Union[str, configparser.ConfigParser]) – This is either a string,in which case it corresponds to the location of the mesh file in .xdmf file format, or a config filethat has this path stored in its settings, under the section Mesh, as parameter mesh_file.

Returns A tuple (mesh, subdomains, boundaries, dx, ds, dS), where mesh is the imported FEMmesh, subdomains is a mesh function for the subdomains, boundaries is a mesh function for theboundaries, dx is a volume measure, ds is a surface measure, and dS is a measure for the interiorfacets.

Return type Tuple[cashocs.geometry.mesh.Mesh, fenics.MeshFunction, fenics.MeshFunction, fen-ics.Measure, fenics.Measure, fenics.Measure]

Notes

In case the boundaries in the Gmsh .msh file are not only marked with numbers (as physical groups), but alsowith names (i.e. strings), these strings can be used with the integration measures dx and ds returned by thismethod. E.g., if one specified the following in a 2D Gmsh .geo file

Physical Surface("domain", 1) = i,j,k;

where i,j,k are representative for some integers, then this can be used in the measure dx (as we are 2D) as follows.The command

dx(1)

is completely equivalent to

dx("domain")

and both can be used interchangeably.

4.6.2 regular_mesh

cashocs.regular_mesh(n=10, length_x=1.0, length_y=1.0, length_z=None, diagonal='right')Creates a mesh corresponding to a rectangle or cube.

This function creates a uniform mesh of either a rectangle or a cube, starting at the origin and having length spec-ified in length_x, length_y, and length_z. The resulting mesh uses n elements along the shortest directionand accordingly many along the longer ones. The resulting domain is

[0, 𝑙𝑒𝑛𝑔𝑡ℎ𝑥] × [0, 𝑙𝑒𝑛𝑔𝑡ℎ𝑦] in 2𝐷,

[0, 𝑙𝑒𝑛𝑔𝑡ℎ𝑥] × [0, 𝑙𝑒𝑛𝑔𝑡ℎ𝑦] × [0, 𝑙𝑒𝑛𝑔𝑡ℎ𝑧] in 3𝐷.

The boundary markers are ordered as follows:

• 1 corresponds to 𝑥 = 0.

122 Chapter 4. API Reference

Page 127: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

• 2 corresponds to 𝑥 = 𝑙𝑒𝑛𝑔𝑡ℎ𝑥.

• 3 corresponds to 𝑦 = 0.

• 4 corresponds to 𝑦 = 𝑙𝑒𝑛𝑔𝑡ℎ𝑦 .

• 5 corresponds to 𝑧 = 0 (only in 3D).

• 6 corresponds to 𝑧 = 𝑙𝑒𝑛𝑔𝑡ℎ𝑧 (only in 3D).

Parameters

• n (int) – Number of elements in the shortest coordinate direction.

• length_x (float) – Length in x-direction.

• length_y (float) – Length in y-direction.

• length_z (Optional[float]) – Length in z-direction, if this is None, then the geometrywill be two-dimensional (default is None).

• diagonal (typing_extensions.Literal[left, right, left/right, right/left, crossed]) – This defines the type of diagonal used to create the box mesh in 2D.This can be one of "right", "left", "left/right", "right/left" or "crossed".

Returns A tuple (mesh, subdomains, boundaries, dx, ds, dS), where mesh is the imported FEMmesh, subdomains is a mesh function for the subdomains, boundaries is a mesh function for theboundaries, dx is a volume measure, ds is a surface measure, and dS is a measure for the interiorfacets.

Return type Tuple[fenics.Mesh, fenics.MeshFunction, fenics.MeshFunction, fenics.Measure, fen-ics.Measure, fenics.Measure]

4.6.3 regular_box_mesh

cashocs.regular_box_mesh(n=10, start_x=0.0, start_y=0.0, start_z=None, end_x=1.0, end_y=1.0,end_z=None, diagonal='right')

Creates a mesh corresponding to a rectangle or cube.

This function creates a uniform mesh of either a rectangle or a cube, with specified start (S_) and end points (E_).The resulting mesh uses n elements along the shortest direction and accordingly many along the longer ones.The resulting domain is

[𝑠𝑡𝑎𝑟𝑡𝑥, 𝑒𝑛𝑑𝑥] × [𝑠𝑡𝑎𝑟𝑡𝑦, 𝑒𝑛𝑑𝑦] in 2𝐷,

[𝑠𝑡𝑎𝑟𝑡𝑥, 𝑒𝑛𝑑𝑥] × [𝑠𝑡𝑎𝑟𝑡𝑦, 𝑒𝑛𝑑𝑦] × [𝑠𝑡𝑎𝑟𝑡𝑧, 𝑒𝑛𝑑𝑧] in 3𝐷.

The boundary markers are ordered as follows:

• 1 corresponds to 𝑥 = 𝑠𝑡𝑎𝑟𝑡𝑥.

• 2 corresponds to 𝑥 = 𝑒𝑛𝑑𝑥.

• 3 corresponds to 𝑦 = 𝑠𝑡𝑎𝑟𝑡𝑦 .

• 4 corresponds to 𝑦 = 𝑒𝑛𝑑𝑦 .

• 5 corresponds to 𝑧 = 𝑠𝑡𝑎𝑟𝑡𝑧 (only in 3D).

• 6 corresponds to 𝑧 = 𝑒𝑛𝑑𝑧 (only in 3D).

Parameters

• n (int) – Number of elements in the shortest coordinate direction.

4.6. Functions 123

Page 128: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

• start_x (float) – Start of the x-interval.

• start_y (float) – Start of the y-interval.

• start_z (Optional[float]) – Start of the z-interval, mesh is 2D if this is None (defaultis None).

• end_x (float) – End of the x-interval.

• end_y (float) – End of the y-interval.

• end_z (Optional[float]) – End of the z-interval, mesh is 2D if this is None (default isNone).

• diagonal (typing_extensions.Literal[right, left, left/right, right/left, crossed]) – This defines the type of diagonal used to create the box mesh in 2D.This can be one of "right", "left", "left/right", "right/left" or "crossed".

Returns A tuple (mesh, subdomains, boundaries, dx, ds, dS), where mesh is the imported FEMmesh, subdomains is a mesh function for the subdomains, boundaries is a mesh function for theboundaries, dx is a volume measure, ds is a surface measure, and dS is a measure for the interiorfacets.

Return type Tuple[fenics.Mesh, fenics.MeshFunction, fenics.MeshFunction, fenics.Measure, fen-ics.Measure, fenics.Measure]

4.6.4 load_config

cashocs.load_config(path)Loads a config object from a config file.

Loads the config from a .ini file via the configparser package.

Parameters path (str) – The path to the .ini file storing the configuration.

Returns The output config file, which includes the path to the .ini file.

Return type configparser.ConfigParser

4.6.5 create_dirichlet_bcs

cashocs.create_dirichlet_bcs(function_space, value, boundaries, idcs, **kwargs)Create several Dirichlet boundary conditions at once.

Wraps multiple Dirichlet boundary conditions into a list, in case they have the same value but are to be defined formultiple boundaries with different markers. Particularly useful for defining homogeneous boundary conditions.

Parameters

• function_space (fenics.FunctionSpace) – The function space onto which the BCsshould be imposed on.

• value (Union[fenics.Constant, fenics.Expression, fenics.Function,float, Tuple[float]]) – The value of the boundary condition. Has to becompatible with the function_space, so that it could also be used as fenics.DirichletBC(function_space, value, ...).

• boundaries (fenics.MeshFunction) – The fenics.MeshFunction object representingthe boundaries.

124 Chapter 4. API Reference

Page 129: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

• idcs (Union[List[Union[int, str]], int, str]) – A list of indices / boundarymarkers that determine the boundaries onto which the Dirichlet boundary conditions shouldbe applied to. Can also be a single entry for a single boundary. If your mesh file is named,then you can also use the names of the boundaries to define the boundary conditions.

• **kwargs – Keyword arguments for fenics.DirichletBC

Returns A list of DirichletBC objects that represent the boundary conditions.

Return type List[fenics.DirichletBC]

Examples

Generate homogeneous Dirichlet boundary conditions for all 4 sides of the unit square

import fenicsimport cashocs

mesh, _, _, _, _, _ = cashocs.regular_mesh(25)V = fenics.FunctionSpace(mesh, 'CG', 1)bcs = cashocs.create_dirichlet_bcs(V, fenics.Constant(0), boundaries,

[1,2,3,4])

4.6.6 newton_solve

cashocs.newton_solve(F, u, bcs, dF=None, shift=None, rtol=1e-10, atol=1e-10, max_iter=50,convergence_type='combined', norm_type='l2', damped=True, inexact=True,verbose=True, ksp=None, ksp_options=None, A_tensor=None, b_tensor=None,is_linear=False)

Parameters

• F (ufl.Form) –

• u (fenics.Function) –

• bcs (Union[fenics.DirichletBC, List[fenics.DirichletBC]]) –

• dF (Optional[ufl.Form]) –

• shift (Optional[ufl.Form]) –

• rtol (float) –

• atol (float) –

• max_iter (int) –

• convergence_type (typing_extensions.Literal[combined, rel, abs]) –

• norm_type (typing_extensions.Literal[l2, linf]) –

• damped (bool) –

• inexact (bool) –

• verbose (bool) –

• ksp (Optional[petsc4py.PETSc.KSP]) –

• ksp_options (Optional[List[List[str]]]) –

4.6. Functions 125

Page 130: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

• A_tensor (Optional[fenics.PETScMatrix]) –

• b_tensor (Optional[fenics.PETScVector]) –

• is_linear (bool) –

Return type fenics.Function

4.6.7 set_log_level

cashocs.set_log_level(level)Determines the log level of cashocs.

Can be used to show, e.g., info and warning messages or to hide them. There are a total of five different levels forthe logs: DEBUG, INFO, WARNING, ERROR, and CRITICAL. The usage of this method is explained in the examplessection.

Parameters level (int) – Should be one of cashocs.LogLevel.DEBUG, cashocs.LogLevel.INFO, cashocs.LogLevel.WARNING, cashocs.LogLevel.ERROR, cashocs.LogLevel.CRITICAL

Return type None

Notes

The log level setting is global, so if you use this interactively, you have to restart / reload your interactive consoleto return to the default settings.

Examples

To set the log level of cashocs, use this method as follows:

import cashocscashocs.set_log_level(cashocs.LogLevel.WARNING)

which only shows messages with a level of WARNING or higher. To use a different level, replace WARNING byDEBUG, INFO, ERROR, or CRITICAL.

4.7 Deprecated Capabilities

Here, we list deprecated functions and classes of cashocs, which can still be used, but are replaced by newer instanceswith more capabilities. These deprecated objects are still maintained for compatibility reasons.

126 Chapter 4. API Reference

Page 131: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

4.7.1 damped_newton_solve

cashocs.damped_newton_solve(F, u, bcs, dF=None, rtol=1e-10, atol=1e-10, max_iter=50,convergence_type='combined', norm_type='l2', damped=True, verbose=True,ksp=None, ksp_options=None)

Damped Newton solve interface, only here for compatibility reasons.

Parameters

• F (ufl.Form) – The variational form of the nonlinear problem to be solved by Newton’smethod.

• u (fenics.Function) – The sought solution / initial guess. It is not assumed that the initialguess satisfies the Dirichlet boundary conditions, they are applied automatically. The methodoverwrites / updates this Function.

• bcs (Union[fenics.DirichletBC, List[fenics.DirichletBC]]) – A list of Dirich-letBCs for the nonlinear variational problem.

• dF (Optional[ufl.Form]) – The Jacobian of F, used for the Newton method. Default isNone, and in this case the Jacobian is computed automatically with AD.

• rtol (float) – Relative tolerance of the solver if convergence_type is either 'combined'or 'rel' (default is rtol = 1e-10).

• atol (float) – Absolute tolerance of the solver if convergence_type is either 'combined'or 'abs' (default is atol = 1e-10).

• max_iter (int) – Maximum number of iterations carried out by the method (default ismax_iter = 50).

• convergence_type (typing_extensions.Literal[combined, rel, abs]) – Deter-mines the type of stopping criterion that is used.

• norm_type (typing_extensions.Literal[l2, linf]) – Determines which norm isused in the stopping criterion.

• damped (bool) – If True, then a damping strategy is used. If False, the classical Newton-Raphson iteration (without damping) is used (default is True).

• verbose (bool) – If True, prints status of the iteration to the console (default is True).

• ksp (Optional[petsc4py.PETSc.KSP]) – The PETSc ksp object used to solve the inner(linear) problem if this is None it uses the direct solver MUMPS (default is None).

• ksp_options (Optional[List[List[str]]]) – The list of options for the linear solver.

Returns The solution of the nonlinear variational problem, if converged. This overwrites the inputfunction u.

Return type fenics.Function

4.7. Deprecated Capabilities 127

Page 132: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Examples

Consider the problem

−∆𝑢 + 𝑢3 = 1 in Ω = (0, 1)2

𝑢 = 0 on Γ.

This is solved with the code

from fenics import *import cashocs

mesh, _, boundaries, dx, _, _ = cashocs.regular_mesh(25)V = FunctionSpace(mesh, 'CG', 1)

u = Function(V)v = TestFunction(V)F = inner(grad(u), grad(v))*dx + pow(u,3)*v*dx - Constant(1)*v*dxbcs = cashocs.create_dirichlet_bcs(V, Constant(0.0), boundaries, [1,2,3,4])cashocs.newton_solve(F, u, bcs)

Deprecated since version 1.5.0: This is replaced by cashocs.newton_solve and will be removed in the future.

4.7.2 create_config

cashocs.create_config(path)Loads a config object from a config file.

Loads the config from a .ini file via the configparser package.

Parameters path (str) – The path to the .ini file storing the configuration.

Returns The output config file, which includes the path to the .ini file.

Return type configparser.ConfigParser

Deprecated since version 1.1.0: This is replaced by load_config and will be removed in the future.

4.7.3 create_bcs_list

cashocs.create_bcs_list(function_space, value, boundaries, idcs, **kwargs)Create several Dirichlet boundary conditions at once.

Wraps multiple Dirichlet boundary conditions into a list, in case they have the same value but are to be defined formultiple boundaries with different markers. Particularly useful for defining homogeneous boundary conditions.

Parameters

• function_space (fenics.FunctionSpace) – The function space onto which the BCsshould be imposed on.

• value (Union[fenics.Constant, fenics.Expression, fenics.Function,float, Tuple[float]]) – The value of the boundary condition. Has to becompatible with the function_space, so that it could also be used as fenics.DirichletBC(function_space, value, ...).

• boundaries (fenics.MeshFunction) – The fenics.MeshFunction object representingthe boundaries.

128 Chapter 4. API Reference

Page 133: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

• idcs (Union[List[Union[int, str]], int, str]) – A list of indices / boundarymarkers that determine the boundaries onto which the Dirichlet boundary conditions shouldbe applied to. Can also be a single integer for a single boundary.

• **kwargs – Keyword arguments for fenics.DirichletBC

Returns A list of DirichletBC objects that represent the boundary conditions.

Return type List[fenics.DirichletBC]

Deprecated since version 1.5.0: This is replaced by cashocs.create_dirichlet_bcs and will be removed in thefuture.

4.8 Sub-Modules

cashocs’ sub-modules include several additional classes and methods that could be potentially useful for the user. Forthe corresponding API documentation, we include the previously detailed objects, too, as to give a complete documen-tation of the sub-module.

4.8.1 Sub-Module geometry

Mesh generation and import tools.

This module consists of tools for for the fast generation or import of meshes into fenics. The import_mesh functionis used to import (converted) GMSH mesh files, and the regular_mesh and regular_box_mesh commands create2D and 3D box meshes which are great for testing.

class cashocs.geometry.DeformationHandler(mesh)A class, which implements mesh deformations.

The deformations can be due to a deformation vector field or a (piecewise) update of the mesh coordinates.

Parameters mesh (fenics.Mesh ) – The fenics mesh which is to be deformed.

Return type None

assign_coordinates(coordinates)Assigns coordinates to self.mesh.

Parameters coordinates (numpy.ndarray) – Array of mesh coordinates, which you want toassign.

Returns True if the assignment was possible, False if not.

Return type bool

coordinate_to_dof(coordinate_deformation)Converts a coordinate deformation to a deformation vector field (dof based).

Parameters coordinate_deformation (numpy.ndarray) – The deformation for the mesh co-ordinates.

Returns The deformation vector field.

Return type fenics.Function

dof_to_coordinate(dof_deformation)Converts a deformation vector field to a coordinate based deformation.

Parameters dof_deformation (fenics.Function) – The deformation vector field.

4.8. Sub-Modules 129

Page 134: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Returns The array which can be used to deform the mesh coordinates.

Return type numpy.ndarray

move_mesh(transformation, validated_a_priori=False)Transforms the mesh by perturbation of identity.

Moves the mesh according to the deformation given by

id + 𝒱(𝑥),

where 𝒱 is the transformation. This represents the perturbation of identity.

Parameters

• transformation (Union[fenics.Function, numpy.ndarray]) – The transforma-tion for the mesh, a vector CG1 Function.

• validated_a_priori (bool) – A boolean flag, which indicates whether an a-priori checkhas already been performed before moving the mesh. Default is False

Returns True if the mesh movement was successful, False otherwise.

Return type bool

revert_transformation()Reverts the previous mesh transformation.

This is used when the mesh quality for the resulting deformed mesh is not sufficient, or when the solutionalgorithm terminates, e.g., due to lack of sufficient decrease in the Armijo rule

Return type None

class cashocs.geometry.MeshQualityA class used to compute the quality of a mesh.

This class implements either a skewness quality measure, one based on the maximum angle of the elements, orone based on the radius ratios. All quality measures have values in [0, 1], where 1 corresponds to the reference(optimal) element, and 0 corresponds to degenerate elements.

Examples

This class can be directly used, without any instantiation, as shown here

import cashocs

mesh, _, _, _, _, _ = cashocs.regular_mesh(10)

min_skew = cashocs.MeshQuality.min_skewness(mesh)avg_skew = cashocs.MeshQuality.avg_skewness(mesh)

min_angle = cashocs.MeshQuality.min_maximum_angle(mesh)avg_angle = cashocs.MeshQuality.avg_maximum_angle(mesh)

min_rad = cashocs.MeshQuality.min_radius_ratios(mesh)avg_rad = cashocs.MeshQuality.avg_radius_ratios(mesh)

min_cond = cashocs.MeshQuality.min_condition_number(mesh)avg_cond = cashocs.MeshQuality.avg_condition_number(mesh)

130 Chapter 4. API Reference

Page 135: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

This works analogously for any mesh compatible with FEniCS.

Return type None

static avg_condition_number(mesh)Computes quality based on the condition number of the reference mapping.

This quality criterion uses the condition number (in the Frobenius norm) of the (linear) mapping from theelements of the mesh to the reference element. Computes the average of the condition number over allelements.

Parameters mesh – The mesh, whose quality shall be computed.

Returns The average mesh quality based on the condition number.

classmethod avg_maximum_angle(mesh)Computes the average quality measure based on the largest angle.

This measures the relative distance of a triangle’s angles or a tetrahedron’s dihedral angles to the corre-sponding optimal angle. The optimal angle is defined as the angle an equilateral (and thus equiangular)element has. This is defined as

1 − max

(𝛼− 𝛼*

𝜋 − 𝛼* , 0

),

where 𝛼 is the corresponding (dihedral) angle of the element and 𝛼* is the corresponding (dihedral) angleof the reference element. To compute the quality measure, the average of this expression over all elementsand all of their (dihedral) angles is computed.

Parameters mesh (fenics.Mesh ) – The mesh, whose quality shall be computed.

Returns The average quality, based on the maximum angle measure.

Return type float

static avg_radius_ratios(mesh)Computes the average radius ratio of the mesh.

This measures the ratio of the element’s inradius to it’s circumradius, normalized by the geometric dimen-sion. This is computed via

𝑑𝑟

𝑅,

where 𝑑 is the spatial dimension, 𝑟 is the inradius, and 𝑅 is the circumradius. To compute the (global)quality measure, the average of this expression over all elements is returned.

Parameters mesh (fenics.Mesh ) – The mesh, whose quality shall be computed.

Returns The average radius ratio of the mesh.

Return type float

classmethod avg_skewness(mesh)Computes the average skewness of the mesh.

This measure the relative distance of a triangle’s angles or a tetrahedron’s dihedral angles to the correspond-ing optimal angle. The optimal angle is defined as the angle an equilateral, and thus equiangular, elementhas. The skewness lies in [0, 1], where 1 corresponds to the case of an optimal (equilateral) element, and0 corresponds to a degenerate element. The skewness corresponding to some (dihedral) angle 𝛼 is definedas

1 − max

(𝛼− 𝛼*

𝜋 − 𝛼*,𝛼* − 𝛼

𝛼* − 0

),

where 𝛼* is the corresponding angle of the reference element. To compute the quality measure, the averageof this expression over all elements and all of their (dihedral) angles is computed.

4.8. Sub-Modules 131

Page 136: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Parameters mesh (fenics.Mesh ) – The mesh, whose quality shall be computed.

Returns The average skewness of the mesh.

Return type float

static min_condition_number(mesh)Computes quality based on the condition number of the reference mapping.

This quality criterion uses the condition number (in the Frobenius norm) of the (linear) mapping from theelements of the mesh to the reference element. Computes the minimum of the condition number over allelements.

Parameters mesh (fenics.Mesh ) – The mesh, whose quality shall be computed.

Returns The minimal condition number quality measure.

Return type float

classmethod min_maximum_angle(mesh)Computes the minimal quality measure based on the largest angle.

This measures the relative distance of a triangle’s angles or a tetrahedron’s dihedral angles to the corre-sponding optimal angle. The optimal angle is defined as the angle an equilateral (and thus equiangular)element has. This is defined as

1 − max

(𝛼− 𝛼*

𝜋 − 𝛼* , 0

),

where 𝛼 is the corresponding (dihedral) angle of the element and 𝛼* is the corresponding (dihedral) angleof the reference element. To compute the quality measure, the minimum of this expression over all elementsand all of their (dihedral) angles is computed.

Parameters mesh (fenics.Mesh ) – The mesh, whose quality shall be computed.

Returns The minimum value of the maximum angle quality measure.

Return type float

static min_radius_ratios(mesh)Computes the minimal radius ratio of the mesh.

This measures the ratio of the element’s inradius to it’s circumradius, normalized by the geometric dimen-sion. This is computed via

𝑑𝑟

𝑅,

where 𝑑 is the spatial dimension, 𝑟 is the inradius, and 𝑅 is the circumradius. To compute the (global)quality measure, the minimum of this expression over all elements is returned.

Parameters mesh (fenics.Mesh ) – The mesh, whose quality shall be computed.

Returns The minimal radius ratio of the mesh.

Return type float

classmethod min_skewness(mesh)Computes the minimal skewness of the mesh.

This measure the relative distance of a triangle’s angles or a tetrahedron’s dihedral angles to the correspond-ing optimal angle. The optimal angle is defined as the angle an equilateral, and thus equiangular, elementhas. The skewness lies in [0, 1], where 1 corresponds to the case of an optimal (equilateral) element, and

132 Chapter 4. API Reference

Page 137: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

0 corresponds to a degenerate element. The skewness corresponding to some (dihedral) angle 𝛼 is definedas

1 − max

(𝛼− 𝛼*

𝜋 − 𝛼*,𝛼* − 𝛼

𝛼* − 0

),

where 𝛼* is the corresponding angle of the reference element. To compute the quality measure, the mini-mum of this expression over all elements and all of their (dihedral) angles is computed.

Parameters mesh (fenics.Mesh ) – The mesh whose quality shall be computed.

Returns The minimum skewness of the mesh.

Return type float

cashocs.geometry.compute_boundary_distance(mesh, boundaries=None, boundary_idcs=None, tol=0.1,max_iter=10)

Computes (an approximation of) the distance to the boundary.

The function iteratively solves the Eikonal equation to compute the distance to the boundary.

The user can specify which boundaries are considered for the distance computation by specifying the parametersboundaries and boundary_idcs. Default is to consider all boundaries.

Parameters

• mesh (fenics.Mesh ) – The dolfin mesh object, representing the computational domain

• boundaries (Optional[fenics.MeshFunction]) – A meshfunction for the boundaries,which is needed in case specific boundaries are targeted for the distance computation (whileothers are ignored), default is None (all boundaries are used).

• boundary_idcs (Optional[List[int]]) – A list of indices which indicate, which partsof the boundaries should be used for the distance computation, default is None (all boundariesare used).

• tol (float) – A tolerance for the iterative solution of the eikonal equation. Default is 1e-1.

• max_iter (int) – Number of iterations for the iterative solution of the eikonal equation.Default is 10.

Returns A fenics function representing an approximation of the distance to the boundary.

Return type fenics.Function

cashocs.geometry.compute_mesh_quality(mesh, quality_type='min', quality_measure='skewness')This computes the mesh quality of a given mesh.

Parameters

• mesh (fenics.Mesh ) – The mesh whose quality shall be computed.

• quality_type (typing_extensions.Literal[min, minimum, avg, average]) –The type of measurement for the mesh quality, either minimum quality or average qualityover all mesh cells, default is ‘min’.

• quality_measure (typing_extensions.Literal[skewness, maximum_angle,radius_ratios, condition_number]) – The type of quality measure which is used tocompute the quality measure, default is ‘skewness’

Returns The quality of the mesh, in the interval [0, 1], where 0 is the worst, and 1 the best possiblequality.

Return type float

4.8. Sub-Modules 133

Page 138: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

cashocs.geometry.generate_measure(idx, measure)Generates a measure based on indices.

Generates a fenics.MeasureSum or _EmptyMeasure object corresponding to measure and the subdomains /boundaries specified in idx. This is a convenient shortcut to writing dx(1) + dx(2) + dx(3) in case manymeasures are involved.

Parameters

• idx (List[int]) – A list of indices for the boundary / volume markers that define the (new)measure.

• measure (fenics.Measure) – The corresponding UFL measure.

Returns The corresponding sum of the measures or an empty measure.

Return type Union[fenics.Measure, cashocs.geometry.measure._EmptyMeasure]

Examples

Here, we create a wrapper for the surface measure on the top and bottom of the unit square:

import fenicsimport cashocs

mesh, _, boundaries, dx, ds, _ = cashocs.regular_mesh(25)top_bottom_measure = cashocs.geometry.generate_measure([3,4], ds)fenics.assemble(1*top_bottom_measure)

cashocs.geometry.import_mesh(input_arg)Imports a mesh file for use with cashocs / FEniCS.

This function imports a mesh file that was generated by GMSH and converted to .xdmf with the command linefunction cashocs-convert. If there are Physical quantities specified in the GMSH file, these are imported to thesubdomains and boundaries output of this function and can also be directly accessed via the measures, e.g., withdx(1), ds(1), etc.

Parameters input_arg (Union[str, configparser.ConfigParser]) – This is either a string,in which case it corresponds to the location of the mesh file in .xdmf file format, or a config filethat has this path stored in its settings, under the section Mesh, as parameter mesh_file.

Returns A tuple (mesh, subdomains, boundaries, dx, ds, dS), where mesh is the imported FEMmesh, subdomains is a mesh function for the subdomains, boundaries is a mesh function for theboundaries, dx is a volume measure, ds is a surface measure, and dS is a measure for the interiorfacets.

Return type Tuple[cashocs.geometry.mesh.Mesh, fenics.MeshFunction, fenics.MeshFunction, fen-ics.Measure, fenics.Measure, fenics.Measure]

134 Chapter 4. API Reference

Page 139: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Notes

In case the boundaries in the Gmsh .msh file are not only marked with numbers (as physical groups), but alsowith names (i.e. strings), these strings can be used with the integration measures dx and ds returned by thismethod. E.g., if one specified the following in a 2D Gmsh .geo file

Physical Surface("domain", 1) = i,j,k;

where i,j,k are representative for some integers, then this can be used in the measure dx (as we are 2D) as follows.The command

dx(1)

is completely equivalent to

dx("domain")

and both can be used interchangeably.

cashocs.geometry.regular_box_mesh(n=10, start_x=0.0, start_y=0.0, start_z=None, end_x=1.0, end_y=1.0,end_z=None, diagonal='right')

Creates a mesh corresponding to a rectangle or cube.

This function creates a uniform mesh of either a rectangle or a cube, with specified start (S_) and end points (E_).The resulting mesh uses n elements along the shortest direction and accordingly many along the longer ones.The resulting domain is

[𝑠𝑡𝑎𝑟𝑡𝑥, 𝑒𝑛𝑑𝑥] × [𝑠𝑡𝑎𝑟𝑡𝑦, 𝑒𝑛𝑑𝑦] in 2𝐷,

[𝑠𝑡𝑎𝑟𝑡𝑥, 𝑒𝑛𝑑𝑥] × [𝑠𝑡𝑎𝑟𝑡𝑦, 𝑒𝑛𝑑𝑦] × [𝑠𝑡𝑎𝑟𝑡𝑧, 𝑒𝑛𝑑𝑧] in 3𝐷.

The boundary markers are ordered as follows:

• 1 corresponds to 𝑥 = 𝑠𝑡𝑎𝑟𝑡𝑥.

• 2 corresponds to 𝑥 = 𝑒𝑛𝑑𝑥.

• 3 corresponds to 𝑦 = 𝑠𝑡𝑎𝑟𝑡𝑦 .

• 4 corresponds to 𝑦 = 𝑒𝑛𝑑𝑦 .

• 5 corresponds to 𝑧 = 𝑠𝑡𝑎𝑟𝑡𝑧 (only in 3D).

• 6 corresponds to 𝑧 = 𝑒𝑛𝑑𝑧 (only in 3D).

Parameters

• n (int) – Number of elements in the shortest coordinate direction.

• start_x (float) – Start of the x-interval.

• start_y (float) – Start of the y-interval.

• start_z (Optional[float]) – Start of the z-interval, mesh is 2D if this is None (defaultis None).

• end_x (float) – End of the x-interval.

• end_y (float) – End of the y-interval.

• end_z (Optional[float]) – End of the z-interval, mesh is 2D if this is None (default isNone).

4.8. Sub-Modules 135

Page 140: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

• diagonal (typing_extensions.Literal[right, left, left/right, right/left, crossed]) – This defines the type of diagonal used to create the box mesh in 2D.This can be one of "right", "left", "left/right", "right/left" or "crossed".

Returns A tuple (mesh, subdomains, boundaries, dx, ds, dS), where mesh is the imported FEMmesh, subdomains is a mesh function for the subdomains, boundaries is a mesh function for theboundaries, dx is a volume measure, ds is a surface measure, and dS is a measure for the interiorfacets.

Return type Tuple[fenics.Mesh, fenics.MeshFunction, fenics.MeshFunction, fenics.Measure, fen-ics.Measure, fenics.Measure]

cashocs.geometry.regular_mesh(n=10, length_x=1.0, length_y=1.0, length_z=None, diagonal='right')Creates a mesh corresponding to a rectangle or cube.

This function creates a uniform mesh of either a rectangle or a cube, starting at the origin and having length spec-ified in length_x, length_y, and length_z. The resulting mesh uses n elements along the shortest directionand accordingly many along the longer ones. The resulting domain is

[0, 𝑙𝑒𝑛𝑔𝑡ℎ𝑥] × [0, 𝑙𝑒𝑛𝑔𝑡ℎ𝑦] in 2𝐷,

[0, 𝑙𝑒𝑛𝑔𝑡ℎ𝑥] × [0, 𝑙𝑒𝑛𝑔𝑡ℎ𝑦] × [0, 𝑙𝑒𝑛𝑔𝑡ℎ𝑧] in 3𝐷.

The boundary markers are ordered as follows:

• 1 corresponds to 𝑥 = 0.

• 2 corresponds to 𝑥 = 𝑙𝑒𝑛𝑔𝑡ℎ𝑥.

• 3 corresponds to 𝑦 = 0.

• 4 corresponds to 𝑦 = 𝑙𝑒𝑛𝑔𝑡ℎ𝑦 .

• 5 corresponds to 𝑧 = 0 (only in 3D).

• 6 corresponds to 𝑧 = 𝑙𝑒𝑛𝑔𝑡ℎ𝑧 (only in 3D).

Parameters

• n (int) – Number of elements in the shortest coordinate direction.

• length_x (float) – Length in x-direction.

• length_y (float) – Length in y-direction.

• length_z (Optional[float]) – Length in z-direction, if this is None, then the geometrywill be two-dimensional (default is None).

• diagonal (typing_extensions.Literal[left, right, left/right, right/left, crossed]) – This defines the type of diagonal used to create the box mesh in 2D.This can be one of "right", "left", "left/right", "right/left" or "crossed".

Returns A tuple (mesh, subdomains, boundaries, dx, ds, dS), where mesh is the imported FEMmesh, subdomains is a mesh function for the subdomains, boundaries is a mesh function for theboundaries, dx is a volume measure, ds is a surface measure, and dS is a measure for the interiorfacets.

Return type Tuple[fenics.Mesh, fenics.MeshFunction, fenics.MeshFunction, fenics.Measure, fen-ics.Measure, fenics.Measure]

136 Chapter 4. API Reference

Page 141: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

4.8.2 Sub-Module io

Module for inputs and outputs.

class cashocs.io.Config(config_file=None)Class for handling the config in cashocs.

Parameters config_file (Optional[str]) – Path to the config file.

Return type None

validate_config()Validates the configuration file.

Return type None

class cashocs.io.OutputManager(optimization_problem)Class handling all of the output.

Parameters optimization_problem (op.OptimizationProblem) – The corresponding opti-mization problem.

Return type None

output(solver)Writes the desired output to files and console.

Parameters solver (optimization_algorithms.OptimizationAlgorithm) – The opti-mization algorithm.

Return type None

output_summary(solver)Writes the summary to files and console.

Parameters solver (optimization_algorithms.OptimizationAlgorithm) – The opti-mization algorithm.

Return type None

set_remesh(remesh_counter)Sets the remesh prefix for pvd files.

Parameters remesh_counter (int) – Number of times remeshing has been performed.

Return type None

cashocs.io.create_config(path)Loads a config object from a config file.

Loads the config from a .ini file via the configparser package.

Parameters path (str) – The path to the .ini file storing the configuration.

Returns The output config file, which includes the path to the .ini file.

Return type configparser.ConfigParser

Deprecated since version 1.1.0: This is replaced by load_config and will be removed in the future.

cashocs.io.load_config(path)Loads a config object from a config file.

Loads the config from a .ini file via the configparser package.

Parameters path (str) – The path to the .ini file storing the configuration.

4.8. Sub-Modules 137

Page 142: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Returns The output config file, which includes the path to the .ini file.

Return type configparser.ConfigParser

cashocs.io.write_out_mesh(mesh, original_msh_file, out_msh_file)Writes out mesh as Gmsh .msh file.

This method updates the vertex positions in the original_gmsh_file, the topology of the mesh and its con-nections are the same. The original GMSH file is kept, and a new one is generated under out_mesh_file.

Parameters

• mesh (fenics.Mesh ) – The mesh object in fenics that should be saved as Gmsh file.

• original_msh_file (str) – Path to the original GMSH mesh file of the mesh object, hasto end with .msh.

• out_msh_file (str) – Path to the output mesh file, has to end with .msh.

Return type None

Notes

The method only works with GMSH 4.1 file format. Others might also work, but this is not tested or ensured inany way.

4.8.3 Sub-Module nonlinear_solvers

Custom solvers for nonlinear equations.

This module has custom solvers for nonlinear PDEs, including a damped Newton method and a Picard iteration forcoupled problems.

cashocs.nonlinear_solvers.damped_newton_solve(F, u, bcs, dF=None, rtol=1e-10, atol=1e-10,max_iter=50, convergence_type='combined',norm_type='l2', damped=True, verbose=True,ksp=None, ksp_options=None)

Damped Newton solve interface, only here for compatibility reasons.

Parameters

• F (ufl.Form) – The variational form of the nonlinear problem to be solved by Newton’smethod.

• u (fenics.Function) – The sought solution / initial guess. It is not assumed that the initialguess satisfies the Dirichlet boundary conditions, they are applied automatically. The methodoverwrites / updates this Function.

• bcs (Union[fenics.DirichletBC, List[fenics.DirichletBC]]) – A list of Dirich-letBCs for the nonlinear variational problem.

• dF (Optional[ufl.Form]) – The Jacobian of F, used for the Newton method. Default isNone, and in this case the Jacobian is computed automatically with AD.

• rtol (float) – Relative tolerance of the solver if convergence_type is either 'combined'or 'rel' (default is rtol = 1e-10).

• atol (float) – Absolute tolerance of the solver if convergence_type is either 'combined'or 'abs' (default is atol = 1e-10).

138 Chapter 4. API Reference

Page 143: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

• max_iter (int) – Maximum number of iterations carried out by the method (default ismax_iter = 50).

• convergence_type (typing_extensions.Literal[combined, rel, abs]) – Deter-mines the type of stopping criterion that is used.

• norm_type (typing_extensions.Literal[l2, linf]) – Determines which norm isused in the stopping criterion.

• damped (bool) – If True, then a damping strategy is used. If False, the classical Newton-Raphson iteration (without damping) is used (default is True).

• verbose (bool) – If True, prints status of the iteration to the console (default is True).

• ksp (Optional[petsc4py.PETSc.KSP]) – The PETSc ksp object used to solve the inner(linear) problem if this is None it uses the direct solver MUMPS (default is None).

• ksp_options (Optional[List[List[str]]]) – The list of options for the linear solver.

Returns The solution of the nonlinear variational problem, if converged. This overwrites the inputfunction u.

Return type fenics.Function

Examples

Consider the problem

−∆𝑢 + 𝑢3 = 1 in Ω = (0, 1)2

𝑢 = 0 on Γ.

This is solved with the code

from fenics import *import cashocs

mesh, _, boundaries, dx, _, _ = cashocs.regular_mesh(25)V = FunctionSpace(mesh, 'CG', 1)

u = Function(V)v = TestFunction(V)F = inner(grad(u), grad(v))*dx + pow(u,3)*v*dx - Constant(1)*v*dxbcs = cashocs.create_dirichlet_bcs(V, Constant(0.0), boundaries, [1,2,3,4])cashocs.newton_solve(F, u, bcs)

Deprecated since version 1.5.0: This is replaced by cashocs.newton_solve and will be removed in the future.

cashocs.nonlinear_solvers.newton_solve(F, u, bcs, dF=None, shift=None, rtol=1e-10, atol=1e-10,max_iter=50, convergence_type='combined', norm_type='l2',damped=True, inexact=True, verbose=True, ksp=None,ksp_options=None, A_tensor=None, b_tensor=None,is_linear=False)

Parameters

• F (ufl.Form) –

• u (fenics.Function) –

4.8. Sub-Modules 139

Page 144: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

• bcs (Union[fenics.DirichletBC, List[fenics.DirichletBC]]) –

• dF (Optional[ufl.Form]) –

• shift (Optional[ufl.Form]) –

• rtol (float) –

• atol (float) –

• max_iter (int) –

• convergence_type (typing_extensions.Literal[combined, rel, abs]) –

• norm_type (typing_extensions.Literal[l2, linf]) –

• damped (bool) –

• inexact (bool) –

• verbose (bool) –

• ksp (Optional[petsc4py.PETSc.KSP]) –

• ksp_options (Optional[List[List[str]]]) –

• A_tensor (Optional[fenics.PETScMatrix]) –

• b_tensor (Optional[fenics.PETScVector]) –

• is_linear (bool) –

Return type fenics.Function

cashocs.nonlinear_solvers.picard_iteration(F_list, u_list, bcs_list, max_iter=50, rtol=1e-10, atol=1e-10,verbose=True, inner_damped=True, inner_inexact=True,inner_verbose=False, inner_max_its=25, ksps=None,ksp_options=None, A_tensors=None, b_tensors=None,inner_is_linear=False)

Solves a system of coupled PDEs via a Picard iteration.

Parameters

• F_list (Union[List[ufl.form], ufl.Form]) – List of the coupled PDEs.

• u_list (Union[List[fenics.Function], fenics.Function]) – List of the statevariables (to be solved for).

• bcs_list (Union[List[fenics.DirichletBC], List[List[fenics.DirichletBC]]]) – List of boundary conditions for the PDEs.

• max_iter (int) – The maximum number of iterations for the Picard iteration.

• rtol (float) – The relative tolerance for the Picard iteration, default is 1e-10.

• atol (float) – The absolute tolerance for the Picard iteration, default is 1e-10.

• verbose (bool) – Boolean flag, if True, output is written to stdout, default is True.

• inner_damped (bool) – Boolean flag, if True, the inner problems are solved with a dampedNewton method, default is True

• inner_inexact (bool) – Boolean flag, if True, the inner problems are solved with a inexactNewton method, default is True

• inner_verbose (bool) – Boolean flag, if True, the inner problems write the history tostdout, default is False.

140 Chapter 4. API Reference

Page 145: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

• inner_max_its (int) – Maximum number of iterations for the inner Newton solver; defaultis 25.

• ksps (Optional[List[petsc4py.PETSc.KSP]]) – List of PETSc KSP objects for solv-ing the inner (linearized) problems, optional. Default is None, in which case the direct solvermumps is used.

• ksp_options (Optional[List[List[List[str]]]]) – List of options for the KSP ob-jects.

• A_tensors (Optional[List[fenics.PETScMatrix]]) – List of matrices for the right-hand sides of the inner (linearized) equations.

• b_tensors (Optional[List[fenics.PETScVector]]) – List of vectors for the left-handsides of the inner (linearized) equations.

• inner_is_linear (bool) – Boolean flag, if this is True, all problems are actually linearones, and only a linear solver is used.

Return type None

4.8.4 Sub-Module utils

Module including utility and helper functions.

This module includes utility and helper functions used in cashocs. They might also be interesting for users, so they arepart of the public API. Includes wrappers that allow to shorten the coding for often recurring actions.

class cashocs.utils.Interpolator(origin_space, target_space)Efficient interpolation between two function spaces.

This is very useful, if multiple interpolations have to be carried out between the same spaces, which is madesignificantly faster by computing the corresponding matrix. The function spaces can even be defined on differentmeshes.

Notes

This class only works properly for continuous Lagrange elements and constant, discontinuous Lagrange elements.

Examples

Here, we consider interpolating from CG1 elements to CG2 elements

import fenicsimport cashocs

mesh, _, _, _, _, _ = cashocs.regular_mesh(25)V1 = fenics.FunctionSpace(mesh, 'CG', 1)V2 = fenics.FunctionSpace(mesh, 'CG', 2)

expr = fenics.Expression('sin(2*pi*x[0])', degree=1)u = fenics.interpolate(expr, V1)

interp = cashocs.utils.Interpolator(V1, V2)interp.interpolate(u)

4.8. Sub-Modules 141

Page 146: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Parameters

• origin_space (fenics.FunctionSpace) – The function space whose objects shall beinterpolated.

• target_space (fenics.FunctionSpace) – The space into which they shall be interpo-lated.

Return type None

interpolate(u)Interpolates function to target space.

The function has to belong to the origin space, i.e., the first argument of __init__, and it is interpolated to thedestination space, i.e., the second argument of __init__. There is no need to call set_allow_extrapolationon the function (this is done automatically due to the method).

Parameters u (fenics.Function) – The function that shall be interpolated.

Returns The result of the interpolation.

Return type fenics.Function

cashocs.utils.create_bcs_list(function_space, value, boundaries, idcs, **kwargs)Create several Dirichlet boundary conditions at once.

Wraps multiple Dirichlet boundary conditions into a list, in case they have the same value but are to be defined formultiple boundaries with different markers. Particularly useful for defining homogeneous boundary conditions.

Parameters

• function_space (fenics.FunctionSpace) – The function space onto which the BCsshould be imposed on.

• value (Union[fenics.Constant, fenics.Expression, fenics.Function,float, Tuple[float]]) – The value of the boundary condition. Has to becompatible with the function_space, so that it could also be used as fenics.DirichletBC(function_space, value, ...).

• boundaries (fenics.MeshFunction) – The fenics.MeshFunction object representingthe boundaries.

• idcs (Union[List[Union[int, str]], int, str]) – A list of indices / boundarymarkers that determine the boundaries onto which the Dirichlet boundary conditions shouldbe applied to. Can also be a single integer for a single boundary.

• **kwargs – Keyword arguments for fenics.DirichletBC

Returns A list of DirichletBC objects that represent the boundary conditions.

Return type List[fenics.DirichletBC]

Deprecated since version 1.5.0: This is replaced by cashocs.create_dirichlet_bcs and will be removed in thefuture.

cashocs.utils.create_dirichlet_bcs(function_space, value, boundaries, idcs, **kwargs)Create several Dirichlet boundary conditions at once.

Wraps multiple Dirichlet boundary conditions into a list, in case they have the same value but are to be defined formultiple boundaries with different markers. Particularly useful for defining homogeneous boundary conditions.

Parameters

• function_space (fenics.FunctionSpace) – The function space onto which the BCsshould be imposed on.

142 Chapter 4. API Reference

Page 147: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

• value (Union[fenics.Constant, fenics.Expression, fenics.Function,float, Tuple[float]]) – The value of the boundary condition. Has to becompatible with the function_space, so that it could also be used as fenics.DirichletBC(function_space, value, ...).

• boundaries (fenics.MeshFunction) – The fenics.MeshFunction object representingthe boundaries.

• idcs (Union[List[Union[int, str]], int, str]) – A list of indices / boundarymarkers that determine the boundaries onto which the Dirichlet boundary conditions shouldbe applied to. Can also be a single entry for a single boundary. If your mesh file is named,then you can also use the names of the boundaries to define the boundary conditions.

• **kwargs – Keyword arguments for fenics.DirichletBC

Returns A list of DirichletBC objects that represent the boundary conditions.

Return type List[fenics.DirichletBC]

Examples

Generate homogeneous Dirichlet boundary conditions for all 4 sides of the unit square

import fenicsimport cashocs

mesh, _, _, _, _, _ = cashocs.regular_mesh(25)V = fenics.FunctionSpace(mesh, 'CG', 1)bcs = cashocs.create_dirichlet_bcs(V, fenics.Constant(0), boundaries,

[1,2,3,4])

cashocs.utils.enlist(arg)Wraps the input argument into a list, if it isn’t a list already.

Parameters arg (Union[Any, List]) – The input argument, which is to wrapped into a list.

Returns The object wrapped into a list.

Return type List

cashocs.utils.moreau_yosida_regularization(term, gamma, measure, lower_threshold=None,upper_threshold=None, shift_lower=None,shift_upper=None)

Implements a Moreau-Yosida regularization of an inequality constraint

The general form of the inequality is of the form

lower_threshold <= term <= upper_threshold

which is defined over the region specified in measure.

In case lower_threshold or upper_threshold are None, they are set to −∞ and ∞, respectively.

Parameters

• term (ufl.core.expr.Expr) – The term inside the inequality constraint.

• gamma (float) – The weighting factor of the regularization.

• measure (fenics.Measure) – The measure over which the inequality constraint is defined.

4.8. Sub-Modules 143

Page 148: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

• lower_threshold (Optional[Union[float, fenics.Function]]) – The lowerthreshold for the inequality constraint. In case this is None, the lower bound is set to −∞.The default is None

• upper_threshold (Optional[Union[float, fenics.Function]]) – The upperthreshold for the inequality constraint. In case this is None, the upper bound is set to ∞.The default is None

• shift_lower (Optional[Union[float, fenics.Function]]) – A shift function forthe lower bound of the Moreau-Yosida regularization. Should be non-positive. In case thisis None, it is set to 0. Default is None.

• shift_upper (Optional[Union[float, fenics.Function]]) – A shift function forthe upper bound of the Moreau-Yosida regularization. Should be non-negative. In case thisis None, it is set to 0. Default is None.

Returns The ufl form of the Moreau-Yosida regularization, to be used in the cost functional.

Return type ufl.Form

cashocs.utils.multiplication(x)Multiplies the elements of a list in a UFL friendly fashion.

Used to build the product of certain UFL expressions to construct a UFL form.

Parameters x (List[Union[ufl.core.expr.Expr, int, float]]) – The list whose entriesshall be multiplied.

Returns The result of the multiplication.

Return type Union[ufl.core.expr.Expr, int, float]

cashocs.utils.summation(x)Sums elements of a list in a UFL friendly fashion.

This can be used to sum, e.g., UFL forms, or UFL expressions that can be used in UFL forms.

Parameters x (List[Union[ufl.core.expr.Expr, int, float]]) – The list of entries thatshall be summed.

Returns Sum of input (same type as entries of input).

Return type Union[ufl.core.expr.Expr, int, float]

Notes

For “usual” summation of integers or floats, the built-in sum function of python or the numpy variant are recom-mended. Still, they are incompatible with FEniCS objects, so this function should be used for the latter.

4.8.5 Sub-Module verification

This module includes tests to verify the correctness of computed gradients.

cashocs.verification.compute_convergence_rates(epsilons, residuals, verbose=True)Computes the convergence rate of the Taylor test.

Parameters

• epsilons (List[float]) – The step sizes.

• residuals (List[float]) – The corresponding residuals.

144 Chapter 4. API Reference

Page 149: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

• verbose (bool) – Prints the result to the console, if True. Default is True.

Returns The computed convergence rates

Return type List[float]

cashocs.verification.control_gradient_test(ocp, u=None, h=None, rng=None)Performs a Taylor test to verify that the computed gradient is correct.

Parameters

• ocp (optimal_control.OptimalControlProblem) – The underlying optimal controlproblem, for which the gradient of the reduced cost function shall be verified.

• u (Optional[List[fenics.Function]]) – The point, at which the gradient shall be ver-ified. If this is None, then the current controls of the optimization problem are used. Defaultis None.

• h (Optional[List[fenics.Function]]) – The direction(s) for the directional (Gateaux)derivative. If this is None, one random direction is chosen. Default is None.

• rng (Optional[np.random.RandomState]) – A numpy random state for calculating arandom direction

Returns The convergence order from the Taylor test. If this is (approximately) 2 or larger, everythingworks as expected.

Return type float

cashocs.verification.shape_gradient_test(sop, h=None, rng=None)Performs a Taylor test to verify that the computed shape gradient is correct.

Parameters

• sop (shape_optimization.ShapeOptimizationProblem) – The underlying shape op-timization problem.

• h (Optional[List[fenics.Function]]) – The direction used to compute the directionalderivative. If this is None, then a random direction is used (default is None).

• rng (Optional[np.random.RandomState]) – A numpy random state for calculating arandom direction

Returns The convergence order from the Taylor test. If this is (approximately) 2 or larger, everythingworks as expected.

Return type float

4.8. Sub-Modules 145

Page 150: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

146 Chapter 4. API Reference

Page 151: Release 1.4.2 SebastianBlauth

CHAPTER

FIVE

CONTRIBUTING GUIDELINES

First off, thanks a lot for taking the time to contribute to cashocs.

5.1 Code of conduct

The project and everyone that participates in it is governed by the cashocs Code of Conduct. In particular, this alsoapplies to all interactions with the project, including issues and pull requests.

5.2 Reporting a bug

• Ensure that the bug was not already reported by searching on GitHub under Issues.

• If you do not find an open issue that adresses the problem, open a new one. Please include a clear title anddescription, and include as much relevant information as possible, and also a minimal working example thatreproduces the bug.

5.3 Fixing a bug

• cashocs uses the black coding style, so please also use that for your suggested fix.

• Make sure that all tests still pass with your fix.

• Open a new pull request with the fix. Ensure that the PR description clearly describes the problem and its solution.Include the corresponding issue number (if applicable).

5.4 Adding or modifying a feature

• Please suggest your changes / additions by opening a new issue on GitHub under Issues, and start writing code(using the conventions established in the project).

• If you receive positive feedback for your suggestion, you can open a new pull request with the changes / additions.Ensure that the PR description clearly describes your modifications / additions, also reference the correspondingissue number where you suggested your idea.

147

Page 152: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

5.5 License

By submitting a pull request, you are licensing your code under the project license and affirming that you either owncopyright (automatic for most individuals) or are authorized to distribute under the project license (e.g., in case youremployer retains copyright on your work).

148 Chapter 5. Contributing Guidelines

Page 153: Release 1.4.2 SebastianBlauth

CHAPTER

SIX

CODE OF CONDUCT

6.1 Our Pledge

In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to makeparticipation in our project and our community a harassment-free experience for everyone, regardless of age, body size,disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economicstatus, nationality, personal appearance, race, religion, or sexual identity and orientation.

6.2 Our Standards

Examples of behavior that contributes to creating a positive environment include:

• Using welcoming and inclusive language

• Being respectful of differing viewpoints and experiences

• Gracefully accepting constructive criticism

• Focusing on what is best for the community

• Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

• The use of sexualized language or imagery and unwelcome sexual attention or advances

• Trolling, insulting/derogatory comments, and personal or political attacks

• Public or private harassment

• Publishing others’ private information, such as a physical or electronic address, without explicit permission

• Other conduct which could reasonably be considered inappropriate in a professional setting

6.3 Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appro-priate and fair corrective action in response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits,issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently anycontributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

149

Page 154: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

6.4 Scope

This Code of Conduct applies within all project spaces, and it also applies when an individual is representing the projector its community in public spaces. Examples of representing a project or community include using an official projecte-mail address, posting via an official social media account, or acting as an appointed representative at an online oroffline event. Representation of a project may be further defined and clarified by project maintainers.

6.5 Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team [email protected]. All complaints will be reviewed and investigated and will result in a response that is deemednecessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regardto the reporter of an incident. Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanentrepercussions as determined by other members of the project’s leadership.

6.6 Attribution

This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq

150 Chapter 6. Code of Conduct

Page 155: Release 1.4.2 SebastianBlauth

CHAPTER

SEVEN

CHANGE LOG

This is cashocs’ change log. Note, that only major and minor releases are covered here as they add new functionalityor might change the API. For a documentation of the maintenance releases, please take a look at https://github.com/sblauth/cashocs/releases.

7.1 in development

• Added the possibility to define additional constraints for the optimization problems as well as solvers which canbe used to solve these new problems. This includes Augmented Lagrangian and Quadratic Penalty methods.

• Added the possibility for users to execute their own code before each solution of the state system or after eachcomputation of the gradient with the help of inject_pre_hook and inject_post_hook.

7.2 1.5.0 (December 22, 2021)

• Major performance increase (particularly for large problems)

• Added support for using the p-Laplacian to compute the shape gradient.

• cashocs now also imports Gmsh Physical Group information when it is given by strings, which can be used inintegration measures (e.g., dx('part1') or ds('inlet'), or for creating Dirichlet boundary conditions (e.g.cashocs.create_dirichlet_bcs(V, Constant(0.0), boundaries, 'dirichlet_boundary')).

• The nonlinear solver (Newton’s method) got an additional inexact parameter, which allows users to use aninexact Newton’s method with iterative solvers. Additionally, users can specify their own Jacobians to be usedin Newton’s method with the parameter dF.

• Users can now specify the weight of the scalar tracking terms individually (this is now documented).

• New configuration file parameters:

– Section ShapeGradient

∗ use_p_laplacian is a boolean flag which enables the use of the p-Laplacian for the computation ofthe shape gradient

∗ p_laplacian_power is an integer parameter specifying the power p used for the p-Laplacian

∗ p_laplacian_stabilization is a float parameter, which acts as stabilization term for the p-Laplacian. This should be positive and small (e.g. 1e-3).

∗ update_inhomogeneous is a boolean parameter, which allows to update the cell volume when us-ing inhomogeneous=True in the ShapeGradient section. This makes small elements have a higherstiffness and updates this over the course of the optimization. Default is False

151

Page 156: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

7.3 1.4.0 (September 3, 2021)

• Added the possibility to compute the stiffness for the shape gradient based on the distance to the boundary usingthe eikonal equation

• Cashocs now supports the tracking of scalar quantities, which are given as integrals of the states / controls/ geometric properties. Input parameter is scalar_tracking_forms, which is a dictionary consisting of'integrand', which is the integrand of the scalar quantity, and 'tracking_goal', which is the (scalar) valuethat shall be achieved. This feature is documented at https://cashocs.readthedocs.io/en/latest/demos/shape_optimization/doc_eikonal_stiffness.html.

• Fixed a bug concerning cashocs’ memory management, which would occur if several OptimizationProblemswere created one after the other

• Changed the coding style to “black”

• Switched printing to f-string syntax for better readability

• Config files are now copied when they are passed to OptimizationProblems, so that manipulation of them is onlypossible before the instance is created

• New configuration file parameters:

– Section ShapeGradient

∗ use_distance_mu is a boolean flag which enables stiffness computation based on distances

∗ dist_min and dist_max describe the minimal and maximum distance to the boundary for which acertain stiffness is used (see below)

∗ mu_min and mu_max describe the stiffness values: If the boundary distance is smaller than dist_min,then mu = mu_min and if the distance is larger than dist_max, we have mu = mu_max

∗ smooth_mu is a boolean flag, which determines how mu is interpolated between dist_min anddist_max: If this is set to False, linear interpolation is used, otherwise, a cubic spline is used

∗ boundaries_dist is a list of boundary indices to which the distance shall be computed

• Small bugfixes and other improvements:

– Switched to pseudo random numbers for the tests for the sake of reproduceability

– fixed some tolerances for the tests

– replaced os.system() calls by subprocess.run()

7.4 1.3.0 (June 11, 2021)

• Improved the remeshing workflow and fixed several smaller bugs concerning it

• New configuration file parameters:

– Section Output

∗ save_pvd_adjoint is a boolean flag which allows users to also save adjoint states in paraview format

∗ save_pvd_gradient is a boolean flag which allows users to save the (shape) gradient(s) in paraviewformat

∗ save_txt is a boolean flag, which allows users to capture the command line output as .txt file

152 Chapter 7. Change Log

Page 157: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

7.5 1.2.0 (December 01, 2020)

• Users can now supply their own bilinear form (or scalar product) for the computation of the shape gradient, whichis then used instead of the linear elasticity formulation. This is documented at https://cashocs.readthedocs.io/en/latest/demos/shape_optimization/doc_custom_scalar_product.html.

• Added a curvature regularization term for shape optimization, which can be enabled via the config files, similarlyto already implemented regularizations. This is documented at https://cashocs.readthedocs.io/en/latest/demos/shape_optimization/doc_regularization.html.

• cashocs can now scale individual terms of the cost functional if this is desired. This allows for a moregranular handling of problems with cost functionals consisting of multiple terms. This also extends to theregularizations for shape optimization, see https://cashocs.readthedocs.io/en/latest/demos/shape_optimization/doc_regularization.html. This feature is documented at https://cashocs.readthedocs.io/en/latest/demos/shape_optimization/doc_scaling.html.

• cashocs now uses the logging module to issue messages for the user. The level of verbosity can be controlled viacashocs.set_log_level().

• New configuration file parameters:

– Section Regularization:

∗ factor_curvature can be used to specify the weight for the curvature regularization term.

∗ use_relative_weights is a boolean which specifies, whether the weights should be used as scalingfactor in front of the regularization terms (if this is False), or whether they should be used to scalethe regularization terms so that they have the prescribed value on the initial iteration (if this is True).

7.6 1.1.0 (November 13, 2020)

• Added the functionality for cashocs to be used as a solver only, where users can specify their custom adjoint equa-tions and (shape) derivatives for the optimization problems. This is documented at https://cashocs.readthedocs.io/en/latest/demos/cashocs_as_solver/solver_index.html.

• Using cashocs.create_config is deprecated and replaced by cashocs.load_config, but the former willstill be supported.

• Configuration files are now not strictly necessary, but still very strongly recommended.

• New configuration file parameters:

– Section Output:

∗ result_dir can be used to specify where cashocs’ output files should be placed.

7.7 1.0.0 (September 18, 2020)

• Initial release of cashocs.

7.5. 1.2.0 (December 01, 2020) 153

Page 158: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

154 Chapter 7. Change Log

Page 159: Release 1.4.2 SebastianBlauth

CHAPTER

EIGHT

CITING

If you use cashocs for your research, I would be grateful if you would cite the following paper

cashocs: A Computational, Adjoint-Based Shape Optimization and Optimal Control SoftwareSebastian BlauthSoftwareX, Volume 13, 2021https://doi.org/10.1016/j.softx.2020.100646

Additionally, if you are using the nonlinear conjugate gradient methods for shape optimization implemented in cashocs,please cite the following paper

Nonlinear Conjugate Gradient Methods for PDE Constrained Shape Optimization Based on→˓Steklov--Poincaré-Type MetricsSebastian BlauthSIAM Journal on Optimization, Volume 31, Issue 3, 2021https://doi.org/10.1137/20M1367738

If you are using BibTeX, you can use the following entries:

@ArticleBlauth2021cashocs,author = Sebastian Blauth,journal = SoftwareX,title = cashocs: A Computational, Adjoint-Based Shape Optimization and Optimal

→˓Control Software,year = 2021,issn = 2352-7110,pages = 100646,volume = 13,doi = https://doi.org/10.1016/j.softx.2020.100646,keywords = PDE constrained optimization, Adjoint approach, Shape optimization,

→˓Optimal control,

as well as

@ArticleBlauth2021Nonlinear,author = Sebastian Blauth,journal = SIAM J. Optim.,title = Nonlinear Conjugate Gradient Methods for PDE Constrained

→˓Shape Optimization Based on Steklov-Poincaré-Type Metrics,year = 2021,number = 3,

(continues on next page)

155

Page 160: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

(continued from previous page)

pages = 1658--1689,volume = 31,doi = 10.1137/20M1367738,fjournal = SIAM Journal on Optimization,

156 Chapter 8. Citing

Page 161: Release 1.4.2 SebastianBlauth

CHAPTER

NINE

LICENSE

cashocs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public Licenseas published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

cashocs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the impliedwarranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General PublicLicense for more details.

You should have received a copy of the GNU General Public License along with cashocs. If not, see https://www.gnu.org/licenses/.

157

Page 162: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

158 Chapter 9. License

Page 163: Release 1.4.2 SebastianBlauth

CHAPTER

TEN

CONTACT / ABOUT

I’m Sebastian Blauth, a scientific employee at Fraunhofer ITWM. I have developed this project as part of my PhD thesis.If you have any questions / suggestions / feedback, etc., you can contact me via [email protected] [email protected].

159

Page 164: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

160 Chapter 10. Contact / About

Page 165: Release 1.4.2 SebastianBlauth

CHAPTER

ELEVEN

INDICES AND TABLES

• genindex

• modindex

• search

161

Page 166: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

162 Chapter 11. Indices and tables

Page 167: Release 1.4.2 SebastianBlauth

PYTHON MODULE INDEX

ccashocs, 103cashocs.geometry, 129cashocs.io, 137cashocs.nonlinear_solvers, 138cashocs.utils, 141cashocs.verification, 144

163

Page 168: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

164 Python Module Index

Page 169: Release 1.4.2 SebastianBlauth

INDEX

Aassign_coordinates()

(cashocs.geometry.DeformationHandlermethod), 129

avg_condition_number()(cashocs.geometry.MeshQuality static method),131

avg_maximum_angle() (cashocs.geometry.MeshQualityclass method), 131

avg_radius_ratios() (cashocs.geometry.MeshQualitystatic method), 131

avg_skewness() (cashocs.geometry.MeshQuality classmethod), 131

Ccashocs

module, 103cashocs.geometry

module, 129cashocs.io

module, 137cashocs.nonlinear_solvers

module, 138cashocs.utils

module, 141cashocs.verification

module, 144compute_adjoint_variables()

(cashocs.OptimalControlProblem method),105

compute_adjoint_variables()(cashocs.ShapeOptimizationProblem method),109

compute_boundary_distance() (in modulecashocs.geometry), 133

compute_convergence_rates() (in modulecashocs.verification), 144

compute_gradient() (cashocs.OptimalControlProblemmethod), 105

compute_mesh_quality() (in modulecashocs.geometry), 133

compute_shape_gradient()

(cashocs.ShapeOptimizationProblem method),109

compute_state_variables()(cashocs.OptimalControlProblem method),105

compute_state_variables()(cashocs.ShapeOptimizationProblem method),109

Config (class in cashocs.io), 137ConstrainedOptimalControlProblem (class in

cashocs), 111ConstrainedShapeOptimizationProblem (class in

cashocs), 114constraint_violation()

(cashocs.EqualityConstraint method), 116constraint_violation()

(cashocs.InequalityConstraint method), 117control_gradient_test() (in module

cashocs.verification), 145coordinate_to_dof()

(cashocs.geometry.DeformationHandlermethod), 129

create_bcs_list() (in module cashocs), 128create_bcs_list() (in module cashocs.utils), 142create_config() (in module cashocs), 128create_config() (in module cashocs.io), 137create_dirichlet_bcs() (in module cashocs), 124create_dirichlet_bcs() (in module cashocs.utils),

142

Ddamped_newton_solve() (in module cashocs), 127damped_newton_solve() (in module

cashocs.nonlinear_solvers), 138DeformationHandler (class in cashocs.geometry), 129dof_to_coordinate()

(cashocs.geometry.DeformationHandlermethod), 129

Eenlist() (in module cashocs.utils), 143EqualityConstraint (class in cashocs), 116

165

Page 170: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

Ggenerate_measure() (in module cashocs.geometry),

133get_vector_field() (cashocs.ShapeOptimizationProblem

method), 109gradient_test() (cashocs.OptimalControlProblem

method), 105gradient_test() (cashocs.ShapeOptimizationProblem

method), 109

Iimport_mesh() (in module cashocs), 122import_mesh() (in module cashocs.geometry), 134InequalityConstraint (class in cashocs), 116inject_post_hook() (cashocs.ConstrainedOptimalControlProblem

method), 112inject_post_hook() (cashocs.ConstrainedShapeOptimizationProblem

method), 115inject_post_hook() (cashocs.OptimalControlProblem

method), 105inject_post_hook() (cashocs.ShapeOptimizationProblem

method), 109inject_pre_hook() (cashocs.ConstrainedOptimalControlProblem

method), 113inject_pre_hook() (cashocs.ConstrainedShapeOptimizationProblem

method), 115inject_pre_hook() (cashocs.OptimalControlProblem

method), 105inject_pre_hook() (cashocs.ShapeOptimizationProblem

method), 109inject_pre_post_hook()

(cashocs.ConstrainedOptimalControlProblemmethod), 113

inject_pre_post_hook()(cashocs.ConstrainedShapeOptimizationProblemmethod), 115

inject_pre_post_hook()(cashocs.OptimalControlProblem method),106

inject_pre_post_hook()(cashocs.ShapeOptimizationProblem method),110

interpolate() (cashocs.utils.Interpolator method),142

Interpolator (class in cashocs.utils), 141

Lload_config() (in module cashocs), 124load_config() (in module cashocs.io), 137

MMeshQuality (class in cashocs.geometry), 130

min_condition_number()(cashocs.geometry.MeshQuality static method),132

min_maximum_angle() (cashocs.geometry.MeshQualityclass method), 132

min_radius_ratios() (cashocs.geometry.MeshQualitystatic method), 132

min_skewness() (cashocs.geometry.MeshQuality classmethod), 132

modulecashocs, 103cashocs.geometry, 129cashocs.io, 137cashocs.nonlinear_solvers, 138cashocs.utils, 141cashocs.verification, 144

moreau_yosida_regularization() (in modulecashocs.utils), 143

move_mesh() (cashocs.geometry.DeformationHandlermethod), 130

multiplication() (in module cashocs.utils), 144

Nnewton_solve() (in module cashocs), 125newton_solve() (in module

cashocs.nonlinear_solvers), 139

OOptimalControlProblem (class in cashocs), 103output() (cashocs.io.OutputManager method), 137output_summary() (cashocs.io.OutputManager

method), 137OutputManager (class in cashocs.io), 137

Ppicard_iteration() (in module

cashocs.nonlinear_solvers), 140

Rregular_box_mesh() (in module cashocs), 123regular_box_mesh() (in module cashocs.geometry),

135regular_mesh() (in module cashocs), 122regular_mesh() (in module cashocs.geometry), 136revert_transformation()

(cashocs.geometry.DeformationHandlermethod), 130

Sset_log_level() (in module cashocs), 126set_remesh() (cashocs.io.OutputManager method),

137shape_gradient_test() (in module

cashocs.verification), 145

166 Index

Page 171: Release 1.4.2 SebastianBlauth

cashocs, Release 1.5.3

ShapeOptimizationProblem (class in cashocs), 107solve() (cashocs.ConstrainedOptimalControlProblem

method), 113solve() (cashocs.ConstrainedShapeOptimizationProblem

method), 115solve() (cashocs.OptimalControlProblem method), 106solve() (cashocs.ShapeOptimizationProblem method),

110summation() (in module cashocs.utils), 144supply_adjoint_forms()

(cashocs.OptimalControlProblem method),106

supply_adjoint_forms()(cashocs.ShapeOptimizationProblem method),111

supply_custom_forms()(cashocs.OptimalControlProblem method),107

supply_custom_forms()(cashocs.ShapeOptimizationProblem method),111

supply_derivatives()(cashocs.OptimalControlProblem method),107

supply_shape_derivative()(cashocs.ShapeOptimizationProblem method),111

Ttotal_constraint_violation()

(cashocs.ConstrainedOptimalControlProblemmethod), 113

total_constraint_violation()(cashocs.ConstrainedShapeOptimizationProblemmethod), 116

Vvalidate_config() (cashocs.io.Config method), 137

Wwrite_out_mesh() (in module cashocs.io), 138

Index 167