Skip to content

Commit ad07598

Browse files
committed
First commit
1 parent f0fad77 commit ad07598

47 files changed

Lines changed: 4477 additions & 1 deletion

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
fail-fast: false
14+
matrix:
15+
python-version: ["3.12", "3.13"]
16+
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
- name: Set up Python ${{ matrix.python-version }}
21+
uses: actions/setup-python@v5
22+
with:
23+
python-version: ${{ matrix.python-version }}
24+
cache: pip
25+
26+
- name: Install package and dev dependencies
27+
run: pip install -e ".[dev]"
28+
29+
- name: Run tests
30+
run: pytest

.gitignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
__pycache__/
2+
*.py[cod]
3+
*.so
4+
.pytest_cache/
5+
.mypy_cache/
6+
.ruff_cache/
7+
.coverage
8+
htmlcov/
9+
dist/
10+
build/
11+
*.egg-info/
12+
.venv/
13+
venv/
14+
.ipynb_checkpoints/
15+
.codex

README.md

Lines changed: 151 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,152 @@
11
# WaveguideModalBPM1D
2-
TE modal analysis, beam propagation (straight guides & couplers), parametric sweeps, and matplotlib-based plots.
2+
3+
> **TL;DR**: Python scientific engine for 1D modal analysis and BPM simulations of optical waveguides and couplers.
4+
5+
Python package for 1D modal analysis and Beam Propagation Method (BPM) simulations.
6+
7+
## What the package includes
8+
9+
- finite-difference modal solver for multilayer structures;
10+
- BPM routines for straight waveguides and couplers;
11+
- helper functions for parametric sweeps;
12+
- visualization functions based on `matplotlib`.
13+
14+
## Repository structure
15+
16+
- `WaveguideModalBPM1D/`: package source code;
17+
- `tests/`: basic automated tests;
18+
- `examples/`: one script per figure (`NN_*.py`), `example_parameters.py` (all gallery numerics explicit), `figure_helpers.py`, `generate_figures.py`;
19+
- `pyproject.toml`: packaging configuration.
20+
21+
## Example figures (`examples/`)
22+
23+
There are **22 numbered scripts** (`01_*.py``22_*.py`). Each configures the `Agg` backend, imports explicit parameters from `examples/example_parameters.py`, runs the minimal simulation for that plot, and writes one PNG under `examples/figures/`. That module lists every wavelength, index stack, grid size, sweep limit, and plot label used in the gallery so the scripts do **not** rely on omitting arguments to the library dataclasses (see **Package defaults** below for what the library would use if you omitted fields). Shared helpers live in `examples/figure_helpers.py` (`save_figure`, optional `silent_stdout`; path setup is also done inside `example_parameters.py` so imports resolve when you run a script from the repo root).
24+
25+
Run **one** example from the repository root:
26+
27+
```bash
28+
pip install -e .
29+
python examples/01_modal_api_profile_and_modes.py
30+
```
31+
32+
Regenerate **all** PNGs in sequence:
33+
34+
```bash
35+
python examples/generate_figures.py
36+
```
37+
38+
| Script | Output PNG | Primary API (same layout where noted) |
39+
|--------|------------|----------------------------------------|
40+
| `01_modal_api_profile_and_modes.py` | `01_modal_api_profile_and_modes.png` | `plot_modal_analysis` |
41+
| `02_modal_api_neff_dispersion.py` | `02_modal_api_neff_dispersion.png` | `plot_dispersion_curves` |
42+
| `03_workflow_multilayer_modes.py` | `03_workflow_multilayer_modes.png` | `plot_multilayer_modes` |
43+
| `04_workflow_dispersion_with_angle_axis.py` | `04_workflow_dispersion_with_angle_axis.png` | `plot_dispersion_with_angle_axis` |
44+
| `05_straight_bpm_fundamental_heatmap.py` | `05_straight_bpm_fundamental_heatmap.png` | `plot_straight_bpm_heatmap` |
45+
| `06_straight_bpm_input_output_profiles.py` | `06_straight_bpm_input_output_profiles.png` | `plot_straight_profile_comparison` |
46+
| `07_parallel_coupler_heatmap.py` | `07_parallel_coupler_heatmap.png` | `plot_coupler_t3_heatmap` (alias `plot_parallel_coupler_heatmap`) |
47+
| `08_parallel_coupler_profiles.py` | `08_parallel_coupler_profiles.png` | `plot_parallel_coupler_profiles` |
48+
| `09_parallel_coupler_power.py` | `09_parallel_coupler_power.png` | `plot_parallel_power_transfer` |
49+
| `10_coupler_heatmap.py` | `10_coupler_heatmap.png` | `plot_coupler_heatmap` |
50+
| `11_coupler_port_power.py` | `11_coupler_port_power.png` | `plot_coupler_power_transfer` |
51+
| `12_coupler_input_output_profiles.py` | `12_coupler_input_output_profiles.png` | `plot_coupler_output_profiles` (wrapper over `plot_input_output_profiles`) |
52+
| `13_coupler_power_and_profiles.py` | `13_coupler_power_and_profiles.png` | `plot_coupler_transfer_and_profiles` |
53+
| `14_coupler_spectral_response.py` | `14_coupler_spectral_response.png` | `plot_coupler_wavelength_response` |
54+
| `15_sweep_parameter_to_lc.py` | `15_sweep_parameter_to_lc.png` | `plot_parameter_to_lc` |
55+
| `16_sweep_parameter_lc.py` | `16_sweep_parameter_lc.png` | `plot_parameter_lc` |
56+
| `17_sweep_parameter_peak_transfer.py` | `17_sweep_parameter_peak_transfer.png` | `plot_parameter_peak_transfer` |
57+
| `18_sweep_gap_to_lc_coupler.py` | `18_sweep_gap_to_lc_coupler.png` | `plot_gap_to_lc_coupler` |
58+
| `19_sweep_gap_to_peak_transfer_coupler.py` | `19_sweep_gap_to_peak_transfer_coupler.png` | `plot_gap_to_peak_transfer_coupler` |
59+
| `20_sweep_gap_parallel_lc_combo.py` | `20_sweep_gap_parallel_lc_combo.png` | `plot_gap_to_lc_parallel_coupler` |
60+
| `21_sweep_gap_parallel_lc_curve.py` | `21_sweep_gap_parallel_lc_curve.png` | `plot_gap_to_lc_curve_parallel_coupler` |
61+
| `22_sweep_gap_parallel_peak_transfer.py` | `22_sweep_gap_parallel_peak_transfer.png` | `plot_gap_to_peak_transfer_parallel_coupler` |
62+
63+
Not given as separate scripts (same figure layout as above): `plot_coupler_t3_profiles_and_transfer` / `plot_parallel_coupler_profiles_and_transfer` (two figures: run `08` and `09`); `plot_gap_to_lc_curve_coupler` (same style as `plot_parameter_lc` / script `16` with coupler-oriented labels).
64+
65+
## Package defaults (library)
66+
67+
These are the **default field values** if you construct the dataclasses without passing arguments (sources: `WaveguideModalBPM1D/parameters.py`, `WaveguideModalBPM1D/analyzer.py`). They are **not** what the example gallery uses; the gallery values are defined in `examples/example_parameters.py`.
68+
69+
### `ModalStructureParams`
70+
71+
| Field | Default |
72+
|-------|---------|
73+
| `lambda_0` | `1.0 * um` |
74+
| `n_points` | `1000` |
75+
| `refractive_indices` | `(3.55, 3.55, 3.60, 3.55, 3.55)` |
76+
| `thicknesses` | `(5.0*um, 0.5*um, 1.0*um, 0.5*um, 5.0*um)` |
77+
78+
### `NotebookConfig`
79+
80+
| Field | Default |
81+
|-------|---------|
82+
| `lambda_0` | `1.0 * um` |
83+
| `n_points` | `1000` |
84+
| `refractive_indices` | `(3.55, 3.60, 3.55)` |
85+
| `thicknesses` | `(50.0*um, 1.0*um, 50.0*um)` |
86+
| `joblib_n_jobs` | `-1` |
87+
| `joblib_backend` | `"loky"` |
88+
| `joblib_verbose` | `5` |
89+
90+
### `CouplerTestParams`
91+
92+
| Field | Default |
93+
|-------|---------|
94+
| `n_core` | `1.50` |
95+
| `n_clad` | `1.42` |
96+
| `window` | `40.0 * um` |
97+
| `lambda_launch` | `1.0 * um` |
98+
| `length_total` | `1764.0 * um` |
99+
| `length_coupling` | `882.0 * um` |
100+
| `port_offset` | `10.0 * um` |
101+
| `core_width` | `1.0 * um` |
102+
| `center_offset` | `1.0 * um` |
103+
| `sigma` | `0.45 * um` |
104+
| `n_points` | `401` |
105+
| `mode_search_count` | `8` |
106+
107+
### Other API defaults (selected)
108+
109+
`WaveguideModalBPM1D.solve_modes`: `polarization="TE"`, `thicknesses=None` (uses config), `n_points=None`, `lambda_launch=None`, `indices=None`, `n_cladding=None` (then cladding index is taken from the outer layers of `indices`), `k_search=10`.
110+
`WaveguideModalBPM1D.compute_dispersion`: `polarization="TE"`, `n_x=1000`, `max_modes_cap=10`.
111+
`sweep_gap_to_lc_coupler` / `sweep_gap_to_lc_parallel_coupler`: `min_fraction=0.05`, `min_power=0.05` (and parallel sweep `extra_margin=5.0*um`, default `gap_values` if omitted).
112+
`sweep_coupler_wavelength_response`: `n_jobs=-1`, `backend="loky"`, `verbose=0`.
113+
114+
## License
115+
116+
This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0) - see the [LICENSE](LICENSE) file for details.
117+
118+
## Local installation
119+
120+
```bash
121+
pip install -e .
122+
```
123+
124+
To install development dependencies:
125+
126+
```bash
127+
pip install -e ".[dev]"
128+
```
129+
130+
To enable optional acceleration with `numba`:
131+
132+
```bash
133+
pip install -e ".[accel]"
134+
```
135+
136+
## Quick example
137+
138+
```python
139+
from WaveguideModalBPM1D import NotebookConfig, WaveguideModalBPM1D, um
140+
141+
config = NotebookConfig(lambda_0=1.0 * um, n_points=400)
142+
analyzer = WaveguideModalBPM1D(config)
143+
modal_te = analyzer.solve_modes(polarization="TE")
144+
145+
print(modal_te["n_effs"])
146+
```
147+
148+
## Tests
149+
150+
```bash
151+
pytest
152+
```

WaveguideModalBPM1D.code-workspace

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"folders": [
3+
{
4+
"name": "WaveguideModalBPM1D",
5+
"path": "."
6+
}
7+
],
8+
"settings": {
9+
"python.testing.pytestEnabled": true,
10+
"python.testing.unittestEnabled": false,
11+
"python.analysis.diagnosticMode": "workspace"
12+
},
13+
"extensions": {
14+
"recommendations": [
15+
"ms-python.python",
16+
"ms-python.vscode-pylance"
17+
]
18+
}
19+
}

WaveguideModalBPM1D/__init__.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
from .analyzer import NotebookConfig, WaveguideAnalysis2D, WaveguideModalBPM1D
2+
from .constants import nm, um
3+
from .coupling_sweep import (
4+
estimate_first_relevant_peak,
5+
estimate_lc_by_supermodes,
6+
plot_gap_to_lc_curve_coupler,
7+
plot_gap_to_lc_coupler,
8+
plot_gap_to_peak_transfer_coupler,
9+
plot_parameter_lc,
10+
plot_parameter_peak_transfer,
11+
plot_parameter_to_lc,
12+
sweep_gap_to_lc_coupler,
13+
sweep_parameter_to_lc,
14+
)
15+
from .modal import (
16+
DispersionAnalysisResult,
17+
ModalAnalysisResult,
18+
analyze_modes,
19+
assemble_helmholtz_operator,
20+
build_index_profile,
21+
compute_dispersion_curves,
22+
plot_dispersion_curves,
23+
plot_modal_analysis,
24+
solve_guided_modes,
25+
)
26+
from .parameters import CouplerTestParams, ModalStructureParams
27+
from .test_cases import (
28+
CouplerSimulationResult,
29+
generate_gaussian_input,
30+
normalize_mode,
31+
simulate_coupler,
32+
)
33+
from .workflows import (
34+
CouplerT3Result,
35+
StraightBPMResult,
36+
plot_coupler_heatmap,
37+
plot_coupler_output_profiles,
38+
plot_coupler_power_transfer,
39+
plot_coupler_transfer_and_profiles,
40+
plot_coupler_t3_heatmap,
41+
plot_coupler_t3_profiles_and_transfer,
42+
plot_coupler_wavelength_response,
43+
plot_dispersion_with_angle_axis,
44+
plot_gap_to_lc_parallel_coupler,
45+
plot_gap_to_lc_curve_parallel_coupler,
46+
plot_gap_to_peak_transfer_parallel_coupler,
47+
plot_input_output_profiles,
48+
plot_multilayer_modes,
49+
plot_parallel_coupler_profiles,
50+
plot_parallel_coupler_heatmap,
51+
plot_parallel_coupler_profiles_and_transfer,
52+
plot_parallel_power_transfer,
53+
plot_straight_bpm_heatmap,
54+
plot_straight_profile_comparison,
55+
print_mode_summary,
56+
run_parallel_coupler_bpm,
57+
run_straight_waveguide_bpm_fundamental,
58+
run_straight_waveguide_bpm_gaussian,
59+
summarize_coupler_output,
60+
sweep_coupler_wavelength_response,
61+
sweep_gap_to_lc_parallel_coupler,
62+
)
63+
64+
__all__ = [
65+
"DispersionAnalysisResult",
66+
"CouplerSimulationResult",
67+
"CouplerT3Result",
68+
"CouplerTestParams",
69+
"ModalAnalysisResult",
70+
"NotebookConfig",
71+
"ModalStructureParams",
72+
"StraightBPMResult",
73+
"WaveguideAnalysis2D",
74+
"WaveguideModalBPM1D",
75+
"analyze_modes",
76+
"assemble_helmholtz_operator",
77+
"build_index_profile",
78+
"compute_dispersion_curves",
79+
"sweep_gap_to_lc_coupler",
80+
"estimate_first_relevant_peak",
81+
"estimate_lc_by_supermodes",
82+
"generate_gaussian_input",
83+
"nm",
84+
"normalize_mode",
85+
"plot_gap_to_lc_coupler",
86+
"plot_gap_to_lc_curve_coupler",
87+
"plot_gap_to_peak_transfer_coupler",
88+
"plot_parameter_lc",
89+
"plot_parameter_peak_transfer",
90+
"plot_gap_to_lc_parallel_coupler",
91+
"plot_gap_to_lc_curve_parallel_coupler",
92+
"plot_gap_to_peak_transfer_parallel_coupler",
93+
"plot_input_output_profiles",
94+
"plot_modal_analysis",
95+
"plot_parallel_coupler_profiles",
96+
"plot_parallel_coupler_heatmap",
97+
"plot_parallel_coupler_profiles_and_transfer",
98+
"plot_parallel_power_transfer",
99+
"plot_dispersion_curves",
100+
"plot_coupler_t3_heatmap",
101+
"plot_coupler_t3_profiles_and_transfer",
102+
"plot_coupler_heatmap",
103+
"plot_coupler_power_transfer",
104+
"plot_coupler_output_profiles",
105+
"plot_coupler_transfer_and_profiles",
106+
"plot_coupler_wavelength_response",
107+
"plot_dispersion_with_angle_axis",
108+
"plot_multilayer_modes",
109+
"plot_parameter_to_lc",
110+
"plot_straight_bpm_heatmap",
111+
"plot_straight_profile_comparison",
112+
"print_mode_summary",
113+
"run_straight_waveguide_bpm_fundamental",
114+
"run_straight_waveguide_bpm_gaussian",
115+
"run_parallel_coupler_bpm",
116+
"simulate_coupler",
117+
"solve_guided_modes",
118+
"summarize_coupler_output",
119+
"sweep_gap_to_lc_parallel_coupler",
120+
"sweep_parameter_to_lc",
121+
"sweep_coupler_wavelength_response",
122+
"um",
123+
]

0 commit comments

Comments
 (0)