Skip to content

Commit

Permalink
condense mode-decomposition theory docs and fix a couple of inconsist…
Browse files Browse the repository at this point in the history
…encies (NanoComp#1382)

* condense mode-decomposition theory docs and fix a couple of inconsistencies

* some fixes

* typo

* clarification

Co-authored-by: Ardavan Oskooi <ardavan.oskooi@gmail.com>
  • Loading branch information
stevengj and oskooi authored Oct 2, 2020
1 parent 5b105c0 commit 54d2b4a
Showing 1 changed file with 53 additions and 55 deletions.
108 changes: 53 additions & 55 deletions doc/docs/Mode_Decomposition.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,28 @@ Meep contains a feature to decompose arbitrary fields into a superposition of th

The theory underlying mode decomposition is described in Chapter 31 ("Modal methods for Maxwell's equations") of [Optical Waveguide Theory](http://www.springer.com/us/book/9780412099502) by Snyder and Love.

Consider a waveguide with propagation axis along the $x$ direction and constant cross section in the transverse direction $\vec\rho=(y,z)$. For a given angular frequency $\omega$ we can solve for the eigenmodes of the structure. Thus, arbitrary fields of the form $\mathbf{E}(\mathbf{r},t) = \mathbf{E}(\mathbf{r}) e^{-i\omega t}$ and $\mathbf{H}(\mathbf{r},t) = \mathbf{H}(\mathbf{r}) e^{-i\omega t}$ can be decomposed into a basis of these eigenmodes:
Consider a waveguide with propagation axis along the $x$ direction and constant cross section in the transverse directions $(y,z)$. Let $\psi = (E_y,E_z,H_y,H_z)$ denote the tranverse components of the electric and magnetic fields. For a given angular frequency ω we can solve for the eigenmodes of the structure: solutions of the form $\psi^\pm_n(y,z) e^{\pm i \beta_n x - i\omega t}$, where $\beta_n$ are the propagation constants of the right ($+$) and left ($-$) traveling modes. (There are also evanescent modes with complex $\beta_n$ values, but we will focus mainly here on the propagating modes with real $\beta_n$.)

Any *arbitrary* fields $\psi$, Fourier-transformed to a particular ω, can be expressed in the basis of these eigenmodes:

$$
\mathbf{E}(\mathbf{r}) =
\mathbf{E}(x,\vec{\rho}) =
\sum_{n} \left\{ \alpha^+_n \mathbf E^+_n(\vec \rho)e^{+i\beta_n x}
+ \alpha^-_n \mathbf E^-_n(\vec \rho)e^{-i\beta_n x}
\right\}
$$
$$
\mathbf{H}(\mathbf{r}) =
\mathbf{H}(x,\vec{\rho}) =
\sum_{n} \left\{ \alpha^+_n \mathbf H^+_n(\vec \rho)e^{+i\beta_n x}
+ \alpha^-_n \mathbf H^-_n(\vec \rho)e^{-i\beta_n x}
\psi(x,y,z) = \begin{pmatrix} E_y \\ E_z \\ H_y \\ H_z \end{pmatrix} =
\sum_{n} \left\{ \alpha^+_n \mathbf \psi^+_n(\vec \rho)e^{+i\beta_n x}
+ \alpha^-_n \mathbf \psi^-_n(\vec \rho)e^{-i\beta_n x}
\right\}
$$

$\beta_n$ are the propagation wavevectors and $\alpha^{\pm}_n$ are the basis coefficients. Mode decomposition involves solving for these unknown quantities. The following steps are involved in the computation:
$\alpha^{\pm}_n$ are the expansion coefficients (the amplitudes of each mode present in the fields). Mode decomposition involves solving for these amplitudes. The following steps are involved in the computation:

1. In Meep, compute the Fourier-transformed fields $\mathbf{E}(\mathbf{r})$ and $\mathbf{H}(\mathbf{r})$ on a surface which is transverse to the waveguide and stored in a `dft_flux` object.
1. In Meep, compute the Fourier-transformed transverse fields $\psi$ on a surface that is transverse to the waveguide, stored in a `dft_flux` object.

2. In MPB, compute the eigenmodes $\mathbf{E}^\pm_n$ and $\mathbf{H}^\pm_n$ as well as the propagation wavevectors $\beta_n$ for the same cross-sectional structure.
2. In MPB, compute the eigenmodes $\psi^\pm_n$ as well as the propagation constants $\beta_n$ for the same cross-sectional structure.

3. Compute the coefficients $\alpha_n^\pm$ for any number of eigenmodes $n=1,2,...$
3. Compute the coefficients $\alpha_n^\pm$ for any number of eigenmodes n=1,2,....

This is all done automatically in Meep using the `get_eigenmode_coefficients` routine.
Meep normalizes the modes $\psi^\pm_n$ to unit power $\Re \int \mathbf{E}^*\times\mathbf{H} = 1$, so that $|\alpha^{\pm}_n|^2$ is equal to the **power**
(Poynting flux) carried by that mode in the Fourier-transformed field $\psi$.

## Function Description

Expand Down Expand Up @@ -70,7 +66,7 @@ The following are the parameters:
+ `eigensolver_tol` is the tolerance to use in the MPB eigensolver. MPB terminates when the eigenvalues stop changing by less than this fractional tolerance.
+ `coeffs` is a user-allocated array of type `std::complex<double>` (shortened hereafter to `cdouble`) of length `2*num_freqs*num_bands` where `num_freqs` is the number of frequencies stored in the `flux` object (equivalent to `flux->Nfreq`) and `num_bands` is the length of the `bands` input array. The expansion coefficients for the mode with frequency `nf` and band index `nb` are stored sequentially as $\alpha^+$, $\alpha^-$ starting at slot `2*nb*num_freqs+nf` of this array.
+ `coeffs` is a user-allocated array of type `std::complex<double>` (shortened hereafter to `cdouble`) of length `2*num_freqs*num_bands` where `num_freqs` is the number of frequencies stored in the `flux` object (equivalent to `flux->Nfreq`) and `num_bands` is the length of the `bands` input array. The expansion coefficients for the mode with frequency `nf` and band index `nb` are stored sequentially as $\alpha^+$, $\alpha^-$ starting at slot `2*nb*num_freqs+nf` of this array
+ `vgrp` is an optional user-allocated `double` array of length `num_freqs*num_bands`. On return, `vgrp[nb*num_freqs + nf]` is the group velocity of the mode with frequency `nf` and band index `nb.` If you do not need this information, simply pass `NULL` for this parameter.
Expand All @@ -95,7 +91,7 @@ vec (*kpoint_func)(double freq, int mode, void *user_data);

for(int nb=0; nb<num_bands; nb++)
for(int nf=0; nf<num_freqs++; nf++)
{
{
// get coefficients of forward- and backward-traveling
// waves in eigenmode bands[nb] at frequency #nf
cdouble AlphaPlus = coeffs[2*nb*num_freqs+nf+0];
Expand Down Expand Up @@ -139,7 +135,7 @@ The return value of `get_eigenmode` is an [opaque pointer](https://en.wikipedia.
// get a single component of the eigenmode field at a given point in space
std::complex<double> eigenmode_amplitude(const vec &p, void *vedata, component c);
// get the group velocity of the eigenmode
// get the group velocity of the eigenmode
double get_group_velocity(void *vedata);
// free all memory associated with the eigenmode
Expand All @@ -161,9 +157,9 @@ This function is implemented in [src/dft.cpp](https://github.com/NanoComp/meep/b
### Computing Overlap Integrals
````
std::complex<double> get_mode_flux_overlap(void *mode_data,
dft_flux *flux,
int num_freq,
std::complex<double> get_mode_flux_overlap(void *mode_data,
dft_flux *flux,
int num_freq,
std::complex<double>overlap[2]);
std::complex<double> get_mode_mode_overlap(void *mode1_data,
Expand All @@ -180,61 +176,63 @@ These functions are implemented in [src/dft.cpp](https://github.com/NanoComp/mee
## How Mode Decomposition Works
The theoretical basis of the mode-decomposition algorithm is the orthogonality relation satisfied by the normal modes:
The theoretical basis of the mode-decomposition algorithm is an orthogonality relation satisfied by the eigenmodes:
$$ \left\langle \mathbf{E}_m^{\sigma} \right|
\left. \mathbf{H}^\tau_n \right\rangle
=C_{m}\delta_{mn}\delta_{\sigma\tau}
$$
\left\langle \psi_m^{\sigma}, \psi_n^{\tau} \right\rangle
=C_{m}\delta_{mn}\delta_{\sigma\tau}
\qquad \{\sigma,\tau\}\in\{+,-\}
$$
where the inner product involves an integration over transverse coordinates:
where the (indefinite) inner product between two fields $\psi=(E_y,E_z,H_y,H_z)$ and $\psi'=(E_y',E_z',H_y',H_z')$ involves an integration over transverse coordinates:
$$ \left\langle \mathbf{f} \right| \left. \mathbf{g} \right\rangle
$$ \left\langle \psi , \psi' \right\rangle
\equiv
\int_{S}
\Big[ \mathbf{f}^*(\vec \rho) \times \mathbf{g}(\vec \rho)\Big]
\Big[ \mathbf{E}^*(\vec \rho) \times \mathbf{H}'(\vec \rho) + \mathbf{E}'(\vec \rho) \times \mathbf{H}^*(\vec \rho)\Big]
\cdot \hat{\mathbf{n}} \, dA
\tag{5}
$$
where $S$ is any surface transverse to the direction of propagation and $\hat{\mathbf{n}}$ is the unit normal vector to $S$ (i.e. $\hat{\mathbf{z}}$ in the case considered above). The normalization constant $C_{m}$ is a matter of convention, but in MPB it is taken to be the group velocity of the mode, $v_m$, times the area $A_S$ of the cross-sectional surface $S$: $$C_m = v_m A_S$$.
Now consider a Meep calculation in which we have accumulated frequency-domain fields $\mathbf E^{\text{meep}}$ and $\mathbf H^{\text{meep}}$ on a `dft_flux` object located on a cross-sectional surface $S$. Invoking the eigenmode expansion and choosing the origin of the $x$ axis to be the position of the cross-sectional plane, the tangential components of the frequency-domain Meep fields take the form:
$$ \mathbf E^{\text{meep}}_\parallel = \sum_{n} (a_n^+ + a_n^-)\mathbf{E}_{n\parallel}^+ $$
where $S$ is a cross-section transverse to the direction of propagation and $\hat{\mathbf{n}}$ is the unit normal vector to $S$ (i.e. $\hat{\mathbf{z}}$ in the case considered above). The normalization constant $C_{m}$ is a matter of convention, but for MPB-computed modes (which normalizes proportional to unit energy) it is effectively the group velocity of the mode, $v_m$, times the area $A_S$ of the cross-sectional surface $S$: $$C_m = 2 v_m A_S$$ However, we can divide the MPB modes by $\sqrt{\int_S \Re[\mathbf{E}^* \times \mathbf{H}]\cdot \hat{\mathbf{n}}}$ to renormalize them to $C_m = 2$, which is equivalent to normalizing the MPB modes to unit power.
$$ \mathbf H^{\text{meep}}_\parallel = \sum_{n} (a_n^+ - a_n^-)\mathbf{H}_{n\parallel}^+ $$
(There is some subtlety about the use of complex conjugation for orthogonality in the inner product above that arises for evanescent modes, which we don't consider here because Meep only computes coefficients of propagating modes. The above definition has the nice property that $\langle \psi, \psi \rangle = 2 \int_S \Re[\mathbf{E}^* \times \mathbf{H}]\cdot \hat{\mathbf{n}} = 2P$ where $P$ is the Poynting flux.)
We have used the well-known relations between the tangential components of the forward- and backward-traveling field modes:
Now consider a Meep calculation in which we have accumulated tranverse frequency-domain fields $\psi^{\text{meep}} = (\mathbf E^{\text{meep}}_\parallel, \mathbf H^{\text{meep}}_\parallel)$ on a `dft_flux` object located on a cross-sectional surface $S$. Invoking the eigenmode expansion and choosing the origin of the $x$ axis to be the position of the cross-sectional plane means that
Meep fields take the form:
$$ \mathbf{E}^+_{n\parallel} =+\mathbf{E}^-_{n\parallel}
\qquad
\mathbf{H}^+_{n\parallel} =-\mathbf{H}^-_{n\parallel}
$$
\psi^{\text{meep}} =
\sum_{n} \left\{ \alpha^+_n \mathbf \psi^+_n(\vec \rho)e^{+i\beta_n x}
+ \alpha^-_n \mathbf \psi^-_n(\vec \rho)e^{-i\beta_n x}
\right\}
$$
Taking the inner product of both equations with the $\mathbf{H}$ and $\mathbf{E}$ fields of each eigenmode, we find
$$ \left\langle \mathbf{H}_m \right|\left. \mathbf{E}^{\text{meep}} \right\rangle =+(a_m^+ + a_m^-) v_m A_S $$
Taking the inner product of this equation with the $\psi_m^\pm$ modes computed
from MPB (renormalized to unit power), we obtain the mode coefficients:
$$ \left\langle \mathbf{E}_m \right|\left. \mathbf{H}^{\text{meep}} \right\rangle =-(a_m^+ - a_m^+) v_m A_S $$
$$
\alpha^\pm_n = \left\langle \psi_m^\pm, \psi^{\text{meep}} \right\rangle \, .
$$
Thus, by evaluating the integrals on the left-hand side of these equations &mdash; numerically, using the MPB-computed eigenmode fields $\{\mathbf{E}_m, \mathbf{H}_m\}$ and the Meep-computed fields $\{\mathbf{E}^{\text{meep}}, \mathbf{H}^{\text{meep}}\}$ as tabulated on the computational grid &mdash; and combining the results appropriately, we can extract the coefficients $\alpha^\pm_m$. This calculation is carried out by the routine `fields::get_mode_flux_overlap`. Although simple in principle, the implementation is complicated by the fact that, in multi-processor calculations, the Meep fields needed to evaluate the integrals are generally not all present on any one processor, but are instead distributed over multiple processors, requiring some interprocess communication to evaluate the full integral.
Some simplifications arise from the fact that, in a constant cross-section waveguide, the tangential components of the forward- and backward-traveling propagating modes are related by a mirror reflection in $x$:
$\mathbf{E}^+_{n\parallel} =+\mathbf{E}^-_{n\parallel}$
and $\mathbf{H}^+_{n\parallel} =-\mathbf{H}^-_{n\parallel}$. This means that we only need to compute the MPB modes once for the forward (+) direction. Also, the $\langle \psi_m^\pm, \psi^{\text{meep}} \rangle$ inner
product involves four integrals (of terms like $E_y H_z$ etc.) that are computed
once each and then combined with the correct signs to obtain $\alpha^\pm_n$.
These integrals are computed numerically by a trapezoidal-type rule on Meep's
Yee grid, interpolating the MPB-computed eigenmode fields as needed. This calculation is carried out by the routine `fields::get_mode_flux_overlap`. Although simple in principle, the implementation is complicated by the fact that, in multi-processor calculations, the Meep fields needed to evaluate the integrals are generally not all present on any one processor, but are instead distributed over multiple processors, requiring some interprocess communication to evaluate the full integral.
The Poynting flux carried by the Meep fields may be expressed in the form:
As mentioned above, the Poynting flux $P$ carried by the Meep fields may be expressed in the form:
$$ S_x = \frac{1}{2}\text{Re }
\left\langle \mathbf{E}^{\text{meep}}\right|
\left. \mathbf{H}^{\text{meep}}\right\rangle
= \frac{1}{2}\sum_n \left\{ |a_n^+|^2 - |a_n^-|^2) \right\} v_n A_S
$$
P = \frac{1}{2} \langle \psi, \psi \rangle = \sum_n \left( |a_n^+|^2 - |a_n^-|^2) \right)
$$
where the right-hand-side is obtained by substituting the modal expansion and
using the mode orthogonality and the normalization $C_n = 2$ chosen above.
Thus, the power carried by a given forward- or backward-traveling eigenmode is given by:
$$ \textit{power} = \frac{|a_n^\pm|^2 v_n A_S}{2S_x} $$
or alternatively,
$$ \textit{power} = |\tilde{\alpha_n^\pm}|^2 $$
$$ |\textit{power}_n^\pm| = |\alpha_n^\pm|^2 $$
where $\tilde{\alpha_n^\pm} \equiv \sqrt{v_n A_S/\left({2S_x}\right)}a_n^\pm$. The $\tilde{\alpha_n^\pm}$ are the eigenmode coefficients returned by `get_eigenmode_coefficients`.
The $\alpha_n^\pm$ are the eigenmode coefficients returned by `get_eigenmode_coefficients`.

0 comments on commit 54d2b4a

Please sign in to comment.