Skip to content

Commit

Permalink
Jupyter notebooks for basics and binary-grating tutorial examples (Na…
Browse files Browse the repository at this point in the history
…noComp#786)

* Jupyter notebooks for Basics and binary grating tutorial examples

* more details on nperiods

* nbviewer links

* nbviewer links
  • Loading branch information
oskooi authored and stevengj committed Mar 27, 2019
1 parent bbe2236 commit e9bb444
Show file tree
Hide file tree
Showing 14 changed files with 2,932 additions and 18 deletions.
2 changes: 1 addition & 1 deletion doc/docs/FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ Note: specifying a complex `amplitude` for the `Source` object does not automati

### How do I model incoherent spontaneous/thermal emission

Semiclassically, spontaneous or thermal emission can be modeled simply as random dipole current sources. One direct way to express this in FDTD is to perform a [Monte Carlo method](https://en.wikipedia.org/wiki/Monte_Carlo_method) by taking an ensemble average of multiple runs involving a collection of random dipole sources. For example, using a custom source function to input white-noise sources, with the appropriate noise spectrum included via postprocessing (assuming linear materials; see e.g. our papers on modeling thermal radiation in the [far field](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.93.213905) or [near field](http://doi.org/10.1103/PhysRevLett.107.114302)). (There is also a "noisy Lorentzian" material that can be used to model thermal fluctuations even more directly as noise in the materials themselves.) As another example, incoherent emission from [excitons](https://en.wikipedia.org/wiki/Exciton) can be modeled with point dipole sources of random phase (set via the `amplitude` property of the [`Source`](Python_User_Interface.md#source)) as described in [Applied Physics Letters, 106, 041111, 2015](https://aip.scitation.org/doi/abs/10.1063/1.4907253) ([pdf](http://ab-initio.mit.edu/~oskooi/papers/Oskooi15_oled.pdf)) and the associated [simulation script](http://www.simpetus.com/projects.html#meep_oled). There are also [alternative methods to model spontaneous emission](http://doi.org/10.1103/PhysRevB.92.134202) that obtain the averaged power flux directly without the cost of multiple Monte-Carlo simulations, at the expense of greater complexity.
Semiclassically, [spontaneous](https://en.wikipedia.org/wiki/Spontaneous_emission) or [thermal](https://en.wikipedia.org/wiki/Thermal_radiation) emission can be modeled simply as random dipole current sources. One direct way to express this in Meep is to use a [Monte Carlo method](https://en.wikipedia.org/wiki/Monte_Carlo_method): take an ensemble average of multiple runs involving a collection of random dipole sources. For example, to model thermal radiation in linear materials, you can use a custom source function to input white-noise sources with the appropriate noise spectrum included via postprocessing; e.g. in the [far field](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.93.213905) or [near field](http://doi.org/10.1103/PhysRevLett.107.114302). There is also a [noisy Lorentzian material](Python_User_Interface.md#noisylorentziansusceptibility-or-noisydrudesusceptibility) that can be used to model thermal fluctuations even more directly as noise in the materials themselves. As another example, incoherent emission from [excitons](https://en.wikipedia.org/wiki/Exciton) can be modeled with point dipole sources of random phase (set via the `amplitude` property of the [`Source`](Python_User_Interface.md#source)) as described in [Applied Physics Letters, 106, 041111, 2015](https://aip.scitation.org/doi/abs/10.1063/1.4907253) ([pdf](http://ab-initio.mit.edu/~oskooi/papers/Oskooi15_oled.pdf)) with associated [simulation script](http://www.simpetus.com/projects.html#meep_oled).

Usage: Sources
--------------
Expand Down
12 changes: 6 additions & 6 deletions doc/docs/Python_Tutorials/Basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ For our first example, let's examine the field pattern excited by a localized [C

### A Straight Waveguide

The simulation script is in [examples/straight-waveguide.py](https://github.com/NanoComp/meep/blob/master/python/examples/straight-waveguide.py).
The simulation script is in [examples/straight-waveguide.py](https://github.com/NanoComp/meep/blob/master/python/examples/straight-waveguide.py). The notebook is [examples/straight-waveguide.ipynb](https://nbviewer.jupyter.org/github/NanoComp/meep/blob/master/python/examples/straight-waveguide.ipynb)

The first thing to do always is to load the Meep library:

Expand Down Expand Up @@ -127,7 +127,7 @@ We see that the the source has excited the waveguide mode but has also excited r

### A 90° Bend

We'll start a new simulation where we look at the fields propagating through a waveguide bend, and we'll do a couple of other things differently as well. The simulation script is in [examples/bent-waveguide.py](https://github.com/NanoComp/meep/blob/master/python/examples/bent-waveguide.py). As usual, the first thing to do is to load the Meep library:
We'll start a new simulation where we look at the fields propagating through a waveguide bend, and we'll do a couple of other things differently as well. The simulation script is in [examples/bent-waveguide.py](https://github.com/NanoComp/meep/blob/master/python/examples/bent-waveguide.py); the notebook is [examples/bent-waveguide.ipynb](https://nbviewer.jupyter.org/github/NanoComp/meep/blob/master/python/examples/bent-waveguide.ipynb). As usual, the first thing to do is to load the Meep library:

```py
import meep as mp
Expand Down Expand Up @@ -260,7 +260,7 @@ We have computed the field patterns for light propagating around a waveguide ben

The basic principles are described in [Introduction](../Introduction.md#transmittancereflectance-spectra). The computation involves keeping track of the fields and their Fourier transform in a certain region, and from this computing the flux of electromagnetic energy as a function of ω. Moreover, we'll get an entire spectrum of the transmittance in a single run, by Fourier-transforming the response to a short pulse. However, in order to normalize the transmitted flux by the incident power to obtain the transmittance, we'll have to do *two* runs, one with and one without the bend (i.e., a straight waveguide).

The simulation script is in [examples/bend-flux.py](https://github.com/NanoComp/meep/blob/master/python/examples/bend-flux.py).
The simulation script is in [examples/bend-flux.py](https://github.com/NanoComp/meep/blob/master/python/examples/bend-flux.py). The notebook is [examples/bend-flux.ipynb](https://github.com/NanoComp/meep/blob/master/python/examples/bend-flux.ipynb)

```py
import meep as mp
Expand Down Expand Up @@ -435,7 +435,7 @@ Creating an oblique planewave source typically requires specifying two parameter

In this example, the plane of incidence which contains $\vec{k}$ and the surface normal vector is $xz$. The source angle θ is defined in degrees in the counterclockwise (CCW) direction around the $y$ axis with 0 degrees along the +$z$ axis. In Meep, a 1d cell is defined along the $z$ direction. When $\vec{k}$ is not set, only the E<sub>x</sub> and H<sub>y</sub> field components are permitted. A non-zero $\vec{k}$ results in a 3d simulation where all field components are allowed and are complex (the fields are real, by default). A current source with E<sub>x</sub> polarization lies in the plane of incidence and corresponds to the convention of $\mathcal{P}$-polarization. In order to model the $\mathcal{S}$-polarization, we must use an E<sub>y</sub> source. This example involves just the $\mathcal{P}$-polarization.

The simulation script is [examples/refl-angular.py](https://github.com/NanoComp/meep/blob/master/python/examples/refl-angular.py)
The simulation script is [examples/refl-angular.py](https://github.com/NanoComp/meep/blob/master/python/examples/refl-angular.py). The notebook is [examples/refl-angular.ipynb](https://nbviewer.jupyter.org/github/NanoComp/meep/blob/master/python/examples/refl-angular.ipynb)

```py
import meep as mp
Expand Down Expand Up @@ -618,7 +618,7 @@ plt.show()
Modes of a Ring Resonator
-------------------------

As described in [Introduction](../Introduction.md#resonant-modes), another common task for FDTD simulation is to find the resonant modes &mdash; frequencies and decay rates &mdash; of some cavity structure. You might want to read that again to recall the basic simulation strategy. We will show how this works for a ring resonator, which is simply a waveguide bent into a circle. This script can be also found in [examples/ring.py](https://github.com/NanoComp/meep/blob/master/python/examples/ring.py). In fact, since this structure has cylindrical symmetry, we can simulate it much more efficiently by using cylindrical coordinates, but for illustration here we'll just use an ordinary 2d simulation.
As described in [Introduction](../Introduction.md#resonant-modes), another common task for FDTD simulation is to find the resonant modes &mdash; frequencies and decay rates &mdash; of some cavity structure. You might want to read that again to recall the basic simulation strategy. We will show how this works for a ring resonator, which is simply a waveguide bent into a circle. This script can be also found in [examples/ring.py](https://github.com/NanoComp/meep/blob/master/python/examples/ring.py); the notebook is [examples/ring.ipynb](https://nbviewer.jupyter.org/github/NanoComp/meep/blob/master/python/examples/ring.ipynb). In fact, since this structure has cylindrical symmetry, we can simulate it much more efficiently by using cylindrical coordinates, but for illustration here we'll just use an ordinary 2d simulation.

As before, we'll define some parameters to describe the geometry, so that we can easily change the structure:

Expand Down Expand Up @@ -779,4 +779,4 @@ mlab.show()
![](../images/prism_epsilon.png)
</center>

Alternatively, the permittivity can be visualized from outside of Python. This involves writing the permittivity data to an HDF5 file using [output_epsilon](../Python_User_Interface.md#output-functions). The HDF5 data is then converted to [VTK](https://en.wikipedia.org/wiki/VTK) via [h5tovtk](https://github.com/NanoComp/h5utils/blob/master/doc/h5tovtk-man.md) of the [h5utils](https://github.com/NanoComp/h5utils) package. VTK data can be visualized using Mayavi or Paraview.
Alternatively, the permittivity can be visualized from outside of Python. This involves writing the permittivity data to an HDF5 file using [output_epsilon](../Python_User_Interface.md#output-functions). The HDF5 data is then converted to [VTK](https://en.wikipedia.org/wiki/VTK) via [h5tovtk](https://github.com/NanoComp/h5utils/blob/master/doc/h5tovtk-man.md) of the [h5utils](https://github.com/NanoComp/h5utils) package. VTK data can be visualized using Mayavi or Paraview.
6 changes: 3 additions & 3 deletions doc/docs/Python_Tutorials/Frequency_Domain_Solver.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ ez_dat = np.zeros((122,122,num_tols), dtype=np.complex_)
for i in range(num_tols):
sim.init_sim()
sim.solve_cw(tols[i], 10000, 10)
ez_dat[:,:,i] = sim.get_array(vol, component=mp.Ez)
ez_dat[:,:,i] = sim.get_array(vol=vol, component=mp.Ez)

err_dat = np.zeros(num_tols-1)
for i in range(num_tols-1):
Expand All @@ -63,7 +63,7 @@ plt.xlabel("frequency-domain solver tolerance");
plt.ylabel("L2 norm of error in fields");
plt.show()

eps_data = sim.get_array(vol, component=mp.Dielectric)
eps_data = sim.get_array(vol=vol, component=mp.Dielectric)
ez_data = np.absolute(ez_dat[:,:,num_tols-1])

plt.figure()
Expand Down Expand Up @@ -104,7 +104,7 @@ dfts = sim.add_dft_fields([mp.Ez], fcen, fcen, 1, where=vol)

sim.run(until_after_sources=100)

eps_data = sim.get_array(vol, component=mp.Dielectric)
eps_data = sim.get_array(vol=vol, component=mp.Dielectric)
ez_data = np.absolute(sim.get_dft_array(dfts, mp.Ez, 0))

plt.figure()
Expand Down
6 changes: 3 additions & 3 deletions doc/docs/Python_Tutorials/Mode_Decomposition.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ The mode-decomposition feature can also be applied to planewaves in homogeneous

A pulsed planewave with E<sub>z</sub> polarization spanning wavelengths of 0.4 to 0.6 μm is normally incident on the grating from the glass substrate. The eigenmode monitor is placed in the air region. We will use mode decomposition to compute the transmittance &mdash; the ratio of the power in the $+x$ direction of the diffracted mode relative to that of the incident planewave &mdash; for the first ten diffraction orders. Two simulations are required: (1) an *empty* cell of homogeneous glass to obtain the incident power of the source, and (2) the grating structure to obtain the diffraction orders. At the end of the simulation, the wavelength, angle, and transmittance for each diffraction order are computed.

The simulation script is in [examples/binary_grating.py](https://github.com/NanoComp/meep/blob/master/python/examples/binary_grating.py).
The simulation script is in [examples/binary_grating.py](https://github.com/NanoComp/meep/blob/master/python/examples/binary_grating.py). The notebook is [examples/binary_grating.ipynb](https://nbviewer.jupyter.org/github/NanoComp/meep/blob/master/python/examples/binary_grating.ipynb)

<center>
![](../images/grating.png)
Expand Down Expand Up @@ -292,7 +292,7 @@ The following script is adapted from the previous binary-grating example involvi

Results are computed for a single wavelength of 0.5 μm. The pulsed planewave is incident at an angle of 10.7°. Its spatial profile is defined using the source amplitude function `pw_amp`. This [anonymous function](https://en.wikipedia.org/wiki/Anonymous_function) takes two arguments, the wavevector and a point in space (both `mp.Vector3`s), and returns a function of one argument which defines the planewave amplitude at that point. A narrow bandwidth pulse is used in order to mitigate the intrinsic discretization effects of the [Yee grid](../Yee_Lattice.md) for oblique planewaves. Also, the `stop_when_fields_decayed` termination criteria is replaced with `until_after_sources`. As a general rule of thumb, the more oblique the planewave source, the longer the run time required to ensure accurate results. There is an additional line monitor between the source and the grating for computing the reflectance. The angle of each reflected/transmitted mode, which can be positive or negative, is computed using its dominant planewave vector. Since the oblique source breaks the symmetry in the $y$ direction, each diffracted order must be computed separately. In total, there are 59 reflected and 39 transmitted orders.

The simulation script is in [examples/binary_grating_oblique.py](https://github.com/NanoComp/meep/blob/master/python/examples/binary_grating_oblique.py).
The simulation script is in [examples/binary_grating_oblique.py](https://github.com/NanoComp/meep/blob/master/python/examples/binary_grating_oblique.py). The notebook is [examples/binary_grating_oblique.ipynb](https://nbviewer.jupyter.org/github/NanoComp/meep/blob/master/python/examples/binary_grating_oblique.ipynb)

```py
import meep as mp
Expand Down Expand Up @@ -484,7 +484,7 @@ Phase Map of a Subwavelength Binary Grating

We can also use the complex mode coefficients to compute the phase (or impedance) of the diffraction orders. This can be used to generate a phase map of the binary grating as a function of its geometric parameters. Phase maps are important for the design of subwavelength phase shifters such as those used in a metasurface lens. When the period of the unit cell is subwavelength, the zeroth-diffraction order is the only propagating wave. In this demonstration, which is adapted from the previous example, we compute the transmittance spectra and phase map of the zeroth-diffraction order (at 0°) for an E<sub>z</sub>-polarized planewave pulse spanning wavelengths of 0.4 to 0.6 μm which is normally incident on a binary grating with a periodicity of 0.35 μm and height of 0.6 μm. The duty cycle of the grating is varied from 0.1 to 0.9 in separate runs.

The simulation script is in [examples/binary_grating_phasemap.py](https://github.com/NanoComp/meep/blob/master/python/examples/binary_grating_phasemap.py).
The simulation script is in [examples/binary_grating_phasemap.py](https://github.com/NanoComp/meep/blob/master/python/examples/binary_grating_phasemap.py). The notebook is [examples/binary_grating_phasemap.ipynb](https://nbviewer.jupyter.org/github/NanoComp/meep/blob/master/python/examples/binary_grating_phasemap.ipynb).

```py
import meep as mp
Expand Down
Loading

0 comments on commit e9bb444

Please sign in to comment.