1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
\begin{comment}
#include <stdio.h>
#include <stdlib.h>
#include <meep.hpp>
using namespace meep;
const int a = 10;
\end{comment}
\section{Computing the band structure of an omniguide}
In this section we give as an example of a more complicated band structure,
a computation of the band structure of an omniguide. The output of this
program is shown in Figure~\ref{omniguidebands}.
\begin{verbatim}
const int num_layers = 3;
const double rcore = 3.0;
double guided_eps(const vec &v) {
double rr = v.r() - rcore;
if (rr > num_layers + 0.3) return 1.0; // outside the entire waveguide
if (rr < 0.0) return 1.0; // vacuum in the core
while (rr > 1.0) rr -= 1.0; // calculate (r - rcore) % 1
if (rr < 0.3) return 21.16; // in the high dielectric
return 1.6*1.6; // in the low dielectric
}
double vacuum_eps(const vec &v) { return 1.0; }
\end{verbatim}
\begin{comment}
int main(int argc, char **argv) {
initialize mpi(argc, argv);
deal_with_ctrl_c();
printf("Running omniguide!\n");
const double ttot = 1000.0;
structure s(volcyl(rcore + num_layers + 0.3, 0.0, a), guided_eps);
const char *dirname = make_output_directory(__FILE__);
\end{comment}
For this band structure example, we use the grace object to create our
plot.
\begin{verbatim}
grace g("bands", dirname);
g.set_range(0.0, 0.35, 0.0, 0.35);
\end{verbatim}
\begin{comment}
s.set_output_directory(dirname);
structure vac(&s);
vac.set_epsilon(vacuum_eps, false);
\end{comment}
Since the m = 0 modes are pure TE or TM, it makes sense to calculate the
two polarizations separately. Not only does this give us more interesting
output, but it doesn't cost us any time, to speak of, and actually makes
the band structure much easier to converge. However, for brevity, I won't
include here in the manual computation of the TM modes, but will skip
straight to the TE modes.
\begin{comment}
{
const int m=0;
g.new_set();
g.set_legend("m = 0, TM");
for (double k=0.0;k<0.356 && !interrupt;k+=0.05) {
char k_and_m[10];
snprintf(k_and_m, 10, "%g-%d", k, m);
printf("Working on k of %g and m=0 TM with a=%d...\n", k, a);
fields f(&vac, m);
f.use_bloch(k);
f.verbose(1);
f.phase_in_material(&s, 1000);
f.initialize_with_n_tm(9);
while (f.is_phasing() && !interrupt) f.step();
f.prepare_for_bands(veccyl(4.801,0.0), ttot, .40, 300, 0.0);
f.prepare_for_bands(veccyl(3.801,0.0), ttot, .40, 300, 0.0);
f.prepare_for_bands(veccyl(3.301,0.0), ttot, .40, 300, 0.0);
const double stoptime = f.time() + ttot;
while (f.time() < stoptime && !interrupt) {
f.record_bands();
f.step();
}
f.grace_bands(&g, 40);
}
}
\end{comment}
\begin{figure}
\label{omniguidebands}
\caption{Omniguide band structure.}
\includegraphics[width=8.8cm,clip=true]{omniguide-out/bands}
\end{figure}
\begin{verbatim}
for (int m=0;m<2 && !interrupt;m++) {
g.new_set();
char m_string[30];
if (m) snprintf(m_string, 30, "m = %d", m);
else snprintf(m_string, 30, "m = 0, TE");
g.set_legend(m_string);
for (double k=0.0;k<0.351 && !interrupt;k+=0.05) {
\end{verbatim}
In order to populate the modes that we are interested in, we first populate
the modes of an empty waveguide (whose modes are known), and then
adiabatically transform from that waveguide into our omniguide structure.
\begin{verbatim}
printf("Working on k of %g and %s with a=%d...\n", k, m_string, a);
fields f(&vac, m);
f.use_bloch(k);
f.verbose(1);
f.phase_in_material(&s, 1000);
\end{verbatim}
We initialize the fields with both TE and TM modes, and then phase in the
epsilon as usual, and then do the actual phasing in of the structure.
\begin{verbatim}
f.initialize_with_n_te(9);
if (m) f.initialize_with_n_tm(9);
while (f.is_phasing() && !interrupt) f.step();
\end{verbatim}
Again, the band structure code is pretty normal, with the only real
difference being that in this case we \emph{really} want to have specify a
large $Q_{min}$, to help meep to distinguish between real modes and
spurious noise. Note that we are using metallic boundary conditions, so
all physical modes should have infinite lifetime.
\begin{verbatim}
f.prepare_for_bands(veccyl(4.801,0.0), ttot, .35, 300, 0.0);
f.prepare_for_bands(veccyl(1.801,0.0), ttot, .35, 300, 0.0);
f.prepare_for_bands(veccyl(2.801,0.0), ttot, .35, 300, 0.0);
const double stoptime = f.time() + ttot;
while (f.time() < stoptime && !interrupt) {
f.record_bands();
f.step();
}
\end{verbatim}
Finally, we just need to compute and output the bands. We are careful here
to keep in mind that when $m > 0$, there are twice as many bands, since
there are both TM and TE modes.
\begin{verbatim}
f.grace_bands(&g, m?80:40);
}
\end{verbatim}
The band is actually printed to disk only when the grace object is
destroyed, which in this case happens just before the program exits.
\begin{comment}
}
}
\end{comment}
|