File: omniguide.tex

package info (click to toggle)
meep 0.10-2.1
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 4,380 kB
  • ctags: 5,469
  • sloc: cpp: 50,653; sh: 8,380; haskell: 744; makefile: 367; perl: 10
file content (149 lines) | stat: -rw-r--r-- 5,059 bytes parent folder | download
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}