diff --git a/doc/docs/Mode_Decomposition.md b/doc/docs/Mode_Decomposition.md
index d3bc3bc09..f72af92c5 100644
--- a/doc/docs/Mode_Decomposition.md
+++ b/doc/docs/Mode_Decomposition.md
@@ -1,6 +1,6 @@
# Mode Decomposition
-Meep contains a feature to decompose arbitrary fields into a superposition of the harmonic modes of a given structure via its integration with the eigenmode solver [MPB](https://mpb.readthedocs.io). This section provides an overview of the theory and implementation of this feature. For examples, see [Tutorial/Mode Decomposition](Python_Tutorials/Mode_Decomposition.md).
+Meep contains a feature to decompose arbitrary fields into a superposition of the harmonic modes of a given structure via its integration with the eigenmode solver [MPB](https://mpb.readthedocs.io). Only dielectric structures with lossless, wavelength-independent, anisotropic $\varepsilon$ are supported by MPB. If dispersive materials are defined in Meep, only the real part of $\varepsilon$ is used. This section provides an overview of the theory and implementation of this feature. For examples, see [Tutorial/Mode Decomposition](Python_Tutorials/Mode_Decomposition.md).
[TOC]
diff --git a/doc/docs/Python_User_Interface.md b/doc/docs/Python_User_Interface.md
index 1dcc0a927..8ceaf20cf 100644
--- a/doc/docs/Python_User_Interface.md
+++ b/doc/docs/Python_User_Interface.md
@@ -1344,7 +1344,8 @@ following fields:
+ `alpha`: the complex eigenmode coefficients as a 3d NumPy array of size
(`len(bands)`, `flux.nfreqs`, `2`). The last/third dimension refers to modes
- propagating in the forward (+) or backward (-) directions.
+ propagating in the forward (+) or backward (-) directions defined relative to
+ the mode's dominant wavevector.
+ `vgrp`: the group velocity as a NumPy array.
+ `kpoints`: a list of `mp.Vector3`s of the `kpoint` used in the mode calculation.
+ `kdom`: a list of `mp.Vector3`s of the mode's dominant wavevector.
@@ -1361,6 +1362,8 @@ Technically, MPB computes $\omega_n(\mathbf{k})$ and then inverts it with Newton
**Note:** for planewaves in homogeneous media, the `kpoints` may *not* necessarily be equivalent to the actual wavevector of the mode. This quantity is given by `kdom`.
+Note that Meep's MPB interface only supports dispersionless non-magnetic materials but it does support anisotropic $\\varepsilon$. Any nonlinearities, magnetic responses $\\mu$ conductivities $\\sigma$, or dispersive polarizations in your materials will be *ignored* when computing the mode decomposition. PML will also be ignored.
+
@@ -2062,7 +2065,9 @@ Given a `Vector3` point `x` which can lie anywhere outside the near-field surfac
including outside the cell and a `near2far` object, returns the computed
(Fourier-transformed) "far" fields at `x` as list of length 6`nfreq`, consisting
of fields $(E_x^1,E_y^1,E_z^1,H_x^1,H_y^1,H_z^1,E_x^2,E_y^2,E_z^2,H_x^2,H_y^2,H_z^2,...)$
-for the frequencies 1,2,…,`nfreq`.
+in Cartesian coordinates and
+$(E_r^1,E_\phi^1,E_z^1,H_r^1,H_\phi^1,H_z^1,E_r^2,E_\phi^2,E_z^2,H_r^2,H_\phi^2,H_z^2,...)$
+in cylindrical coordinates for the frequencies 1,2,…,`nfreq`.
@@ -2837,7 +2842,7 @@ def stop_when_dft_decayed(tol=1e-11,
Return a `condition` function, suitable for passing to `Simulation.run` as the `until`
-or `until_after_sources` parameter, that checks the `Simulation`'s dft objects every $t$
+or `until_after_sources` parameter, that checks the `Simulation`'s DFT objects every $t$
timesteps, and stops the simulation once all the field components and frequencies of *every*
DFT object have decayed by at least some tolerance `tol` (default is 1e-11). The time interval
$t$ is determined automatically based on the frequency content in the DFT monitors.
@@ -5984,8 +5989,8 @@ def __init__(self,
+ **`side` [`side` constant ]** — Specify which side, `Low` or `High` of the
boundary or boundaries to put PML on. e.g. if side is `Low` and direction is
- `X`, then a PML layer is added to the $-x$ boundary. Default is the special
- value `ALL`, which puts PML layers on both sides.
+ `meep.X`, then a PML layer is added to the $-x$ boundary. Default is the special
+ value `meep.ALL`, which puts PML layers on both sides.
+ **`R_asymptotic` [`number`]** — The asymptotic reflection in the limit of
infinite resolution or infinite PML thickness, for reflections from air (an
diff --git a/doc/docs/Python_User_Interface.md.in b/doc/docs/Python_User_Interface.md.in
index b39d2c7ce..1b323aa0d 100644
--- a/doc/docs/Python_User_Interface.md.in
+++ b/doc/docs/Python_User_Interface.md.in
@@ -181,6 +181,8 @@ Technically, MPB computes $\omega_n(\mathbf{k})$ and then inverts it with Newton
**Note:** for planewaves in homogeneous media, the `kpoints` may *not* necessarily be equivalent to the actual wavevector of the mode. This quantity is given by `kdom`.
+Note that Meep's MPB interface only supports dispersionless non-magnetic materials but it does support anisotropic $\\varepsilon$. Any nonlinearities, magnetic responses $\\mu$ conductivities $\\sigma$, or dispersive polarizations in your materials will be *ignored* when computing the mode decomposition. PML will also be ignored.
+
@@ Simulation.add_mode_monitor @@
`add_mode_monitor` works properly with arbitrary symmetries, but may be suboptimal because the Fourier-transformed region does not exploit the symmetry. As an optimization, if you have a mirror plane that bisects the mode monitor, you can instead use `add_flux` to gain a factor of two, but in that case you *must* also pass the corresponding `eig_parity` to `get_eigenmode_coefficients` in order to only compute eigenmodes with the corresponding mirror symmetry.
diff --git a/python/simulation.py b/python/simulation.py
index 4261b6430..99a5b8330 100644
--- a/python/simulation.py
+++ b/python/simulation.py
@@ -197,8 +197,8 @@ def __init__(self, thickness,
+ **`side` [`side` constant ]** — Specify which side, `Low` or `High` of the
boundary or boundaries to put PML on. e.g. if side is `Low` and direction is
- `X`, then a PML layer is added to the $-x$ boundary. Default is the special
- value `ALL`, which puts PML layers on both sides.
+ `meep.X`, then a PML layer is added to the $-x$ boundary. Default is the special
+ value `meep.ALL`, which puts PML layers on both sides.
+ **`R_asymptotic` [`number`]** — The asymptotic reflection in the limit of
infinite resolution or infinite PML thickness, for reflections from air (an
@@ -546,7 +546,7 @@ def __init__(self, where=None, center=None, size=None):
class DftObj(object):
- """Wrapper around dft objects that allows delayed initialization of the structure.
+ """Wrapper around DFT objects that allows delayed initialization of the structure.
When splitting the structure into chunks for parallel simulations, we want to know all
of the details of the simulation in order to ensure that each processor gets a similar
@@ -2754,7 +2754,9 @@ def get_farfield(self, near2far, x):
including outside the cell and a `near2far` object, returns the computed
(Fourier-transformed) "far" fields at `x` as list of length 6`nfreq`, consisting
of fields $(E_x^1,E_y^1,E_z^1,H_x^1,H_y^1,H_z^1,E_x^2,E_y^2,E_z^2,H_x^2,H_y^2,H_z^2,...)$
- for the frequencies 1,2,…,`nfreq`.
+ in Cartesian coordinates and
+ $(E_r^1,E_\phi^1,E_z^1,H_r^1,H_\phi^1,H_z^1,E_r^2,E_\phi^2,E_z^2,H_r^2,H_\phi^2,H_z^2,...)$
+ in cylindrical coordinates for the frequencies 1,2,…,`nfreq`.
"""
return mp._get_farfield(near2far.swigobj, py_v3_to_vec(self.dimensions, x, is_cylindrical=self.is_cylindrical))
@@ -3549,7 +3551,8 @@ def get_eigenmode_coefficients(self, flux, bands, eig_parity=mp.NO_PARITY, eig_v
+ `alpha`: the complex eigenmode coefficients as a 3d NumPy array of size
(`len(bands)`, `flux.nfreqs`, `2`). The last/third dimension refers to modes
- propagating in the forward (+) or backward (-) directions.
+ propagating in the forward (+) or backward (-) directions defined relative to
+ the mode's dominant wavevector.
+ `vgrp`: the group velocity as a NumPy array.
+ `kpoints`: a list of `mp.Vector3`s of the `kpoint` used in the mode calculation.
+ `kdom`: a list of `mp.Vector3`s of the mode's dominant wavevector.
@@ -4523,7 +4526,7 @@ def _stop(sim):
def stop_when_dft_decayed(tol=1e-11, minimum_run_time=0, maximum_run_time=None):
"""
Return a `condition` function, suitable for passing to `Simulation.run` as the `until`
- or `until_after_sources` parameter, that checks the `Simulation`'s dft objects every $t$
+ or `until_after_sources` parameter, that checks the `Simulation`'s DFT objects every $t$
timesteps, and stops the simulation once all the field components and frequencies of *every*
DFT object have decayed by at least some tolerance `tol` (default is 1e-11). The time interval
$t$ is determined automatically based on the frequency content in the DFT monitors.