meep_adjoint
: A python package for adjoint sensitivity analysis in MEEP¶
This is the root of the documentation tree for meep_adjoint
.
Jump directly to the package-wide Table of Contents below,
or read on for a quick-start summary.
What does this package do?¶
You’ll find a longer answer in the Overview (and a more succinct one in the API Reference), but, in a nutshell: It extends the computational capabilities of the core meep solver in a particular way that facilitates interaction with numerical optimization algorithms, opening the door to intelligent design tools that automatically design devices to meet given performance specifications.
Wait, what exactly does the package do again?
If that was a bit vague, we can be more specific about precisely what
meep_adjoint
does. Consider a typical design problem in which we seek to tune a device geometry to optimize some performance metric. For example, in the right-angle router example in themeep_adjoint
example gallery, we are designing a four-waveguide interconnect for an optical network, and our goal is to choose the permittivity distribution \(\epsilon(\mathbf{x})\) in the junction region to steer incoming optical signals arriving on the West port around a 90-degree bend to the North port, ideally with zero leakage power emitted from the South and East ports:Mathematical formulation of design-optimization problems
To formulate this problem mathematically so we can hand it off to a numerical optimizer, we might begin by expressing the unknown design function as an expansion in some convenient finite set of basis functions:
\[\epsilon(\mathbf x)\approx\sum_{d=1}^D \beta_d b_d(\mathbf x)\]Then each possible design configuration corresponds to a \(D\)-dimensional vector of coefficient values \(\boldsymbol{\beta}=\{\beta_1,\cdots,\beta_D\}\), while the metric defining the performance of a design—the quantity we are trying to optimize—is a (real-valued, scalar) function of a vector-valued argument, the objective function \(f^\text{obj}(\boldsymbol{\beta}).\) For the right-angle router with fixed input power entering the West port, we could define our objective to be simply to maximize output power from the North port, i.e.
\[f^\text{obj}(\boldsymbol{\beta}) = S_\text{North} \tag{1}\]where \(S_\text{North}\) denotes the outgoing power flux (integral of normal Poynting vector) through the North flux monitor. Alternatively, assuming the input power is delivered in its entirety by a single mode—call it mode \(m\)— of the West waveguide (as would be the case if we excited our FDTD simulations with an
EigenmodeSource
tuned to mode \(m\)), we could optimize for maximal output power carried by mode \(m\) of the North waveguide, or equivalently for maximal magnitude of the forward-traveling b`mode-expansion coefficient`_ evaluated at the North flux monitor, in which case we would instead have\[f^\text{obj}(\boldsymbol{\beta}) = |P^m_\text{North}|^2 \tag{2}\]where :py:`P^m_\text{North}` denotes the coefficient of the
math
:$m$th forward-traveling waveguide mode at the North flux monitor. (The use of symbols \(S\) and \(P^m\) respectively for Poynting flux and forward-traveling mode-expansion coefficient is part of themeep_adjoint
rules for labeling objective quantities.)Mathematical formulation of design-optimization problems
For our in the router problem a real-valued scalar device given by a and we can picture the process of device optimization as a journey through a \(D\)-dimensional space in search of the magical point \(\boldsymbol{\beta}_*\) at which single point moving through a location. To the performance of a location. To the performance of a
For a
or equivalently to a \(D\)-dimensional vector \({\boldsymbol{\beta}}\), ranges values of the \(D\) coefficients evice design is specified by the \(D\)-dimensional vector of numbers \(\boldsymbol{\beta}\)
sum_{d=1}^D beta_d b_d(mathbf x)
Then, for given fixed values of the input power, operating frequency, and other parameters, the design metric we are trying to optimize—that is, our objective function \(f^\text{obj}\)—may be thought of as a function of the \(D\)-dimensional vector of expansion coefficients \(\boldsymbol{\beta}\), i.e.
\[ \begin{align}\begin{aligned} f^\text{obj}(\boldsymbol{\beta}) =\text{power output from \textbf{North} port} \equiv S_{\text{North}}\\ There's just one problem, which perhaps already occurred to you if you have any experience with high-dimensional optimization:\\and asks for the optimal\end{aligned}\end{align} \]Then, for given fixed values of the input power, operating frequency, and other parameters, the ia the West input waveguide port
- ^text{design}(mathbf x)approx
sum_{d=1}^D beta_d b_d(mathbf x)
Then, for given fixed values of the input power, operating frequency, and other parameters, the ^text{design}(mathbf x)approx sum_{d=1}^D beta_d b_d(mathbf x)
Then, for given fixed values of the input power, operating frequency, and other parameters, the ia the West input waveguide port to the North output wav
Here \(\epsilon(x)\)
\[\epsilon(\mathbf x)=\sum \beta_d b_d(\mathbf x)\]Now suppose some region of the material geometry is free to be tweaked
you’re a device designer tasked with maximizing some performance metric $f$ expressed as a function of these output quantities—for example, we might put \(f=S_2(\omega_3)\) to maximize flux through the 2nda flux region at the 3rd frequency, or \(f = (S_1(\omega_3) - S_2(\omega_3))^2\) to maximize the difference between two fluxes, etc.
The scope of meep_adjoint
Q. Does this mean that the package only computes objective-function gradients? That is, it doesn’t actually do any optimization?
- A. The primary mission of
meep_adjoint
is to compute objective-function gradients. This is the task the package guarantees to execute efficiently and accurately, and it’s one that’s self-contained, unambiguous, and easily testable. 1
The larger question of how best to use gradient information for
design automation—which involves questions such as which of the
myriad available gradient-based optimization algorithms to use,
and how to configure its tunable parameters—is officially beyond the
purview of meep_adjoint
, and indeed is much too broad
a problem to be treated with anything approaching comprehensiveness
by any single package. We hope meep_adjoint
will be
helpful to meep
users as they navigate this
vast domain.
With all of that by way of disclaimer, however, we note that
meep_adjoint
does ship with one (rather simple-minded)
implementation of an optimization algorithm—namely, a
basic gradient-descent solver.
Per the discussion above, we make
no claim as to the robustness or efficiency of this solver,
and we encourage users to consider it a first step in the
process of optimizing any geometry, to be replaced by more
sophisticated solvers as necessary; but, having said that,
we note that the simple built-in optimizer suffices to
yield good results on all the problems considered in
the example gallery.
What does a typical workflow look like?¶
You’ll find a full step-by-step walkthrough in the Tutorial and additional guided case studies in the Example gallery, but here is a quick rundown:
1) Initialization and Problem Definition:
You begin by creating an instance of optimization_problem
This is the top-level python class exported by meep_adjoint
,
analogous to the Simulation
class in the core
meep
python module
; it stores all data and state
relevant to the progress of a design optimization, and
you will access most meep_adjoint
functionality
via its class methods.
2) Interactive single-point calculations Before launching a full-blown iterative optimization run that could run for hours or days, you will probably want to run some sanity-check calculations involving your geometry. These include…**(section incomplete)**
3) Full iterative optimization: Launch your optimization run and monitor its progress via graphical or other indicators.
How is the documentation structured?¶
Table of Contents¶
- Overview
- Tutorial
- Example Gallery
- Installation
- Configuration and customization
- General reference
- Visualization Module
- Test suite
- High-level (public) API
- Low-level (internal) API
TimeStepper
: Interface to computational back-end provided by meep or other FDTD solverObjectiveFunction
: Evaluation of objective-function values and partial derivativesDFTCell
: Storage for frequency-domain field components and evaluation of objective quantitiesSubregion
: Rationalized, unified handling of spatial subregions
Indices and tables¶
..###################################################################### ..###################################################################### ..######################################################################
- 1
For example, one obvious test of the correctness of
meep_adjoint
is to estimate objective-function derivatives by numerical finite-differencing and compare to components of the adjoint-method gradient. This is the basis of one of the tests in themeep_adjoint
unit-test suite, and also of the holey waveguide example in the example gallery.