What’s new in Tidy3d?#

This notebook will walk through the changes between the Tdy3D version released in March 2022 and the version used before that.

If you are a new user and not familiar with our original version, this tutorial can be useful, but you may rather see one of our other ones for a more direct walkthrough of the features.

[1]:
# First, lets import the main packages we'll need
import numpy as np
import matplotlib.pylab as plt
import tidy3d as td
[19:46:33] WARNING  This version of Tidy3D was pip installed from the 'tidy3d-beta' repository on   __init__.py:103
                    PyPI. Future releases will be uploaded to the 'tidy3d' repository. From now on,                
                    please use 'pip install tidy3d' instead.                                                       
           INFO     Using client version: 1.9.0rc1                                                  __init__.py:121

Global Changes#

Here we will discuss some of the general changes that apply to all Tidy3d importable components.

Topics covered will include:

  • Defining Tidy3d components.

  • Saving and loading from file.

  • Getting help / debugging.

  • logging

Background#

All Tidy3d components are defined using the pydantic package. As such, each tidy3d object corresponds to a data structure that has rigidly defined allowable types and values, which get validated automatically whenever you inialize an object.

This has several advantges, including.

  • Catching bugs in the tidy3d components as early as possible.

  • Automatically generated schema for tidy3d simulation specifications.

  • Simple and reliable IO.

Defining Tidy3d Components#

It also requires a bit more due-diligence on the user side:

  • All tidy3d components must use keyword arguments in their definitions, eg. Medium(2.0) becomes Medium(permittivity=2.0) to be explicit.

[2]:
# wrong way
try:
    td.Medium(2.0)
except Exception as e:
    td.log.info(e)

# correct way
m = td.Medium(permittivity=2.0)

           INFO     __init__() takes exactly 1 positional argument (2 given)                        3217355834.py:5

Saving and Loading Tidy3d Components#

All tidy3d components can be saved to file as json or yaml format using the instance.to_file(path) and class.from_file(path) methods.

For example, let’s save and load a td.Box instance.

[3]:
my_box = td.Box(center=(1, 2, 3), size=(2, 2, 3))

my_box.to_file("data/box.json")

# note, `from_file` is a @classmethod so need to call it from `td.Box` not `my_box`.
your_box = td.Box.from_file("data/box.json")

print(my_box)
print(your_box)
print(my_box == your_box)

type='Box' center=(1.0, 2.0, 3.0) size=(2.0, 2.0, 3.0)
type='Box' center=(1.0, 2.0, 3.0) size=(2.0, 2.0, 3.0)
True

Getting Help#

Sometimes you might want to get some information about a component without needing to look at the documentation. For this, each tidy3d component has a .help() method that will print out information about the stored data inside of the component.

Here’s an example.

[4]:
monitor = td.FieldMonitor(size=(2, 2, 0), freqs=[200e12], name="monitor")

monitor.help()

╭─────────────────────── <class 'tidy3d.components.monitor.FieldMonitor'> ───────────────────────╮
 :class:`Monitor` that records electromagnetic fields in the frequency domain.                  
                                                                                                
 ╭────────────────────────────────────────────────────────────────────────────────────────────╮ 
  FieldMonitor(                                                                               
  type='FieldMonitor',                                                                    
  center=(0.0, 0.0, 0.0),                                                                 
  size=(2.0, 2.0, 0.0),                                                                   
  name='monitor',                                                                         
  freqs=(200000000000000.0,),                                                             
  apodization=ApodizationSpec(                                                            
  │   │   start=None,                                                                         
  │   │   end=None,                                                                           
  │   │   width=None,                                                                         
  │   │   type='ApodizationSpec'                                                              
  ),                                                                                      
  fields=('Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'),                                            
  interval_space=(1, 1, 1),                                                               
  colocate=False                                                                          
  )                                                                                           
 ╰────────────────────────────────────────────────────────────────────────────────────────────╯ 
                                                                                                
    apodization = ApodizationSpec(start=None, end=None, width=None, type='ApodizationSpec')     
   bounding_box = Box(type='Box', center=(0.0, 0.0, 0.0), size=(2.0, 2.0, 0.0))                 
         bounds = ((-1.0, -1.0, 0.0), (1.0, 1.0, 0.0))                                          
         center = (0.0, 0.0, 0.0)                                                               
       colocate = False                                                                         
         fields = ('Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz')                                          
          freqs = (200000000000000.0,)                                                          
       geometry = Box(type='Box', center=(0.0, 0.0, 0.0), size=(2.0, 2.0, 0.0))                 
 interval_space = (1, 1, 1)                                                                     
           name = 'monitor'                                                                     
    plot_params = PlotParams(                                                                   
                      alpha=0.4,                                                                
                      edgecolor='orange',                                                       
                      facecolor='orange',                                                       
                      fill=True,                                                                
                      hatch=None,                                                               
                      linewidth=3.0,                                                            
                      type='PlotParams'                                                         
                  )                                                                             
           size = (2.0, 2.0, 0.0)                                                               
           type = 'FieldMonitor'                                                                
      zero_dims = [2]                                                                           
╰────────────────────────────────────────────────────────────────────────────────────────────────╯

Changes to Core Components#

Here we will discuss the changes to the core package, specifically changes to how the core components (sources, monitors, etc) are defined.

Topics covered will include:

  • Mediums.

  • Geometries.

  • Structures.

  • Sources.

  • Monitors.

  • Modes.

  • PML / Absorbing boundaries.

  • Simulations.

Mediums#

As before, mediums define the optical properties of the materials within the simulation.

PEC#

The simplest medium is td.PEC, which just signifies a perfect electrical conductor (no E field allowed within).

[5]:
pec_medium = td.PEC

Non-dispersive mediums#

Non-dispersive mediums are defined using the Medium object and can be specified by either permittivity and conductivity (optional) values, or from n, k refractive index values.

[6]:
lossless_dielectric = td.Medium(permittivity=4.0)
lossy_dielectric = td.Medium(permittivity=4.0, conductivity=1.0)
lossy_dielectric_from_nk = td.Medium.from_nk(n=2.0, k=0.1, freq=150e12)

Anisotropic mediums#

Tidy3d currently only supports diagonally anisotropic media without dispersion.

This kind of medium can be simply defined by specifing three Medium objects for the xx, yy, zz components of the permittivity / conductivity tensor.

[7]:
anisotropic_medium = td.AnisotropicMedium(
    xx=lossless_dielectric, yy=lossy_dielectric, zz=lossy_dielectric_from_nk
)

Dispersive mediums#

Dispersive mediums can be defined in three ways:

  • Imported from our material_library.

  • Defined directly by specifying the parameters in the various supplied dispersive models.

  • Fitted to optical n-k data using the dispersion fitting tool plugin (more info later).

[8]:
# material library
silver = td.material_library["Ag"]
silver_variants = silver.variants
print("variants for silver include: ", list(silver_variants.keys()))
silver = silver_variants["JohnsonChristy1972"]

# models
lorentz_model = td.Lorentz(eps_inf=2.0, coeffs=[(1, 2, 3), (4, 5, 6)])
sellmeier_model = td.Sellmeier(coeffs=[(1, 2), (3, 4)])

variants for silver include:  ['Rakic1998BB', 'JohnsonChristy1972', 'RakicLorentzDrude1998', 'Yang2015Drude']

Medium Methods#

The complex-valued permittivity of a medium at a given frequency can be sampled using the .eps_model(freq) method.

And the n, k values can be plotted over a frequency range using the .plot(freqs) method.

[9]:
freqs_hz = 1e12 * np.linspace(50, 200, 1001)
print(
    f"complex relative permittivity at freqs_hz = \n\t {lossy_dielectric.eps_model(freqs_hz)}\n"
)

ax = lossy_dielectric_from_nk.plot(freqs_hz)

complex relative permittivity at freqs_hz =
         [4.+359.5020714j  4.+358.42679103j 4.+357.35792385j ... 4. +90.01053365j
 4. +89.94297508j 4. +89.87551785j]

../_images/notebooks_WhatsNew_18_1.png

Geometries#

The new version of Tidy3D introduces Geometry objects, which do the heavy lifting for any components with some spatial extent.

There are only 4 primitive geometries:

Note that GdsSlab was removed, but GDS cells can still be loaded as Polyslab objects using PolySlab.from_gds() classmethod. Please refer to the tutorial notebook on GDS importing for more details.

Geometry objects have many useful methods.

[10]:
s1 = td.Sphere(radius=1, center=(0, 0, 0))
s2 = td.Box(center=(1, 1, 1), size=(1, 1, 1))

# do two geometric object intersect?
print(s1.intersects(s2))

# does the object intersect a plane?
print(s1.intersects_plane(z=10))

# get polygons that intersect sphere at plane x=0
print(s1.intersections(x=0))

# get bounds (rmin, rmax) of geometry
print(s1.bounds)

# get td.Box() for bounding box of geometry
print(s1.bounding_box.help())

# evaluate whether point(s) are inside of geometry
print(s1.inside(x=0, y=1, z=1))
print(s1.inside(x=np.linspace(-1, 1, 5), y=np.zeros(5), z=np.ones(5)))

# plot the geometry at a cross sectional plane
ax = s1.plot(y=0)

True
False
[<POLYGON ((1 0, 0.995 -0.098, 0.981 -0.195, 0.957 -0.29, 0.924 -0.383, 0.882...>]
((-1.0, -1.0, -1.0), (1.0, 1.0, 1.0))
╭───────────────────── <class 'tidy3d.components.geometry.Box'> ─────────────────────╮
 Rectangular prism.                                                                 
    Also base class for :class:`Simulation`, :class:`Monitor`, and :class:`Source`. 
                                                                                    
 ╭────────────────────────────────────────────────────────────────────────────────╮ 
  Box(type='Box', center=(0.0, 0.0, 0.0), size=(2.0, 2.0, 2.0))                   
 ╰────────────────────────────────────────────────────────────────────────────────╯ 
                                                                                    
 bounding_box = Box(type='Box', center=(0.0, 0.0, 0.0), size=(2.0, 2.0, 2.0))       
       bounds = ((-1.0, -1.0, -1.0), (1.0, 1.0, 1.0))                               
       center = (0.0, 0.0, 0.0)                                                     
     geometry = Box(type='Box', center=(0.0, 0.0, 0.0), size=(2.0, 2.0, 2.0))       
  plot_params = PlotParams(                                                         
                    alpha=1.0,                                                      
                    edgecolor=None,                                                 
                    facecolor=None,                                                 
                    fill=True,                                                      
                    hatch=None,                                                     
                    linewidth=1.0,                                                  
                    type='PlotParams'                                               
                )                                                                   
         size = (2.0, 2.0, 2.0)                                                     
         type = 'Box'                                                               
    zero_dims = []                                                                  
╰────────────────────────────────────────────────────────────────────────────────────╯
None
False
[False False  True False False]
../_images/notebooks_WhatsNew_20_3.png

Note, because simulations, monitors, and sources all are defined spatially, they inherit from Box and contain these methods as well, which can come in handy when doing validation.

Structures#

The new version of tidy3d redefines the notion of Structure as something that simply contains a Geometry and a Medium. Therefore, the call structure is a bit different.

[11]:
# old way
try:
    dielectric_box = td.Structure(
        center=(0, 0, 0), size=(1, 1, 1), medium=td.Medium(permittivity=2.0)
    )
except Exception as e:
    td.log.info(e)

# new way
dielectric_box = td.Structure(
    geometry=td.Box(center=(0, 0, 0), size=(1, 1, 1)),
    medium=td.Medium(permittivity=2.0),
)

[19:46:34] INFO     3 validation errors for Structure                                               4244360487.py:7
                    geometry                                                                                       
                      field required (type=value_error.missing)                                                    
                    center                                                                                         
                      extra fields not permitted (type=value_error.extra)                                          
                    size                                                                                           
                      extra fields not permitted (type=value_error.extra)                                          

Sources#

Sources work more or less similarly to the old version, with a few minor API changes.

  1. PointDipole and VolumeSource were combined into a single VolumeSource object. For a dipole, specify the size=(0,0,0).

  2. Instead of specifying injection axis, plane wave, mode source, and gaussian beam sources must have a planar geometry (one size=0 element) and direction ('+' or '-') specifying the direction along the normal axis to send the fields.

[12]:
# note the change in kwarg values
gaussian = td.GaussianPulse(freq0=150e12, fwidth=10e12)

# z polarized dipole at origin
dipole = td.UniformCurrentSource(
    center=(0, 0, 0), size=(0, 0, 0), source_time=gaussian, polarization="Ez"
)

# z polarized plane wave propagating in -x
plane_wave = td.PlaneWave(
    center=(0, 0, 0),
    size=(0, td.inf, td.inf),
    source_time=gaussian,
    pol_angle=np.pi / 2,
    direction="-",
)

Monitors#

Monitors have received some major changes in the new version. Before, monitors were split up according to whether they measured values in the time or frequency domain.

  • TimeMonitor

  • FreqMonitor

The contents of the store argument told the solver what kind of data to load into the monitor data.

In the new version, each monitor stores a single type of data and we have expanded the number of monitors.

The following monitors measure their corresponding values in the frequency-domain

And the following measure their values in the time-domain

This splitting up of monitor types means less accounting about what values are stored, and each monitor type has a corresponding data type in the simulation data.

Otherwise, monitors function very similarly, with a few minor API changes.

Note: all monitors must be named (have a name argument supplied). The data returned by the server will be indexed by the monitor name.

[13]:
# measures Ex, Ey, Hz fields on the plane at frequency 150THz
mon1 = td.FieldMonitor(
    center=(1, 0, 0),
    size=(td.inf, td.inf, 0),
    fields=["Ex", "Ey", "Hz"],
    freqs=[150e12],
    name="fields_at_150THz",
)

# measures time dependence of flux through a plane every 5 time steps between a window of (start, stop)
mon2 = td.FluxTimeMonitor(
    center=(1, 0, 0),
    size=(td.inf, td.inf, 0),
    start=1e-13,
    stop=3e-13,
    interval=5,
    name="flux_over_time",
)

Modes#

Mode objects have also gone through major revisions.

In the previous versions of Tidy3D, there were convenience functions for viewing mode profiles (Simulation.viz_modes), and ultimately the mode information needed to be set manually using Simulation.set_mode().

In the new version, we introduce a ModeSpec object that stores all of the specifiction needed for the mode solver to know which modes to inject or measure in the ModeSource and ModeMonitor objects.

For example:

[14]:
# default mode solver spec (returns first mode)
fundamental = td.ModeSpec()

# tell the mode solver to return 4 modes
first_4_modes = td.ModeSpec(num_modes=4)

# have mode solver return 4 modes around the target effective index
complicated = td.ModeSpec(num_modes=4, target_neff=2.0)

Using the mode specifications, we can make modal sources or monitors similar to before.

[15]:
# inject the fundamental mode
mode_source = td.ModeSource(
    center=(0, 0, -1),
    size=(td.inf, td.inf, 0),
    source_time=gaussian,
    mode_spec=fundamental,
    mode_index=0,
    direction="+",
)

# do modal decomposition and return amplitude data for the first 4 modes
mode_mon = td.ModeMonitor(
    center=(0, 0, +1),
    size=(td.inf, td.inf, 0),
    freqs=freqs_hz,
    mode_spec=first_4_modes,
    name="modes",
)

The td.plugins.ModeSolver is designed to help users come up with the correct ModeSpec for their problem, at which point it can be used directly in ModeSource and ModeMonitor objects without setting it explicitly using a Simulation method. For more details, refer to the mode solver tutorial notebook.

Absorbing Boundaries#

Absorbing boundaries are defined a bit differently in the new version, there are three types of boundaries

  • td.PML() defines a standard PML, with an adjustable number of layers.

  • td.StablePML() defines a PML with ‘stable’ profile, which can reduce divergence at the expense of more layers.

  • td.Absorber() defines adiabatically increasing conductivity values at the edges of the simultion, which can dramatically improve stability of simulations involving dispersive materials, again at the expense of more layers.

As before, these layers add to the simulation size defined in Simulation.

Also as before, it is important to extend any structures all the way through the PML if they are meant to be touching the simulation boundary on that side.

To define a sequence of PML lyers on the x, y, z sides of the simulation, one may use the convenience functions provided in td.BoundarySpec() and td.Boundary(), as shown below.

Periodic boundaries are always used on each side of the simulation, so if a boundary is not specified along a dimension, the simulation will be periodic in that direction.

[16]:
# standard absorber on x, PML with 20 layers on y, no PML on z (periodic BC)
boundary_spec = td.BoundarySpec(
    x=td.Boundary.absorber(), y=td.Boundary.pml(num_layers=20), z=td.Boundary.periodic()
)

Simulations#

Finally, as before, Simulation objects contain all of the specifications needed to run the Tidy3D simulation and contain all of the previous components.

Again, there are some minor API changes, but overall they look very similar.

  • Simulation accepts an optional medium parameter, specifying the background medium (air by default).

  • mesh_step and resolution were removed in favor of a grid_spec, which specifies how the grid is to be generated along each of the three directions. These are discussed in more detail here.

[17]:
sim = td.Simulation(
    size=(4, 4, 4),
    grid_spec=td.GridSpec.uniform(dl=0.2),
    run_time=1e-12,
    boundary_spec=td.BoundarySpec(x=td.Boundary.periodic(), y=td.Boundary.pml(), z=td.Boundary.periodic()),
    structures=[dielectric_box],
    sources=[dipole],
    monitors=[mon1, mon2],
)

A defined Simulation also provides several useful methods in addition to the ones inhereted from Box.

[18]:
# get permittivity at yee cell centers in a volume defined by a box.
sim.epsilon(td.Box(size=(1, 0, 1)), "centers")

# get a `td.Grid` containing all information about spatial locations in the FDTD / yee grid
print(sim.grid.centers)

# plot the simulation cross section
f, (ax1, ax2) = plt.subplots(1, 2, tight_layout=True, figsize=(10, 4))

# plot the structures, PML, sources, mediums
ax1 = sim.plot(x=0, ax=ax1)

# same thing but plot structure in grayscale using permittivity value
ax1 = sim.plot_eps(x=0, ax=ax2)

# add the FDTD grid boundaries
ax2 = sim.plot_grid(x=0, ax=ax2)

x=(-1.9, -1.7000000000000002, -1.5, -1.2999999999999998, -1.1, -0.8999999999999999, -0.6999999999999998, -0.4999999999999999, -0.29999999999999993, -0.09999999999999998, 0.10000000000000009, 0.30000000000000027, 0.5000000000000002, 0.7000000000000002, 0.9000000000000001, 1.1, 1.3000000000000003, 1.5000000000000002, 1.7000000000000002, 1.9000000000000001) y=(-4.299999999999999, -4.1, -3.8999999999999995, -3.6999999999999997, -3.4999999999999996, -3.3, -3.0999999999999996, -2.9, -2.6999999999999997, -2.5, -2.3, -2.1, -1.9, -1.7000000000000002, -1.5, -1.2999999999999998, -1.1, -0.8999999999999999, -0.6999999999999998, -0.4999999999999999, -0.29999999999999993, -0.09999999999999998, 0.10000000000000009, 0.30000000000000027, 0.5000000000000002, 0.7000000000000002, 0.9000000000000001, 1.1, 1.3000000000000003, 1.5000000000000002, 1.7000000000000002, 1.9000000000000001, 2.0999999999999996, 2.3, 2.499999999999999, 2.6999999999999993, 2.8999999999999986, 3.0999999999999988, 3.299999999999998, 3.4999999999999982, 3.6999999999999975, 3.8999999999999977, 4.099999999999998, 4.299999999999997) z=(-1.9, -1.7000000000000002, -1.5, -1.2999999999999998, -1.1, -0.8999999999999999, -0.6999999999999998, -0.4999999999999999, -0.29999999999999993, -0.09999999999999998, 0.10000000000000009, 0.30000000000000027, 0.5000000000000002, 0.7000000000000002, 0.9000000000000001, 1.1, 1.3000000000000003, 1.5000000000000002, 1.7000000000000002, 1.9000000000000001) type='Coords'
../_images/notebooks_WhatsNew_37_1.png

Changes to Simulation Submission#

Here we will discuss changes made to the process for submitting, managing, monitoring, and loading simulations from our server.

Topics covered will include: * tidy3d.web functions. * working with tidy3d.web.Job and tidy3d.web.Batch convenience containers.

[19]:
import tidy3d.web as web

Web interface#

The new web interface provides the same functions as the original version with a few major changes.

Usually, the most convenient way to run a single simulation in one line is with web.run(), which simply performs all of the necessary steps one by one.

Note, in the new version, the output of the simultion is a separate data object called a SimulationData. Whereas before it was a Simulation object with the data loaded inside of it. We will discuss this is more detail in the following section.

[20]:
sim_data = web.run(sim, task_name="web_demo", path="data/data.hdf5")

[19:46:35] INFO     Created task 'web_demo' with task_id '159e3c1a-9b6f-4a35-9aba-68c5701e96b4'.      webapi.py:120
[19:46:38] INFO     Maximum FlexUnit cost: 0.025                                                      webapi.py:253
           INFO     status = queued                                                                   webapi.py:262
[19:46:41] INFO     status = preprocess                                                               webapi.py:274
[19:46:47] INFO     starting up solver                                                                webapi.py:278
[19:46:54] INFO     running solver                                                                    webapi.py:284
[19:46:55] INFO     status = postprocess                                                              webapi.py:307
[19:46:58] INFO     status = success                                                                  webapi.py:307
           INFO     Billed FlexUnit cost: 0.025                                                       webapi.py:311
[19:46:59] INFO     downloading file "output/monitor_data.hdf5" to "data/data.hdf5"                   webapi.py:593
[19:47:00] INFO     loading SimulationData from data/data.hdf5                                        webapi.py:415
           WARNING  Simulation final field decay value of 0.00486 is greater than the simulation      webapi.py:421
                    shutoff threshold of 1e-05. Consider simulation again with large run_time                      
                    duration for more accurate results.                                                            

Containers#

The new version also contains the convenience containers Job and Batch for managing single and multiple tasks without needing to account for the task_id and other metadata.

They follow the same basic API as the web. functions, except Batch objects return generators that can be iterated through to give SimulationData for each task, rather than returning it one by one. This cuts down on memory for several large jobs.

While we wont cover all of the details here, for more information, see the tutorial on the Web API or look at the examples in the other notebooks.

Changes to Output Data#

Here we will discuss changes made to the output data from a simulation.

Topics covered will include:

  • SimulationData objects.

  • Obtaining information about a completed FDTD simulation.

  • Selecting data by monitor or field value.

  • Post-processing and visualizing data.

Simulation Data#

As mentioned, tidy3d data is now separated from the Simulation object that led to its creation.

We call the data container for a single task a SimulationData object.

In addition to storing the data for each of the individual monitors in the simulation, it has it’s own useful functionality.

[21]:
# print the log, which is stored as an attribute rather than as its own file
print(sim_data.log)

# get a copy of the original Simulation, so it also doesnt need to be stored separately
sim_data.simulation.help()

Simulation domain Nx, Ny, Nz: [20, 44, 20]
Applied symmetries: (0, 0, 0)
Number of computational grid points: 1.8400e+04.
Using subpixel averaging: True
Number of time steps: 2.6240e+03
Automatic shutoff factor: 1.00e-05
Time step (s): 3.8131e-16


Compute source modes time (s):     0.0158
Compute monitor modes time (s):    0.0020
Rest of setup time (s):            3.0944

Running solver for 2624 time steps...
- Time step    104 / time 3.97e-14s (  4 % done), field decay: 1.00e+00
- Time step    209 / time 7.97e-14s (  8 % done), field decay: 1.00e+00
- Time step    314 / time 1.20e-13s ( 12 % done), field decay: 5.47e-01
- Time step    419 / time 1.60e-13s ( 16 % done), field decay: 4.20e-01
- Time step    524 / time 2.00e-13s ( 20 % done), field decay: 3.28e-01
- Time step    629 / time 2.40e-13s ( 24 % done), field decay: 1.27e-01
- Time step    734 / time 2.80e-13s ( 28 % done), field decay: 1.24e-02
- Time step    839 / time 3.20e-13s ( 32 % done), field decay: 4.07e-02
- Time step    944 / time 3.60e-13s ( 36 % done), field decay: 1.23e-01
- Time step   1049 / time 4.00e-13s ( 40 % done), field decay: 1.46e-01
- Time step   1154 / time 4.40e-13s ( 44 % done), field decay: 1.00e-01
- Time step   1259 / time 4.80e-13s ( 48 % done), field decay: 3.70e-02
- Time step   1364 / time 5.20e-13s ( 52 % done), field decay: 6.51e-03
- Time step   1469 / time 5.60e-13s ( 56 % done), field decay: 2.47e-02
- Time step   1574 / time 6.00e-13s ( 60 % done), field decay: 5.65e-02
- Time step   1679 / time 6.40e-13s ( 64 % done), field decay: 6.46e-02
- Time step   1784 / time 6.80e-13s ( 68 % done), field decay: 4.11e-02
- Time step   1889 / time 7.20e-13s ( 72 % done), field decay: 1.43e-02
- Time step   1994 / time 7.60e-13s ( 76 % done), field decay: 3.80e-03
- Time step   2099 / time 8.00e-13s ( 80 % done), field decay: 1.31e-02
- Time step   2204 / time 8.40e-13s ( 84 % done), field decay: 2.64e-02
- Time step   2309 / time 8.80e-13s ( 88 % done), field decay: 2.97e-02
- Time step   2414 / time 9.20e-13s ( 92 % done), field decay: 1.90e-02
- Time step   2519 / time 9.61e-13s ( 96 % done), field decay: 5.62e-03
- Time step   2623 / time 1.00e-12s (100 % done), field decay: 4.86e-03

Solver time (s):                   0.4162

╭─────────────────────────────── <class 'tidy3d.components.simulation.Simulation'> ───────────────────────────────╮
 Contains all information about Tidy3d simulation.                                                               
                                                                                                                 
 ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ 
  Simulation(                                                                                                  
  type='Simulation',                                                                                       
  center=(0.0, 0.0, 0.0),                                                                                  
  size=(4.0, 4.0, 4.0),                                                                                    
  run_time=1e-12,                                                                                          
  medium=Medium(name=None, frequency_range=None, type='Medium', permittivity=1.0, conductivity=0.0),       
  symmetry=(0, 0, 0),                                                                                      
  structures=(                                                                                             
  │   │   Structure(                                                                                           
  │   │   │   geometry=Box(type='Box', center=(0.0, 0.0, 0.0), size=(1.0, 1.0, 1.0)),                          
  │   │   │   name=None,                                                                                       
  │   │   │   type='Structure',                                                                                
  │   │   │   medium=Medium(                                                                                   
  │   │   │   │   name=None,                                                                                   
  │   │   │   │   frequency_range=None,                                                                        
  │   │   │   │   type='Medium',                                                                               
  │   │   │   │   permittivity=2.0,                                                                            
  │   │   │   │   conductivity=0.0                                                                             
  │   │   │   )                                                                                                
  │   │   ),                                                                                                   
  ),                                                                                                       
  sources=(                                                                                                
  │   │   UniformCurrentSource(                                                                                
  │   │   │   type='UniformCurrentSource',                                                                     
  │   │   │   center=(0.0, 0.0, 0.0),                                                                          
  │   │   │   size=(0.0, 0.0, 0.0),                                                                            
  │   │   │   source_time=GaussianPulse(                                                                       
  │   │   │   │   amplitude=1.0,                                                                               
  │   │   │   │   phase=0.0,                                                                                   
  │   │   │   │   type='GaussianPulse',                                                                        
  │   │   │   │   freq0=150000000000000.0,                                                                     
  │   │   │   │   fwidth=10000000000000.0,                                                                     
  │   │   │   │   offset=5.0                                                                                   
  │   │   │   ),                                                                                               
  │   │   │   name=None,                                                                                       
  │   │   │   polarization='Ez'                                                                                
  │   │   ),                                                                                                   
  ),                                                                                                       
  boundary_spec=BoundarySpec(                                                                              
  │   │   x=Boundary(                                                                                          
  │   │   │   plus=Periodic(name=None, type='Periodic'),                                                       
  │   │   │   minus=Periodic(name=None, type='Periodic'),                                                      
  │   │   │   type='Boundary'                                                                                  
  │   │   ),                                                                                                   
  │   │   y=Boundary(                                                                                          
  │   │   │   plus=PML(                                                                                        
  │   │   │   │   name=None,                                                                                   
  │   │   │   │   type='PML',                                                                                  
  │   │   │   │   num_layers=12,                                                                               
  │   │   │   │   parameters=PMLParams(                                                                        
  │   │   │   │   │   sigma_order=3,                                                                           
  │   │   │   │   │   sigma_min=0.0,                                                                           
  │   │   │   │   │   sigma_max=1.5,                                                                           
  │   │   │   │   │   type='PMLParams',                                                                        
  │   │   │   │   │   kappa_order=3,                                                                           
  │   │   │   │   │   kappa_min=1.0,                                                                           
  │   │   │   │   │   kappa_max=3.0,                                                                           
  │   │   │   │   │   alpha_order=1,                                                                           
  │   │   │   │   │   alpha_min=0.0,                                                                           
  │   │   │   │   │   alpha_max=0.0                                                                            
  │   │   │   │   )                                                                                            
  │   │   │   ),                                                                                               
  │   │   │   minus=PML(                                                                                       
  │   │   │   │   name=None,                                                                                   
  │   │   │   │   type='PML',                                                                                  
  │   │   │   │   num_layers=12,                                                                               
  │   │   │   │   parameters=PMLParams(                                                                        
  │   │   │   │   │   sigma_order=3,                                                                           
  │   │   │   │   │   sigma_min=0.0,                                                                           
  │   │   │   │   │   sigma_max=1.5,                                                                           
  │   │   │   │   │   type='PMLParams',                                                                        
  │   │   │   │   │   kappa_order=3,                                                                           
  │   │   │   │   │   kappa_min=1.0,                                                                           
  │   │   │   │   │   kappa_max=3.0,                                                                           
  │   │   │   │   │   alpha_order=1,                                                                           
  │   │   │   │   │   alpha_min=0.0,                                                                           
  │   │   │   │   │   alpha_max=0.0                                                                            
  │   │   │   │   )                                                                                            
  │   │   │   ),                                                                                               
  │   │   │   type='Boundary'                                                                                  
  │   │   ),                                                                                                   
  │   │   z=Boundary(                                                                                          
  │   │   │   plus=Periodic(name=None, type='Periodic'),                                                       
  │   │   │   minus=Periodic(name=None, type='Periodic'),                                                      
  │   │   │   type='Boundary'                                                                                  
  │   │   ),                                                                                                   
  │   │   type='BoundarySpec'                                                                                  
  ),                                                                                                       
  monitors=(                                                                                               
  │   │   FieldMonitor(                                                                                        
  │   │   │   type='FieldMonitor',                                                                             
  │   │   │   center=(1.0, 0.0, 0.0),                                                                          
  │   │   │   size=(inf, inf, 0.0),                                                                            
  │   │   │   name='fields_at_150THz',                                                                         
  │   │   │   freqs=(150000000000000.0,),                                                                      
  │   │   │   apodization=ApodizationSpec(start=None, end=None, width=None, type='ApodizationSpec'),           
  │   │   │   fields=('Ex', 'Ey', 'Hz'),                                                                       
  │   │   │   interval_space=(1, 1, 1),                                                                        
  │   │   │   colocate=False                                                                                   
  │   │   ),                                                                                                   
  │   │   FluxTimeMonitor(                                                                                     
  │   │   │   type='FluxTimeMonitor',                                                                          
  │   │   │   center=(1.0, 0.0, 0.0),                                                                          
  │   │   │   size=(inf, inf, 0.0),                                                                            
  │   │   │   name='flux_over_time',                                                                           
  │   │   │   start=1e-13,                                                                                     
  │   │   │   stop=3e-13,                                                                                      
  │   │   │   interval=5,                                                                                      
  │   │   │   normal_dir='+',                                                                                  
  │   │   │   exclude_surfaces=None                                                                            
  │   │   )                                                                                                    
  ),                                                                                                       
  grid_spec=GridSpec(                                                                                      
  │   │   grid_x=UniformGrid(type='UniformGrid', dl=0.2),                                                      
  │   │   grid_y=UniformGrid(type='UniformGrid', dl=0.2),                                                      
  │   │   grid_z=UniformGrid(type='UniformGrid', dl=0.2),                                                      
  │   │   wavelength=None,                                                                                     
  │   │   override_structures=(),                                                                              
  │   │   type='GridSpec'                                                                                      
  ),                                                                                                       
  shutoff=1e-05,                                                                                           
  subpixel=True,                                                                                           
  normalize_index=0,                                                                                       
  courant=0.99,                                                                                            
  version='1.9.0rc2'                                                                                       
  )                                                                                                            
 ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ 
                                                                                                                 
 background_structure = Structure(                                                                               
                            geometry=Box(type='Box', center=(0.0, 0.0, 0.0), size=(inf, inf, inf)),              
                            name=None,                                                                           
                            type='Structure',                                                                    
                            medium=Medium(                                                                       
                                name=None,                                                                       
                                frequency_range=None,                                                            
                                type='Medium',                                                                   
                                permittivity=1.0,                                                                
                                conductivity=0.0                                                                 
                            )                                                                                    
                        )                                                                                        
        boundary_spec = BoundarySpec(                                                                            
                            x=Boundary(                                                                          
                                plus=Periodic(name=None, type='Periodic'),                                       
                                minus=Periodic(name=None, type='Periodic'),                                      
                                type='Boundary'                                                                  
                            ),                                                                                   
                            y=Boundary(                                                                          
                                plus=PML(                                                                        
                                    name=None,                                                                   
                                    type='PML',                                                                  
                                    num_layers=12,                                                               
                                    parameters=PMLParams(                                                        
                                        sigma_order=3,                                                           
                                        sigma_min=0.0,                                                           
                                        sigma_max=1.5,                                                           
                                        type='PMLParams',                                                        
                                        kappa_order=3,                                                           
                                        kappa_min=1.0,                                                           
                                        kappa_max=3.0,                                                           
                                        alpha_order=1,                                                           
                                        alpha_min=0.0,                                                           
                                        alpha_max=0.0                                                            
                                    )                                                                            
                                ),                                                                               
                                minus=PML(                                                                       
                                    name=None,                                                                   
                                    type='PML',                                                                  
                                    num_layers=12,                                                               
                                    parameters=PMLParams(                                                        
                                        sigma_order=3,                                                           
                                        sigma_min=0.0,                                                           
                                        sigma_max=1.5,                                                           
                                        type='PMLParams',                                                        
                                        kappa_order=3,                                                           
                                        kappa_min=1.0,                                                           
                                        kappa_max=3.0,                                                           
                                        alpha_order=1,                                                           
                                        alpha_min=0.0,                                                           
                                        alpha_max=0.0                                                            
                                    )                                                                            
                                ),                                                                               
                                type='Boundary'                                                                  
                            ),                                                                                   
                            z=Boundary(                                                                          
                                plus=Periodic(name=None, type='Periodic'),                                       
                                minus=Periodic(name=None, type='Periodic'),                                      
                                type='Boundary'                                                                  
                            ),                                                                                   
                            type='BoundarySpec'                                                                  
                        )                                                                                        
         bounding_box = Box(type='Box', center=(0.0, 0.0, 0.0), size=(4.0, 4.0, 4.0))                            
               bounds = ((-2.0, -2.0, -2.0), (2.0, 2.0, 2.0))                                                    
           bounds_pml = ((-2.0, -4.3999999999999995, -2.0), (2.0, 4.399999999999997, 2.0))                       
               center = (0.0, 0.0, 0.0)                                                                          
       complex_fields = False                                                                                    
              courant = 0.99                                                                                     
      custom_datasets = []                                                                                       
                   dt = 3.8131497373958257e-16                                                                   
      frequency_range = (110000000000000.0, 190000000000000.0)                                                   
             geometry = Box(type='Box', center=(0.0, 0.0, 0.0), size=(4.0, 4.0, 4.0))                            
                 grid = Grid(                                                                                    
                            boundaries=Coords(                                                                   
                                x=(                                                                              
                                    -2.0,                                                                        
                                    -1.8,                                                                        
                                    -1.6,                                                                        
                                    -1.4,                                                                        
                                    -1.2,                                                                        
                                    -1.0,                                                                        
                                    -0.7999999999999998,                                                         
                                    -0.5999999999999999,                                                         
                                    -0.3999999999999999,                                                         
                                    -0.19999999999999996,                                                        
                                    0.0,                                                                         
                                    0.20000000000000018,                                                         
                                    0.40000000000000036,                                                         
                                    0.6000000000000001,                                                          
                                    0.8000000000000003,                                                          
                                    1.0,                                                                         
                                    1.2000000000000002,                                                          
                                    1.4000000000000004,                                                          
                                    1.6,                                                                         
                                    1.8000000000000003,                                                          
                                    2.0                                                                          
                                ),                                                                               
                                y=(                                                                              
                                    -4.3999999999999995,                                                         
                                    -4.199999999999999,                                                          
                                    -3.9999999999999996,                                                         
                                    -3.8,                                                                        
                                    -3.5999999999999996,                                                         
                                    -3.3999999999999995,                                                         
                                    -3.1999999999999997,                                                         
                                    -3.0,                                                                        
                                    -2.8,                                                                        
                                    -2.5999999999999996,                                                         
                                    -2.4,                                                                        
                                    -2.2,                                                                        
                                    -2.0,                                                                        
                                    -1.8,                                                                        
                                    -1.6,                                                                        
                                    -1.4,                                                                        
                                    -1.2,                                                                        
                                    -1.0,                                                                        
                                    -0.7999999999999998,                                                         
                                    -0.5999999999999999,                                                         
                                    -0.3999999999999999,                                                         
                                    -0.19999999999999996,                                                        
                                    0.0,                                                                         
                                    0.20000000000000018,                                                         
                                    0.40000000000000036,                                                         
                                    0.6000000000000001,                                                          
                                    0.8000000000000003,                                                          
                                    1.0,                                                                         
                                    1.2000000000000002,                                                          
                                    1.4000000000000004,                                                          
                                    1.6,                                                                         
                                    1.8000000000000003,                                                          
                                    2.0,                                                                         
                                    2.1999999999999997,                                                          
                                    2.3999999999999995,                                                          
                                    2.599999999999999,                                                           
                                    2.799999999999999,                                                           
                                    2.9999999999999987,                                                          
                                    3.1999999999999984,                                                          
                                    3.399999999999998,                                                           
                                    3.599999999999998,                                                           
                                    3.7999999999999976,                                                          
                                    3.9999999999999973,                                                          
                                    4.1999999999999975,                                                          
                                    4.399999999999997                                                            
                                ),                                                                               
                                z=(                                                                              
                                    -2.0,                                                                        
                                    -1.8,                                                                        
                                    -1.6,                                                                        
                                    -1.4,                                                                        
                                    -1.2,                                                                        
                                    -1.0,                                                                        
                                    -0.7999999999999998,                                                         
                                    -0.5999999999999999,                                                         
                                    -0.3999999999999999,                                                         
                                    -0.19999999999999996,                                                        
                                    0.0,                                                                         
                                    0.20000000000000018,                                                         
                                    0.40000000000000036,                                                         
                                    0.6000000000000001,                                                          
                                    0.8000000000000003,                                                          
                                    1.0,                                                                         
                                    1.2000000000000002,                                                          
                                    1.4000000000000004,                                                          
                                    1.6,                                                                         
                                    1.8000000000000003,                                                          
                                    2.0                                                                          
                                ),                                                                               
                                type='Coords'                                                                    
                            ),                                                                                   
                            type='Grid'                                                                          
                        )                                                                                        
            grid_spec = GridSpec(                                                                                
                            grid_x=UniformGrid(type='UniformGrid', dl=0.2),                                      
                            grid_y=UniformGrid(type='UniformGrid', dl=0.2),                                      
                            grid_z=UniformGrid(type='UniformGrid', dl=0.2),                                      
                            wavelength=None,                                                                     
                            override_structures=(),                                                              
                            type='GridSpec'                                                                      
                        )                                                                                        
               medium = Medium(                                                                                  
                            name=None,                                                                           
                            frequency_range=None,                                                                
                            type='Medium',                                                                       
                            permittivity=1.0,                                                                    
                            conductivity=0.0                                                                     
                        )                                                                                        
           medium_map = {                                                                                        
                            Medium(name=None, frequency_range=None, type='Medium', permittivity=1.0,             
                        conductivity=0.0): 0,                                                                    
                            Medium(name=None, frequency_range=None, type='Medium', permittivity=2.0,             
                        conductivity=0.0): 1                                                                     
                        }                                                                                        
              mediums = [                                                                                        
                            Medium(                                                                              
                                name=None,                                                                       
                                frequency_range=None,                                                            
                                type='Medium',                                                                   
                                permittivity=1.0,                                                                
                                conductivity=0.0                                                                 
                            ),                                                                                   
                            Medium(                                                                              
                                name=None,                                                                       
                                frequency_range=None,                                                            
                                type='Medium',                                                                   
                                permittivity=2.0,                                                                
                                conductivity=0.0                                                                 
                            )                                                                                    
                        ]                                                                                        
             monitors = (                                                                                        
                            FieldMonitor(                                                                        
                                type='FieldMonitor',                                                             
                                center=(1.0, 0.0, 0.0),                                                          
                                size=(inf, inf, 0.0),                                                            
                                name='fields_at_150THz',                                                         
                                freqs=(150000000000000.0,),                                                      
                                apodization=ApodizationSpec(                                                     
                                    start=None,                                                                  
                                    end=None,                                                                    
                                    width=None,                                                                  
                                    type='ApodizationSpec'                                                       
                                ),                                                                               
                                fields=('Ex', 'Ey', 'Hz'),                                                       
                                interval_space=(1, 1, 1),                                                        
                                colocate=False                                                                   
                            ),                                                                                   
                            FluxTimeMonitor(                                                                     
                                type='FluxTimeMonitor',                                                          
                                center=(1.0, 0.0, 0.0),                                                          
                                size=(inf, inf, 0.0),                                                            
                                name='flux_over_time',                                                           
                                start=1e-13,                                                                     
                                stop=3e-13,                                                                      
                                interval=5,                                                                      
                                normal_dir='+',                                                                  
                                exclude_surfaces=None                                                            
                            )                                                                                    
                        )                                                                                        
      normalize_index = 0                                                                                        
            num_cells = 17600                                                                                    
       num_pml_layers = [[0, 0], [12, 12], [0, 0]]                                                               
       num_time_steps = 2624                                                                                     
         nyquist_step = 5                                                                                        
          plot_params = PlotParams(                                                                              
                            alpha=1.0,                                                                           
                            edgecolor=None,                                                                      
                            facecolor=None,                                                                      
                            fill=True,                                                                           
                            hatch=None,                                                                          
                            linewidth=1.0,                                                                       
                            type='PlotParams'                                                                    
                        )                                                                                        
      pml_thicknesses = [(0.0, 0.0), (2.3999999999999995, 2.399999999999997), (0.0, 0.0)]                        
             run_time = 1e-12                                                                                    
              shutoff = 1e-05                                                                                    
  simulation_geometry = Box(                                                                                     
                            type='Box',                                                                          
                            center=(0.0, -1.3322676295501878e-15, 0.0),                                          
                            size=(4.0, 8.799999999999997, 4.0)                                                   
                        )                                                                                        
                 size = (4.0, 4.0, 4.0)                                                                          
              sources = (                                                                                        
                            UniformCurrentSource(                                                                
                                type='UniformCurrentSource',                                                     
                                center=(0.0, 0.0, 0.0),                                                          
                                size=(0.0, 0.0, 0.0),                                                            
                                source_time=GaussianPulse(                                                       
                                    amplitude=1.0,                                                               
                                    phase=0.0,                                                                   
                                    type='GaussianPulse',                                                        
                                    freq0=150000000000000.0,                                                     
                                    fwidth=10000000000000.0,                                                     
                                    offset=5.0                                                                   
                                ),                                                                               
                                name=None,                                                                       
                                polarization='Ez'                                                                
                            ),                                                                                   
                        )                                                                                        
           structures = (                                                                                        
                            Structure(                                                                           
                                geometry=Box(type='Box', center=(0.0, 0.0, 0.0), size=(1.0, 1.0, 1.0)),          
                                name=None,                                                                       
                                type='Structure',                                                                
                                medium=Medium(                                                                   
                                    name=None,                                                                   
                                    frequency_range=None,                                                        
                                    type='Medium',                                                               
                                    permittivity=2.0,                                                            
                                    conductivity=0.0                                                             
                                )                                                                                
                            ),                                                                                   
                        )                                                                                        
             subpixel = True                                                                                     
             symmetry = (0, 0, 0)                                                                                
                tmesh = array([0.00000000e+00, 3.81314974e-16, 7.62629947e-16, ...,                              
                               9.99426546e-13, 9.99807861e-13, 1.00018918e-12])                                  
                 type = 'Simulation'                                                                             
              version = '1.9.0rc2'                                                                               
          wvl_mat_min = 1.413235200620076                                                                        
            zero_dims = []                                                                                       
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

Monitor Data#

Data for each monitor is stored as its own td.MonitorData instance.

Whereas before we needed to access data using sim.data(monitor), now we can access the data by monitor.name from the SimulationData using square brackets.

The data are stored as xarray objects, which means they work similar to numpy arrays but provide many additional useful features. For more details refer to the tutorial on data visualization.

[22]:
flux_data = sim_data["flux_over_time"].flux
flux_data.plot()
plt.title("flux over time")
plt.show()

../_images/notebooks_WhatsNew_46_0.png

For field data, we can further index by fields specified in the monitor, as follows.

[23]:
Ey = sim_data["fields_at_150THz"].Ey

Ey.real.plot(x="x", y="y", robust=True)
plt.title("real{Ey(x, y)}")
plt.show()

../_images/notebooks_WhatsNew_48_0.png

Finally, SimulationData provides a method for potting field data with structure overlay, similar to sim.viz_fields2D().

[24]:
sim_data.plot_field("fields_at_150THz", "Ey", val="real")
plt.show()

../_images/notebooks_WhatsNew_50_0.png

Plugins#

Here we will discuss the plugins that support and extend functionalities of Tidy3D, including:

These plugins are designed to import and make use of Tidy3D components described above, but the Tidy3D components have no dependence on the plugins by design. In this sense, they can be considered “external” packages that are useful for defining simulation components.

We won’t go into the details in this notebook as each of the plugins has its own example tutorial notebook.

Dispersion Fitting#

We provide a tool for fitting optical data to create dispersive mediums.

Given a file or arrays containing wavelength, n, and (optionally) k data, this tool will fit the data to a pole-residue model with some constraints and parameters.

After fitting, the user can visualize and inspect the results.

This process can be repeated until the user is satisfied, at which point the tool can return a dispersive medium for use in the Simulation.

Mode Solver#

The mode solver is a similar tool for coming up with ModeSpec objects for a given source or monitor.

The tool takes a reference simulation containing some waveguide or other structure definitions to feed to the core solver. It also requires a Box specifying the plane on which to solve the modes for.

Then, the user can iteratively send different ModeSpec objects, solve for the results, visulize, and repeat the process until satisfied.

The resulting ModeSpec can be saved directly, or used in conjunction with the mode solver settings to return a ModeSource or [ModeMonitor]((https://docs.flexcompute.com/projects/tidy3d/en/v1.9.0rc2/_autosummary/tidy3d.ModeMonitor.html).

Near2Far#

Finally, the near field to far field transformation tool is used to transform FieldMonitor data to far field data or scattering cross section data.

The user specifies a the frequency-domain field data to use as near field source, these fields are converted to equivalent surface currents, and a computation is performed to give the radiation vectors emanating from the monitor location.

Then, the user can obtain the field patterns or scattered power as a function of position or angle using the various projection methods.

Conclusion#

We hope this gives a useful overview of the main changes in the revamped version of Tidy3D.

We highly recommend you check out the various tutorial notebooks if you have more specific questions or want to dive deeper in any of the topics.

[ ]:

[ ]: