Tidy3D first walkthrough#

Our first tutorial focuses on illustrating the basic setup, run, and analysis of a Tidy3D simulation. In this example, we will simulate a plane wave impinging on dielectric slab with a triangular pillar made of a lossy dielectric sitting on top. First, we import everything needed.

[1]:
# standard python imports
import h5py
import matplotlib.pyplot as plt
import numpy as np

# tidy3d imports
import tidy3d as td
from tidy3d import web

We begin by initializing general simulation parameters. To streamline the setup and management of frequency-related values, we use the convenience class FreqRange.

Note that the perfectly matched layer (PML) regions extend outside the user-defined simulation domain. As a result, the total computational domain is larger than the specified simulation region—unlike in some solvers where the PML occupies a portion of the domain itself.

[2]:
# Simulation domain size (in micron)
sim_size = [4, 4, 4]

# Central frequency and bandwidth of pulsed excitation, in Hz
freq0 = 2e14
fwidth = 1e13

# set frequency range
freq_range = td.FreqRange(freq0=freq0, fwidth=fwidth)

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

The run time of a simulation depends a lot on whether there are any long-lived resonances. In our example here, there is no strong resonance. Thus, we do not need to run the simulation much longer than after the sources have decayed. We thus set the run time based on the source bandwidth.

[3]:
# Total time to run in seconds
run_time = 2 / fwidth

Structures and materials#

Next, we initialize the simulated structure. The structure consists of two Structure objects. Each object consists of a Geometry and a Medium to define the spatial extent and material properties, respectively. Note that the size of any object (structure, source, or monitor) can extend beyond the simulation domain, and is truncated at the edges of that domain.

Note: For best results, structures that intersect with the PML or simulation edges should extend extend all the way through. In many such cases, an “infinite” size td.inf can be used to define the size along that dimension.

[4]:
# Lossless dielectric specified directly using relative permittivity
material1 = td.Medium(permittivity=6.0)

# Lossy dielectric defined from the real and imaginary part of the refractive index
material2 = td.Medium.from_nk(n=1.5, k=0.0, freq=freq_range.freq0)
# material2 = td.Medium(permittivity=2.)


# Rectangular slab, extending infinitely in x and y with medium `material1`
box = td.Structure(geometry=td.Box(center=[0, 0, 0], size=[td.inf, td.inf, 1]), medium=material1)

# Triangle in the xy-plane with a finite extent in z
equi_tri_verts = [[-1 / 2, -1 / 4], [1 / 2, -1 / 4], [0, np.sqrt(3) / 2 - 1 / 4]]

poly = td.Structure(
    geometry=td.PolySlab(
        vertices=(2 * np.array(equi_tri_verts)).tolist(),
        # vertices=equi_tri_verts,
        slab_bounds=(0.5, 1.0),
        axis=2,
    ),
    medium=material2,
)

Sources#

Next, we define a source injecting a normal-incidence plane-wave from above. The time dependence of the source is a Gaussian pulse. A source can be added to multiple simulations. After we add the source to a specific simulation, such that the total run time is known, we can use in-built plotting tools to visualize its time- and frequency-dependence, which we will show below.

[5]:
psource = td.PlaneWave(
    center=(0, 0, 1.5),
    direction="-",
    size=(td.inf, td.inf, 0),
    source_time=freq_range.to_gaussian_pulse(),
    pol_angle=np.pi / 2,
)

Monitors#

Finally, we can also add some monitors that will record the fields that we request during the simulation run.

The two monitor types for measuring fields are FieldMonitor and FieldTimeMonitor, which record the frequency-domain and time-domain fields, respectively.

FieldMonitor objects operate by running a discrete Fourier transform of the fields at a given set of frequencies to perform the calculation “in-place” with the time stepping. FieldMonitor objects are useful for investigating the steady-state field distribution in 2D or even 3D regions of the simulation.

FieldTimeMonitor objects are best used to monitor the time dependence of the fields at a single point, but they can also be used to create “animations” of the field pattern evolution. Because spatially large FieldMonitor objects can lead to a very large amount of data that needs to be stored, an optional start and stop time can be supplied, as well as an interval specifying the amount of time steps between each measurement (default of 1).

[6]:
# measure time domain fields at center location, measure every 5 time steps
time_mnt = td.FieldTimeMonitor(center=[0, 0, 0], size=[0, 0, 0], interval=5, name="field_time")

# measure the steady state fields at central frequency in the xy plane and the xz plane.
freq_mnt1 = td.FieldMonitor(
    center=[0, 0, -1], size=[20, 20, 0], freqs=freq_range.freqs(num_points=1), name="field1"
)
freq_mnt2 = td.FieldMonitor(
    center=[0, 0, 0], size=[20, 0, 20], freqs=freq_range.freqs(num_points=1), name="field2"
)

Simulation#

Now we can initialize the Simulation with all the elements defined above. A nonuniform simulation grid is generated automatically based on a given minimum number of cells per wavelength in each material (10 by default), using the frequencies defined in the source.

Tidy3D uses a hybrid floating-point precision by default as it is practically sufficient in almost all cases, double precision should only be explored in large simulations when very high accuracy is desired. Even then, it might not have a noticeable effect over other sources of numerical error like the finite grid. As this is a small example with a minimal cost, we will simply demonstrate you can leverage this option depending on your simulation goals.

[7]:
# Initialize simulation
sim = td.Simulation(
    size=sim_size,
    grid_spec=td.GridSpec.auto(min_steps_per_wvl=20),
    structures=[box, poly],
    sources=[psource],
    monitors=[time_mnt, freq_mnt1, freq_mnt2],
    run_time=run_time,
    boundary_spec=boundary_spec,
    precision="double",
)

We can check the simulation monitors just to make sure everything looks right.

[8]:
for m in sim.monitors:
    m.help()
╭───────────────────────────── <class 'tidy3d.components.monitor.FieldTimeMonitor'> ──────────────────────────────╮
 class FieldTimeMonitor(*, attrs: dict = <factory>, type: Literal['FieldTimeMonitor'] = 'FieldTimeMonitor',      
 center: typing.Annotated[tuple[typing.Annotated[object, BeforeValidator(func=<function                          
 traced_alias.<locals>._validate_box_or_container at 0x7f64651faca0>, json_schema_input_type=PydanticUndefined), 
 PlainSerializer(func=<function traced_alias.<locals>._serialize_traced at 0x7f64651fad40>,                      
 return_type=PydanticUndefined, when_used='json'), <tidy3d.components.autograd.types._TracedAliasJsonSchema      
 object at 0x7f646522c710>], typing.Annotated[object, BeforeValidator(func=<function                             
 traced_alias.<locals>._validate_box_or_container at 0x7f64651faca0>, json_schema_input_type=PydanticUndefined), 
 PlainSerializer(func=<function traced_alias.<locals>._serialize_traced at 0x7f64651fad40>,                      
 return_type=PydanticUndefined, when_used='json'), <tidy3d.components.autograd.types._TracedAliasJsonSchema      
 object at 0x7f646522c710>], typing.Annotated[object, BeforeValidator(func=<function                             
 traced_alias.<locals>._validate_box_or_container at 0x7f64651faca0>, json_schema_input_type=PydanticUndefined), 
 PlainSerializer(func=<function traced_alias.<locals>._serialize_traced at 0x7f64651fad40>,                      
 return_type=PydanticUndefined, when_used='json'), <tidy3d.components.autograd.types._TracedAliasJsonSchema      
 object at 0x7f646522c710>]], WithJsonSchema(json_schema={'type': 'array', 'minItems': 3, 'maxItems': 3,         
 'prefixItems': [{'type': 'number'}, {'type': 'number'}, {'type': 'number'}]}, mode=None)] = (0.0, 0.0, 0.0),    
 size: typing.Annotated[tuple[typing.Annotated[object, BeforeValidator(func=<function                            
 traced_alias.<locals>._validate_box_or_container at 0x7f64651fac00>, json_schema_input_type=PydanticUndefined), 
 PlainSerializer(func=<function traced_alias.<locals>._serialize_traced at 0x7f64651fa7a0>,                      
 return_type=PydanticUndefined, when_used='json'), <tidy3d.components.autograd.types._TracedAliasJsonSchema      
 object at 0x7f6465215150>], typing.Annotated[object, BeforeValidator(func=<function                             
 traced_alias.<locals>._validate_box_or_container at 0x7f64651fac00>, json_schema_input_type=PydanticUndefined), 
 PlainSerializer(func=<function traced_alias.<locals>._serialize_traced at 0x7f64651fa7a0>,                      
 return_type=PydanticUndefined, when_used='json'), <tidy3d.components.autograd.types._TracedAliasJsonSchema      
 object at 0x7f6465215150>], typing.Annotated[object, BeforeValidator(func=<function                             
 traced_alias.<locals>._validate_box_or_container at 0x7f64651fac00>, json_schema_input_type=PydanticUndefined), 
 PlainSerializer(func=<function traced_alias.<locals>._serialize_traced at 0x7f64651fa7a0>,                      
 return_type=PydanticUndefined, when_used='json'), <tidy3d.components.autograd.types._TracedAliasJsonSchema      
 object at 0x7f6465215150>]], WithJsonSchema(json_schema={'type': 'array', 'minItems': 3, 'maxItems': 3,         
 'prefixItems': [{'minimum': 0, 'type': 'number'}, {'minimum': 0, 'type': 'number'}, {'minimum': 0, 'type':      
 'number'}]}, mode=None)], name: typing.Annotated[str, MinLen(min_length=1)], interval_space:                    
 tuple[typing.Annotated[int, Gt(gt=0)], typing.Annotated[int, Gt(gt=0)], typing.Annotated[int, Gt(gt=0)]] = (1,  
 1, 1), colocate: bool = True, use_colocated_integration: bool = True, start: typing.Annotated[float, Ge(ge=0)]  
 = 0.0, stop: Optional[Annotated[float, Ge(ge=0)]] = None, interval: Optional[Annotated[int, Gt(gt=0)]] = None,  
 fields: tuple[typing.Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'], ...] = ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'])  
 -> None:                                                                                                        
                                                                                                                 
 :class:`~tidy3d.Monitor` that records electromagnetic fields in the time domain.                                
                                                                                                                 
          bounding_box = <property object at 0x7f6464ba8720>                                                     
                bounds = <property object at 0x7f6465228db0>                                                     
              geometry = <property object at 0x7f6457c68130>                                                     
 model_computed_fields = {}                                                                                      
          model_config = {                                                                                       
                             'arbitrary_types_allowed': True,                                                    
                             'defer_build': True,                                                                
                             'validate_default': True,                                                           
                             'populate_by_name': True,                                                           
                             'ser_json_inf_nan': 'strings',                                                      
                             'extra': 'forbid',                                                                  
                             'frozen': True,                                                                     
                             'validate_by_alias': True,                                                          
                             'validate_by_name': True                                                            
                         }                                                                                       
           model_extra = <property object at 0x7f6465a94b80>                                                     
          model_fields = {                                                                                       
                             'attrs': FieldInfo(                                                                 
                                 annotation=dict,                                                                
                                 required=False,                                                                 
                                 default_factory=dict,                                                           
                                 title='Attributes',                                                             
                                 description="Dictionary storing arbitrary metadata for a Tidy3D object. This    
                         dictionary can be freely used by the user for storing data without affecting the        
                         operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D      
                         fields, ``attrs`` are mutable. For example, the following is allowed for setting an     
                         ``attr`` ``obj.attrs['foo'] = bar``. Also note that Tidy3D will raise a ``TypeError``   
                         if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are 
                         serializable by calling ``obj.model_dump_json()``."                                     
                             ),                                                                                  
                             'type': FieldInfo(                                                                  
                                 annotation=Literal['FieldTimeMonitor'],                                         
                                 required=False,                                                                 
                                 default='FieldTimeMonitor'                                                      
                             ),                                                                                  
                             'center': FieldInfo(                                                                
                                 annotation=tuple[Annotated[object, BeforeValidator, PlainSerializer,            
                         _TracedAliasJsonSchema], Annotated[object, BeforeValidator, PlainSerializer,            
                         _TracedAliasJsonSchema], Annotated[object, BeforeValidator, PlainSerializer,            
                         _TracedAliasJsonSchema]],                                                               
                                 required=False,                                                                 
                                 default=(0.0, 0.0, 0.0),                                                        
                                 title='Center',                                                                 
                                 description='Center of object in x, y, and z.',                                 
                                 json_schema_extra={'units': 'um'},                                              
                                 metadata=[                                                                      
                                     WithJsonSchema(                                                             
                                         json_schema={                                                           
                                             'type': 'array',                                                    
                                             'minItems': 3,                                                      
                                             'maxItems': 3,                                                      
                                             'prefixItems': [                                                    
                                                 {'type': 'number'},                                             
                                                 {'type': 'number'},                                             
                                                 {'type': 'number'}                                              
                                             ]                                                                   
                                         },                                                                      
                                         mode=None                                                               
                                     )                                                                           
                                 ]                                                                               
                             ),                                                                                  
                             'size': FieldInfo(                                                                  
                                 annotation=tuple[Annotated[object, BeforeValidator, PlainSerializer,            
                         _TracedAliasJsonSchema], Annotated[object, BeforeValidator, PlainSerializer,            
                         _TracedAliasJsonSchema], Annotated[object, BeforeValidator, PlainSerializer,            
                         _TracedAliasJsonSchema]],                                                               
                                 required=True,                                                                  
                                 title='Size',                                                                   
                                 description='Size in x, y, and z directions.',                                  
                                 json_schema_extra={'units': 'um'},                                              
                                 metadata=[                                                                      
                                     WithJsonSchema(                                                             
                                         json_schema={                                                           
                                             'type': 'array',                                                    
                                             'minItems': 3,                                                      
                                             'maxItems': 3,                                                      
                                             'prefixItems': [                                                    
                                                 {'minimum': 0, 'type': 'number'},                               
                                                 {'minimum': 0, 'type': 'number'},                               
                                                 {'minimum': 0, 'type': 'number'}                                
                                             ]                                                                   
                                         },                                                                      
                                         mode=None                                                               
                                     )                                                                           
                                 ]                                                                               
                             ),                                                                                  
                             'name': FieldInfo(                                                                  
                                 annotation=str,                                                                 
                                 required=True,                                                                  
                                 title='Name',                                                                   
                                 description='Unique name for monitor.',                                         
                                 metadata=[MinLen(min_length=1)]                                                 
                             ),                                                                                  
                             'interval_space': FieldInfo(                                                        
                                 annotation=tuple[Annotated[int, Gt], Annotated[int, Gt], Annotated[int, Gt]],   
                                 required=False,                                                                 
                                 default=(1, 1, 1),                                                              
                                 title='Spatial Interval',                                                       
                                 description='Number of grid step intervals between monitor recordings. If equal 
                         to 1, there will be no downsampling. If greater than 1, the step will be applied, but   
                         the first and last point of the monitor grid are always included.'                      
                             ),                                                                                  
                             'colocate': FieldInfo(                                                              
                                 annotation=bool,                                                                
                                 required=False,                                                                 
                                 default=True,                                                                   
                                 title='Colocate Fields',                                                        
                                 description='Toggle whether fields should be colocated to grid cell boundaries  
                         (i.e. primal grid nodes).'                                                              
                             ),                                                                                  
                             'use_colocated_integration': FieldInfo(                                             
                                 annotation=bool,                                                                
                                 required=False,                                                                 
                                 default=True,                                                                   
                                 title='Use Colocated Integration',                                              
                                 description='Only takes effect when ``colocate=False``. If ``True``, flux, dot  
                         products, and overlap integrals still use fields interpolated to grid cell boundaries   
                         (colocated), even though the field data is stored at native Yee grid positions.         
                         Experimental feature that can give improved accuracy by avoiding interpolation of       
                         fields to Yee cell positions for integration.'                                          
                             ),                                                                                  
                             'start': FieldInfo(                                                                 
                                 annotation=float,                                                               
                                 required=False,                                                                 
                                 default=0.0,                                                                    
                                 title='Start Time',                                                             
                                 description='Time at which to start monitor recording.',                        
                                 json_schema_extra={'units': 'sec'},                                             
                                 metadata=[Ge(ge=0)]                                                             
                             ),                                                                                  
                             'stop': FieldInfo(                                                                  
                                 annotation=Union[Annotated[float, Ge], NoneType],                               
                                 required=False,                                                                 
                                 default=None,                                                                   
                                 title='Stop Time',                                                              
                                 description='Time at which to stop monitor recording.  If not specified, record 
                         until end of simulation.',                                                              
                                 json_schema_extra={'units': 'sec'}                                              
                             ),                                                                                  
                             'interval': FieldInfo(                                                              
                                 annotation=Union[Annotated[int, Gt], NoneType],                                 
                                 required=False,                                                                 
                                 default=None,                                                                   
                                 title='Time Interval',                                                          
                                 description='Sampling rate of the monitor: number of time steps between each    
                         measurement. Set ``interval`` to 1 for the highest possible resolution in time. Higher  
                         integer values downsample the data by measuring every ``interval`` time steps. This can 
                         be useful for reducing data storage as needed by the application.'                      
                             ),                                                                                  
                             'fields': FieldInfo(                                                                
                                 annotation=tuple[Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'], ...],             
                                 required=False,                                                                 
                                 default=['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'],                                   
                                 title='Field Components',                                                       
                                 description='Collection of field components to store in the monitor.'           
                             )                                                                                   
                         }                                                                                       
      model_fields_set = <property object at 0x7f64653611c0>                                                     
           plot_params = <property object at 0x7f6457c680e0>                                                     
             zero_dims = <property object at 0x7f6464951d00>                                                     
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─────────────────────────────── <class 'tidy3d.components.monitor.FieldMonitor'> ────────────────────────────────╮
 class FieldMonitor(*, attrs: dict = <factory>, type: Literal['FieldMonitor'] = 'FieldMonitor', center:          
 typing.Annotated[tuple[typing.Annotated[object, BeforeValidator(func=<function                                  
 traced_alias.<locals>._validate_box_or_container at 0x7f64651faca0>, json_schema_input_type=PydanticUndefined), 
 PlainSerializer(func=<function traced_alias.<locals>._serialize_traced at 0x7f64651fad40>,                      
 return_type=PydanticUndefined, when_used='json'), <tidy3d.components.autograd.types._TracedAliasJsonSchema      
 object at 0x7f646522c710>], typing.Annotated[object, BeforeValidator(func=<function                             
 traced_alias.<locals>._validate_box_or_container at 0x7f64651faca0>, json_schema_input_type=PydanticUndefined), 
 PlainSerializer(func=<function traced_alias.<locals>._serialize_traced at 0x7f64651fad40>,                      
 return_type=PydanticUndefined, when_used='json'), <tidy3d.components.autograd.types._TracedAliasJsonSchema      
 object at 0x7f646522c710>], typing.Annotated[object, BeforeValidator(func=<function                             
 traced_alias.<locals>._validate_box_or_container at 0x7f64651faca0>, json_schema_input_type=PydanticUndefined), 
 PlainSerializer(func=<function traced_alias.<locals>._serialize_traced at 0x7f64651fad40>,                      
 return_type=PydanticUndefined, when_used='json'), <tidy3d.components.autograd.types._TracedAliasJsonSchema      
 object at 0x7f646522c710>]], WithJsonSchema(json_schema={'type': 'array', 'minItems': 3, 'maxItems': 3,         
 'prefixItems': [{'type': 'number'}, {'type': 'number'}, {'type': 'number'}]}, mode=None)] = (0.0, 0.0, 0.0),    
 size: typing.Annotated[tuple[typing.Annotated[object, BeforeValidator(func=<function                            
 traced_alias.<locals>._validate_box_or_container at 0x7f64651fac00>, json_schema_input_type=PydanticUndefined), 
 PlainSerializer(func=<function traced_alias.<locals>._serialize_traced at 0x7f64651fa7a0>,                      
 return_type=PydanticUndefined, when_used='json'), <tidy3d.components.autograd.types._TracedAliasJsonSchema      
 object at 0x7f6465215150>], typing.Annotated[object, BeforeValidator(func=<function                             
 traced_alias.<locals>._validate_box_or_container at 0x7f64651fac00>, json_schema_input_type=PydanticUndefined), 
 PlainSerializer(func=<function traced_alias.<locals>._serialize_traced at 0x7f64651fa7a0>,                      
 return_type=PydanticUndefined, when_used='json'), <tidy3d.components.autograd.types._TracedAliasJsonSchema      
 object at 0x7f6465215150>], typing.Annotated[object, BeforeValidator(func=<function                             
 traced_alias.<locals>._validate_box_or_container at 0x7f64651fac00>, json_schema_input_type=PydanticUndefined), 
 PlainSerializer(func=<function traced_alias.<locals>._serialize_traced at 0x7f64651fa7a0>,                      
 return_type=PydanticUndefined, when_used='json'), <tidy3d.components.autograd.types._TracedAliasJsonSchema      
 object at 0x7f6465215150>]], WithJsonSchema(json_schema={'type': 'array', 'minItems': 3, 'maxItems': 3,         
 'prefixItems': [{'minimum': 0, 'type': 'number'}, {'minimum': 0, 'type': 'number'}, {'minimum': 0, 'type':      
 'number'}]}, mode=None)], name: typing.Annotated[str, MinLen(min_length=1)], interval_space:                    
 tuple[typing.Annotated[int, Gt(gt=0)], typing.Annotated[int, Gt(gt=0)], typing.Annotated[int, Gt(gt=0)]] = (1,  
 1, 1), colocate: bool = True, use_colocated_integration: bool = True, freqs: typing.Annotated[numpy.ndarray,    
 BeforeValidator(func=<function _from_complex_dict at 0x7f646531fc40>,                                           
 json_schema_input_type=PydanticUndefined), BeforeValidator(func=<function array_alias.<locals>.<lambda> at      
 0x7f64651f9760>, json_schema_input_type=PydanticUndefined), PlainSerializer(func=<function _auto_serializer at  
 0x7f64651380e0>, return_type=PydanticUndefined, when_used='json'), WithJsonSchema(json_schema={'type':          
 'ArrayLike', 'x-array-dtype': '<f8', 'x-array-ndim': 1, 'x-array-shape': None, 'x-array-forbid_nan': True,      
 'x-array-scalar_to_1d': True, 'x-array-strict': False}, mode=None)], apodization:                               
 tidy3d.components.apodization.ApodizationSpec = <factory>, fields: tuple[typing.Literal['Ex', 'Ey', 'Ez', 'Hx', 
 'Hy', 'Hz'], ...] = ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']) -> None:                                              
                                                                                                                 
 :class:`~tidy3d.Monitor` that records electromagnetic fields in the frequency domain.                           
                                                                                                                 
          bounding_box = <property object at 0x7f6464ba8720>                                                     
                bounds = <property object at 0x7f6465228db0>                                                     
       frequency_range = <property object at 0x7f6457c9bd80>                                                     
              geometry = <property object at 0x7f6457c68130>                                                     
 model_computed_fields = {}                                                                                      
          model_config = {                                                                                       
                             'arbitrary_types_allowed': True,                                                    
                             'defer_build': True,                                                                
                             'validate_default': True,                                                           
                             'populate_by_name': True,                                                           
                             'ser_json_inf_nan': 'strings',                                                      
                             'extra': 'forbid',                                                                  
                             'frozen': True,                                                                     
                             'validate_by_alias': True,                                                          
                             'validate_by_name': True                                                            
                         }                                                                                       
           model_extra = <property object at 0x7f6465a94b80>                                                     
          model_fields = {                                                                                       
                             'attrs': FieldInfo(                                                                 
                                 annotation=dict,                                                                
                                 required=False,                                                                 
                                 default_factory=dict,                                                           
                                 title='Attributes',                                                             
                                 description="Dictionary storing arbitrary metadata for a Tidy3D object. This    
                         dictionary can be freely used by the user for storing data without affecting the        
                         operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D      
                         fields, ``attrs`` are mutable. For example, the following is allowed for setting an     
                         ``attr`` ``obj.attrs['foo'] = bar``. Also note that Tidy3D will raise a ``TypeError``   
                         if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are 
                         serializable by calling ``obj.model_dump_json()``."                                     
                             ),                                                                                  
                             'type': FieldInfo(                                                                  
                                 annotation=Literal['FieldMonitor'],                                             
                                 required=False,                                                                 
                                 default='FieldMonitor'                                                          
                             ),                                                                                  
                             'center': FieldInfo(                                                                
                                 annotation=tuple[Annotated[object, BeforeValidator, PlainSerializer,            
                         _TracedAliasJsonSchema], Annotated[object, BeforeValidator, PlainSerializer,            
                         _TracedAliasJsonSchema], Annotated[object, BeforeValidator, PlainSerializer,            
                         _TracedAliasJsonSchema]],                                                               
                                 required=False,                                                                 
                                 default=(0.0, 0.0, 0.0),                                                        
                                 title='Center',                                                                 
                                 description='Center of object in x, y, and z.',                                 
                                 json_schema_extra={'units': 'um'},                                              
                                 metadata=[                                                                      
                                     WithJsonSchema(                                                             
                                         json_schema={                                                           
                                             'type': 'array',                                                    
                                             'minItems': 3,                                                      
                                             'maxItems': 3,                                                      
                                             'prefixItems': [                                                    
                                                 {'type': 'number'},                                             
                                                 {'type': 'number'},                                             
                                                 {'type': 'number'}                                              
                                             ]                                                                   
                                         },                                                                      
                                         mode=None                                                               
                                     )                                                                           
                                 ]                                                                               
                             ),                                                                                  
                             'size': FieldInfo(                                                                  
                                 annotation=tuple[Annotated[object, BeforeValidator, PlainSerializer,            
                         _TracedAliasJsonSchema], Annotated[object, BeforeValidator, PlainSerializer,            
                         _TracedAliasJsonSchema], Annotated[object, BeforeValidator, PlainSerializer,            
                         _TracedAliasJsonSchema]],                                                               
                                 required=True,                                                                  
                                 title='Size',                                                                   
                                 description='Size in x, y, and z directions.',                                  
                                 json_schema_extra={'units': 'um'},                                              
                                 metadata=[                                                                      
                                     WithJsonSchema(                                                             
                                         json_schema={                                                           
                                             'type': 'array',                                                    
                                             'minItems': 3,                                                      
                                             'maxItems': 3,                                                      
                                             'prefixItems': [                                                    
                                                 {'minimum': 0, 'type': 'number'},                               
                                                 {'minimum': 0, 'type': 'number'},                               
                                                 {'minimum': 0, 'type': 'number'}                                
                                             ]                                                                   
                                         },                                                                      
                                         mode=None                                                               
                                     )                                                                           
                                 ]                                                                               
                             ),                                                                                  
                             'name': FieldInfo(                                                                  
                                 annotation=str,                                                                 
                                 required=True,                                                                  
                                 title='Name',                                                                   
                                 description='Unique name for monitor.',                                         
                                 metadata=[MinLen(min_length=1)]                                                 
                             ),                                                                                  
                             'interval_space': FieldInfo(                                                        
                                 annotation=tuple[Annotated[int, Gt], Annotated[int, Gt], Annotated[int, Gt]],   
                                 required=False,                                                                 
                                 default=(1, 1, 1),                                                              
                                 title='Spatial Interval',                                                       
                                 description='Number of grid step intervals between monitor recordings. If equal 
                         to 1, there will be no downsampling. If greater than 1, the step will be applied, but   
                         the first and last point of the monitor grid are always included.'                      
                             ),                                                                                  
                             'colocate': FieldInfo(                                                              
                                 annotation=bool,                                                                
                                 required=False,                                                                 
                                 default=True,                                                                   
                                 title='Colocate Fields',                                                        
                                 description='Toggle whether fields should be colocated to grid cell boundaries  
                         (i.e. primal grid nodes).'                                                              
                             ),                                                                                  
                             'use_colocated_integration': FieldInfo(                                             
                                 annotation=bool,                                                                
                                 required=False,                                                                 
                                 default=True,                                                                   
                                 title='Use Colocated Integration',                                              
                                 description='Only takes effect when ``colocate=False``. If ``True``, flux, dot  
                         products, and overlap integrals still use fields interpolated to grid cell boundaries   
                         (colocated), even though the field data is stored at native Yee grid positions.         
                         Experimental feature that can give improved accuracy by avoiding interpolation of       
                         fields to Yee cell positions for integration.'                                          
                             ),                                                                                  
                             'freqs': FieldInfo(                                                                 
                                 annotation=ndarray,                                                             
                                 required=True,                                                                  
                                 title='Frequencies',                                                            
                                 description='Array or list of frequencies stored by the field monitor.',        
                                 json_schema_extra={'units': 'Hz'},                                              
                                 metadata=[                                                                      
                                     BeforeValidator(                                                            
                                         func=<function _from_complex_dict at 0x7f646531fc40>,                   
                                         json_schema_input_type=PydanticUndefined                                
                                     ),                                                                          
                                     BeforeValidator(                                                            
                                         func=<function array_alias.<locals>.<lambda> at 0x7f64651f9760>,        
                                         json_schema_input_type=PydanticUndefined                                
                                     ),                                                                          
                                     PlainSerializer(                                                            
                                         func=<function _auto_serializer at 0x7f64651380e0>,                     
                                         return_type=PydanticUndefined,                                          
                                         when_used='json'                                                        
                                     ),                                                                          
                                     WithJsonSchema(                                                             
                                         json_schema={                                                           
                                             'type': 'ArrayLike',                                                
                                             'x-array-dtype': '<f8',                                             
                                             'x-array-ndim': 1,                                                  
                                             'x-array-shape': None,                                              
                                             'x-array-forbid_nan': True,                                         
                                             'x-array-scalar_to_1d': True,                                       
                                             'x-array-strict': False                                             
                                         },                                                                      
                                         mode=None                                                               
                                     )                                                                           
                                 ]                                                                               
                             ),                                                                                  
                             'apodization': FieldInfo(                                                           
                                 annotation=ApodizationSpec,                                                     
                                 required=False,                                                                 
                                 default_factory=ApodizationSpec,                                                
                                 title='Apodization Specification',                                              
                                 description='Sets parameters of (optional) apodization. Apodization applies a   
                         windowing function to the Fourier transform of the time-domain fields into              
                         frequency-domain ones, and can be used to truncate the beginning and/or end of the time 
                         signal, for example to eliminate the source pulse when studying the eigenmodes of a     
                         system. Note: apodization affects the normalization of the frequency-domain fields.'    
                             ),                                                                                  
                             'fields': FieldInfo(                                                                
                                 annotation=tuple[Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'], ...],             
                                 required=False,                                                                 
                                 default=['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'],                                   
                                 title='Field Components',                                                       
                                 description='Collection of field components to store in the monitor.'           
                             )                                                                                   
                         }                                                                                       
      model_fields_set = <property object at 0x7f64653611c0>                                                     
           plot_params = <property object at 0x7f6457c680e0>                                                     
             zero_dims = <property object at 0x7f6464951d00>                                                     
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─────────────────────────────── <class 'tidy3d.components.monitor.FieldMonitor'> ────────────────────────────────╮
 class FieldMonitor(*, attrs: dict = <factory>, type: Literal['FieldMonitor'] = 'FieldMonitor', center:          
 typing.Annotated[tuple[typing.Annotated[object, BeforeValidator(func=<function                                  
 traced_alias.<locals>._validate_box_or_container at 0x7f64651faca0>, json_schema_input_type=PydanticUndefined), 
 PlainSerializer(func=<function traced_alias.<locals>._serialize_traced at 0x7f64651fad40>,                      
 return_type=PydanticUndefined, when_used='json'), <tidy3d.components.autograd.types._TracedAliasJsonSchema      
 object at 0x7f646522c710>], typing.Annotated[object, BeforeValidator(func=<function                             
 traced_alias.<locals>._validate_box_or_container at 0x7f64651faca0>, json_schema_input_type=PydanticUndefined), 
 PlainSerializer(func=<function traced_alias.<locals>._serialize_traced at 0x7f64651fad40>,                      
 return_type=PydanticUndefined, when_used='json'), <tidy3d.components.autograd.types._TracedAliasJsonSchema      
 object at 0x7f646522c710>], typing.Annotated[object, BeforeValidator(func=<function                             
 traced_alias.<locals>._validate_box_or_container at 0x7f64651faca0>, json_schema_input_type=PydanticUndefined), 
 PlainSerializer(func=<function traced_alias.<locals>._serialize_traced at 0x7f64651fad40>,                      
 return_type=PydanticUndefined, when_used='json'), <tidy3d.components.autograd.types._TracedAliasJsonSchema      
 object at 0x7f646522c710>]], WithJsonSchema(json_schema={'type': 'array', 'minItems': 3, 'maxItems': 3,         
 'prefixItems': [{'type': 'number'}, {'type': 'number'}, {'type': 'number'}]}, mode=None)] = (0.0, 0.0, 0.0),    
 size: typing.Annotated[tuple[typing.Annotated[object, BeforeValidator(func=<function                            
 traced_alias.<locals>._validate_box_or_container at 0x7f64651fac00>, json_schema_input_type=PydanticUndefined), 
 PlainSerializer(func=<function traced_alias.<locals>._serialize_traced at 0x7f64651fa7a0>,                      
 return_type=PydanticUndefined, when_used='json'), <tidy3d.components.autograd.types._TracedAliasJsonSchema      
 object at 0x7f6465215150>], typing.Annotated[object, BeforeValidator(func=<function                             
 traced_alias.<locals>._validate_box_or_container at 0x7f64651fac00>, json_schema_input_type=PydanticUndefined), 
 PlainSerializer(func=<function traced_alias.<locals>._serialize_traced at 0x7f64651fa7a0>,                      
 return_type=PydanticUndefined, when_used='json'), <tidy3d.components.autograd.types._TracedAliasJsonSchema      
 object at 0x7f6465215150>], typing.Annotated[object, BeforeValidator(func=<function                             
 traced_alias.<locals>._validate_box_or_container at 0x7f64651fac00>, json_schema_input_type=PydanticUndefined), 
 PlainSerializer(func=<function traced_alias.<locals>._serialize_traced at 0x7f64651fa7a0>,                      
 return_type=PydanticUndefined, when_used='json'), <tidy3d.components.autograd.types._TracedAliasJsonSchema      
 object at 0x7f6465215150>]], WithJsonSchema(json_schema={'type': 'array', 'minItems': 3, 'maxItems': 3,         
 'prefixItems': [{'minimum': 0, 'type': 'number'}, {'minimum': 0, 'type': 'number'}, {'minimum': 0, 'type':      
 'number'}]}, mode=None)], name: typing.Annotated[str, MinLen(min_length=1)], interval_space:                    
 tuple[typing.Annotated[int, Gt(gt=0)], typing.Annotated[int, Gt(gt=0)], typing.Annotated[int, Gt(gt=0)]] = (1,  
 1, 1), colocate: bool = True, use_colocated_integration: bool = True, freqs: typing.Annotated[numpy.ndarray,    
 BeforeValidator(func=<function _from_complex_dict at 0x7f646531fc40>,                                           
 json_schema_input_type=PydanticUndefined), BeforeValidator(func=<function array_alias.<locals>.<lambda> at      
 0x7f64651f9760>, json_schema_input_type=PydanticUndefined), PlainSerializer(func=<function _auto_serializer at  
 0x7f64651380e0>, return_type=PydanticUndefined, when_used='json'), WithJsonSchema(json_schema={'type':          
 'ArrayLike', 'x-array-dtype': '<f8', 'x-array-ndim': 1, 'x-array-shape': None, 'x-array-forbid_nan': True,      
 'x-array-scalar_to_1d': True, 'x-array-strict': False}, mode=None)], apodization:                               
 tidy3d.components.apodization.ApodizationSpec = <factory>, fields: tuple[typing.Literal['Ex', 'Ey', 'Ez', 'Hx', 
 'Hy', 'Hz'], ...] = ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']) -> None:                                              
                                                                                                                 
 :class:`~tidy3d.Monitor` that records electromagnetic fields in the frequency domain.                           
                                                                                                                 
          bounding_box = <property object at 0x7f6464ba8720>                                                     
                bounds = <property object at 0x7f6465228db0>                                                     
       frequency_range = <property object at 0x7f6457c9bd80>                                                     
              geometry = <property object at 0x7f6457c68130>                                                     
 model_computed_fields = {}                                                                                      
          model_config = {                                                                                       
                             'arbitrary_types_allowed': True,                                                    
                             'defer_build': True,                                                                
                             'validate_default': True,                                                           
                             'populate_by_name': True,                                                           
                             'ser_json_inf_nan': 'strings',                                                      
                             'extra': 'forbid',                                                                  
                             'frozen': True,                                                                     
                             'validate_by_alias': True,                                                          
                             'validate_by_name': True                                                            
                         }                                                                                       
           model_extra = <property object at 0x7f6465a94b80>                                                     
          model_fields = {                                                                                       
                             'attrs': FieldInfo(                                                                 
                                 annotation=dict,                                                                
                                 required=False,                                                                 
                                 default_factory=dict,                                                           
                                 title='Attributes',                                                             
                                 description="Dictionary storing arbitrary metadata for a Tidy3D object. This    
                         dictionary can be freely used by the user for storing data without affecting the        
                         operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D      
                         fields, ``attrs`` are mutable. For example, the following is allowed for setting an     
                         ``attr`` ``obj.attrs['foo'] = bar``. Also note that Tidy3D will raise a ``TypeError``   
                         if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are 
                         serializable by calling ``obj.model_dump_json()``."                                     
                             ),                                                                                  
                             'type': FieldInfo(                                                                  
                                 annotation=Literal['FieldMonitor'],                                             
                                 required=False,                                                                 
                                 default='FieldMonitor'                                                          
                             ),                                                                                  
                             'center': FieldInfo(                                                                
                                 annotation=tuple[Annotated[object, BeforeValidator, PlainSerializer,            
                         _TracedAliasJsonSchema], Annotated[object, BeforeValidator, PlainSerializer,            
                         _TracedAliasJsonSchema], Annotated[object, BeforeValidator, PlainSerializer,            
                         _TracedAliasJsonSchema]],                                                               
                                 required=False,                                                                 
                                 default=(0.0, 0.0, 0.0),                                                        
                                 title='Center',                                                                 
                                 description='Center of object in x, y, and z.',                                 
                                 json_schema_extra={'units': 'um'},                                              
                                 metadata=[                                                                      
                                     WithJsonSchema(                                                             
                                         json_schema={                                                           
                                             'type': 'array',                                                    
                                             'minItems': 3,                                                      
                                             'maxItems': 3,                                                      
                                             'prefixItems': [                                                    
                                                 {'type': 'number'},                                             
                                                 {'type': 'number'},                                             
                                                 {'type': 'number'}                                              
                                             ]                                                                   
                                         },                                                                      
                                         mode=None                                                               
                                     )                                                                           
                                 ]                                                                               
                             ),                                                                                  
                             'size': FieldInfo(                                                                  
                                 annotation=tuple[Annotated[object, BeforeValidator, PlainSerializer,            
                         _TracedAliasJsonSchema], Annotated[object, BeforeValidator, PlainSerializer,            
                         _TracedAliasJsonSchema], Annotated[object, BeforeValidator, PlainSerializer,            
                         _TracedAliasJsonSchema]],                                                               
                                 required=True,                                                                  
                                 title='Size',                                                                   
                                 description='Size in x, y, and z directions.',                                  
                                 json_schema_extra={'units': 'um'},                                              
                                 metadata=[                                                                      
                                     WithJsonSchema(                                                             
                                         json_schema={                                                           
                                             'type': 'array',                                                    
                                             'minItems': 3,                                                      
                                             'maxItems': 3,                                                      
                                             'prefixItems': [                                                    
                                                 {'minimum': 0, 'type': 'number'},                               
                                                 {'minimum': 0, 'type': 'number'},                               
                                                 {'minimum': 0, 'type': 'number'}                                
                                             ]                                                                   
                                         },                                                                      
                                         mode=None                                                               
                                     )                                                                           
                                 ]                                                                               
                             ),                                                                                  
                             'name': FieldInfo(                                                                  
                                 annotation=str,                                                                 
                                 required=True,                                                                  
                                 title='Name',                                                                   
                                 description='Unique name for monitor.',                                         
                                 metadata=[MinLen(min_length=1)]                                                 
                             ),                                                                                  
                             'interval_space': FieldInfo(                                                        
                                 annotation=tuple[Annotated[int, Gt], Annotated[int, Gt], Annotated[int, Gt]],   
                                 required=False,                                                                 
                                 default=(1, 1, 1),                                                              
                                 title='Spatial Interval',                                                       
                                 description='Number of grid step intervals between monitor recordings. If equal 
                         to 1, there will be no downsampling. If greater than 1, the step will be applied, but   
                         the first and last point of the monitor grid are always included.'                      
                             ),                                                                                  
                             'colocate': FieldInfo(                                                              
                                 annotation=bool,                                                                
                                 required=False,                                                                 
                                 default=True,                                                                   
                                 title='Colocate Fields',                                                        
                                 description='Toggle whether fields should be colocated to grid cell boundaries  
                         (i.e. primal grid nodes).'                                                              
                             ),                                                                                  
                             'use_colocated_integration': FieldInfo(                                             
                                 annotation=bool,                                                                
                                 required=False,                                                                 
                                 default=True,                                                                   
                                 title='Use Colocated Integration',                                              
                                 description='Only takes effect when ``colocate=False``. If ``True``, flux, dot  
                         products, and overlap integrals still use fields interpolated to grid cell boundaries   
                         (colocated), even though the field data is stored at native Yee grid positions.         
                         Experimental feature that can give improved accuracy by avoiding interpolation of       
                         fields to Yee cell positions for integration.'                                          
                             ),                                                                                  
                             'freqs': FieldInfo(                                                                 
                                 annotation=ndarray,                                                             
                                 required=True,                                                                  
                                 title='Frequencies',                                                            
                                 description='Array or list of frequencies stored by the field monitor.',        
                                 json_schema_extra={'units': 'Hz'},                                              
                                 metadata=[                                                                      
                                     BeforeValidator(                                                            
                                         func=<function _from_complex_dict at 0x7f646531fc40>,                   
                                         json_schema_input_type=PydanticUndefined                                
                                     ),                                                                          
                                     BeforeValidator(                                                            
                                         func=<function array_alias.<locals>.<lambda> at 0x7f64651f9760>,        
                                         json_schema_input_type=PydanticUndefined                                
                                     ),                                                                          
                                     PlainSerializer(                                                            
                                         func=<function _auto_serializer at 0x7f64651380e0>,                     
                                         return_type=PydanticUndefined,                                          
                                         when_used='json'                                                        
                                     ),                                                                          
                                     WithJsonSchema(                                                             
                                         json_schema={                                                           
                                             'type': 'ArrayLike',                                                
                                             'x-array-dtype': '<f8',                                             
                                             'x-array-ndim': 1,                                                  
                                             'x-array-shape': None,                                              
                                             'x-array-forbid_nan': True,                                         
                                             'x-array-scalar_to_1d': True,                                       
                                             'x-array-strict': False                                             
                                         },                                                                      
                                         mode=None                                                               
                                     )                                                                           
                                 ]                                                                               
                             ),                                                                                  
                             'apodization': FieldInfo(                                                           
                                 annotation=ApodizationSpec,                                                     
                                 required=False,                                                                 
                                 default_factory=ApodizationSpec,                                                
                                 title='Apodization Specification',                                              
                                 description='Sets parameters of (optional) apodization. Apodization applies a   
                         windowing function to the Fourier transform of the time-domain fields into              
                         frequency-domain ones, and can be used to truncate the beginning and/or end of the time 
                         signal, for example to eliminate the source pulse when studying the eigenmodes of a     
                         system. Note: apodization affects the normalization of the frequency-domain fields.'    
                             ),                                                                                  
                             'fields': FieldInfo(                                                                
                                 annotation=tuple[Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'], ...],             
                                 required=False,                                                                 
                                 default=['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'],                                   
                                 title='Field Components',                                                       
                                 description='Collection of field components to store in the monitor.'           
                             )                                                                                   
                         }                                                                                       
      model_fields_set = <property object at 0x7f64653611c0>                                                     
           plot_params = <property object at 0x7f6457c680e0>                                                     
             zero_dims = <property object at 0x7f6464951d00>                                                     
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

Visualization functions#

We can now use the some in-built plotting functions to make sure that we have set up the simulation as we desire.

First, let’s take a look at the source time dependence.

[9]:
# Visualize source
psource.source_time.plot(np.linspace(0, run_time, 1001))
plt.show()
../_images/notebooks_Simulation_17_0.png

And now let’s visualize the simulation.

For this, we will plot three cross sections at z=0.75, y=0, and x=0, respectively.

The relative permittivity of objects is plotted in grayscale.

By default, sources are overlaid in green, monitors in yellow, and PML boundaries in gray.

[10]:
fig, ax = plt.subplots(1, 3, figsize=(13, 4))
sim.plot_eps(z=0.75, freq=freq_range.freq0, ax=ax[0])
sim.plot_eps(y=0.01, freq=freq_range.freq0, ax=ax[1])
sim.plot_eps(x=0, freq=freq_range.freq0, ax=ax[2])
plt.show()
../_images/notebooks_Simulation_19_0.png

Alternatively, we can also plot the structures with a fake color based on the material they are made of.

[11]:
fig, ax = plt.subplots(1, 3, figsize=(12, 3))
sim.plot(z=0.75, ax=ax[0])
sim.plot(y=0.01, ax=ax[1])
sim.plot(x=0, ax=ax[2])
plt.show()
../_images/notebooks_Simulation_21_0.png

Running through the web API#

Now that the simulation is constructed, we can run it using the web API of Tidy3D. First, we submit the project. Note that we can give it a custom name.

[12]:
task_id = web.upload(sim, task_name="Simulation")
07:19:26 UTC Created task 'Simulation' with resource_id
             'fdve-f43fef39-8a9e-4410-af43-3844ee6f8272' and task_type 'FDTD'.
             Task folder: 'default'.
07:19:28 UTC 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.

The task is still in draft status and will not run until we call the start function. Before that, we may want to check the estimated cost of the task. This is the maximum possible cost, and can be lower in case of early shutoff.

[13]:
estimate_cost = web.estimate_cost(task_id)
07:19:29 UTC 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.

We can now start the task, and if we want to, continuously monitor its status and wait until the run is successful. The monitor function will keep running until either a 'success' or 'error' status is returned.

[14]:
# web.start(task_id, solver_version="improve_python_overgap-0.0.0")
web.start(task_id)
web.monitor(task_id, verbose=True)
             status = queued
07:19:30 UTC 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.
07:19:37 UTC status = preprocess
07:19:42 UTC starting up solver
             running solver
07:19:44 UTC status = postprocess
07:19:47 UTC status = success

We can also use the real_cost function once the task is complete to check the cost that was actually billed. It may take a few seconds before it is available.

[15]:
import time

time.sleep(4)
real_cost = web.real_cost(task_id)
07:19:53 UTC Billed flex credit cost: 0.025.
             Note: the task cost pro-rated due to early shutoff was below the
             minimum threshold, due to fast shutoff. Decreasing the simulation
             'run_time' should decrease the estimated, and correspondingly the
             billed cost of such tasks.

Loading and analyzing data#

After a successful run, we can download the results and load them into our simulation model. We use the download_results function from our web API, which downloads a single hdf5 file containing all the monitor data, a log file, and a json file defining the original simulation (same as what you’ll get if you run sim.to_json() on the current object). Optionally, you can provide a folder in which to store the files. In the example below, the results are stored in the data/ folder.

[16]:
sim_data = web.load(task_id, path="data/sim_data.hdf5")

# Show the output of the log file
print(sim_data.log)
07:19:55 UTC Loading results from data/sim_data.hdf5
             WARNING: Simulation final field decay value of 1.0 is greater than 
             the simulation shutoff threshold of 1e-05. Consider running the    
             simulation again with a larger 'run_time' duration for more        
             accurate results.                                                  
             WARNING: Warning messages were found in the solver log. For more   
             information, check 'SimulationData.log' or use                     
             'web.download_log(task_id)'.                                       
[07:19:36] INFO: Auto meshing using wavelength 1.4999 defined from sources.
           INFO: Auto meshing using wavelength 1.4999 defined from sources.
           INFO: Auto meshing using wavelength 1.4999 defined from sources.
           USER: Simulation domain Nx, Ny, Nz: [156, 156, 104]
           USER: Applied symmetries: (0, 0, 0)
           USER: Number of computational grid points: 2.6462e+06.
           USER: Subpixel averaging method: SubpixelSpec()
           USER: Number of time steps: 3.4930e+03
           USER: Automatic shutoff factor: 1.00e-05
           USER: Time step (s): 5.7275e-17
           USER:

[07:19:37] USER: Compute source modes time (s):     0.6181
           WARNING: Provided source time dependence appears not to fully decay
           by the chosen run time, broadband source set up may not be accurate.
           You may need to increase simulation run time.
           WARNING: Provided source time dependence appears not to fully decay
           by the chosen run time, broadband source set up may not be accurate.
           You may need to increase simulation run time.
           USER: Rest of setup time (s):            0.3828
[07:19:38] USER: Compute monitor modes time (s):    0.0003
[07:19:42] USER: Solver time (s):                   3.3070
           USER: Time-stepping speed (cells/s):     3.08e+09
           USER: Loading data for monitor field_time
           USER: Loading data for monitor field1
           USER: Loading data for monitor field2
           USER: Post-processing time (s):          0.4123

 ====== SOLVER LOG ======

Processing grid and structures...
Building FDTD update coefficients...
Solver setup time (s):             0.2940

Running solver for 3493 time steps...
- Time step    139 / time 7.96e-15s (  4 % done), field decay: 1.00e+00
- Time step    279 / time 1.60e-14s (  8 % done), field decay: 1.00e+00
- Time step    419 / time 2.40e-14s ( 12 % done), field decay: 1.00e+00
- Time step    558 / time 3.20e-14s ( 16 % done), field decay: 1.00e+00
- Time step    698 / time 4.00e-14s ( 20 % done), field decay: 1.00e+00
- Time step    838 / time 4.80e-14s ( 24 % done), field decay: 1.00e+00
- Time step    978 / time 5.60e-14s ( 28 % done), field decay: 1.00e+00
- Time step   1117 / time 6.40e-14s ( 32 % done), field decay: 1.00e+00
- Time step   1257 / time 7.20e-14s ( 36 % done), field decay: 1.00e+00
- Time step   1397 / time 8.00e-14s ( 40 % done), field decay: 1.00e+00
- Time step   1536 / time 8.80e-14s ( 44 % done), field decay: 1.00e+00
- Time step   1676 / time 9.60e-14s ( 48 % done), field decay: 1.00e+00
- Time step   1816 / time 1.04e-13s ( 52 % done), field decay: 1.00e+00
- Time step   1956 / time 1.12e-13s ( 56 % done), field decay: 1.00e+00
- Time step   2095 / time 1.20e-13s ( 60 % done), field decay: 1.00e+00
- Time step   2235 / time 1.28e-13s ( 64 % done), field decay: 1.00e+00
- Time step   2375 / time 1.36e-13s ( 68 % done), field decay: 1.00e+00
- Time step   2514 / time 1.44e-13s ( 72 % done), field decay: 1.00e+00
- Time step   2654 / time 1.52e-13s ( 76 % done), field decay: 1.00e+00
- Time step   2794 / time 1.60e-13s ( 80 % done), field decay: 1.00e+00
- Time step   2934 / time 1.68e-13s ( 84 % done), field decay: 1.00e+00
- Time step   3073 / time 1.76e-13s ( 88 % done), field decay: 1.00e+00
- Time step   3213 / time 1.84e-13s ( 92 % done), field decay: 1.00e+00
- Time step   3353 / time 1.92e-13s ( 96 % done), field decay: 1.00e+00
- Time step   3492 / time 2.00e-13s (100 % done), field decay: 1.00e+00
Time-stepping time (s):            2.9989
Data write time (s):               0.0115

Visualization functions#

Finally, we can now use the in-built visualization tools to examine the results. Below, we plot the y-component of the field recorded by the two frequency monitors (this is the dominant component since the source is y-polarized).

[17]:
fig, ax = plt.subplots(1, 2, figsize=(10, 4))
sim_data.plot_field("field1", "Ey", z=-1.0, ax=ax[0], val="real")
sim_data.plot_field("field2", "Ey", ax=ax[1], val="real")
plt.show()
../_images/notebooks_Simulation_33_0.png

Monitor data#

The raw field data can be accessed through indexing by monitor name directly.

For plenty of discussion on accessing and manipulating data, refer to the data visualization tutorial.

[18]:
mon1_data = sim_data["field1"]
mon1_data.Ex
<xarray.ScalarFieldDataArray (x: 157, y: 157, z: 1, f: 1)> Size: 394kB
array([[[[ 0.00000000e+00-0.00000000e+00j]],

        [[ 4.48203150e-07+1.31972893e-07j]],

        [[ 3.28867231e-06+9.01092482e-07j]],

        ...,

        [[ 5.53139835e-07-2.67624859e-09j]],

        [[ 3.61294851e-08-4.11692073e-09j]],

        [[ 0.00000000e+00-0.00000000e+00j]]],


       [[[ 0.00000000e+00-0.00000000e+00j]],

        [[ 2.01065001e-06+5.66329251e-07j]],

        [[ 1.47039524e-05+6.04044284e-06j]],
...
        [[-2.79244519e-07+2.49222499e-08j]],

        [[-1.78363466e-08+3.46077729e-09j]],

        [[ 0.00000000e+00-0.00000000e+00j]]],


       [[[ 0.00000000e+00-0.00000000e+00j]],

        [[-2.99808838e-08-2.24377945e-09j]],

        [[-2.08019756e-07+1.15107060e-08j]],

        ...,

        [[-3.09108161e-08+8.87712743e-09j]],

        [[-2.32996161e-09+5.34137600e-10j]],

        [[ 0.00000000e+00-0.00000000e+00j]]]], shape=(157, 157, 1, 1))
Coordinates:
  * x        (x) float64 1kB -2.364 -2.333 -2.303 -2.273 ... 2.303 2.333 2.364
  * y        (y) float64 1kB -2.367 -2.337 -2.306 -2.276 ... 2.295 2.325 2.354
  * z        (z) float64 8B -1.0
  * f        (f) float64 8B 2e+14
Attributes:
    long_name:  field value
[19]:
ax = mon1_data.Ez.real.plot()
../_images/notebooks_Simulation_36_0.png

We can use this raw data for example to also plot the time-domain fields recorded in the FieldTimeMonitor, which look largely like a delayed version of the source input, indicating that no resonant features were excited.

[20]:
time_data = sim_data["field_time"]
fig, ax = plt.subplots(1)
time_data.Ey.plot()
ax.set_ylabel("$E_y(t)$ [V/m]")
plt.show()
../_images/notebooks_Simulation_38_0.png

Permittivity data#

We can also query the relative permittivity in the simulation within a volume parameterized by a td.Box. The method Simulation.epsilon(box, coord_key) returns the permittivity within the specified volume.

The coord_key specifies at what locations in the yee cell to evaluate the permittivity at (eg. 'centers', 'Ey', 'Hz', etc.).

[21]:
volume = td.Box(center=(0, 0, 0.75), size=(5, 5, 0))

# at Yee cell centers
eps_centers = sim.epsilon(box=volume, coord_key="centers")

# at Ex locations in the yee cell
eps_Ex = sim.epsilon(box=volume, coord_key="Ex")

Return an xarray DataArray containing the complex-valued permittivity values at the Yee cell centers and the “Ex” within the box.

We can then plot or post-process this data as we wish.

[22]:
f, (ax1, ax2) = plt.subplots(1, 2, tight_layout=True, figsize=(10, 4))

eps_centers.real.plot(x="x", y="y", cmap="Greys", ax=ax1)
eps_Ex.real.plot(x="x", y="y", cmap="Greys", ax=ax2)
ax1.set_title("epsilon_r at centers")
ax2.set_title("epsilon_r at Ex locations")

plt.show()
../_images/notebooks_Simulation_42_0.png

For simulation examples, please visit our examples page. If you are new to the finite-difference time-domain (FDTD) method, we highly recommend going through our FDTD101 tutorials.