In this lecture, we show how to apply FDTD to solve a slightly more complicated EM problem involving a photonic crystal slab that supports guided resonance.
- Explain the importance of setting up sufficient runtime in computing transmission spectrum, so that the field of the long-lived mode can decay to a negligible value.
- Show the long decay tail of the mode in the time domain, the transmission spectrum that exhibits Fano-resonant lineshape.
In this tutorial, we show how to apply FDTD to solve a slightly more complicated EM problem involving a photonic crystal slab that supports guided resonance. In particular, we reproduce the findings of Shanhui et al. (2003), which is linked here.
For more details, refer to the Tidy3d documentation.
# standard python imports
import numpy as np
import matplotlib.pyplot as plt
import tidy3d as td
from tidy3d import web
Next, let us define some key parameters.
runtime = 100.0 # in unit of 1/frequency bandwidth of the source
dPML = 1.0 # space between PhC slabs and PML, in unit of longest wavelength of interest
Let us define some basic parameters.
# Wavelength and frequency range
freq_range = (75e12, 135e12)
lambda_range = (td.constants.C_0/freq_range[1], td.constants.C_0/freq_range[0])
freq0 = np.sum(freq_range)/2
# central frequency, frequency pulse width
lambda0 = td.C_0 / freq0
width = 0.3
freqw = width * (freq_range[1] - freq_range[0])
# runtime
t_stop = runtime/freqw
print(f"Total runtime <= {t_stop*1e12} ps")
# frequencies and wavelengths of monitor
Nfreq = 1001
monitor_freqs = np.linspace(freq_range[0], freq_range[1], Nfreq)
monitor_lambdas = td.constants.C_0 / monitor_freqs
# PhC slab
period = 1.0 # um, period along x- and y- direction
t_slab = 0.55 # um, thickness
ep_slab = 12 # permittivity
mat_slab = td.Medium(permittivity=ep_slab, name='silicon')
# PhC air hole
radius = 0.2 # um, radius
ep_hole = 1 #permittivity
mat_hole = td.Medium(permittivity=ep_hole, name='air')
# Grid size # um
dl = lambda_range[0] / 30 / np.sqrt(ep_slab) # 30 grids per smallest wavelength in medium
print(f"dl = {dl*1000} nm")
# space between PhC slabs and PML
spacing = dPML * lambda_range[-1]
# simulation size
sim_size = Lx, Ly, Lz = (period, period, 2*spacing + t_slab)
Total runtime <= 5.555555555555555 ps dl = 21.368550163866615 nm
Now we set everything else up (structures, sources, monitors, simulation) to run the example.
First, we define the unit cell of PhC, made of a high-index slab and an air hole.
slab = td.Structure(
geometry=td.Box(
center=(0, 0, 0),
size=(td.inf,td.inf,t_slab),
),
medium=mat_slab,
name='slab',
)
hole = td.Structure(
geometry=td.Cylinder(
center=(0, 0, 0),
axis=2,
radius=radius,
length=t_slab,
),
medium=mat_hole,
name='air hole',
)
We must now define the excitation conditions and field monitors. We will excite the slab using a normally incident (along z) planewave, polarized along the x direciton.
# Here we define the planewave source, placed just in advance (towards negative z) of the slab
source = td.PlaneWave(
source_time = td.GaussianPulse(
freq0=freq0,
fwidth=freqw
),
size=(td.inf, td.inf, 0),
center=(0, 0, -Lz/2+spacing/2),
direction='+',
pol_angle=0,
name='planewave',
)
Here we define the field monitor, placed past (towards positive z) of the PhC slab.
# We are interested in measuring the transmitted flux, so we set it to be an oversized plane.
monitor = td.FluxMonitor(
center = (0, 0, Lz/2 - spacing/2),
size = (td.inf, td.inf, 0),
freqs = monitor_freqs,
name='flux',
)
Additionally, we also place a time monitor in the middle of the field monitor plane to monitor the time evolution of the field.
# We are interested in measuring the time evolution at a single point in the field monitor plane
monitor_time = td.FieldTimeMonitor(
center = (0, 0, Lz/2 - spacing/2),
size = (0, 0, 0),
fields = ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'],
name='time',
)
Now it is time to define the simulation object.
sim = td.Simulation(
center = (0, 0, 0),
size = sim_size,
grid_spec = td.GridSpec.uniform(dl=dl),
structures = [slab,hole],
sources = [source],
monitors = [monitor,monitor_time],
run_time = t_stop,
shutoff = 1e-7,
boundary_spec = td.BoundarySpec.pml(z=True),
normalize_index = None,
)
Let's now plot the permittivity profile to confirm that the structure was defined correctly. We use the Simulation.plot()
method to plot the materials only, which assigns a different color to each slab without knowledge of the material properties.
fig, ax = plt.subplots(1, 2, tight_layout=True, figsize=(10, 4))
sim.plot(z=0., ax=ax[0]);
sim.plot(x=0, freq=freq0, ax=ax[1]);
plt.show()
We can also take a look at the source to make sure it's defined correctly over our frequency range of interst.
# Check probe and source
f, (ax1, ax2) = plt.subplots(1, 2, tight_layout=True, figsize=(8, 4))
plot_time = 0.2e-12
ax1 = sim.sources[0].source_time.plot(times=np.linspace(0, plot_time, 1001), ax=ax1)
ax1.set_xlim(0, plot_time)
ax1.legend(('source amplitude',))
ax2 = sim.sources[0].source_time.plot_spectrum(times=np.linspace(0, sim.run_time, 10001), val = 'abs', ax=ax2)
fill_max = 45e-16
ymax = 60e-16
ax2.fill_between(freq_range, [-0e-16, -0e-16], [fill_max, fill_max], alpha=0.4, color='g')
ax2.legend(('source spectrum', 'measurement'))
ax2.set_ylim(-1e-16, ymax)
plt.show()
Finally, we define a simulation object without PhC slab to normalize transmission.
sim0 = sim.copy(update={'structures':[]})
We will submit the simulation to run as a new project.
sim_data0 = web.run(sim0, task_name='lecture03_PhC_normalization', path=f'data/data0_PhC_run{runtime}_PML{dPML}.hdf5')
sim_data = web.run(sim, task_name='lecture03_PhC_transmission', path=f'data/data_PhC_run{runtime}_PML{dPML}.hdf5')
Once the simulation has completed, we can download the results and load them into the simulation object.
Now, we compute the transmitted flux and plot the transmission spectrum.
# Retrieve the power flux through the monitor plane.
transmission0 = sim_data0['flux'].flux
transmission = sim_data['flux'].flux
transmission_normalized = transmission / transmission0
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 4), tight_layout=True)
transmission0.plot(ax=ax1, label='no PhC')
transmission.plot(ax=ax1, label='with PhC')
ax1.set_xlim((freq_range[0],freq_range[1]))
transmission_normalized.plot(ax=ax2)
ax2.hlines(1.0,freq_range[0],freq_range[1],linestyles='dashed',color='black')
ax2.hlines(0.0,freq_range[0],freq_range[1],linestyles='dashed',color='black')
ax2.set_xlim((freq_range[0],freq_range[1]))
ax1.legend()
ax1.set_title('raw transmission')
ax2.set_title('normalized transmission')
plt.show()
To compare to the results in Fig.2 of the paper, let's plot the transmission as a function of frequency in the unit of c/period
plt.figure()
plt.plot(monitor_freqs*period/td.C_0, transmission_normalized, label='normalized transmission')
plt.xlabel('frequency (c/period)')
plt.xlim([0.25, 0.45])
plt.hlines(1.0,0.25,0.45,linestyles='dashed',color='black')
plt.hlines(0.0,0.25,0.45,linestyles='dashed',color='black')
plt.ylabel('Transmitted')
plt.show()
Finally, we look into the time evolution of Ex at the center of the flux monitor.
time_data = sim_data['time']
time_data0 = sim_data0['time']
fig, ax = plt.subplots(1,2,figsize=(8, 4), tight_layout=True)
ylim = 2
xlim = t_stop
# with PhC
Ex = time_data.Ex
Ex.plot(ax=ax[1])
ax[1].set_ylim([-ylim,ylim])
ax[1].set_xlim([0,xlim])
ax[1].set_ylabel('$E_x(t)$ [V/m]')
ax[1].set_title('with PhC')
# without PhC
Ex0 = time_data0.Ex
Ex0.plot(ax=ax[0])
ax[0].set_ylabel('$E_x(t)$ [V/m]')
ax[0].set_xlim([0,xlim])
ax[0].set_ylim([-ylim,ylim])
ax[0].set_title('without PhC')
plt.show()
Without PhC, the field decays rapidly; with PhC, a long detail tail is clearly visible.
FDTD 101: Lecture 3
This is the third video in the introduction to the finite difference time domain method or the FDTD method. I'm Shanhui Fan from Flexcompute.
In our previous video we have looked at using FDTD method to compute the transmission through a uniform dielectric slab. In this video, we are going to do a more complex structure of a transmission through a photonic crystal slab. The structure is shown here on the left, but it consists of a high index dielectric slab with a periodic array of air holes introduced into the slab. The geometric parameters are provided below here. The period is set to be one micron and then the radius is 200 nanometers and the thickness is 550 nanometers. The permittivity of the slab is 12 which roughly corresponds to silicon in the infrared. And we will compute the transmission spectrum of light normally incident upon the slab. On the right here is the computed transmission spectrum. And the spectrum consists of a smoothly varying background with two resonant features near 115 and 120 terahertz where the transmission varies very sharply from one to zero over a narrow frequency range. The detailed physics of this transmission spectrum is very interesting. You can look at this reference. Here we're going to focus primarily on the FDTD setup that allows you to get a transmission spectrum. But the thing that we would need to highlight is the fact that if you look at the transmission spectrum, there are these two very strong resonant features. We will focus on some of the consideration of using FDTD method when you try to study systems that support strong optical resonance.
Let's start the first step: we need to set up the computational cell. Here we're considering a structure that is infinitely periodic in the xy plane. As is typical, we're going to choose the computational domain to be only a single unit cell of this infinity periodic structure.
This is how the computational domain looks like. At the middle here is a single unit cell structure. On top and bottom here, we put in a perfectly matched layers boundary condition that are used to absorb incident waves. And then on the side here we put in a periodic boundary condition to simulate an infinitely periodic structure. And we excite a plane wave incident upon the structure with a plane wave source, and we assume an x-polarized current to generate polarized incident waves. And we look at the transmitted field by looking at the flux and the field on the other side of the structure. We choose the discretization to be sufficiently small to resolve both the structural features and the wavelengths inside the material. These are standard if you recall what we have discussed in the second video. In general, one nice aspect about FDTD is that many of the considerations that you have in complex structures are very similar to the considerations that you have in simulating simple structures.
With this we can put in a source. The source that we use here is a plane wave source with a gaussian envelope. And we choose in this case a relatively short pulse so that we can produce a broad-band spectrum covering the frequency range from 80 to approximately 130 terahertz.
With this we run two simulations. One is without the photonic crystal slab and that produces the blue curve here and that gives a characterization of the incident wave spectrum. We then put the photonic crystal slab in and that produced the red spectrum here on the top and that's the amplitude of the transmitted wave. We then take the ratio between the spectra with and without the photonic crystal slab and that gives you the nice transmission spectrum at the bottom, which is the spectrum that we show in the very beginning of this tutorial.
Now one very important consideration in simulating systems with highly resonant features is that you will need to run the simulation long enough. And to illustrate this point on the top here, I'm showing the time evolution of the electric field along the X direction at a monitor point on the blue planet on the left. And what you can see here in this time trajectory is that you have an initial pulse passing through the structure with a long tail generated afterwards. This long tail extends very far, all the way to a few picoseconds. And in the time slot B here, we again plot the field as a function of time and you can see the exponential decay and a beating pattern on top of it. Now, if you recall we have two resonant features here. These resonant features are slightly different frequencies. And the beating pattern here is related to the frequency difference between these two resonances.
To obtain a nice-looking spectrum on the right, we run the simulation to a time of about six picoseconds so that all the amplitudes in the resonance essentially decay to zero. We choose the computational time duration to be significantly longer than the lifetime of the system. If we do that, we can get a nice transmission spectrum.
On the other hand, if you don't run the simulation long enough, you won't get the desired result. Here is an example, where instead we only do the Fourier transform over a simulation time or 0.56 picosecond corresponding to the blue break on the left. In this time duration, the initial pulse has passed and we capture part of the exponential decay of the resonance. However, the amplitude of the resonance has not decayed to zero. If that's the duration that you choose, then you obtain a spectrum as indicated on the right. It is somewhere resembling the spectrum that I showed you in previous slides. However, on one hand, you see that the resonance gets more smooth and in particular you do not see the short transition from one to zero over a narrow frequency range. The one and the zero there are required by energy conservation considerations. Here you don't get either zero or one because we do not fully capture the energy in the exponential decay of the resonance. The other thing that you see in this spectrum is there are lots of oscillations. These oscillations come from the fact we truncate the time series before the field amplitude goes to zero.
To get the nice looking spectrum that faithfully captures the physics of the structure, you will need to run the simulation significantly longer than the lifetime of the system. Now having a spectrum like this, typically one would want to gain further insight. For example, one would like to visualize how the field of one of the resonances looks like. In FDTD, this is actually straightforwardly done. Instead of using a broad-band spectrum of a source to excite the system as we have done this previously. What you can do is to choose a narrow band spectrum, thus a much longer pulse in the dipole source. We'll show an example where we try to study a bit more of the first resonance peak near 115 THz. We choose a source spectrum indicated by the blue curve here. On the right, I'm plotting the Ex field at the monitor point as a function of time. Again, you see an initial pulse is now actually much longer than the previous example and therefore generate a narrow band spectrum. As well as the exponential decay of the resonance. In this case, you see a pure exponential decay without the beating pattern that we've seen in the previous example, and this is because now we selectively excite only one resonance.
Having generated the field plot as a function of time, you can then select a particular time duration during which the system is going through pure exponential decay. For example, we can select the time duration as indicated by the blue brace there. And at that time duration, you can then look at the field distribution. Since the system is going through pure exponential decay now. It gives you a sense of how the resonance looks like. So here I'm plotting the Ex field on the vertical slice as indicated by the yellow in the computational domain. This slice cuts through the structures. You can see that inside the dielectric structure, the field is not uniform and is strongly enhanced compared to the outside. And that is the resonant feature. Once you go outside the slab in the Z direction on the other hand, you can see that the field very quickly becomes uniform along the X direction. This is because we're in the non-diffracting regime. Once you go sufficiently away from the structure, you only get plane waves. And this is a field plot, but you can also generate a movie. In the movie, you can see that in the structure the field oscillates back and forth and then it produces a pure plane wave radiating out outside the structure.
To end the video, let me just briefly comment that FDTD is a very nice method for studying systems with high quality factor resonances. In the long time after a pause excitation, the behavior of the structure is dominated by the high Q resonance. Therefore, you can always excite the high Q resonance as long as your source has some spectral overlap. And this is in contrast to the frequency domain method where to excite high Q resonance. You have to choose your expectation frequency very precisely. To summarize, I give you some of the considerations on using FDTD method to simulate structures with high quality factors.