Using the mode solver for optical mode analysis
Using the mode solver for optical mode analysis
This tutorial shows how to use the mode solver plugin in Tidy3D.
Setup
We first set up the mode solver with information about our system. We start by setting parameters
Then we set up a simulation, in this case including a straight waveguide and periodic boundary conditions. Note that Tidy3D warns us that we have not added any sources in our Simulation object, however for purposes of mode solving it is not necessary.
Initialize Mode Solver
With our system defined, we can now create our mode solver. We first need to specify on what plane we want to solve the modes using a td.Box() object.
The mode solver can now compute the modes given a ModeSpec object that specifies everything about the modes we’re looking for, for example:
num_modes: how many modes to compute.
target_neff: float, default=None, initial guess for the effective index of the mode; if not specified, the modes with the largest real part of the effective index are computed.
The full list of specification parameters can be found here.
We can also specify a list of frequencies at which to solve for the modes.
Finally, we can initialize the ModeSolver, and call the solve method.
We can also summarize useful mode information using to_dataframe(). Note that the group index was not computed; this can be included by setting group_index_step=True in the ModeSpec.
Visualizing Mode Data
The mode_info object contains information about the effective index of the mode and the field profiles, as well as the mode_spec that was used in the solver. The effective index data and the field profile data is in the form of xarray DataArrays.
We can for example plot the real part of the effective index for all three modes as follows.
The raw data can also be accessed.
first mode effective index at freq0: n_eff = 1.75, k_eff = 0.00e+00
The fields stored in mode_data can be visualized using in-built xarray methods.
Alternatively, we can use the in-built plot_field method of mode_data, which also allows us to overlay the structures in the simulation. The image also looks slightly different because the plot_field method uses robust=True option by default, which scales the colorbar to between the 2nd and 98th percentile of the data.
Choosing the mode of interest
We can also look at the other modes that were computed.
This looks like an Ez-dominant mode. Finally, next-order mode has mixed polarization.
Exporting Results
This looks promising!
Now we can choose the mode specifications to use in our mode source and mode monitors. These can be created separately, can be exported directly from the mode solver, for example:
15:35:29 UTC Created task 'mode_simulation' with resource_id
'fdve-eeb45fbc-9afc-47a6-b120-a7cfe459b0b5' and task_type 'FDTD'.
15:35:30 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.
15:35:31 UTC status = queued
To cancel the simulation, use 'web.abort(task_id)' or
'web.delete(task_id)' or abort/delete the task in the web UI.
Terminating the Python script will not stop the job running on the
cloud.
15:35:43 UTC status = preprocess
15:35:46 UTC status = postprocess
15:35:50 UTC status = success
15:35:52 UTC starting up solver
15:35:53 UTC running solver
early shutoff detected at 11%, exiting.
15:35:54 UTC status = success
15:35:55 UTC Loading results from data/simulation_data.hdf5
We can now plot the in-plane field and the modal amplitudes. Since we injected mode 2 and we just have a straight waveguide, all the power recorded by the modal monitor is in mode 2, going backwards.
Storing server-side computed modes
We can also use a ModeSolverMonitor to store the modes as they are computed server-side. This is illustrated below. We will also request in the mode specification that the modes are filtered by their tm polarization. In this particular simulation, TM refers to Ez polarization. The effect of the filtering is that modes with a tm polarization fraction larger than or equal to 0.5 will come first in the list of modes (while still ordered by decreasing effective index). After that,
the set of predominantly te-polarized modes (tm fraction < 0.5) follows.
15:35:56 UTC Created task 'mode_simulation' with resource_id
'fdve-73a38dc0-dfb0-439f-87bf-d18610a1f9bb' and task_type 'FDTD'.
15:35:57 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.
15:35:58 UTC status = queued
To cancel the simulation, use 'web.abort(task_id)' or
'web.delete(task_id)' or abort/delete the task in the web UI.
Terminating the Python script will not stop the job running on the
cloud.
15:36:12 UTC starting up solver
15:36:15 UTC early shutoff detected at 7%, exiting.
15:36:17 UTC status = success
15:36:21 UTC Loading results from data/simulation_data.hdf5
Note the different ordering of the recorded modes compared to what we saw above, with the fundamental TM mode coming first.
Now the fundamental Ez-polarized mode is injected, and as before it is the only one that the mode monitor records any intensity in.
We can also have a look at the mode fields stored in the ModeFieldMonitor either directly using xarray methods as above, or using the Tidy3D SimulationData in-built field plotting.
Subpixel averaging
The mode solver applies subpixel averaging automatically when the tidy3d-extras package is installed (pip install "tidy3d[extras]"). Subpixel averaging smooths the material interfaces on the Yee grid, which increases the computation accuracy, with the whole calculation running locally. Alternatively, the mode solver can also be run in the cloud with web.run(mode_solver, task_name="mode_solver"), in which case subpixel averaging is applied as well.
To see its effect, we can disable subpixel averaging by setting td.config.simulation.use_local_subpixel = False. We use the previous mode solver as an example:
15:36:22 UTC WARNING: Use the remote mode solver with subpixel averaging for
better accuracy through 'tidy3d.web.run(...)' or the deprecated
'tidy3d.plugins.mode.web.run(...)'. Alternatively, you can install
the package 'tidy3d-extras' using 'pip install "tidy3d"' and set
'config.simulation.use_local_subpixel=True'.
To demonstrate the accuracy improvement, we can show a convergence plot comparing the results with and without subpixel averaging on a waveguide that doesn’t align with the mesh, in this case a dielectric rod.
Solving for resolution = 10
Solving for resolution = 12
Solving for resolution = 14
Solving for resolution = 16
Solving for resolution = 18
Solving for resolution = 20
Solving for resolution = 22
Solving for resolution = 24
Solving for resolution = 26
Solving for resolution = 28
Solving for resolution = 30
Mode tracking
As typical for eigenvalue type solvers, the Tidy3D’s mode solver finds the modes at each frequency in the order corresponding to the magnitudes of the found eigenvalues (effective index). Since the effective index of a mode generally depends on frequency and can become larger or smaller in magnitude compared to the effective index values of other modes, the same mode_index could end up corresponding to physically different modes at different frequencies near mode crossings. To avoid such a
mismatch, ModeSolver automatically tracks the modes across frequencies based on their overlap values (see discussion on mode decomposition), so that each mode_index corresponds to the same physical mode throughout the frequency range. This behavior is controlled by the parameter track_freq of the ModeSortSpec object, passed to ModeSpec through its sort_spec parameter. It can be set to either
None, "lowest", "central" (default), or "highest", where in the first case no tracking is performed while in the other three cases tracking starts from the specified frequency. Additionally, any unsorted mode solver data (objects of type ModeSolverData) can be sorted afterwards by using the function ModeSolverData.overlap_sort(). Note that for mode sources and mode monitors sorting is always performed internally.
We calculate twelve modes at eleven different frequencies for a layered waveguide with the default tracking:
Again, Tidy3D is warning us that the simulation does not contain a source. However, since this simulation is used to construct the mode solver and will not be run directly, we can ignore this warning.
By inspecting the values of effective indices we note that some of them come very close to each other, indicating mode crossings. Thanks to the automatic tracking, each mode_index still corresponds to the same physical mode throughout the considered frequency range.
Indeed, by plotting field distributions for the calculated modes we can confirm that the modes are consistently tracked across all frequencies.
Note that depending on the particular situation, the mode sorting, whether default or by hands, might not successfully resolve the tracking of all modes throughout the chosen frequency range. Possible reasons for that: - A mode is physically disappearing at a certain frequency point. - A mode is not included in the calculated number of modes, num_modes, for certain frequency points. In this case, increasing num_modes might alleviate the issue. - Presence of degenerate modes at certain
frequencies.
Group Index
The mode solver can also be used to directly calculate the group index of the calculated mode. It is important to have mode tracking enabled, to avoid differentiating wrong mode pairs around mode crossings.
Notes / Considerations
This mode solver runs locally, which means it does not require credits to run.
When the tidy3d-extras package is installed, the local mode solver applies subpixel averaging, so its results match the modes stored in a ModeSolverMonitor during a simulation run. Without tidy3d-extras, or with td.config.simulation.use_local_subpixel = False, subpixel averaging is not applied locally, and the results are less accurate.
Symmetries are applied if they are defined in the simulation and the mode plane center sits on the simulation center.
In cases when the number of modes/frequency points and/or the dimensions of mode solver plane are large and tracking of modes is not important then it might be beneficial to turn off the default mode sorting for increased computational efficiency.