TIDY3D
LEARNING CENTER

Complete this course to earn 50 FlexCredits Credits are added to your account when all course items are checked in green.

Introduction to FDTD Simulation

By Tyler Hughes, Zongfu Yu and Shanhui Fan

In this lecture, we will describe the basic concepts of EM simulation using FDTD.

- How Maxwell's equations can be solved computationally in the context of a photonic device.
- Discretization of the simulation space using the finite difference method.
- A demonstration on how we solve for the electromagnetic fields radiated by a dipole source.

Share On:
Download .ipynb View Presentation Slides
Additional information: This was updated in Apr 15, 2022

Tutorial 1: intro to FDTD

This tutorial will walk you through setting up a simple dipole radiation simulation in Tidy3D.

For more details, refer to the Tidy3d documentation.

Setup

First we import Tidy3D and the other packages needed. If it is not installed, please perform the installation and account authentication by following the detailed instructions here.

# imports
import matplotlib.pylab as plt
import tidy3d as td
from tidy3d import web

td.config.local_cache.enabled = False

Then, we will define the basic simulation parameters. Note that the length scale is microns.

# simulation parameters
side_length = 9.0
grid_size = 50e-3

# apply a PML in all directions
boundary_spec = td.BoundarySpec.all_sides(boundary=td.PML())

# spectrum and resolution parameters
lambda0 = 1.0
freq0 = td.C_0 / lambda0
fwidth = freq0 / 50
run_time = 200 / freq0

Next, we define the objects present in our simulation, specifically the source and monitor.

# define dipole source at origin pointing in z
dipole_source = td.PointDipole(
    center=(0, 0, 0),
    source_time=td.GaussianPulse(freq0=freq0, fwidth=fwidth),
    polarization="Ez",
    name="dipole",
)
# define monitor to measure fields in xz plane at central frequency
monitor = td.FieldMonitor(
    center=(0, 0, 0),
    size=(td.inf, 0, td.inf),
    freqs=[freq0],
    name="freq_domain",
)

And finally, we put everything together in a Simulation object, which contains all of the specs needed to run the simulation.

# define simulation
simulation = td.Simulation(
    size=(side_length, side_length, side_length),
    grid_spec=td.GridSpec.uniform(dl=grid_size),
    structures=[],
    sources=[dipole_source],
    monitors=[monitor],
    run_time=run_time,
    boundary_spec=boundary_spec,
)

Running Simulation

To run the simulation, we will call the web.run() function, passing our Simulation and some parameters about the task name and the path to download the data file.

# run simulation
sim_data = web.run(
    simulation, task_name="lecture01_dipole", path="data/data_dipole.hdf5"
)
16:02:28 UTC Created task 'lecture01_dipole' with resource_id                   
             'fdve-4324d3d1-499a-4ce0-a79a-d44a1aa46cd7' and task_type 'FDTD'.  
             Task folder: 'default'.                                            

             Estimated FlexCredit cost: 0.025. This assumes the FDTD solver runs
             for the full simulation time; if early shutoff is reached, the     
             billed cost can be lower. Use 'web.real_cost(task_id)' to get the  
             billed FlexCredit cost after a simulation run.                     
             status = queued                                                    
             To cancel the simulation, use 'web.abort(task_id)' or              
             'web.delete(task_id)' or abort/delete the task in the web UI.      
             Terminating the Python script will not stop the job running on the 
             cloud.                                                             

16:02:40 UTC starting up solver                                                 
             running solver                                                     
             early shutoff detected at 8%, exiting.                             

             status = queued                                                    
16:02:52 UTC status = running                                                   
16:02:54 UTC status = postprocess                                               
16:02:56 UTC status = success                                                   


             Loading results from data/data_dipole.hdf5                         

Post Run Analysis

After the job is done, all of the data is loaded into the SimulationData object called sim_data in this example.

From this, we can plot the results and make sure it looks reasonable.

# check that frequency domain fields look good
ax = sim_data.plot_field("freq_domain", "Ez", y=0, f=freq0)
plt.show()

Adding Complexity

To make things more interesting, let’s run the same simulation, but adding a few structures in the mix. For now, let’s just add a few dielectric box objects to see how that changes the results.

# define the boxes
epsilon_box = 3
center_offset_box = 1.6
size_box = 1.8
medium = td.Medium(permittivity=epsilon_box, name="medium")

box_top = td.Structure(
    geometry=td.Box(
        center=(0, 0, center_offset_box),
        size=(size_box, size_box, size_box),
    ),
    medium=medium,
    name="box top",
)

bot_bot_r = td.Structure(
    geometry=td.Box(
        center=(+center_offset_box, 0, -center_offset_box),
        size=(size_box, size_box, size_box),
    ),
    medium=medium,
    name="box bottom right",
)

bot_bot_l = td.Structure(
    geometry=td.Box(
        center=(-center_offset_box, 0, -center_offset_box),
        size=(size_box, size_box, size_box),
    ),
    medium=medium,
    name="box bottom left",
)
# make a new simulation with the boxes added
simulation_boxes = td.Simulation(
    size=(side_length, side_length, side_length),
    grid_spec=td.GridSpec.uniform(dl=grid_size),
    structures=[box_top, bot_bot_r, bot_bot_l],
    sources=[dipole_source],
    monitors=[monitor],
    run_time=run_time,
    boundary_spec=boundary_spec,
)

# visualize the simulation first, before running
ax = simulation_boxes.plot(y=0.01)
plt.show()

# run simulation
sim_data_boxes = web.run(
    simulation_boxes,
    task_name="lecture01_several_box",
    path="data/data_several_box.hdf5",
)
16:02:59 UTC Created task 'lecture01_several_box' with resource_id              
             'fdve-fc1a6242-6dd5-4222-b78d-6cbd435be18f' and task_type 'FDTD'.  
             Task folder: 'default'.                                            

             Estimated FlexCredit cost: 0.025. This assumes the FDTD solver runs
             for the full simulation time; if early shutoff is reached, the     
             billed cost can be lower. Use 'web.real_cost(task_id)' to get the  
             billed FlexCredit cost after a simulation run.                     
             status = queued                                                    
             To cancel the simulation, use 'web.abort(task_id)' or              
             'web.delete(task_id)' or abort/delete the task in the web UI.      
             Terminating the Python script will not stop the job running on the 
             cloud.                                                             

16:03:11 UTC starting up solver                                                 
             running solver                                                     
16:03:15 UTC early shutoff detected at 68%, exiting.                            

             status = postprocess                                               
16:03:17 UTC status = success                                                   


             Loading results from data/data_several_box.hdf5                    
ax = sim_data_boxes.plot_field("freq_domain", "Ez", y=0, f=freq0)
plt.show()