## File: omniguide.tex

package info (click to toggle)
meep 0.10-2.1
 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 \begin{comment} #include #include #include 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}