This is a solo research repository. This guide documents the project conventions, development environment setup, and the steps for adding new simulation modules.
- Python 3.8 or higher
- Lumerical Design Suite (required for running simulations)
- Conda (recommended) or virtualenv
Scripts are not installed as a package. Two paths must be on PYTHONPATH:
- The repository root — so
project_layout.pyandsim_registry.pyare importable - The Lumerical
api/pythondirectory — solumapiis importable
VSCode — create or edit .env at the repo root:
PYTHONPATH=C:\Program Files\Lumerical\vXXX\api\python;D:\path\to\lumerical-py-scripts
Spyder — add both paths via Tools → PYTHONPATH manager → Add Path.
Replace vXXX with your installed Lumerical version (e.g. v232).
pip install ruff pre-commit
pre-commit installFollow these steps to stay consistent with the existing 27 modules.
<DOMAIN>/<module_name>/
├── README.md ← copy from README_TEMPLATE.md and fill in
├── user_inputs/
│ ├── user_simulation_parameters.py
│ ├── user_sweep_parameters.py
│ └── user_materials.py ← DEVICE modules only
├── <analysis_subdir>/
│ └── <analysis_script>.py
└── <render_script>.py ← optional
Add a SimSpec entry to the SIMS dict:
"fdtd.my_new_module": SimSpec(
key="fdtd.my_new_module",
domain="FDTD",
module="my_new_module",
templates=["my_template.fsp"],
figure_groups=["Transmission", "Fields"],
create_lumerical_dir=False,
),Keys follow the pattern {domain_lowercase}.{module_name} (e.g. "fdtd.adiabatic_dc").
from project_layout import setup
spec, out, templates = setup("fdtd.my_new_module", __file__)
template_fsp = templates[0]
figures_dir = out["figure_groups"]["Transmission"]At minimum complete: Purpose, What this module does, Quick Start, Folder Structure, and Status sections.
Add a ### subsection for the new module in FDTD/README.md, MODE/README.md,
or DEVICE/README.md as appropriate.
| Context | Convention | Rationale |
|---|---|---|
Analysis functions (get*, extraction/processing) |
camelCase |
Mirrors Lumerical's own API (getdata, getresult, setnamed) |
| Render / infrastructure functions | snake_case |
Standard Python (e.g. add_fde_region, waveguide_draw) |
| Constants and module-level parameters | UPPER_CASE |
PEP 8 convention |
Do not rename existing functions. Renaming would silently break scripts that import them and provides no functional benefit.
Use Google-style docstrings throughout. The canonical example is
FDTD/adiabatic_directional_coupler/transmission/getFrequencyResponse.py.
Rule by function type:
| Function type | Required docstring |
|---|---|
Module-level (every .py file) |
Short paragraph: what it computes, what monitors/data it uses |
| Functions with multiple parameters | Full Args: + Returns: blocks |
| Single-argument analysis functions | Args: + Returns: blocks (recommended) |
Render functions (e.g. waveguide_draw) |
One-liner summary is sufficient |
user_inputs/user_*.py |
Module-level comment + inline parameter annotations |
Module-level docstring example:
"""
Extract the cross-port and through-port transmission spectra from FDTD monitors.
Monitors expected: ``cross_transmission``, ``through_transmission``, ``source``.
"""Function-level docstring example:
def getCrossResponse(fdtd):
"""Extract transmission response from FDTD monitors.
Args:
fdtd: FDTD simulation object from lumapi.
Returns:
tuple: (T1, T2, f) where T1 is the through-port transmission (ndarray),
T2 is the bar-port transmission (ndarray), and f is the frequency
array (ndarray).
"""Render function example:
def add_fde_region(mode):
"""Add and configure the FDE region and mesh in the MODE simulation."""user_inputs/user_*.py files are intentionally flat parameter namespaces.
Wildcard imports (from module.user_inputs.user_parameters import *) are a
deliberate design choice — they expose all parameters to analysis scripts without
requiring explicit listing. These are excluded from linting rules; do not
convert them to explicit imports.
Target 100 characters. The linter is configured with line-length = 100.
Existing files that exceed this are grandfathered in via extend-ignore = ["E501"].
Apply the limit to all new code.
ruff check . # report all lint issues
ruff check . --fix # auto-fix safe issues
ruff format . # auto-format code styleOr via pre-commit on staged files only:
pre-commit run ruffTo run all hooks across the entire repo (useful after initial install):
pre-commit run --all-files- No automated test suite. All simulation scripts require a running Lumerical license to execute. The CI pipeline runs linting only — it does not execute any simulation code.
- Results directories are not tracked. The
.gitignoreexcludes allResults/directories. Only scripts and user inputs are version-controlled. - lumapi is not in requirements.txt. It is a proprietary system dependency
installed with Lumerical Design Suite and must be configured via
PYTHONPATHas described in the setup section above.