Design optimization with the meep adjoint solver: A reference manual¶
As described in the Overview, the first step in
using mp.adjoint
is to write a python script implementing
a subclass of the OptimizationProblem
abstract base class
defined by mp.adjoint
. Once that's ready, you can run
your script with commandline options instructing mp.adjoint
to carry out various calculations; these may be singlepoint
calculations, in which the geometry is fixed at given set
of values you specify for the design variables (thus defining
a single point in the space of possible input), or fullblown
iterative optimizations in which mp.adjoint
automatically
evolves the design variables toward the values that optimize
your objective.
table of contents
Defining your problem: Writing a python script for
mp.adjoint
a. The
OptimizationProblem
abstract base classb. Mandatory classmethod overrides:
init_problem
andcreate_sim
c. Defining your objective function
d. Objective regions, extra regions, design region
*Running your problem, Part 1: *: Singlepoint calculations
b. Evaluating the objective function value and gradient at a single design point
c. Testing gradient components by finitedifferencing
d. Running many singlepoint calculations in parallel:
ParallelDesignTester
*Running your problem, Part 2: *: Iterative design optimization
1. Defining your problem: Writing a python script for mp.adjoint
¶
1a. The OptimizationProblem
abstract base class¶
As described in the Overview, the python script
that drives your mp.adjoint
session implements a subclass
of the OptimizationProblem
base class defined by mp.adjoint.
This is a highlevel abstraction of the designautomation
process; the base class knows how to do various general things
involving meep geometries and objective
functions, but is lacking crucial information from you,
without which it can't do anything on its own.
That is to say, OptimizationProblem
is an
abstract base class
with two pure virtual methods that your derived class
must override to describe the specifics of your design problem.
1b. Mandatory classmethod overrides: init_problem
and create_sim
¶
More specifically, your subclass of OptimizationProblem
must furnish implementations of the following two pure virtual
methods left unimplemented in the base class. (Click the header
bars to unfold the description of each item.)
init_problem
: Onetime initialization
Your init_problem
routine will be called once, at the beginning of a mp.adjoint
session; think of it as the class constructor. (Indeed, it is called from the
parent class constructor.)
It has two purposes: (a) to give you a chance to complete any onetime initialization
tasks you need to do, and (b) to communicate to the base class the
CommonElementsOfOptimizationGeometries
needed to turn a generic meep simulation into an optimization problem.

Calling convention:
def init_problem(self,args)
args
: Structure containing values of all commandline options.

Return values:
The routine should return a 5tuple
fstr, objective_regions, extra_regions, design_region, basis
where

fstr
is a string specifying your objective function 
objective_regions
is a list of regions over which to compute frequencydomain (DFT) fields needed to evaluate the quantities on which your objective function depends 
extra_regions
is a list of additional regions over which to compute DFT fields for postprocessing or visualization; it will often be just the empty list[]

design_region
is a region encompassing the variablepermittivity region of your geometry 
basis
is a specification of the set of basis functions used to expand the permittivity. This is a subclass of theBasis
base class defined bymeep.adjoint
; you may implement your own arbitrary basis, or use one of several predefined bases provided bymeep.adjoint.
create_sim
: Instantiating a geometry with given design variables
Your create_sim
routine will be called each time mp.adjoint
needs to
compute your objective function for a particular set of designvariable
values.
Optional classmethod override: add_args
¶
add_args
: Configure problemspecific commandline arguments
The OptimizationProblem
base class defines a
large number of generalpurpose commandline options,
with judiciously chosen default values, to control mp.adjoint
calculations.
In many cases you will want (1) to reconfigure the default values as
appropriate for your problem, (2) to add additional options relevant to
your specific geometry. Your subclass can do both of these things by overriding
the add_args
class method, which will be called just before the actual
commandline arguments are parsed.
Prototype: init_args(self,parser)

parser
:argparse
A structure that has been initialized with all builtin
mp.adjoint
options and their default values. You may callparser.set_defaults
to change the default values of builtin options andparser.add_argument
to add new options. (The actual values specified for all arguments are made available to you via theargs
parameter passed to yourinit_problem
routine.)
Return values: None.
1d. Defining your objective function¶
Your objective function is specified by the string fstr
that you return as
the first element in the 5tuple return value of init_problem.
Your objective function will depend on one or more objective quantities,
such as power fluxes or eigenmode expansion coefficients, associated
with specific objective regions in your geometry. mp.adjoint
defines
a convention for assigning a unique character string to each
objective function in your geometry. Your fstr
should use
these labels to refer to the objective quantities on which it
depends.
Naming convention for objective quantities
Quantity Label Power flux through flux region r
S_r
Expansion coefficient for forwardtravelling eigenmode n at flux region r
Pn_r
Expansion coefficient for backwardtravelling eigenmode n at flux region r
Mn_r
Note that the fluxregion label
r
may be a character string likeeast
if yourinit_problem
method assigned a name to theDFTCell
for that region. Otherwise,r
is an integervalued index corresponding to the zerobased index of the DFT cell in theobjective_regions
list returned by yourinit_problem
.
1e. Selecting an expansion basis¶
The basis
field returned by init_problem
is a subclass of the
Basis
base class implemented by meep.adjoint.
You can write
your own subclass to define an arbitrary basis, or use one of the
builtin basis sets provided by meep.adjoint.
A good default
choice is FiniteElementBasis
:
basis = FiniteElementBasis(lx=4, ly=4, density=4)
which defines a basis of localized
functions over a rectangle of dimensions l_x
×l_y
with density
elements per unit length.
1f. Defining your own expansion basis¶
If none of the preimplemented basis sets suffices for your needs,
you may define your own arbitrary basis by implementing a new subclass
of the Basis
abstract base class in mp.adjoint
. This class abstracts
the representation of a spatiallyvarying permittivity function as a
finite linear combination of scalar basis functions,
$$ \epsilon(\mathbf{x})=\sum \beta_n b_n(\mathbf{x}).$$
The base class defines several methods related to this task and provides
default nonperformanceoptimized implementations for most of these, which
should be fine for most use cases. However, for design optimization of
large structures there are two junctures, bookending each iteration of
the iterative optimization process, in which a sluggish Basis
implementation could potentially slow things down significantly:
(1) At the beginning of each iteration, Basis.call() is invoked
once for each Yeegrid pixel in the design region.
(2) At the end of each iteration, Basis.project()
is called
to compute the basisfunction projection of the objectivefunction
gradient g(\mathbf{x}) \equiv \partial f/\partial \epsilon(\mathbf{x}).
The easiest way to implement your own basis
is probably to start with one of the existing subclasses
in mp.adjoint
, such as SimpleFiniteElementBasis
or PlaneWaveBasis
,
and modify appropriately, subject to the following guidelines.

Your subclass must furnish an override for the pure virtual
__call__
method in the base class. This method accepts a single input argumentp
of typemp.Vector3
(coordinates of evaluation point) and returns the value of the full basisfunction expansion atp
, i.e. \sum \beta_n b_n(\mathbf{p}), with the$\beta_n$ coefficient values taken from the
np.arrayvalued class field
beta_vector` defined in the parent class. 
The constructor (
__init__
method) of your subclass must call the base class constructor, which accepts a single integervalued parameterdim
specifying the number of functions in the basis. 
The base class provides default implementations of all other class methods, so in principle a bareminimum subclass need not do anything beyond the above for for a bareminimum implementation. However, as noted above, for performance reasons you may wish to override
project()
with an implementation that exploits special features of your basis to accelerate the calculation.
2. Running your problem: Visualization, singlepoint calculations, and full iterative optimization¶
Having implemented your script, you can execute it as a python script to run various calculations specified by commandline options.
2a. Visualizing your geometry¶
2b. Evaluating the objective function value and gradient at a single design point¶
2c. Testing gradient components by finitedifferencing¶
2d. Running many singlepoint calculations in parallel: ParallelDesignTester
¶
2e. Full iterative optimization¶
2f. Running many singlepoint calculations in parallel: ParallelDesignTester
¶
4. Builtin commandline options¶
The following commandline options are defined by the OptimizationProblem
base class and are available in all mp.adjoint
sessions.
Options affecting meep timestepping¶
Option  Description 

res 
resolution 
dpml 
PML thickness (1 → autodetermined) 
fcen 
center frequency 
df 
frequency width 
source_mode 
mode index of eigenmode source 
dft_reltol 
convergence threshold for end of timestepping 
dft_timeout 
max runtime in units of last_source_time 
dft_interval 
meep time DFT convergence checks in units of last_source_time 
Options affecting outputs from meep computations¶
Option  Description 

nfreq 
number of output frequencies 
full_dfts 
compute DFT fields over full volume 
complex_fields 
force complex fields 
filebase 
base name of output files 
Options specifying initial values for basisfunction coefficients¶
Option  Description 

betafile 
file of expansion coefficients 
beta 
set value of expansion coefficient 
eps_design 
functional expression for initial design permittivity 
Options describing the calculation to be done¶
Option  Description 

eval_objective 
evaluate objective function value 
eval_gradient 
evaluate objective function value and gradient 
gradient_qname 
name of objective quantity to differentiate via adjoint method 
fd_order 
finitedifference order (0,1,2) 
fd_index 
index of differentiation variable 
fd_rel_delta 
relative finitedifference delta 
optimize 
perform automated design optimization 
Options affecting optimization¶
Option  Description 

alpha 
gradient descent relaxation parameter 
min_alpha 
minimum value of alpha 
max_alpha 
maximum value of alpha 
boldness 
sometimes you just gotta live a little 
timidity 
can\'t be too careful in this dangerous world 
max_iters 
max number of optimization iterations 
Options configurating adjointsolver options¶
Option  Description 

verbose 
produce more output 
concise 
produce less output 
visualize 
produce visualization graphics 
label_source_regions 
label source regions in visualization plots 
logfile 
log file name 
pickle_data 
save state to binary data file 
animate_component 
plot timedomain field component 
animate_interval 
meep time between animation frames 