Metadata-Version: 2.5
Name: photonhub
Version: 0.1.5
Summary: Python client for the PhotonHub GPU FDTD photonics solver
Project-URL: Homepage, https://leapfield.ai/
Project-URL: Repository, https://github.com/Leapfield/photonhub-sdk
Project-URL: Beta access and support, https://leapfield.ai/#request
Author: LeapField
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: FDTD,electromagnetics,photonics,simulation
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Scientific/Engineering :: Physics
Requires-Python: >=3.11
Requires-Dist: certifi
Requires-Dist: matplotlib
Requires-Dist: numpy
Requires-Dist: pydantic>=2.6
Requires-Dist: scipy
Requires-Dist: xarray
Provides-Extra: app
Requires-Dist: fastapi; extra == 'app'
Requires-Dist: gdstk; extra == 'app'
Requires-Dist: h5py; extra == 'app'
Requires-Dist: mcp<2,>=1; extra == 'app'
Requires-Dist: plotly; extra == 'app'
Requires-Dist: uvicorn; extra == 'app'
Provides-Extra: gds
Requires-Dist: gdstk; extra == 'gds'
Provides-Extra: hdf5
Requires-Dist: h5py; extra == 'hdf5'
Provides-Extra: mcp
Requires-Dist: mcp<2,>=1; extra == 'mcp'
Provides-Extra: notebook
Requires-Dist: nbformat; extra == 'notebook'
Provides-Extra: replicate
Requires-Dist: pyyaml; extra == 'replicate'
Provides-Extra: server
Requires-Dist: fastapi; extra == 'server'
Requires-Dist: uvicorn; extra == 'server'
Provides-Extra: test
Requires-Dist: fastapi; extra == 'test'
Requires-Dist: gdstk; extra == 'test'
Requires-Dist: h5py; extra == 'test'
Requires-Dist: httpx; extra == 'test'
Requires-Dist: ipywidgets; extra == 'test'
Requires-Dist: mcp<2,>=1; extra == 'test'
Requires-Dist: nbformat; extra == 'test'
Requires-Dist: plotly; extra == 'test'
Requires-Dist: pytest; extra == 'test'
Requires-Dist: pyyaml; extra == 'test'
Requires-Dist: ruff<0.17,>=0.16; extra == 'test'
Requires-Dist: shapely; extra == 'test'
Requires-Dist: uvicorn; extra == 'test'
Provides-Extra: viz
Requires-Dist: ipywidgets; extra == 'viz'
Requires-Dist: plotly; extra == 'viz'
Requires-Dist: shapely; extra == 'viz'
Description-Content-Type: text/markdown

# photonhub

Python client for the PhotonHub FDTD solver. The pydantic models in
`photonhub.components` are the single source of truth for the simulation
JSON wire format; the published simulation schema is generated from them via
`python -m photonhub.schema emit`.

## Install

Python 3.11+:

```sh
python -m pip install photonhub
```

(From a monorepo checkout: `python -m pip install -e ./photonhub`.)

That installs the full scripting client: build simulations, estimate cost,
run on the **cloud GPU** (`ph.cloud.run_quoted(sim, max_usd=...)` with your beta
API key), and read results, with no compiler and no engine build. **Local** runs
(`ph.run_local`) also need the `phsolver` engine binary, which pip does not
ship: invited beta participants receive the standalone headless solver
archive (install it with `photonhub install-solver --archive <file> --sha256
<digest>`, or point `$PHOTONHUB_SOLVER` at it or put it on `PATH`; the copy inside
the desktop app is locked to that app and is not a standalone command), and
developers with the monorepo build it with
`cmake -S engine -B build && cmake --build build`.

Optional extras: `photonhub[viz]` (interactive/3D plots), `[gds]` (GDSII
import/export), `[hdf5]` (HDF5 result export), `[replicate]`, `[notebook]`,
and the service extras below.

```python
import photonhub as ph

sim = ph.Simulation(
    size_um=(4.0, 4.0, 4.0),
    grid=ph.UniformMesh(dl_um=0.05),
    run=ph.RunSpec(run_time_s=8.0e-14),
    sources=[
        ph.PointDipole(
            center_um=(2.0, 2.0, 2.0),
            polarization="Ez",
            source_time=ph.GaussianPulse(freq0_hz=1.934e14, fwidth_hz=4.0e13),
        )
    ],
    monitors=[
        ph.TimeMonitor(name="probe", center_um=(3.0, 2.0, 2.0), fields=["Ez"]),
        ph.SnapshotMonitor(name="final", fields=["Ex", "Ey", "Ez"]),
    ],
)

data = ph.run_local(sim)        # finds phsolver, runs it, parses outputs
probe = data["probe"]           # xarray.DataArray, dims ('t', 'component')
```

Optional command-line services are kept out of the base SDK dependency set:

```sh
python -m pip install 'photonhub[mcp]'
photonhub-mcp                    # optionally pass a result directory to preload

python -m pip install 'photonhub[server]'
photonhub-serve-viz              # local result/preview HTTP service (loopback, unauthenticated:
                                 # single-user machines only; --enable-notebook opts into code cells)
```

The `photonhub[app]` extra includes both service dependency sets plus the
desktop app's file-format integrations.

## See your simulation before you run it

Every `Simulation` plots itself: geometry, sources, monitors, PML, and the
**permittivity the solver actually meshes**, with matplotlib (built in; plotly
for 3D). `grid=True` overlays the mesh cell edges so you can check resolution:

```python
sim.plot(z=2.0)                   # scene cross-section through the source
sim.plot_index(z=2.0, grid=True)    # the permittivity the run sees + the mesh overlay
sim.plot_3d()                     # interactive 3D  (pip install photonhub[viz])
```

## What you can do today

Shipped surface as of schema **v1.21.0-alpha.1** (a dispersive solver core
cross-checked against analytic references: multi-pole Lorentz + Drude ADE
with a fitted metals library (Au/Ag/Cu/Al) and PEC structures, with recorded
CPU↔GPU equivalence (the 0.1.4 GPU solver image passed all 65 GPU
equivalence tests on 2026-09-28) under the numerical contract's tolerances; plus full-vector mode
injection, GDS import (`ph.import_gds`), adjoint gradients, and silicon
photonic-circuit tools):

- **Ports and declarative setup:** `ph.Port` names a plane, a guide and a
  mode. `ph.Simulation(ports=..., source="in", wlens_um=...,
  domain=ph.Domain(...), mesh=ph.Mesh(...))` fits the box around your
  structures, builds the mesh, launches the driven port and records every
  port; `data.transmission("out")` and `data.reflection()` read them back as
  spectra. `symmetry=` reduces a symmetric device to the half the solver
  steps, and every view and readout shows the whole device.
- **Run a simulation:** `ph.run_local(sim)` (subprocess + file protocol;
  `device="cpu"|"gpu"|"gpu:N"`), `ph.submit(sim)` and `ph.Batch(...)` for many
  sims in flight.
- **Know the cost first:** `sim.cost_estimate()` (or `ph.quote(sim)`)
  returns a dollar estimate
  from an overridable planning rate per cell and time step *before* you press run; the
  default is an estimator input, not a production billing commitment.
- **Geometry:** `Box`, `Sphere`, `Cylinder` (full, or an annular sector / ring
  via `inner_radius_um` + `angle_start_rad` / `angle_stop_rad`), and `Polygon` (an
  extruded polygon, e.g. a taper).
- **Sources:** `PointDipole`, `PlaneWave` (normal-incidence TF/SF; oblique
  via `Simulation.with_oblique_plane_wave` + Bloch boundaries, schema 1.18),
  the closed `TFSFBox` scattering box (single-run cross-sections with PML on
  all sides), and the `mode_launch` waveguide-mode builder that declared ports
  use, all driven by a `GaussianPulse` or a steady-state `CW` carrier. The
  `ModeSource` wire type remains for legacy scalar-mode compatibility.
- **Monitors:** `TimeMonitor`, `SnapshotMonitor`, `ProfileMonitor`,
  and `PowerMonitor`: fp64 DFT field and flux power. A DFT plane may carry the
  optional `ModePort` authoring recipe; the engine strictly validates and then
  ignores that metadata while recording the same raw fields, and result
  post-processing performs the requested modal projection. Workbench keeps one
  shared wavelength sweep across ports; port planes/windows stay outside
  PML/absorber cells; and preflight requires one downstream driven port linked
  to the first wire-order normalization source with no other active excitation,
  so an unevaluable S-column is rejected before the time-domain run.
- **Component library:** `ph.library.straight / bend / taper / crossing /
  coupler / ring`: each returns a `Component` (structures + ports) in ~one line.
- **Material library:** `ph.materials`: 20 literature materials (Si, SiO2,
  Si3N4, GaAs, InP, Ge, LiNbO3, sapphire, AlN, TiO2, MgF2, CaF2, PMMA, ...)
  with cited dispersion data and validity ranges. `Si.medium(1.55)` freezes
  the index at one wavelength; `Si.medium(band_um=(1.5, 1.6))` least-squares
  fits the engine's single Lorentz pole over the band (Courant-safe pole
  placement; it warns when the fitted index is off by more than 1e-3).
  Bring measured ellipsometry data
  via `materials.Material.from_nk_data(...)`.
- **Mode-resolved transmission by hand:** the `photonhub.analysis` pipeline
  that declared ports build for you, `solve_yee_mode` → `mode_launch` →
  `mode_monitor` → `transmission(out, in, data)`, returns `{freq_hz: T}`. Use
  `solve_yee_mode_bank` / `solve_modes_by_freq` for a broadband launch and readout;
  the legacy `ModeSolver` / `mode_source` path remains for scalar and adjoint
  compatibility. Full complex multiport S-matrices:
  `analysis.smatrix` (`SPort` + `assemble_smatrix`, one run per driven port,
  a multi-port S-parameter driver).
- **Meshing:** `UniformMesh`, or `GradedMesh` + `auto_mesh` for a
  cells-per-λ graded mesh; `MeshOverride` (a per-structure mesh override) forces
  a target spacing inside a geometry regardless of material:
  `sim.with_mesh_overrides(MeshOverride(geometry=Box(...), dl_um=(0.02,0.02,None)))`.
  Graded meshes run on CPU, single GPU, and multi-GPU with PML/absorber,
  dispersive media, DFT/flux monitors, and plane-wave/mode sources. They
  reject the full-tensor subpixel methods (`tensor_full`, `contour_full`).
- **Mode solving:** the FDE plugins provide the lightweight semi-vectorial
  `ModeSolver` and the full-vector `VectorModeSolver`, including bent/leaky
  modes with complex `n_eff` and bend-loss readout.
- **Visualization:** `Simulation.plot` / `plot_index` (draws Box / Sphere /
  Cylinder / Polygon; `grid=True` overlays the mesh) / `plot_3d`,
  `RunResult.plot_field`, and the module-level `photonhub.viz.plot_mode`
  (FDE mode heatmap) and `photonhub.viz.plot_spectrum` (`T` vs λ).
- **Export:** HDF5 converter for the parsed results.
- **Correctness aids:** pydantic models reject structural errors at
  construction, the capability manifest catches client/engine drift, and
  `phsolver validate` is authoritative for grid/device constraints. Subpixel
  smoothing supports Box / Sphere / Cylinder / Polygon; non-dispersive scenes
  default to contour smoothing, while dispersive scenes default off unless the
  user opts in.

### Limits (today)

This is a **dispersive** solver core cross-checked against analytic references,
plus silicon photonic-circuit tools:

- Dispersion is **multi-pole ADE**: Lorentz + Drude poles per medium
  (metals/plasmonics; numerical definition in the numerics reference, §19; the
  single- and multi-pole/Drude scenes are in the recorded GPU equivalence
  inventory under §8 tolerances, dated 2026-08-27) on
  top of relative permittivity + Ohmic conductivity; a passivity-enforced
  pole fitter and anisotropic poles are still open. Explicit
  subpixel + Lorentz runs are supported and equivalence-tested, but the client
  keeps their construction default off and warns callers to use the stabilized
  PML profile.
- S-matrix assembly (`analysis.smatrix`) costs **one simulation per driven
  port**; there is no single-run multiport solve.
- Open issues and their workarounds are listed on the documentation site's
  [known limitations](https://leapfield.ai/docs/guides/known-limitations/)
  page.

Net: shapes go in and **mode-resolved transmission** comes out: declare ports
and read `data.transmission("out")`, or solve the eigenmode, inject it with
`mode_launch`, ratio two `mode_monitor` planes, and plot `T(λ)`; or assemble
the full S-matrix with `analysis.smatrix`.

## Learn more

- **[API documentation and guides](https://leapfield.ai/docs/)**: the reference for
  the supported simulation, analysis, cloud and visualization namespaces, plus
  install and quickstart guides.
- [PhotonHub product overview](https://leapfield.ai/#product)
- [Request beta access or support](https://leapfield.ai/#request)

The worked-example gallery of executed notebooks lives in the project source
tree and is shown on the documentation site's examples page.
