You are on page 1of 15

Meep

Download
Release notes
FAQ
Meep manual
Introduction
Installation
Tutorial
Reference
C++ Tutorial
C++ Reference
Acknowledgements
License and Copyright
Meep Tutorial
From AbInitio
In this page, we'll go through a couple of simple examples that illustrate the process of
computing elds, transmission/reection spectra, and resonant modes in Meep. All of the
examples here are two-dimensional calculations, simply because they are quicker than 3d
computations and they illustrate most of the essential features, but of course Meep can do
similar calculations in 3d.
This tutorial uses the libctl/Scheme scripting interface to Meep, which is what we expect
most users to employ most of the time. There is also a C++ interface that may give
additional exibility in some situations; that is described in the C++ tutorial.
In order to convert the HDF5 output les of Meep into images of the elds and so on, this
tutorial uses our free h5utils programs. (You could also use any other program, such as
Matlab (http://www.mathworks.com/access/helpdesk/help/techdoc/ref/hdf5read.html) ,
that supports reading HDF5 les.)
Contents
1 The ctl le
2 Fields in a waveguide
2.1 A straight waveguide
2.2 A 90 bend
2.2.1 Output tips and tricks
3 Transmission spectrum around a waveguide bend
4 Modes of a ring resonator
4.1 Exploiting symmetry
5 More examples
6 Editors and ctl
The ctl le
The use of Meep revolves around the control le, abbreviated "ctl" and typically called something like foo.ctl
(although you can use any le name you wish). The ctl le species the geometry you wish to study, the current
sources, the outputs computed, and everything else specic to your calculation. Rather than a at, inexible le
format, however, the ctl le is actually written in a scripting language. This means that it can be everything from a
simple sequence of commands setting the geometry, etcetera, to a full-edged program with user input, loops, and
anything else that you might need.
Don't worry, thoughsimple things are simple (you don't need to be a Real Programmer
(http://catb.org/esr/jargon/html/R/Real-Programmer.html) ), and even there you will appreciate the exibility that a
scripting language gives you. (e.g. you can input things in any order, without regard for whitespace, insert
comments where you please, omit things when reasonable defaults are available...)
The ctl le is actually implemented on top of the libctl library, a set of utilities that are in turn built on top of the
Scheme language. Thus, there are three sources of possible commands and syntax for a ctl le:
Scheme, a powerful and beautiful programming language developed at MIT, which has a particularly simple
syntax: all statements are of the form (function arguments...). We run Scheme under the GNU
Guile interpreter (designed to be plugged into programs as a scripting and extension language). You don't
need to know much Scheme for a basic ctl le, but it is always there if you need it; you can learn more about
it from these Guile and Scheme links.
libctl, a library that we built on top of Guile to simplify communication between Scheme and scientic
computation software. libctl sets the basic tone of the interface and denes a number of useful functions
(such as multi-variable optimization, numeric integration, and so on). See the libctl manual pages.
Meep itself, which denes all the interface features that are specic to FDTD calculations. This manual is
primarily focused on documenting these features.
At this point, please take a moment to leaf through the libctl tutorial to get a feel for the basic style of the interface,
before we get to the Meep-specic stuff below. (If you've used MPB, all of this stuff should already be familiar,
although Meep is somewhat more complex because it can perform a wider variety of computations.)
Okay, let's continue with our tutorial. The Meep program is normally invoked by running something like the
following at the Unix command-line (herein denoted by the unix% prompt):
unix% meep foo.ctl >& foo.out
which reads the ctl le foo.ctl and executes it, saving the output to the le foo.out. However, if you invoke
meep with no arguments, you are dropped into an interactive mode in which you can type commands and see their
results immediately. If you do that now, you can paste in the commands from the tutorial as you follow it and see
what they do.
Fields in a waveguide
For our rst example, let's examine the eld pattern excited by a localized CW source in a waveguide rst
straight, then bent. Our waveguide will have (non-dispersive) and width 1. That is, we pick units of
length so that the width is 1, and dene everything in terms of that (see also units in meep).
A straight waveguide
Before we dene the structure, however, we have to dene the computational cell. We're going to put a source at
one end and watch it propagate down the waveguide in the x direction, so let's use a cell of length 16 in the x
direction to give it some distance to propagate. In the y direction, we just need enough room so that the boundaries
(below) don't affect the waveguide mode; let's give it a size of 8. We now specify these sizes in our ctl le via the
geometry-lattice variable:
(set! geometry-lattice (make lattice (size 16 8 no-size)))
(The name geometry-lattice comes from MPB, where it can be used to dene a more general periodic
lattice. Although Meep supports periodic structures, it is less general than MPB in that afne grids are not
supported.) set! is a Scheme command to set the value of an input variable. The last no-size parameter says
that the computational cell has no size in the z direction, i.e. it is two-dimensional.
Now, we can add the waveguide. Most commonly, the structure is specied by a list of geometric objects, stored
in the geometry variable. Here, we do:
(set! geometry (list
(make block (center 0 0) (size infinity 1 infinity)
(material (make dielectric (epsilon 12))))))
The waveguide is specied by a block (parallelepiped) of size , with !=12, centered at (0,0) (the
center of the computational cell). By default, any place where there are no objects there is air (!=1), although this
can be changed by setting the default-material variable. The resulting structure is shown at right.
Now that we have the structure, we need to specify the current sources, which is specied as a list called
Dielectric function (black = high,
white = air), for straight
waveguide simulation.
sources of source objects. The simplest thing is to add a point source J
z
:
(set! sources (list
(make source
(src (make continuous-src (frequency 0.15)))
(component Ez)
(center -7 0))))
Here, we gave the source a frequency of 0.15, and specied a continuous-
src which is just a xed-frequency sinusoid exp( " i#t) that (by default) is
turned on at t = 0. Recall that, in Meep units, frequency is specied in units of
2$c, which is equivalent to the inverse of vacuum wavelength. Thus, 0.15 corresponds to a vacuum wavelength of
about 1 / 0.15 = 6.67, or a wavelength of about 2 in the materialthus, our waveguide is half a
wavelength wide, which should hopefully make it single-mode. (In fact, the cutoff for single-mode behavior in this
waveguide is analytically solvable, and corresponds to a frequency of 1/2%11 or roughly 0.15076.) Note also that to
specify a J
z
, we specify a component Ez (e.g. if we wanted a magnetic current, we would specify Hx, Hy, or Hz).
The current is located at ( " 7,0), which is 1 unit to the right of the left edge of the cellwe always want to leave a
little space between sources and the cell boundaries, to keep the boundary conditions from interfering with them.
Speaking of boundary conditions, we want to add absorbing boundaries around our cell. Absorbing boundaries in
Meep are handled by perfectly matched layers (PML) which aren't really a boundary condition at all, but rather a
ctitious absorbing material added around the edges of the cell. To add an absorbing layer of thickness 1 around all
sides of the cell, we do:
(set! pml-layers (list (make pml (thickness 1.0))))
pml-layers is a list of pml objectsyou may have more than one pml object if you want PML layers only on
certain sides of the cell, e.g. (make pml (thickness 1.0) (direction X) (side High)) species
a PML layer on only the + x side. Now, we note an important point: the PML layer is inside the cell, overlapping
whatever objects you have there. So, in this case our PML overlaps our waveguide, which is what we want so that it
will properly absorb waveguide modes. The nite thickness of the PML is important to reduce numerical
reections; see perfectly matched layers for more information.
Meep will discretize this structure in space and time, and that is specied by a single variable, resolution, that
gives the number of pixels per distance unit. We'll set this resolution to 10, which corresponds to around 67
pixels/wavelength, or around 20 pixels/wavelength in the high-dielectric material. (In general, at least 8
pixels/wavelength in the highest dielectric is a good idea.) This will give us a cell.
(set! resolution 10)
Now, we are ready to run the simulation! We do this by calling the run-until function. The rst argument to
run-until is the time to run for, and the subsequent arguments specify elds to output (or other kinds of
analyses at each time step):
(run-until 200
(at-beginning output-epsilon)
(at-end output-efield-z))
Here, we are outputting the dielectric function ! and the electric-eld component E
z
, but have wrapped the output
functions (which would otherwise run at every time step) in at-beginning and at-end, which do just what
they say. There are several other such functions to modify the output behaviorand you can, of course, write your
own, and in fact you can do any computation or output you want at any time during the time evolution (and even
modify the simulation while it is running).
It should complete in a few seconds. If you are running interactively, the two output les will be called eps-
000000.00.h5 and ez-000200.00.h5 (notice that the le names include the time at which they were
output). If we were running a tutorial.ctl le, then the outputs will be tutorial-eps-000000.00.h5
and tutorial-ez-000200.00.h5. In any case, we can now analyze and visualize these les with a wide
variety of programs that support the HDF5 format, including our own h5utils, and in particular the h5topng
program to convert them to PNG images.
unix% h5topng -S3 eps-000000.00.h5
This will create eps-000000.00.png, where the -S3 increases the image scale by 3 (so that it is around 450
pixels wide, in this case). In fact, precisely this command is what created the dielectric image above. Much more
interesting, however, are the elds:
unix% h5topng -S3 -Zc dkbluered -a yarg -A eps-000000.00.h5 ez-000200.00.h5
Briey, the -Zc dkbluered makes the color scale go from dark blue (negative) to white (zero) to dark red
(positive), and the -a/-A options overlay the dielectric function as light gray contours. This results in the image:
Here, we see that the the source has excited the waveguide mode, but has also excited radiating elds propagating
away from the waveguide. At the boundaries, the eld quickly goes to zero due to the PML layers. If we look
carefully (click on the image to see a larger view), we see somethinge elsethe image is "speckled" towards the
right side. This is because, by turning on the current abruptly at t = 0, we have excited high-frequency components
(very high order modes), and we have not waited long enough for them to die away; we'll eliminate these in the
next section by turning on the source more smoothly.
A 90 bend
Now, we'll start a new simulation where we look at the elds in a bent waveguide, and we'll do a couple of other
things differently as well. If you are running Meep interactively, you will want to get rid of the old structure and
elds so that Meep will re-initialize them:
(reset-meep)
Then let's set up the bent waveguide, in a slightly bigger computational cell, via:
(set! geometry-lattice (make lattice (size 16 16 no-size)))
(set! geometry (list
(make block (center -2 -3.5) (size 12 1 infinity)
(material (make dielectric (epsilon 12))))
(make block (center 3.5 2) (size 1 12 infinity)
(material (make dielectric (epsilon 12))))))
(set! pml-layers (list (make pml (thickness 1.0))))
(set! resolution 10)
Note that we now have two blocks, both off-center to produce the bent waveguide structure pictured at right. As
illustrated in the gure, the origin (0,0) of the coordinate system is at the center of the computational cell, with
Bent waveguide dielectric function and coordinate
system.
positive y being downwards in h5topng, and thus the block
of size 12&1 is centered at ( " 2, " 3.5). Also shown in green
is the source plane at x = " 7 (see below).
We also need to shift our source to y = " 3.5 so that it is still
inside the waveguide. While we're at it, we'll make a couple
of other changes. First, a point source does not couple very
efciently to the waveguide mode, so we'll expand this into a
line source the same width as the waveguide by adding a
size property to the source (a future version of Meep will
allow you to use a current with the exact eld pattern as
computed by MPB). Second, instead of turning the source on
suddenly at t = 0 (which excites many other frequencies
because of the discontinuity), we will ramp it on slowly
(technically, Meep uses a tanh turn-on function) over a time
proportional to the width of 20 time units (a little over
three periods). Finally, just for variety, we'll specify the
(vacuum) wavelength instead of the frequency; again,
we'll use a wavelength such that the waveguide is half a
wavelength wide.
Finally, we'll run the simulation. Instead of running output-efield-z only at the end of the simulation,
however, we'll run it at every 0.6 time units (about 10 times per period) via (at-every 0.6 output-
efield-z). By itself, this would output a separate le for every different output time, but instead we'll use
another feature of Meep to output to a single three-dimensional HDF5 le, where the third dimension is time:
(run-until 200
(at-beginning output-epsilon)
(to-appended "ez" (at-every 0.6 output-efield-z)))
Here, "ez" determines the name of the output le, which will be called ez.h5 if you are running interactively or
will be prexed with the name of the le name for a ctl le (e.g. tutorial-ez.h5 for tutorial.ctl). If we
run h5ls on this le (a standard utility, included with HDF5, that lists the contents of the HDF5 le), we get:
unix% h5ls ez.h5
ez Dataset {161, 161, 330/Inf}
That is, the le contains a single dataset ez that is a 162&162&330 array, where the last dimension is time. (This is
rather a large le, 69MB; later, we'll see ways to reduce this size if we only want images.) Now, we have a number
of choices of how to output the elds. To output a single time slice, we can use the same h5topng command as
before, but with an additional -t option to specify the time index: e.g. h5topng -t 229 will output the last
time slice, similar to before. Instead, let's create an animation of the elds as a function of time. First, we have to
create images for all of the time slices:
unix% h5topng -t 0:329 -R -Zc dkbluered -a yarg -A eps-000000.00.h5 ez.h5
This is similar to the command before, with two new options: -t 0:329 outputs images for all time indices from
0 to 329, i.e. all of the times, and the the -R ag tells h5topng to use a consistent color scale for every image
(instead of scaling each image independently). Then, we have to convert these images into an animation in some
(set! sources (list
(make source
(src (make continuous-src
(wavelength (* 2 (sqrt 12))) (width 20)))
(component Ez)
(center -7 -3.5) (size 0 1))))
x by time
slice of bent
waveguide
(vertical =
time).
format. For this, we'll use the free ImageMagick convert program (although there is other software that will do
the trick as well).
unix% convert ez.t*.png ez.gif
Here, we are using an animated GIF format for the output, which is not the most efcient animation format (e.g.
ez.mpg, for MPEG format, would be better), but it is unfortunately the only format supported by this Wiki
software. This results in the following animation :
It is clear that the transmission around the bend is rather low for this frequency and structure
both large reection and large radiation loss are clearly visible. Moreover, since we operating are
just barely below the cutoff for single-mode behavior, we are able to excite a second leaky mode
after the waveguide bend, whose second-order mode pattern (superimposed with the fundamental
mode) is apparent in the animation. At right, we show a eld snapshot from a simulation with a
larger cell along the y direction, in which you can see that the second-order leaky mode decays
away, leaving us with the fundamental mode propagating downward.
Instead of doing an animation, another interesting possibility is to make an image from a
slice. Here is the y = " 3.5 slice, which gives us an image of the elds in the rst waveguide
branch as a function of time.
unix% h5topng -0y -35 -Zc dkbluered ez.h5
Here, the -0y -35 species the y = " 3.5 slice, where we have multiplied by 10 (our resolution)
to get the pixel coordinate.
Output tips and tricks
Above, we outputted the full 2d data slice at every 0.6 time units, resulting in a 69MB le. This is not too bad by
today's standards, but you can imagine how big the output le would get if we were doing a 3d simulation, or even
a larger 2d simulationone can easily generate gigabytes of les, which is not only wasteful but is also slow.
Instead, it is possible to output more efciently if you know what you want to look at.
To create the movie above, all we really need are the images corresponding to each time. Images can be stored
much more efciently than raw arrays of numbersto exploit this fact, Meep allows you to output PNG images
instead of HDF5 les. In particular, instead of output-efield-z as above, we can use (output-png Ez
"-Zc dkbluered"), where Ez is the component to output and the "-Zc dkbluered" are options for
h5topng (which is the program that is actually used to create the image les). That is:
(run-until 200 (at-every 0.6 (output-png Ez "-Zc bluered")))
will output a PNG le le every 0.6 time units, which can then be combined with convert as above to create a
movie. The movie will be similar to the one before, but not identical because of how the color scale is determined.
Before, we used the -R option to make h5topng use a uniform color scale for all images, based on the
minimum/maximum eld values over all time steps. That is not possible, here, because we output an image before
knowing the eld values at future time steps. Thus, what output-png does is to set its color scale based on the
minimum/maximum eld values from all past timestherefore, the color scale will slowly "ramp up" as the source
turns on.
The above command outputs zillions of .png les, and it is somewhat annoying to have them clutter up our
directory. Instead, we can use the following command before run-until:
(use-output-directory)
This will put all of the output les (.h5, .png, etcetera) into a newly-created subdirectory, called by default
filename-out/ if our ctl le is filename.ctl.
What if we want to output an slice, as above? To do this, we only really wanted the values at y = " 3.5, and
therefore we can exploit another powerful Meep output featureMeep allows us to output only a subset of the
computational cell. This is done using the in-volume function, which (like at-every and to-appended) is
another function that modies the behavior of other output functions. In particular, we can do:
(run-until 200
(to-appended "ez-slice"
(at-every 0.6
(in-volume (volume (center 0 -3.5) (size 16 0))
output-efield-z))))
The rst argument to in-volume is a volume, specied by (volume (center ...) (size ...)),
which applies to all of the nested output functions. (Note that to-appended, at-every, and in-volume are
cumulative regardless of what order you put them in.) This creates the output le ez-slice.h5 which contains a
dataset of size 162&330 corresponding to the desired slice.
Transmission spectrum around a waveguide bend
Above, we computed the eld patterns for light propagating around a waveguide bend. While this is pretty, the
results are not quantitatively satisfying. We'd like to know exactly how much power makes it around the bend, how
much is reected, and how much is radiated away. How can we do this?
The basic principles were described in the Meep introduction; please re-read that section if you have forgotten.
Basically, we'll tell Meep to keep track of the elds and their Fourier transforms in a certain region, and from this
compute the ux of electromagnetic energy as a function of #. Moreover, we'll get an entire spectrum of the
transmission in a single run, by Fourier-transforming the response to a short pulse. However, in order to normalize
the transmission (to get transmission as a fraction of incident power), we'll have to do two runs, one with and one
without a bend.
This control le will be more complicated than before, so you'll denitely want it as a separate le rather than
typing it interactively. See the bend-flux.ctl le included with Meep in its examples/ directory.
Above, we hard-coded all of the parameters like the cell size, the waveguide width, etcetera. For serious work,
however, this is inefcientwe often want to explore many different values of such parameters. For example, we
may want to change the size of the cell, so we'll dene it as:
(define-param sx 16) ; size of cell in X direction
(define-param sy 32) ; size of cell in Y direction
(set! geometry-lattice (make lattice (size sx sy no-size)))
(Notice that a semicolon ";" begins a comment, which is ignored by Meep.) define-param is a libctl feature to
dene variables that can be overridden from the command line. We could now do meep sx=17 tut-wvg-
bend-trans.ctl to change the X size to 17, without editing the ctl le, for example. We'll also dene a couple
of parameters to set the width of the waveguide and the "padding" between it and the edge of the computational
cell:
(define-param pad 4) ; padding distance between waveguide and cell edge
(define-param w 1) ; width of waveguide
In order to dene the waveguide positions, etcetera, we will now have to use arithmetic. For example, the y center
of the horizontal waveguide will be given by -0.5 * (sy - w - 2*pad). At least, that is what the
expression would look like in C; in Scheme, the syntax for 1 + 2 is (+ 1 2), and so on, so we will dene the
vertical and horizontal waveguide centers as:
(define wvg-ycen (* -0.5 (- sy w (* 2 pad)))) ; y center of horiz. wvg
(define wvg-xcen (* 0.5 (- sx w (* 2 pad)))) ; x center of vert. wvg
Now, we have to make the geometry, as before. This time, however, we really want two geometries: the bend, and
also a straight waveguide for normalization. We could do this with two separate ctl les, but that is annoying.
Instead, we'll dene a parameter no-bend? which is true for the straight-waveguide case and false for the
bend.
(define-param no-bend? false) ; if true, have straight waveguide, not bend
Now, we dene the geometry via two cases, with an if statementthe Scheme syntax is (if predicate? if-
true if-false).
(set! geometry
(if no-bend?
(list
(make block
(center 0 wvg-ycen)
(size infinity w infinity)
(material (make dielectric (epsilon 12)))))
(list
(make block
(center (* -0.5 pad) wvg-ycen)
(size (- sx pad) w infinity)
(material (make dielectric (epsilon 12))))
(make block
(center wvg-xcen (* 0.5 pad))
(size w (- sy pad) infinity)
(material (make dielectric (epsilon 12)))))))
Thus, if no-bend? is true we make a single block for a straight waveguide, and otherwise we make two blocks
for a bent waveguide.
The source is now a gaussian-src instead of a continuous-src, parameterized by a center frequency and a
frequency width (the width of the Gaussian spectrum), which we'll dene via define-param as usual.
(define-param fcen 0.15) ; pulse center frequency
(define-param df 0.1) ; pulse width (in frequency)
(set! sources (list
(make source
(src (make gaussian-src (frequency fcen) (fwidth df)))
(component Ez)
(center (+ 1 (* -0.5 sx)) wvg-ycen)
(size 0 w))))
Notice how we're using our parameters like wvg-ycen and w: if we change the dimensions, everythign will now
shift automatically. The boundary conditions and resolution are set as before, except that now we'll use set-
param! so that we can override the resolution from the command line.:
(set! pml-layers (list (make pml (thickness 1.0))))
(set-param! resolution 10)
Finally, we have to specify where we want Meep to compute the ux spectra, and at what frequencies. (This must
be done after specifying the geometry, sources, resolution, etcetera, because all of the eld parameters are
initialized when ux planes are created.)
(define-param nfreq 100) ; number of frequencies at which to compute flux
(define trans ; transmitted flux
(add-flux fcen df nfreq
(if no-bend?
(make flux-region
(center (- (/ sx 2) 1.5) wvg-ycen) (size 0 (* w 2)))
(make flux-region
(center wvg-xcen (- (/ sy 2) 1.5)) (size (* w 2) 0)))))
(define refl ; reflected flux
(add-flux fcen df nfreq
(make flux-region
(center (+ (* -0.5 sx) 1.5) wvg-ycen) (size 0 (* w 2)))))
We compute the uxes through a line segment twice the width of the waveguide, located at the beginning or end of
the waveguide. (Note that the ux lines are separated by 1 from the boundary of the cell, so that they do not lie
within the absorbing PML regions.) Again, there are two cases: the transmitted ux is either computed at the right
or the bottom of the computational cell, depending on whether the waveguide is straight or bent.
Here, the uxes will be computed for 100 (nfreq) frequencies centered on fcen, from fcen-df/2 to
fcen+df/2. That is, we only compute uxes for frequencies within our pulse bandwidth. This is important
because, to far outside the pulse bandwidth, the spectral power is so low that numerical errors make the computed
uxes useless.
Now, as described in the Meep introduction, computing reection spectra is a bit tricky because we need to separate
the incident and reected elds. We do this in Meep by saving the Fourier-transformed elds from the
normalization run (no-bend?=true), and loading them, negated, before the other runs. The latter subtracts the
Fourier-transformed incident elds from the Fourier transforms of the scattered elds; logically, we might subtract
these after the run, but it turns out to be more convenient to subtract the incident elds rst and then accumulate the
Fourier transform. All of this is accomplished with two commands, save-flux (after the normalization run) and
load-minus-flux (before the other runs). We can call them as follows:
(if (not no-bend?) (load-minus-flux "refl-flux" refl))
(run-sources+ 500 (at-beginning output-epsilon))
(if no-bend? (save-flux "refl-flux" refl))
This uses a le called refl-flux.h5, or actually bend-flux-refl-flux.h5 (the ctl le name is used as a
prex) to store/load the Fourier transformed elds in the ux planes. The (run-sources+ 500) runs the
simulation until the Gaussian source has turned off (which is done automatically once it has decayed for a few
standard deviations), plus an additional 500 time units.
Why do we keep running after the source has turned off? Because we must give the pulse time to propagate
completely across the cell. Moreover, the time required is a bit tricky to predict when you have complex structures,
because there might be resonant phenomena that allow the source to bounce around for a long time. Therefore, it is
convenient to specify the run time in a different way: instead of using a xed time, we require that the | E
z
|
2
at the
end of the waveguide must have decayed by a given amount (e.g. 1/1000) from its peak value. We can do this via:
(run-sources+
(stop-when-fields-decayed 50 Ez
(if no-bend?
(vector3 (- (/ sx 2) 1.5) wvg-ycen)
(vector3 wvg-xcen (- (/ sy 2) 1.5)))
1e-3))
stop-when-fields-decayed takes four arguments: (stop-when-fields-decayed dT component
pt decay-by). What it does is, after the sources have turned off, it keeps running for an additional dT time
units every time the given |component|
2
at the given point has not decayed by at least decay-by from its peak
value for all times within the previous dT. In this case, dT=50, the component is E
z
, the point is at the center of the
ux plane at the end of the waveguide, and decay-by=0.001. So, it keeps running for an additional 50 time
units until the square amplitude has decayed by 1/1000 from its peak: this should be sufcient to ensure that the
Fourier transforms have converged.
Finally, we have to output the ux values:
(display-fluxes trans refl)
This prints a series of outputs like:
flux1:, 0.1, 7.91772317108475e-7, -3.16449591437196e-7
flux1:, 0.101010101010101, 1.18410865137737e-6, -4.85527604203706e-7
flux1:, 0.102020202020202, 1.77218779386503e-6, -7.37944901819701e-7
flux1:, 0.103030303030303, 2.63090852112034e-6, -1.11118350510327e-6
flux1:, ...
This is comma-delimited data, which can easily be imported into any spreadsheet or plotting program (e.g. Matlab):
the rst column is the frequency, the second is the transmitted power, and the third is the reected power.
Now, we need to run the simulation twice, once with no-bend?=true and once with no-bend?=false (the
default):
unix% meep no-bend?=true bend-flux.ctl | tee bend0.out
unix% meep bend-flux.ctl | tee bend.out
(The tee command is a useful Unix command that saves the output to a le and displays it on the screen, so that
we can see what is going on as it runs.) Then, we should pull out the flux1 lines into a separate le to import them
into our plotting program:
unix% grep flux1: bend0.out > bend0.dat
unix% grep flux1: bend.out > bend.dat
Now, we import them to Matlab (using its dlmread command), and plot the results:
What are we plotting here? The transmission is the transmitted ux (second column of bend.dat) divided by the
incident ux (second column of bend0.dat), to give us the fraction of power transmitted. The reection is the
reected ux (third column of bend.dat) divided by the incident ux (second column of bend0.dat); we also
have to multiply by " 1 because all uxes in Meep are computed in the positive-coordinate direction by default, and
we want the ux in the " x direction. Finally, the loss is simply 1 - transmission - reection.
We should also check whether our data is converged, by increasing the resolution and cell size and seeing by how
much the numbers change. In this case, we'll just try doubling the cell size:
unix% meep sx=32 sy=64 no-bend?=true bend-flux.ctl |tee bend0-big.out
unix% meep sx=32 sy=64 bend-flux.ctl |tee bend-big.out
Again, we must run both simulations in order to get the normalization right. The results are included in the plot
above as dotted linesyou can see that the numbers have changed slightly for transmission and loss, probably
stemming from interference between light radiated directly from the source and light propagating around the
waveguide. To be really condent, we should probably run the simulation again with an even bigger cell, but we'll
call it enough for this tutorial.
Modes of a ring resonator
As described in the Meep introduction, another common task for FDTD simulation is to nd the resonant modes
frequencies and decay ratesof some electromagnetic cavity structure. (You might want to read that introduction
again to recall the basic computational strategy.) Here, we will show how this works for perhaps the simplest
example of a dielectric cavity: a ring resonator, which is simply a waveguide bent into a circle. (This can be also
found in the examples/ring.ctl le included with Meep.) In fact, since this structure has cylindrical
symmetry, we can simulate it much more efciently by using cylindrical coordinates, but for illustration here we'll
just use an ordinary 2d simulation.
As before, we'll dene some parameters to describe the geometry, so that we can easily change the structure:
(define-param n 3.4) ; index of waveguide
(define-param w 1) ; width of waveguide
(define-param r 1) ; inner radius of ring
(define-param pad 4) ; padding between waveguide and edge of PML
(define-param dpml 2) ; thickness of PML
(define sxy (* 2 (+ r w pad dpml))) ; cell size
(set! geometry-lattice (make lattice (size sxy sxy no-size)))
How do we make a circular waveguide? So far, we've only seen block objects, but Meep also lets you specify
cylinders, spheres, ellipsoids, and cones, as well as user-specied dielectric functions. In this case, we'll use two
cylinder objects, one inside the other:
(set! geometry (list
(make cylinder (center 0 0) (height infinity)
(radius (+ r w)) (material (make dielectric (index n))))
(make cylinder (center 0 0) (height infinity)
(radius r) (material air))))
(set! pml-layers (list (make pml (thickness dpml))))
(set-param! resolution 10)
Later objects in the geometry list take precedence over (lie "on top of") earlier objects, so the second air (
) cylinder cuts a circular hole out of the larger cylinder, leaving a ring of width w.
Now, we don't know the frequency of the mode(s) ahead of time, so we'll just hit the structure with a broad
Gaussian pulse to excite all of the (TM polarized) modes in a chosen bandwidth:
(define-param fcen 0.15) ; pulse center frequency
(define-param df 0.1) ; pulse width (in frequency)
(set! sources (list
(make source
(src (make gaussian-src (frequency fcen) (fwidth df)))
(component Ez) (center (+ r 0.1) 0))))
Finally, we are ready to run the simulation. The basic idea is to run until the sources are nished, and then to run for
some additional period of time. In that additional period, we'll perform some signal-processing on the elds at some
point with harminv to identify the frequencies and decay rates of the modes that were excited:
(run-sources+ 300
(at-beginning output-epsilon)
(after-sources (harminv Ez (vector3 (+ r 0.1)) fcen df)))
The signal-processing is performed by the harminv function, which takes four arguments: the eld component
(here Ez) and position (here (r + 0.1,0)) to analyze, and a frequency range given by a center frequency and
bandwidth (here, the same as the source pulse). Note that we wrap harminv in (after-sources ...), since
we only want to analyze the frequencies in the source-free system (the presence of a source will distort the
analysis). At the end of the run, harminv prints a series of lines (beginning with harminv0:, to make it easy to
grep for) listing the frequencies it found:
There are six columns (in addition to the label), comma-delimited for easy import into other programs. The
meaning of these columns is as follows. Harminv analyzes the elds f(t) at the given point, and expresses this as a
sum of modes (in the specied bandwidth):
harminv0:, frequency, imag. freq., Q, |amp|, amplitude, error
harminv0:, 0.118101575043663, -7.31885828253851e-4, 80.683059081382, 0.00341388964904578, -0.00305022905294175-0.00153321402956404i, 1.02581433904604e-5
harminv0:, 0.147162555528154, -2.32636643253225e-4, 316.29272471914, 0.0286457663908165, 0.0193127882016469-0.0211564681361413i, 7.32532621851082e-7
harminv0:, 0.175246750722663, -5.22349801171605e-5, 1677.48461212767, 0.00721133215656089, -8.12770506086109e-4-0.00716538314235085i, 1.82066436470489e-7
for complex amplitudes a
n
and complex frequencies #
n
. The six columns relate to these quantities. The rst column
is the real part of #
n
, expressed in our usual 2$c units, and the second column is the imaginary parta negative
imaginary part corresponds to an exponential decay. This decay rate, for a cavity, is more often expressed as a
dimensionless "lifetime" Q, dened by:
(Q is the number of optical periods for the energy to decay by exp( " 2$), and 1 / Q is the fractional bandwidth at
half-maximum of the resonance peak in Fourier domain.) This Q is the third column of the output. The fourth and
fth columns are the absolute value | a
n
| and complex amplitudes a
n
. The last column is a crude measure of the
error in the frequency (both real and imaginary)...if the error is much larger than the imaginary part, for example,
then you can't trust the Q to be accurate. Note: this error is only the uncertainty in the signal processing, and tells
you nothing about the errors from nite resolution, nite cell size, and so on!
An interesting question is how long should we run the simulation, after the sources are turned off, in order to
analyze the frequencies. With traditional Fourier analysis, the time would be proportional to the frequency
resolution required, but with harminv the time is much shorter. Here, for example, there are three modes. The last
has a Q of 1677, which means that the mode decays for about 2000 periods or about 2000/0.175 = 10
4
time units.
We have only analyzed it for about 300 time units, however, and the estimated uncertainty in the frequency is 10
" 7
(with an actual error of about 10
" 6
, from below)! In general, you need to increase the run time to get more
accuracy, and to nd very high Q values, but not by muchin our own work, we have successfully found Q = 10
9
modes by analyzing only 200 periods.
In this case, we found three modes in the specied bandwith, at frequencies of 0.118, 0.147, and 0.175, with
corresponding Q values of 81, 316, and 1677. (As was shown by Marcatilli in 1969, the Q of a ring resonator
increases exponentially with the product of # and ring radius.) Now, suppose that we want to actually see the eld
patterns of these modes. No problem: we just re-run the simulation with a narrow-band source around each mode
and output the eld at the end.
In particular, to output the eld at the end we might add an (at-end output-efield-z) argument to our
run-sources+ function, but this is problematic: we might be unlucky and output at a time when the E
z
eld is
almost zero (i.e. when all of the energy is in the magnetic eld), in which case the picture will be deceptive. Instead,
at the end of the run we'll output 20 eld snapshots over a whole period 1/fcen by appending the command:
(run-until (/ 1 fcen) (at-every (/ 1 fcen 20) output-efield-z))
Now, we can get our modes just by running e.g.:
unix% meep fcen=0.118 df=0.01 ring.ctl
After each one of these commands, we'll convert the elds into PNG images and thence into an animated GIF (as
with the bend movie, above), via:
unix% h5topng -RZc dkbluered -C ring-eps-000000.00.h5 ring-ez-*.h5
unix% convert ring-ez-*.png ring-ez-0.118.gif
The resulting animations for (from left to right) 0.118, 0.147, and 0.175, are below, in which you can clearly see the
radiating elds that produce the losses:
(Each of these modes is, of course, doubly-degenerate according to the representations of the symmetry
group. The other mode is simply a slight rotation of this mode to make it odd through the x axis, whereas we
excited only the even modes due to our source symmetry. Equivalently, one can form clockwise and counter-
clockwise propagating modes by taking linear combinations of the even/odd modes, corresponding an angular '
dependence for m = 3, 4, and 5 in this case.)
You may have noticed, by the way, that when you run with the narrow-bandwidth source, harminv gives you
slightly different frequency and Q estimates, with a much smaller error estimatethis is not too strange, since by
exciting a single mode you generate a cleaner signal that can be analyzed more accurately. For example, the narrow-
bandwidth source for the # = 0.175 mode gives:
which differs by about 0.000001 (10
" 6
) from the earlier estimate; the difference in Q is, of course, larger because a
small absolute error in # gives a larger relative error in the small imaginary frequency.
Exploiting symmetry
In this case, because we have a mirror symmetry plane (the x axis) that preserves both the structure and the sources,
we can exploit this mirror symmetry to speed up the computation. (See also exploiting symmetry in Meep.) In
particular, everything about the input le is the same except that we add a single line, right after we specify the
sources:
(set! symmetries (list (make mirror-sym (direction Y))))
This tells Meep to exploit a mirror-symmetry plane through the origin perpendicular to the y direction. Meep does
not check whether your system really has this symmetryyou should only specify symmetries that really preserve
your structure and your sources.
Everything else about your simulation is the same: you can still get the elds at any point, the output le still covers
the whole ring, and the harminv outputs are exactly the same. Internally, however, Meep is only doing computations
with half of the structure, and the simulation is around twice as fast (YMMV).
In general, the symmetry of the sources may require some phase. For example, if our source was in the y direction
instead of the z direction, then the source would be odd under mirror ips through the x axis. We would specify this
by (make mirror-sym (direction Y) (phase -1)). See the Meep reference for more symmetry
possibilities.
In this case, we actually have a lot more symmetry that we could potentially exploit, if we are willing to restrict the
symmetry of our source/elds to a particular angular momentum (i.e. angular dependence e
im'
). See also: Ring
resonator in cylindrical coordinates for how to solve for modes of this cylindrical geometry much more efciently.
More examples
harminv0:, 0.175247426698716, -5.20844416909221e-5, 1682.33949533974, 0.185515412838043, 0.127625313330642-0.13463932485617i, 7.35320734698267e-12
The examples above sufce to illustrate the most basic features of Meep. However, there are many more advanced
features that have not been demonstrated here. So, we hope to add, over time, a sequence of examples that exhibit
more complicated structures and computational techniques. The ones we have so far are listed below.
If you have a good example you would like to share, feel free to register for a user name and log in, and then add a
link to a new page for your example below. (Please prex the link with "Meep Tutorial/". Simple examples
illustrating a specic concept are preferred.)
Meep Tutorial/Ring resonator in cylindrical coordinates
Meep Tutorial/Band diagram, resonant modes, and transmission in a holey waveguide
Meep Tutorial/Third harmonic generation (Kerr nonlinearity)
Meep Tutorial/Material dispersion
Meep Tutorial/Local density of states (Purcell enhancement)
Meep Tutorial/Optical forces (Maxwell stress tensor)
Editors and ctl
It is useful to have emacs use its scheme-mode for editing ctl les, so that hitting tab indents nicely, and so on.
emacs does this automatically for les ending with ".scm"; to do it for les ending with ".ctl" as well, add the
following lines to your ~/.emacs le:
(if (assoc "\\.ctl" auto-mode-alist)
nil
(nconc auto-mode-alist '(("\\.ctl" . scheme-mode))))
(Incidentally, emacs scripts are written in "elisp," a language closely related to Scheme.)
If you don't use emacs (or derivatives such as Aquamacs), it would be good to nd another editor that supports a
Scheme mode. For example, jEdit (http://www.jedit.org/) is a free/open-source cross-platform editor with Scheme-
syntax support. Another option is GNU gedit (http://projects.gnome.org/gedit/) (for GNU/Linux and Unix); in fact,
S. Hessam Moosavi Mehr has donated a hilighting mode for Meep/MPB (http://github.com/hessammehr/meepmpb-
highlight) that specially highlights the Meep/MPB keywords.
Retrieved from "http://ab-initio.mit.edu/wiki/index.php/Meep_Tutorial"
Categories: Meep | Meep examples
This page was last modied 05:19, 29 September 2012.
This page has been accessed 294,122 times.
Privacy policy
About AbInitio
Disclaimers

You might also like