Installation and getting started#

Installation#

Python

You can install PyLumerical using pip.

First, create a virtual environment and activate it to avoid dependency conflicts and to keep your global Python environment clean.

Note

If you have multiple Python versions installed, ensure you are using the right executable for the virtual environment. The supported Python versions are at the top of this page.

1python -m venv .venv
2source .venv/bin/activate
1python -m venv .venv
2.venv\\Scripts\\activate.bat
1python -m venv .venv
2.venv\\Scripts\\Activate.ps1

Then, upgrade pip to the latest version, and install PyLumerical with the package name ansys-lumerical-core.

1python -m pip install -U pip
2python -m pip install ansys-lumerical-core

Tip

Using a virtual environment isn’t a requirement, but it’s a best practice for Python development. PyLumerical is compatible with various Python IDEs including VS Code, Jupyter Notebook, and Cursor. After installation, you can use your preferred editor to start using PyLumerical. Refer to the documentation of your IDE for instructions on how to use the virtual environment.

Requirements#

You must have an Ansys Lumerical GUI license along with Lumerical 2022 R1 or later on your computer to use PyLumerical. For more information, please visit the licensing page on the Ansys Optics website.

Upon importing PyLumerical, the autodiscovery logic automatically locates the Lumerical installation path and configures interop. If autodiscovery fails, set the LUMERICAL_HOME environment variable before import and start a new Python session.

To use the Lumerical photonic inverse design module lumopt2, you must have Ansys Lumerical FDTD™ version 2026 R1.2 or later installed on your computer. The autodiscovery logic automatically locates the lumopt2 module if it is available.

Importing modules#

To use PyLumerical for simulation automation:

1import ansys.lumerical.core as lumapi

Tip

When imported this way, you can directly use your scripts written with the legacy lumapi Python module.

To use the lumopt2 inverse design module, use the code below. For further information, see the lumopt2 introduction page.

1import ansys.lumerical.core.lumopt2 as lmpt

Warning

  • To ensure correct functionality, only import lumopt2 through ansys.lumerical.core.

  • Manual sys.path overrides for lumopt2 are unsupported. The lumopt2 module bundled with Ansys Lumerical products silently takes precedence over those added to sys.path.

My first PyLumerical project#

The code snippet below provides a simple project of using PyLumerical to drive a Lumerical FDTD simulation with an array of nanoholes on a gold film atop a glass substrate.

Step 1 - Import and simulation parameters

Import PyLumerical and define various simulation parameters.

Show imports
1
2from collections import OrderedDict
3
4import matplotlib.pyplot as plt
5
6import ansys.lumerical.core as lumapi
7
Show parameter definition
 1# Define parameters
 2
 3filename = "Nanohole_array.fsp"
 4
 5# Parameters related to the patterned film
 6periodicity = 400e-9  # 400 nm periodic array
 7film_thickness = 100e-9
 8hole_radius = 100e-9  # radius of the nanoholes
 9nx = ny = 3  # Number of nanoholes
10
11# Parameters for the substrate
12substrate_thickness = 1e-6
13substrate_span = 1.2e-6
14
15# FDTD region and mesh
16fdtd_z_span = 1e-6  # Ensure span is large enough to capture both T, R monitors
17transmission_z = 0.4e-6  # z position of top "T" monitor
18reflection_z = -0.2e-6  # z position of bottom "R" monitor
19dx = 0.01e-6  # mesh override resolution
20
21# Source and wavelengths
22source_z = 0.3e-6  # position of source
23wavelength_start = 0.4e-6
24wavelength_stop = 0.7e-6

Step 2 - Build simulation

Set up the simulation, including the region, geometry, materials, source, and monitors.

Show simulation setup
 1# Initialize session and build simulation objects. Set hide = True to hide the Lumerical GUI.
 2
 3with lumapi.FDTD(hide=False) as fdtd:
 4    # Add the substrate
 5    fdtd.addrect(name="substrate", 
 6                 x_span=substrate_span, 
 7                 y_span=substrate_span, 
 8                 z_max=0, 
 9                 z_min=substrate_thickness, 
10                 material="SiO2 (Glass) - Palik")
11
12    # Add the gold film
13    fdtd.addrect(name="film", 
14                 x_span=substrate_span, 
15                 y_span=substrate_span, 
16                 z_max=film_thickness, 
17                 z_min=0, 
18                 material="Au (Gold) - CRC")
19
20    # Add the nanohole array in the gold layer
21    # For this, we use the built-in rectangular photonic crystal object from the library
22    pc_props = {
23        "name": "nanoholes",
24        "material": "etch",
25        "radius": hole_radius,
26        "z": film_thickness / 2,
27        "z span": film_thickness,
28        "nx": nx,
29        "ny": ny,
30        "ax": periodicity,
31        "ay": periodicity,
32    }
33    fdtd.addobject("rect_pc")
34    fdtd.set(pc_props)
35
36    # Set up the simulation region
37    fdtd_geometry_props = {"x": 0, "x span": periodicity, "y": 0, "y span": periodicity, "z": 0, "z span": fdtd_z_span}
38    # Use symmetric boundary conditions in x and y and steep angle PML profile in z
39    fdtd_boundary_props = {
40        "allow symmetry on all boundaries": 1,
41        "x min bc": "anti-symmetric",
42        "x max bc": "anti-symmetric",
43        "y min bc": "symmetric",
44        "y max bc": "symmetric",
45        "z min bc": "PML",
46        "z max bc": "PML",
47        "pml profile": 3,
48    }
49    # Combine properties settings into one dictionary
50    fdtd_props = OrderedDict({**fdtd_geometry_props, **fdtd_boundary_props})
51    fdtd.addfdtd(properties=fdtd_props)
52
53    # Add a mesh override region around the holes
54    fdtd.addmesh(dx=dx, dy=dx, dz=dx, based_on_a_structure=1, structure="circle")
55
56    # Add plane wave source
57    fdtd.addplane(injection_axis="z-axis", direction="backward", x_span=substrate_span, y_span=substrate_span, z=source_z)
58    fdtd.setglobalsource("wavelength start", wavelength_start)
59    fdtd.setglobalsource("wavelength stop", wavelength_stop)
60
61    # Set up frequency domain monitors to measure R and T
62    # First, set global monitor properties
63    # Source limits will be used by default to define min/max wavelength
64    fdtd.setglobalmonitor("frequency points", 50)
65    # Now add the monitors
66    fdtd.adddftmonitor(name="T_monitor", 
67                       monitor_type="2D Z-normal", 
68                       x_span=substrate_span, 
69                       y_span=substrate_span, 
70                       z=transmission_z)
71    fdtd.adddftmonitor(name="R_monitor", 
72                       monitor_type="2D Z-normal", 
73                       x_span=substrate_span, 
74                       y_span=substrate_span, 
75                       z=reflection_z)
76
77    # zoom CAD view around simulation region
78    fdtd.select("FDTD")
79    fdtd.setview("extent")
80
81    fdtd.save(filename)
82    print("File saved to folder as: " + filename)

The simulation file is saved in the current working directory - you can open it in the Lumerical GUI to check the simulation setup.

Simulation setup

Step 3 - Run and plot results

Run the simulation and plot the transmission and reflection spectra.

Show simulation run and plotting
 1# Open the file and run the simulation! Visualize the T/R spectrum.
 2with lumapi.FDTD(filename, hide=True) as fdtd:
 3    print("Starting simulation now...")
 4    fdtd.run()
 5    print("Run completed.")
 6
 7    # Retrieve results
 8    T = fdtd.getresult("T_monitor", "T")  # Returns lumerical dataset T vs lambda/f
 9    R = fdtd.getresult("R_monitor", "T")
10
11    # Visualize using matplotlib
12    fig, ax = plt.subplots()
13    ax.plot(T["lambda"] * 1e9, T["T"], label="Transmission")
14    ax.plot(R["lambda"] * 1e9, -1 * R["T"], label="Reflection")  # light traveling along -z so T result is negative
15    ax.set_xlabel("Wavelength [nm]")
16    ax.set_ylabel("T/R")
17    ax.legend()
18    plt.show()

The figure below shows the transmission and reflection spectrum of the array.

Transmission spectrum

Full script

Show full script for copy and paste
  1# --- Imports ---
  2
  3from collections import OrderedDict
  4
  5import matplotlib.pyplot as plt
  6
  7import ansys.lumerical.core as lumapi
  8
  9# --- Imports end ---
 10
 11# --- Parameters ---
 12# Define parameters
 13
 14filename = "Nanohole_array.fsp"
 15
 16# Parameters related to the patterned film
 17periodicity = 400e-9  # 400 nm periodic array
 18film_thickness = 100e-9
 19hole_radius = 100e-9  # radius of the nanoholes
 20nx = ny = 3  # Number of nanoholes
 21
 22# Parameters for the substrate
 23substrate_thickness = 1e-6
 24substrate_span = 1.2e-6
 25
 26# FDTD region and mesh
 27fdtd_z_span = 1e-6  # Ensure span is large enough to capture both T, R monitors
 28transmission_z = 0.4e-6  # z position of top "T" monitor
 29reflection_z = -0.2e-6  # z position of bottom "R" monitor
 30dx = 0.01e-6  # mesh override resolution
 31
 32# Source and wavelengths
 33source_z = 0.3e-6  # position of source
 34wavelength_start = 0.4e-6
 35wavelength_stop = 0.7e-6
 36# --- Parameters end ---
 37
 38# --- Simulation setup ---
 39# Initialize session and build simulation objects. Set hide = True to hide the Lumerical GUI.
 40
 41with lumapi.FDTD(hide=False) as fdtd:
 42    # Add the substrate
 43    fdtd.addrect(name="substrate", 
 44                 x_span=substrate_span, 
 45                 y_span=substrate_span, 
 46                 z_max=0, 
 47                 z_min=substrate_thickness, 
 48                 material="SiO2 (Glass) - Palik")
 49
 50    # Add the gold film
 51    fdtd.addrect(name="film", 
 52                 x_span=substrate_span, 
 53                 y_span=substrate_span, 
 54                 z_max=film_thickness, 
 55                 z_min=0, 
 56                 material="Au (Gold) - CRC")
 57
 58    # Add the nanohole array in the gold layer
 59    # For this, we use the built-in rectangular photonic crystal object from the library
 60    pc_props = {
 61        "name": "nanoholes",
 62        "material": "etch",
 63        "radius": hole_radius,
 64        "z": film_thickness / 2,
 65        "z span": film_thickness,
 66        "nx": nx,
 67        "ny": ny,
 68        "ax": periodicity,
 69        "ay": periodicity,
 70    }
 71    fdtd.addobject("rect_pc")
 72    fdtd.set(pc_props)
 73
 74    # Set up the simulation region
 75    fdtd_geometry_props = {"x": 0, "x span": periodicity, "y": 0, "y span": periodicity, "z": 0, "z span": fdtd_z_span}
 76    # Use symmetric boundary conditions in x and y and steep angle PML profile in z
 77    fdtd_boundary_props = {
 78        "allow symmetry on all boundaries": 1,
 79        "x min bc": "anti-symmetric",
 80        "x max bc": "anti-symmetric",
 81        "y min bc": "symmetric",
 82        "y max bc": "symmetric",
 83        "z min bc": "PML",
 84        "z max bc": "PML",
 85        "pml profile": 3,
 86    }
 87    # Combine properties settings into one dictionary
 88    fdtd_props = OrderedDict({**fdtd_geometry_props, **fdtd_boundary_props})
 89    fdtd.addfdtd(properties=fdtd_props)
 90
 91    # Add a mesh override region around the holes
 92    fdtd.addmesh(dx=dx, dy=dx, dz=dx, based_on_a_structure=1, structure="circle")
 93
 94    # Add plane wave source
 95    fdtd.addplane(injection_axis="z-axis", direction="backward", x_span=substrate_span, y_span=substrate_span, z=source_z)
 96    fdtd.setglobalsource("wavelength start", wavelength_start)
 97    fdtd.setglobalsource("wavelength stop", wavelength_stop)
 98
 99    # Set up frequency domain monitors to measure R and T
100    # First, set global monitor properties
101    # Source limits will be used by default to define min/max wavelength
102    fdtd.setglobalmonitor("frequency points", 50)
103    # Now add the monitors
104    fdtd.adddftmonitor(name="T_monitor", 
105                       monitor_type="2D Z-normal", 
106                       x_span=substrate_span, 
107                       y_span=substrate_span, 
108                       z=transmission_z)
109    fdtd.adddftmonitor(name="R_monitor", 
110                       monitor_type="2D Z-normal", 
111                       x_span=substrate_span, 
112                       y_span=substrate_span, 
113                       z=reflection_z)
114
115    # zoom CAD view around simulation region
116    fdtd.select("FDTD")
117    fdtd.setview("extent")
118
119    fdtd.save(filename)
120    print("File saved to folder as: " + filename)
121# --- Simulation setup end --
122
123
124# --- Run ---
125# Open the file and run the simulation! Visualize the T/R spectrum.
126with lumapi.FDTD(filename, hide=True) as fdtd:
127    print("Starting simulation now...")
128    fdtd.run()
129    print("Run completed.")
130
131    # Retrieve results
132    T = fdtd.getresult("T_monitor", "T")  # Returns lumerical dataset T vs lambda/f
133    R = fdtd.getresult("R_monitor", "T")
134
135    # Visualize using matplotlib
136    fig, ax = plt.subplots()
137    ax.plot(T["lambda"] * 1e9, T["T"], label="Transmission")
138    ax.plot(R["lambda"] * 1e9, -1 * R["T"], label="Reflection")  # light traveling along -z so T result is negative
139    ax.set_xlabel("Wavelength [nm]")
140    ax.set_ylabel("T/R")
141    ax.legend()
142    plt.show()
143# --- Run end ---

Further resources#

User guide

Information on key concepts of PyLumerical.

User guide
API reference

Reference for the PyLumerical API.

API reference
Examples

Gallery of examples using PyLumerical.

Examples
Lumerical scripting commands

Reference for Lumerical scripting commands.

https://optics.ansys.com/hc/en-us/articles/360037228834-Lumerical-scripting-language-By-category
Photonic inverse design with lumopt2

Introduction to using lumopt2 for photonic inverse design.

Introduction to photonic inverse design with lumopt2