{"id":50257032,"url":"https://github.com/ai4optics/difftmm","last_synced_at":"2026-05-27T07:01:06.234Z","repository":{"id":354845599,"uuid":"1203244545","full_name":"AI4Optics/DiffTMM","owner":"AI4Optics","description":"Differentiable Transfer-Matrix Method thin film solver. ","archived":false,"fork":false,"pushed_at":"2026-04-30T12:23:53.000Z","size":5129,"stargazers_count":6,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-09T04:48:08.643Z","etag":null,"topics":["berreman4x4","differentiable-optics","fresnel-equations","inverse-design","optical-coatings","optics","thin-films","transfer-matrix-method"],"latest_commit_sha":null,"homepage":"","language":"Jupyter Notebook","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AI4Optics.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-06T21:33:55.000Z","updated_at":"2026-05-08T07:05:13.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/AI4Optics/DiffTMM","commit_stats":null,"previous_names":["ai4optics/difftmm","singer-yang/difftmm"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/AI4Optics/DiffTMM","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AI4Optics%2FDiffTMM","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AI4Optics%2FDiffTMM/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AI4Optics%2FDiffTMM/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AI4Optics%2FDiffTMM/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AI4Optics","download_url":"https://codeload.github.com/AI4Optics/DiffTMM/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AI4Optics%2FDiffTMM/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33554780,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-27T02:00:06.184Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["berreman4x4","differentiable-optics","fresnel-equations","inverse-design","optical-coatings","optics","thin-films","transfer-matrix-method"],"created_at":"2026-05-27T07:01:02.858Z","updated_at":"2026-05-27T07:01:06.223Z","avatar_url":"https://github.com/AI4Optics.png","language":"Jupyter Notebook","funding_links":[],"categories":[],"sub_categories":[],"readme":"# DiffTMM: Differentiable Transfer Matrix Method\n\nA PyTorch-based differentiable thin film solver for multi-layer optical coatings. Supports both isotropic and anisotropic materials with full autograd for inverse design.\n\n## Advantages over NumPy TMM\n\n| Feature               | NumPy TMM ([sbyrnes321/tmm](https://github.com/sbyrnes321/tmm)) | DiffTMM                                                            |\n| --------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------ |\n| Differentiable        | No                                                           | Yes (PyTorch autograd)                                             |\n| GPU acceleration      | No (CPU only)                                                | Yes (CUDA)                                                         |\n| Batch processing      | No (sequential)                                              | Yes (vectorized)                                                   |\n| Anisotropic materials | No (isotropic only)                                          | Yes (4x4 transfer matrix)                                          |\n| Speed (batch=16)      | 1x baseline                                                  | **~190x** (isotropic 2x2), **~134x** (anisotropic 4x4) |\n\n## Installation\n\n```bash\ngit clone https://github.com/singer-yang/DiffTMM.git\ncd DiffTMM\npip install torch numpy matplotlib scipy\n```\n\n## Quick Start\n\n### Forward Simulation (`1_forward_simu.ipynb`)\n\nInitialize a film stack with known refractive indices and thicknesses, then compute Fresnel coefficients at arbitrary wavelengths and angles.\n\n```python\nimport torch\nfrom difftmm import IsotropicFilmSolver\n\n# Define film stack: Glass | Ta2O5 | SiO2 | Ta2O5 | Glass\nsolver = IsotropicFilmSolver(\n    mat_in=1.5,                           # incident medium\n    mat_out=1.5,                          # exit medium\n    mat_ls=[2.10, 1.46, 2.10],            # interior layer indices\n    thickness_ls=[0.080, 0.120, 0.080],   # thicknesses in um\n    device=torch.device(\"cuda\"),\n)\n\n# Compute Fresnel coefficients: ts, tp, rs, rp\nangles = torch.linspace(0, 1.2, 100, device=solver.device)\nts, tp, rs, rp = solver.simulate(theta=angles, wvln=[0.45, 0.55, 0.65])\n# Output shape: (n_mirrors, n_wvlns, n_angles)\n```\n\n### Inverse Design via Differentiable Optimization (`2_inverse_design.ipynb`)\n\nGiven target Fresnel coefficients, recover unknown film thicknesses using gradient-based optimization.\n\n```python\nimport torch\nfrom difftmm import create_jones_matrix_isotropic\n\n# Film stack with unknown thicknesses\nn_list = torch.tensor([2.10, 1.46, 2.10, 1.46, 2.10], device=\"cuda\")\nd_param = torch.nn.Parameter(torch.randn(5, device=\"cuda\") * 0.5)\n\ndef param_to_thickness(p):\n    return torch.sigmoid(p) * 0.19 + 0.01  # map to [0.01, 0.20] um\n\n# Optimization loop\noptimizer = torch.optim.Adam([d_param], lr=0.02)\nfor step in range(3000):\n    optimizer.zero_grad()\n    d = param_to_thickness(d_param)\n    pred = forward_tmm(n_list, d, n_in=1.0, n_out=1.52, inp=inp)\n    loss = ((pred - target).real ** 2 + (pred - target).imag ** 2).mean()\n    loss.backward()\n    optimizer.step()\n```\n\n**Result**: Layer thicknesses recovered from random initialization:\n\n```\nLayer     GT (nm)   Recovered (nm)    Error (nm)\n  1        60.00           60.00          0.00\n  2       130.00          130.00          0.00\n  3        85.00           85.00          0.00\n  4       110.00          110.00          0.00\n  5        70.00           70.00          0.00\n```\n\n## Two Solvers\n\n- **`difftmm.IsotropicFilmSolver`** — Fast 2x2 transfer matrix method for isotropic materials (~190x faster than NumPy TMM)\n- **`difftmm.FilmSolver`** (also `AnisotropicFilmSolver`) — General 4x4 transfer matrix method for both isotropic and anisotropic materials (~134x faster than NumPy TMM)\n\nBoth solvers share the same API:\n\n```python\nsolver = Solver(\n    mat_in=1.0,                    # incident medium refractive index\n    mat_out=1.52,                  # exit medium refractive index\n    mat_ls=[2.1, 1.46],            # interior layer refractive indices\n    thickness_ls=[0.08, 0.12],     # thicknesses in um (optional, random if None)\n    device=torch.device(\"cuda\"),\n)\nts, tp, rs, rp = solver.simulate(theta, wvln)\n```\n\n## Real Materials\n\nDiffTMM ships with wavelength-dependent refractive index support via the\n`Material` class. Look up materials by name (case-insensitive):\n\n```python\nfrom difftmm import IsotropicFilmSolver, Material, list_materials\n\n# Bundled catalogs: CDGM/SCHOTT/MISC AGF glasses + thin-film n+k tables\nprint(len(list_materials()), \"materials available\")\n\n# Pass material names directly to a solver — they're auto-wrapped in Material()\nsolver = IsotropicFilmSolver(\n    mat_in=\"air\",\n    mat_out=\"N-BK7\",                    # Sellmeier (AGF)\n    mat_ls=[\"TiO2\", \"SiO2\"],            # n+k tables for thin-film materials\n    thickness_ls=[0.06, 0.10],\n)\nts, tp, rs, rp = solver.simulate(theta=angles, wvln=[0.45, 0.55, 0.65])\n```\n\nScalars (float/complex) and strings can be mixed freely in `mat_ls`.\nFor the 4×4 `FilmSolver`, anisotropic per-axis dispersion is expressed as\na `(mat_x, mat_y, mat_z)` tuple per layer.\n\nDispersion models supported in v1: **Sellmeier** (analytical, real n) and\n**linear interpolation** (lookup tables, complex n + ik).\n\n## Incoherent Layers (thick substrates)\n\nFor stacks containing layers thicker than the source's coherence length\n(typically anything thicker than ~10 μm for broadband illumination), the\nfully-coherent calculation produces dense Fabry-Perot ripples that do not\nappear in real measurements. The `IncoherentIsotropicFilmSolver` lets you\nmark individual layers as incoherent (`'i'`) while keeping thin films\ncoherent (`'c'`):\n\n```python\nimport torch\nfrom difftmm import IncoherentIsotropicFilmSolver\n\n# Stack: air | 100 nm TiO2 | 1 mm glass | air\nsolver = IncoherentIsotropicFilmSolver(\n    mat_in=1.0,\n    mat_out=1.0,\n    mat_ls=[2.40, 1.52],\n    c_list=[\"c\", \"i\"],           # TiO2 coherent, glass incoherent\n    thickness_ls=[0.100, 1000.0],\n    device=torch.device(\"cuda\"),\n)\nRs, Rp, Ts, Tp = solver.simulate(\n    theta=torch.tensor([0.0]),\n    wvln=[0.55],\n)\n# Returns real power coefficients in [0, 1].\n```\n\n`c_list` is per-interior-layer; the two semi-infinite media are always\ntreated as incoherent. The coherent path (`IsotropicFilmSolver`) and the\nincoherent path (`IncoherentIsotropicFilmSolver`) share the same forward\nmathematics for coherent stacks, so an all-`'c'` `c_list` (with\nincoherent semi-infinite endpoints) produces results consistent with the\ncoherent solver up to the loss of complex phase.\n\nOnly the 2x2 isotropic solver supports incoherent layers today.\nAnisotropic incoherent TMM is tracked as future work.\n\n## Accuracy Validation\n\nValidated against the reference NumPy TMM library ([sbyrnes321/tmm](https://github.com/sbyrnes321/tmm)) on surface plasmon resonance (SPR) calculations:\n\n![SPR Comparison](https://raw.githubusercontent.com/singer-yang/DiffTMM/main/benchmarks/surface_plasmon_resonance_all_coefficients.png)\n\nThe anisotropic 4x4 solver is validated for energy conservation, isotropic limit accuracy, cross-polarization coupling, and reciprocity:\n\n![Anisotropic Validation](https://raw.githubusercontent.com/singer-yang/DiffTMM/main/benchmarks/anisotropic_tmm_comparison.png)\n\n## Performance Benchmarks\n\n### Speed (batch=16, NVIDIA RTX 5090)\n\n![Speed Comparison](https://raw.githubusercontent.com/singer-yang/DiffTMM/main/benchmarks/speed_comparison_tmm_vs_film_solver_batch.png)\n\n| Layers | TMM NumPy (s) | Anisotropic 4x4 (s) | Isotropic 2x2 (s) | Speedup (4x4) | Speedup (2x2) |\n| ------ | ------------- | ------------------- | ----------------- | ------------- | ------------- |\n| 3      | 0.281         | 0.003               | 0.001             | 84.1x         | 233.0x        |\n| 11     | 0.577         | 0.005               | 0.003             | 128.4x        | 201.1x        |\n| 25     | 1.076         | 0.008               | 0.006             | 133.7x        | 186.4x        |\n| 39     | 1.574         | 0.010               | 0.009             | 165.1x        | 182.2x        |\n\n### GPU Memory (batch=16, forward + backward)\n\n![Memory Comparison](https://raw.githubusercontent.com/singer-yang/DiffTMM/main/benchmarks/memory_comparison_solvers.png)\n\nThe isotropic 2x2 solver uses ~23x less GPU memory than the anisotropic 4x4 solver. NumPy TMM is CPU-only (0 GPU memory).\n\n## Repository Structure\n\n```\n├── difftmm/                            # Importable package\n│   ├── __init__.py                     #   Public API\n│   ├── film_solver_isotropic.py        #   2x2 isotropic solver (fast)\n│   ├── film_solver_anisotropic.py      #   4x4 anisotropic solver (general)\n│   ├── film_solver_incoherent.py       #   2x2 isotropic solver with incoherent layers\n│   └── material/                       #   Wavelength-dependent materials\n│       ├── __init__.py\n│       ├── materials.py                #     Material class and catalog loaders\n│       └── catalogs/                   #     Bundled glass + thin-film data\n├── 1_forward_simu.ipynb                # Example: forward simulation\n├── 2_inverse_design.ipynb              # Example: differentiable inverse design\n├── 3_real_materials.ipynb              # Example: real materials\n├── 4_incoherent_film.ipynb             # Example: incoherent / thick-substrate solver\n├── tmm_numpy/                          # Reference NumPy TMM library\n├── benchmarks/                         # Accuracy and performance benchmarks\n├── tests/                              # Pytest suite\n├── pyproject.toml                      # Packaging metadata\n├── CITATION.cff                        # Citation metadata\n└── README.md\n```\n\n## Physics\n\n- **2x2 transfer matrix method**: Standard formulation for isotropic multi-layer films\n- **4x4 transfer matrix method**: General formulation for anisotropic (birefringent) media\n- Snell's law, Fresnel equations, evanescent wave handling beyond critical angle\n- Bidirectional propagation (forward and reverse through the film stack)\n- Complete polarization handling via Jones calculus\n\n## References\n\n- S. J. Byrnes, \"Multilayer optical calculations,\" [arXiv:1603.02720](https://arxiv.org/abs/1603.02720)\n- Steven Byrnes' TMM library: [github.com/sbyrnes321/tmm](https://github.com/sbyrnes321/tmm)\n- Yang, X., Liu, Z., Nie, Z., Fan, Q., Shi, Z., Bonar, J., \u0026 Heidrich, W. (2026). \"End-to-end differentiable design of geometric waveguide displays.\" *arXiv preprint* [arXiv:2601.04370](https://arxiv.org/abs/2601.04370)\n\n## License\n\nDiffTMM is licensed under the [Apache License 2.0](LICENSE).\n\nThe bundled NumPy TMM reference library (`tmm_numpy/`) is by Steven Byrnes and is licensed under the [MIT License](tmm_numpy/LICENSE.txt).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fai4optics%2Fdifftmm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fai4optics%2Fdifftmm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fai4optics%2Fdifftmm/lists"}