lightsmith 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (257) hide show
  1. {lightsmith-0.2.0 → lightsmith-0.3.0}/.gitignore +2 -0
  2. {lightsmith-0.2.0 → lightsmith-0.3.0}/AGENTS.md +5 -4
  3. lightsmith-0.3.0/CHANGELOG.md +268 -0
  4. {lightsmith-0.2.0 → lightsmith-0.3.0}/CITATION.cff +4 -4
  5. {lightsmith-0.2.0 → lightsmith-0.3.0}/PKG-INFO +5 -5
  6. {lightsmith-0.2.0 → lightsmith-0.3.0}/README.md +3 -3
  7. lightsmith-0.3.0/docs/api/core.md +13 -0
  8. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/benchmarks/agents.md +6 -5
  9. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/cli.md +1 -0
  10. lightsmith-0.3.0/docs/discretization.md +56 -0
  11. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/index.md +8 -6
  12. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/install.md +2 -1
  13. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/materials.md +10 -10
  14. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/mcp.md +15 -12
  15. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/pdk.md +2 -2
  16. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/problems/bands.md +1 -1
  17. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/problems/circuit.md +1 -1
  18. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/problems/device.md +7 -3
  19. lightsmith-0.3.0/docs/problems/emission.md +53 -0
  20. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/problems/index.md +19 -16
  21. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/problems/layer-stack.md +1 -1
  22. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/problems/mode.md +1 -1
  23. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/problems/optimization.md +1 -1
  24. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/problems/periodic.md +1 -1
  25. lightsmith-0.3.0/docs/problems/scattering.md +120 -0
  26. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/quickstart.md +24 -18
  27. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/solvers/bem.md +4 -1
  28. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/solvers/bpm.md +2 -1
  29. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/solvers/dda.md +2 -2
  30. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/solvers/fdfd.md +9 -2
  31. lightsmith-0.3.0/docs/solvers/fdtd.md +571 -0
  32. lightsmith-0.3.0/docs/solvers/in-development/fdtd-roadmap.md +140 -0
  33. lightsmith-0.3.0/docs/solvers/in-development/index.md +8 -0
  34. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/solvers/index.md +6 -4
  35. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/solvers/inverse-3d.md +1 -1
  36. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/solvers/inverse.md +3 -2
  37. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/solvers/mie.md +6 -0
  38. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/solvers/quasistatic.md +1 -1
  39. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/solvers/tmm.md +1 -1
  40. {lightsmith-0.2.0 → lightsmith-0.3.0}/llms.txt +6 -5
  41. {lightsmith-0.2.0 → lightsmith-0.3.0}/mkdocs.yml +5 -0
  42. {lightsmith-0.2.0 → lightsmith-0.3.0}/pyproject.toml +2 -2
  43. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/__init__.py +3 -3
  44. lightsmith-0.3.0/src/lightsmith/api.py +227 -0
  45. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_bem/mesh.py +49 -5
  46. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fde/grid.py +176 -148
  47. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fde/modes.py +8 -5
  48. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fde/section.py +11 -6
  49. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fdfd/engine.py +17 -8
  50. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fdfd/grid.py +38 -16
  51. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fdfd3d/engine.py +3 -1
  52. lightsmith-0.3.0/src/lightsmith/backends/_fdtd/absorption.py +91 -0
  53. lightsmith-0.3.0/src/lightsmith/backends/_fdtd/beam.py +190 -0
  54. lightsmith-0.3.0/src/lightsmith/backends/_fdtd/device.py +601 -0
  55. lightsmith-0.3.0/src/lightsmith/backends/_fdtd/emission.py +258 -0
  56. lightsmith-0.3.0/src/lightsmith/backends/_fdtd/engine.py +923 -0
  57. lightsmith-0.3.0/src/lightsmith/backends/_fdtd/grid.py +210 -0
  58. lightsmith-0.3.0/src/lightsmith/backends/_fdtd/layered.py +482 -0
  59. lightsmith-0.3.0/src/lightsmith/backends/_fdtd/layered_far.py +216 -0
  60. lightsmith-0.3.0/src/lightsmith/backends/_fdtd/options.py +92 -0
  61. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fdtd/periodic.py +40 -19
  62. lightsmith-0.3.0/src/lightsmith/backends/_fdtd/ports.py +378 -0
  63. lightsmith-0.3.0/src/lightsmith/backends/_fdtd/scattering.py +736 -0
  64. lightsmith-0.3.0/src/lightsmith/backends/_fdtd/setup.py +773 -0
  65. lightsmith-0.3.0/src/lightsmith/backends/_fdtd/substrate.py +190 -0
  66. lightsmith-0.3.0/src/lightsmith/backends/_fdtd/symmetry.py +240 -0
  67. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fdtd/tfsf.py +68 -48
  68. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/base.py +17 -2
  69. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/bem.py +28 -3
  70. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/bpm.py +1 -0
  71. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/circuit.py +1 -0
  72. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/dda.py +23 -9
  73. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/eme.py +1 -0
  74. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/fde.py +1 -0
  75. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/fdfd.py +7 -6
  76. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/fdtd.py +56 -11
  77. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/mie.py +2 -2
  78. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/mie_native.py +91 -5
  79. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/pwe.py +2 -1
  80. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/quasistatic.py +1 -0
  81. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/rcwa.py +1 -0
  82. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/tmatrix_treams.py +2 -1
  83. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/tmm.py +1 -0
  84. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/cli.py +16 -2
  85. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/device.py +16 -1
  86. lightsmith-0.3.0/src/lightsmith/discretize.py +513 -0
  87. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/inverse/backend.py +19 -2
  88. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/materials.py +22 -0
  89. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/mcp_server/_worker.py +19 -30
  90. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/mcp_server/kinds.py +12 -2
  91. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/mcp_server/remote.py +3 -0
  92. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/mcp_server/server.py +19 -7
  93. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/mcp_server/summaries.py +1 -0
  94. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/problems.py +350 -306
  95. lightsmith-0.3.0/src/lightsmith/progress.py +57 -0
  96. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/raster.py +33 -0
  97. lightsmith-0.3.0/src/lightsmith/resonance.py +72 -0
  98. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/results.py +84 -3
  99. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/spec.py +33 -1
  100. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_bem.py +21 -0
  101. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_bpm.py +30 -0
  102. lightsmith-0.3.0/tests/test_core.py +248 -0
  103. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_dda.py +40 -0
  104. lightsmith-0.3.0/tests/test_discretization.py +208 -0
  105. lightsmith-0.3.0/tests/test_emission.py +114 -0
  106. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_fde.py +35 -0
  107. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_fdfd.py +136 -0
  108. lightsmith-0.3.0/tests/test_fdtd.py +618 -0
  109. lightsmith-0.3.0/tests/test_fdtd_device.py +277 -0
  110. lightsmith-0.3.0/tests/test_fdtd_graded.py +410 -0
  111. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_fdtd_periodic.py +14 -0
  112. lightsmith-0.3.0/tests/test_fdtd_substrate.py +611 -0
  113. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_materials.py +12 -0
  114. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_mcp_server.py +47 -2
  115. lightsmith-0.3.0/tests/test_optics.py +184 -0
  116. lightsmith-0.3.0/tests/test_progress.py +110 -0
  117. lightsmith-0.3.0/tests/test_resonance.py +41 -0
  118. lightsmith-0.2.0/CHANGELOG.md +0 -91
  119. lightsmith-0.2.0/docs/api/core.md +0 -9
  120. lightsmith-0.2.0/docs/problems/scattering.md +0 -82
  121. lightsmith-0.2.0/docs/solvers/fdtd.md +0 -145
  122. lightsmith-0.2.0/src/lightsmith/api.py +0 -114
  123. lightsmith-0.2.0/src/lightsmith/backends/_fdtd/engine.py +0 -470
  124. lightsmith-0.2.0/src/lightsmith/backends/_fdtd/options.py +0 -42
  125. lightsmith-0.2.0/src/lightsmith/backends/_fdtd/scattering.py +0 -235
  126. lightsmith-0.2.0/src/lightsmith/backends/_fdtd/setup.py +0 -261
  127. lightsmith-0.2.0/tests/test_core.py +0 -95
  128. lightsmith-0.2.0/tests/test_fdtd.py +0 -221
  129. {lightsmith-0.2.0 → lightsmith-0.3.0}/LICENSE +0 -0
  130. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/api/backends.md +0 -0
  131. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/api/circuits.md +0 -0
  132. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/api/index.md +0 -0
  133. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/api/inverse.md +0 -0
  134. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/api/layout.md +0 -0
  135. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/api/materials.md +0 -0
  136. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/api/pdk.md +0 -0
  137. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/api/problems.md +0 -0
  138. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/api/results.md +0 -0
  139. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/api/spec.md +0 -0
  140. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/benchmarks/index.md +0 -0
  141. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/changelog.md +0 -0
  142. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/contributing.md +0 -0
  143. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/conventions.md +0 -0
  144. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/landscape.md +0 -0
  145. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/solvers/circuit.md +0 -0
  146. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/solvers/eme.md +0 -0
  147. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/solvers/fde.md +0 -0
  148. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/solvers/pwe.md +0 -0
  149. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/solvers/rcwa.md +0 -0
  150. {lightsmith-0.2.0 → lightsmith-0.3.0}/docs/solvers/tmatrix.md +0 -0
  151. {lightsmith-0.2.0 → lightsmith-0.3.0}/examples/circuit_mzi.py +0 -0
  152. {lightsmith-0.2.0 → lightsmith-0.3.0}/examples/circuit_ring.py +0 -0
  153. {lightsmith-0.2.0 → lightsmith-0.3.0}/examples/circuit_splitter_tree.py +0 -0
  154. {lightsmith-0.2.0 → lightsmith-0.3.0}/examples/drude_sphere.json +0 -0
  155. {lightsmith-0.2.0 → lightsmith-0.3.0}/examples/inverse_design_3d_mode_converter.json +0 -0
  156. {lightsmith-0.2.0 → lightsmith-0.3.0}/examples/inverse_design_3d_mode_converter.py +0 -0
  157. {lightsmith-0.2.0 → lightsmith-0.3.0}/examples/inverse_design_bend.py +0 -0
  158. {lightsmith-0.2.0 → lightsmith-0.3.0}/examples/mcp_client.py +0 -0
  159. {lightsmith-0.2.0 → lightsmith-0.3.0}/examples/metalens_rcwa.py +0 -0
  160. {lightsmith-0.2.0 → lightsmith-0.3.0}/examples/pdk_mzi.py +0 -0
  161. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/__init__.py +0 -0
  162. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_bem/__init__.py +0 -0
  163. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_bem/fields.py +0 -0
  164. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_bem/operators.py +0 -0
  165. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_bem/singular.py +0 -0
  166. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_bpm/__init__.py +0 -0
  167. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_bpm/engine.py +0 -0
  168. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_bpm/operator.py +0 -0
  169. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_bpm/pade.py +0 -0
  170. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_bpm/tridiag.py +0 -0
  171. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_eme/__init__.py +0 -0
  172. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fde/__init__.py +0 -0
  173. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fdfd/__init__.py +0 -0
  174. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fdfd/linsolve.py +0 -0
  175. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fdfd/modes.py +0 -0
  176. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fdfd/operators.py +0 -0
  177. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fdfd/ports.py +0 -0
  178. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fdfd3d/__init__.py +0 -0
  179. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fdfd3d/grid.py +0 -0
  180. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fdfd3d/linsolve.py +0 -0
  181. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fdfd3d/modes.py +0 -0
  182. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fdfd3d/operators.py +0 -0
  183. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fdfd3d/ports.py +0 -0
  184. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fdtd/__init__.py +0 -0
  185. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_fdtd/media.py +0 -0
  186. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_pwe/__init__.py +0 -0
  187. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_pwe/engine.py +0 -0
  188. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_pwe/geometry.py +0 -0
  189. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_pwe/solvers.py +0 -0
  190. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_rcwa/__init__.py +0 -0
  191. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_rcwa/core.py +0 -0
  192. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_rcwa/fourier.py +0 -0
  193. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/backends/_rcwa/linalg.py +0 -0
  194. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/circuits/__init__.py +0 -0
  195. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/circuits/engine.py +0 -0
  196. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/circuits/models.py +0 -0
  197. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/circuits/touchstone.py +0 -0
  198. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/Ag/Johnson.yml +0 -0
  199. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/Ag/McPeak.yml +0 -0
  200. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/Ag/Rakic-LD.yml +0 -0
  201. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/Al/McPeak.yml +0 -0
  202. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/Al/Rakic-LD.yml +0 -0
  203. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/Al/Rakic.yml +0 -0
  204. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/Au/Johnson.yml +0 -0
  205. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/Au/McPeak.yml +0 -0
  206. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/Au/Rakic-LD.yml +0 -0
  207. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/Cu/Johnson.yml +0 -0
  208. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/Cu/McPeak.yml +0 -0
  209. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/Cu/Rakic-LD.yml +0 -0
  210. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/H2O/Daimon-24.0C.yml +0 -0
  211. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/H2O/Hale.yml +0 -0
  212. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/Si/Aspnes.yml +0 -0
  213. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/Si/Green-2008.yml +0 -0
  214. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/Si/Li-293K.yml +0 -0
  215. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/Si/Schinke.yml +0 -0
  216. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/SiO2/Lemarchand.yml +0 -0
  217. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/SiO2/Malitson.yml +0 -0
  218. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/TiO2/Devore-o.yml +0 -0
  219. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/TiO2/Sarkar.yml +0 -0
  220. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/TiO2/Siefke.yml +0 -0
  221. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/data/materials/manifest.json +0 -0
  222. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/inverse/__init__.py +0 -0
  223. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/inverse/export.py +0 -0
  224. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/inverse/objectives.py +0 -0
  225. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/inverse/optimizers.py +0 -0
  226. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/inverse/parametrization.py +0 -0
  227. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/inverse/spec.py +0 -0
  228. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/inverse/topopt.py +0 -0
  229. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/layout.py +0 -0
  230. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/materials_fit.py +0 -0
  231. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/mcp_server/__init__.py +0 -0
  232. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/mcp_server/__main__.py +0 -0
  233. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/mcp_server/budget.py +0 -0
  234. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/mcp_server/config.py +0 -0
  235. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/mcp_server/jobs.py +0 -0
  236. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/mcp_server/matlib.py +0 -0
  237. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/optics/__init__.py +0 -0
  238. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/optics/propagation.py +0 -0
  239. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/pdk/__init__.py +0 -0
  240. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/pdk/cells.py +0 -0
  241. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/pdk/component.py +0 -0
  242. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/pdk/fitting.py +0 -0
  243. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/pdk/flow.py +0 -0
  244. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/pdk/technology.py +0 -0
  245. {lightsmith-0.2.0 → lightsmith-0.3.0}/src/lightsmith/py.typed +0 -0
  246. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_circuit.py +0 -0
  247. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_eme.py +0 -0
  248. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_fdfd3d.py +0 -0
  249. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_inverse.py +0 -0
  250. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_layout.py +0 -0
  251. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_mie_native.py +0 -0
  252. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_pdk.py +0 -0
  253. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_pwe.py +0 -0
  254. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_quasistatic.py +0 -0
  255. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_rcwa.py +0 -0
  256. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_tmatrix_treams.py +0 -0
  257. {lightsmith-0.2.0 → lightsmith-0.3.0}/tests/test_tmm.py +0 -0
@@ -38,3 +38,5 @@ src-tauri/target/
38
38
 
39
39
  # outputs of examples
40
40
  examples/output/
41
+ inverse_bend_out/
42
+ inverse_3d_out/
@@ -4,10 +4,10 @@ Guidance for AI agents (and humans) using or developing lightsmith.
4
4
 
5
5
  ## Using the library
6
6
 
7
- 1. Build a problem of one of the kinds in `lightsmith/problems.py` (scattering, layer_stack, periodic, mode, device, bands, circuit, optimization); `lightsmith schema` prints the JSON Schema of all of them. Units are **nm**; wavelengths are **vacuum** wavelengths.
7
+ 1. Build a problem of one of the kinds in `lightsmith/problems.py` (scattering, emission, layer_stack, periodic, mode, device, bands, circuit, optimization); `lightsmith schema` prints the JSON Schema of all of them. Units are **nm**; wavelengths are **vacuum** wavelengths.
8
8
  2. Call `estimate` before `solve` for grid-based solvers (DDA, FDTD, FDFD, RCWA, PWE): it reports problem size, precision and memory without solving.
9
9
  3. `solve(problem, method="auto")` picks the preferred applicable method for the problem kind (see `AUTO_ORDER` in `api.py`). Errors explain why a backend was skipped and what to change.
10
- 4. `compare(problem, methods=[...])` cross-checks methods; Mie is the reference for single spheres, otherwise the first method listed.
10
+ 4. `compare(problem, methods=[...])` cross-checks methods; Mie is the reference for single spheres, otherwise the first method listed (or, with no list, the one `auto` would pick).
11
11
  5. Results carry `provenance` (backend versions, device, precision, iterations, residuals) and `warnings`. Check `warnings` before trusting numbers.
12
12
 
13
13
  Component-to-circuit flow (`lightsmith.pdk`): `get_component(cell, **params)` builds layout + ports (port centres are the S-parameter reference planes; names o1, o2, ... as gdsfactory); `flow.simulate` solves its `DeviceProblem` via `solve` (2D effective-index plan view by default); `flow.component_model` fits and caches the S-parameters (key = cell, params, technology, band, solver, options); circuit netlists use `{"component": "pdk:<cell>", "settings": {<params>, <FlowSettings>}}`. Technologies are `Technology` JSON (`generic_soi()` uses only open data). Compare circuits with direct simulations only when both use the same solver and grid (`FlowSettings(method=..., waveguide_model="device")`): FDFD's numerical dispersion at the default grid is ~1e-2 in neff, and with the default 4x subpixel sampling the grid alignment of waveguide edges shifts neff by ~7e-3 between instances (use `subsamples: 16`).
@@ -15,10 +15,11 @@ Component-to-circuit flow (`lightsmith.pdk`): `get_component(cell, **params)` bu
15
15
  Interfaces, all JSON in / JSON out:
16
16
 
17
17
  - Python: `import lightsmith as ls`
18
- - CLI: `lightsmith {doctor,backends,schema,estimate,solve,compare}` — errors are JSON on stderr, exit code 1.
18
+ - CLI: `lightsmith {doctor,backends,schema,estimate,discretization,solve,compare}` — errors are JSON on stderr, exit code 1.
19
+ `discretization` (`ls.discretization`) shows what a backend will discretise (grid, mesh, dipoles, harmonics, cells) without solving.
19
20
  - MCP: `lightsmith-mcp` (stdio; `--http` for streamable HTTP). Tools:
20
21
  - discovery: `list_problem_kinds`, `get_schema(kind)`, `list_backends`, `check_environment`, `validate_problem`;
21
- - solving: `estimate`, `solve`, `start_solve`, `compare`;
22
+ - solving: `estimate`, `get_discretization`, `solve`, `start_solve`, `compare`;
22
23
  - jobs: `get_job`, `list_jobs`, `cancel_job`, `get_result`;
23
24
  - materials: `search_materials`, `get_material`, `fit_drude_lorentz`.
24
25
 
@@ -0,0 +1,268 @@
1
+ # Changelog
2
+
3
+ All notable changes to the `lightsmith` library are recorded here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
5
+ [semantic versioning](https://semver.org/) (while the version is 0.x, minor releases may break the API).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.3.0] - 2026-11-08
10
+
11
+ - `device="auto"` runs on the CPU, with a warning, when the problem will not fit in the GPU's free memory. Before,
12
+ `examples/pdk_mzi.py` took FDFD's block LU (12.9 GB) onto a 12 GB GPU, where Windows paged it for hours, although
13
+ SuperLU on the CPU needs 0.8 GB. `estimate` reports the same choice (`device`, `device_note`). Naming a device
14
+ still gets that device.
15
+ - The MCP server's solver process reports progress through `lightsmith.progress`: every wavelength or iteration of a
16
+ solve, and each method of a `compare`. Inverse design goes through `solve`, so `device="auto"` treats it the same.
17
+ - 2D FDFD rasterises the geometry once per solve, as 3D does, and tests each structure only inside its bounding box.
18
+ For the whole MZI of `examples/pdk_mzi.py` that took 690 of 846 s per wavelength, against 76 s for the factorisation.
19
+
20
+ ### Fixed
21
+
22
+ - `method="auto"` passes over a 2D FDFD problem that exceeds `max_cells` and goes on to FDTD; the estimate now says
23
+ `fits: false` instead of raising, and only an explicit solve is refused.
24
+ - FDFD accepts 2D ports with z size 0, as the `Port` schema documents, and refuses only a true z normal. The MCP server's
25
+ device example now leaves room for absorbing layers, so it runs on EME, BPM, FDFD and FDTD.
26
+ - The MCP budget now covers 2D FDFD and 2D inverse design: their estimates report `memory_bytes` for the solver the device
27
+ will use.
28
+ - FDTD devices apply the same dispersive time-step limit as every other FDTD problem kind.
29
+ - The Mie refusal suggested `tmatrix` for non-spherical particles, which refuses them too; it now names `bem` and `dda`, as do
30
+ the MCP prompts.
31
+ - CLI usage errors are JSON on stderr with exit status 1, like every other failure.
32
+ - `discretization` no longer assumes a third-party backend has a built-in backend's internals; it reports no plan unless the
33
+ plugin overrides `Backend.discretization`.
34
+ - Backends' `differentiable` flag now means "has a torch-differentiable entry point", and native Mie and PWE set it.
35
+
36
+ ### Added
37
+
38
+ - **Progress callbacks and cancellation**: `solve(..., progress=callback)` and `compare(..., progress=callback)` call back with
39
+ `{"stage", "fraction", ...}` while solving: DDA per wavelength and incidence, BEM and FDFD per wavelength, FDTD per chunk of
40
+ steps, inverse design per iteration. A callback may raise `lightsmith.progress.Cancelled` to stop.
41
+ - Backends declare `options_model`, so `list_backends` on the MCP server and `/v1/backends` on Cloud carry each backend's
42
+ options as a JSON Schema.
43
+ - Every result records `provenance.versions` (library, NumPy, PyTorch when used). Under `method="auto"`, results and estimates
44
+ record `auto_skipped`: why the earlier backends were passed over. DDA results keep their BiCGStab residuals.
45
+ - `tests/test_optics.py` validates `lightsmith.optics` against closed forms; tests for the DDA's `weighted` and
46
+ `extrapolate` modes, which also lose their "experimental" label in favour of what they do and where they fail.
47
+ - The agent benchmark gained an emission task (44 tasks; every problem kind is now covered, and a test enforces it). Its gold
48
+ nanorod task now asks for the resonance wavelength, on which BEM and DDA agree.
49
+
50
+ - **`lightsmith.discretization(problem, method)`**, `lightsmith discretization` and the MCP tool `get_discretization`: what a backend
51
+ will discretise, before any solve, with a common envelope (`layout_kind`, a labelled `summary`, a `payload`, the
52
+ estimate, warnings, and the library's refusal in `error`). FDTD: the Yee grid, TFSF and flux boxes, CPML,
53
+ refinement regions and mirror planes; unit cells of periodic structures and layer stacks; device grids and
54
+ ports. FDFD device grids and ports, inverse-design regions, the DDA dipole lattice, the BEM surface mesh, Mie
55
+ and T-matrix multipole orders, RCWA harmonics, FDE grids, EME and BPM cells, PWE k-paths and plane waves. Each
56
+ calls the backend's own planning code and never solves. `Backend.discretization` lets plugins answer too.
57
+ See `docs/discretization.md`.
58
+
59
+ - **FDTD graded grids for device problems**: `mesh_override` boxes and `grid: "auto"` (each structure refined
60
+ to `cells_per_wavelength` in its own material) now work for `kind: "device"`, in 2D and 3D. Ports sit in
61
+ uniform cells along their normals; across their windows the cells may be graded, and the port modes come
62
+ from the FDE problem on the same non-uniform cross-section (the FDE grid gained per-cell widths), so they stay
63
+ exact for the grid: a straight guide still transmits |S21| = 1 with the grid's phase (1e-10 rad). A
64
+ 500 → 900 nm 2D step graded from 25 to 10 nm is within 2e-5 of a uniform 10 nm run with 63 % of the cells,
65
+ and a 3D wire step graded from 40 to 15 nm within 8e-6 of a uniform 15 nm run with 45 % of the cells.
66
+ - **FDTD graded grids** (scattering): `grid: "auto"` refines each particle's bounding box to the spacing its
67
+ material and size need, and `mesh_override: [{center_nm, size_nm, spacing_nm}]` adds refinement boxes. The
68
+ cells grade back to the base spacing at most `grading_ratio` (1.25) per cell. The grid is a tensor product
69
+ with independent per-axis widths. The Yee update uses primary and dual width arrays, so it conserves the
70
+ same discrete energy as the uniform one, on the CPU and on CUDA with CUDA graphs. The CPML, TFSF tables
71
+ (exact discrete background of the graded 1D problem, still leak-free), layered substrates, conformal
72
+ smoothing (metals' vertex tensor included), flux and far-field surfaces, near fields, particle absorption
73
+ and mirror planes all follow the widths. An n = 3.5, r = 20 nm sphere is within 0.11 % of a uniform 2 nm run, whose own error against Mie is
74
+ 0.7 %, with 153 k cells instead of 242 k. A Drude sphere of r = 10 nm at 0.5 nm cells needs 488 k cells
75
+ instead of 1.74 M (2.1× faster in double precision). Its spectrum differs from the uniform run by at most
76
+ 7e-4 of the peak, against a 13 % discretisation error. Particles on glass or on an absorbing substrate
77
+ agree within 0.34 %, and far fields within 0.1 % of the uniform run's. The coarsest cells must stay fine:
78
+ any change of cell size h reflects about (k h)²/16 of a wave, so `grid: "auto"` uses 60 cells per
79
+ background wavelength (`background_cells_per_wavelength`). A uniform grid gives today's run bit for bit.
80
+ Scattering only, with plane waves along an axis (or graded only along the axes the wave does not vary along).
81
+ - **FDTD device problems** (`kind: "device"`, 3D and 2D): S-parameters between waveguide ports. Each port
82
+ mode is an exact eigenmode of the FDTD grid itself: the FDE cross-section problem solved with the
83
+ leapfrog frequency, the discrete propagation constant and each node's discrete material response, then
84
+ interpolated over the band from Chebyshev nodes. So the TFSF mode sources launch one way only, and the
85
+ monitors split the fields into forward and backward modes exactly. A straight silicon wire transmits with
86
+ |S21| = 1 to 1e-6 and the grid's own phase. A 2D width step matches FDFD to 3e-5 (TE) and 3.4e-4 (TM) at
87
+ dl = 10 nm, and a 3D one is converged to 1e-4 between dx = 25 and 15 nm. Device problems default to
88
+ `subpixel` smoothing (port modes need a diagonal permittivity). `polarization` selects TE or TM in 2D.
89
+ - **FDTD mirror symmetries** (`symmetry: "auto"`, the default; `"off"` turns them off). A scattering run
90
+ whose particles are mirror-symmetric about their centre, lit by a plane wave that travels in the mirror
91
+ plane and is polarised in it (a PMC plane) or normal to it (a PEC plane), keeps half the grid per plane:
92
+ 2× or 4× fewer cells. The conformal tensors, metals' vertex tensor included, are folded across the
93
+ planes, so cross sections, near fields and far fields match the full run to 1e-11 in double precision,
94
+ over substrates and absorbing substrates too. On the GPU, runs of 1–5 M cells are 1.55–2.3× faster (3.7×
95
+ in steady state at 15 M cells). The provenance and `estimate` report the planes used.
96
+ - **FDTD conformal meshing.** `mesh_refinement` (`staircase`, `volume_average`, `subpixel`, `conformal`). The
97
+ new default, `conformal`, adds the off-diagonal terms of tensor subpixel smoothing, symmetrised for
98
+ stability. Dielectric sphere C_ext error at dx = 6 nm falls from 1.1 % to 0.04 %. At metal interfaces
99
+ the full dispersive tensor is applied at grid vertices as a sum of passive congruences, so it is stable
100
+ by construction. On a Drude sphere's plasmon band it cuts the C_ext error 2–4× compared with diagonal
101
+ smoothing (2.5 % against 6.6 % RMS at dx = 2 nm), and the error now falls as the grid is refined.
102
+ - **FDTD far field** (`outputs.far_field`): near-to-far-field projection of the scattered fields, within
103
+ 0.4 % of Mie.
104
+ - **Dipole emission** (`kind: "emission"`): Purcell factor, radiative enhancement, efficiency and
105
+ radiation pattern of a point dipole near particles. Exact for one sphere in native Mie; any geometry in
106
+ FDTD (within 0.2 % of Mie next to a dielectric sphere).
107
+ - **Gaussian beams** (`illumination: GaussianBeam`, FDTD): a focused beam as a sum of TFSF plane waves at
108
+ fixed angles (the waist scales with the wavelength, as for a lens of fixed NA); cross sections per unit
109
+ focal intensity. Within 0.13 % of Mie at the focus and 0.1 % of the beam profile off axis.
110
+ - **FDTD substrates** (`Simulation.substrate`): particles on or above a non-absorbing half-space, lit from
111
+ above at any angle or through the substrate, including total internal reflection. The TFSF box takes
112
+ the background field (incident, reflected and transmitted waves) from an auxiliary column at normal
113
+ incidence. At oblique incidence it comes from tables of the exact discrete background (a 1D discrete
114
+ problem along z per frequency, then an inverse FFT). Either way it does not leak where it cuts the
115
+ interface. C_sca is within 0.2–0.5 % of a dipole reference for a sphere above glass (1.7 % for p
116
+ under total internal reflection, where the dipole model is least exact). Near fields are supported;
117
+ absorbing substrates and far fields are not yet.
118
+ - **FDTD absorbing substrates and far fields over substrates.** Particles over metals or other absorbing
119
+ substrates. Over one, `c_abs` is the particles' own absorption, from the grid's exact discrete Poynting
120
+ balance on their nodes; it equals the inflow through a closed box around the particle to 1e-6. `c_sca` is
121
+ the power scattered upward, and `c_ext` the power taken from the reflected wave (the reflectance change).
122
+ `outputs.far_field` now works over any substrate, into both half-spaces, by reciprocity with the grid's
123
+ own layered background. Against a multipole reference, a sphere over an absorbing dielectric is within
124
+ 0.1 %, and one over a Drude metal within 0.14 %. Over glass the new quantities reproduce the box fluxes
125
+ to 3e-4. `precision: "auto"` runs double over an absorbing substrate: in float32 a metal's long
126
+ ring-down left rounding noise of up to 1.2 % in C_sca.
127
+ - **Leak-free plane waves and Gaussian beams at any angle** (FDTD scattering). Every plane wave, and every
128
+ component of a Gaussian beam, is fed from tables of the grid's exact discrete plane wave (the oblique
129
+ substrate method, with a uniform background), so the TFSF box does not leak at any direction. A sphere's
130
+ C_ext agrees between directions to 4e-5 (0.35 % before). A 20 nm sphere is within 0.1 % of Mie: with the
131
+ 1D-fed source, the incident flux through the box did not cancel, giving errors up to 22 % at 800 nm. A beam
132
+ on a 40 nm sphere is within 0.04 % of Mie at the focus and off axis (0.13 % before). Gaussian beams now
133
+ support near-field output.
134
+ - **Resonances** (`outputs.resonances`): wavelengths, Q factors and amplitudes from the FDTD ring-down,
135
+ through the new `lightsmith.resonance.harmonic_inversion` (multi-channel matrix pencil).
136
+
137
+ ### Changed
138
+
139
+ - FDTD scattering stops when the scattered field has decayed, not the total field. The incident pulse
140
+ no longer sets the peak, so weak, sharp resonances are no longer cut off: a 15 nm Drude sphere's
141
+ spectrum rippled by ±10 %.
142
+ - FDTD `pml_cells` defaults to 16 with a substrate (10 otherwise).
143
+ - FDTD voxelisation evaluates the geometry once per point of the half-cell lattice, where it used to test each
144
+ field position's 26 neighbours separately for every component. The result is the same, and it is 4× faster
145
+ (45 s → 10 s for a 2.5 M-cell 3D MMI).
146
+ - FDTD scattering: the default TFSF padding and PML gap are now at least 3 % of the longest wavelength
147
+ in the medium, so refining the grid no longer moves the monitors closer to the particle.
148
+ - FDTD: the table-fed plane-wave source updates all face slabs of a kind in one gather and scatter, and
149
+ stops waiting once the pulse has passed (the wrapped edge of the table's inverse FFT had set it to the
150
+ whole table), so small scattering runs are 2.3–2.8× faster with the same results.
151
+ - Documentation describes problems through the Python models first; saving and loading them as JSON
152
+ files for the CLI and MCP server is covered in the quick start.
153
+
154
+ ### Fixed
155
+
156
+ - Inverse design: `estimate` now applies the optimisation-level solver options (`OptimizationProblem.options`),
157
+ merged over the device's key by key as the optimiser merges them (`inverse.backend.device_problem`); it used
158
+ the device's options alone.
159
+ - FDTD options: the `pml_cells` description gives the device default (12), and the `mesh_override` description
160
+ no longer names another product.
161
+ - FDTD: the time step is reduced where a dispersive (Drude–Lorentz) material would make the update unstable
162
+ on a coarse grid, checked from the update's eigenvalues over the grid's spatial frequencies. The
163
+ Johnson–Christy gold fit diverged at dx ≥ 20 nm, and lossy constants at dx near half a wavelength.
164
+ - **3D devices with ports facing y** (FDE ports, EME, BPM): the cross-section's local x axis was global z,
165
+ so `"te"` selected the vertical-E mode and BPM's `bend_radius_nm` bent the guide out of the chip plane.
166
+ Local x is now the in-plane transverse axis for ports facing x or y, as it already was in 2D. Results for
167
+ ports facing x, and for all 2D devices, are unchanged.
168
+ - **`compare`**: device, circuit, mode and band results now report differences (they came back empty);
169
+ without a method list the reference is the method `auto` would pick, not the alphabetically first
170
+ backend; relative cross-section differences are floored at 0.1 % of the reference extinction, so a
171
+ lossless particle's near-zero absorption no longer gives huge relative errors. Results that cannot be
172
+ compared are listed under `not_compared`.
173
+ - **FDTD periodic and layer-stack transmission** into an absorbing substrate is referred to the interface,
174
+ as in TMM and RCWA. Before, T was taken a few cells inside the substrate (Si at 420 nm read 0.744 instead
175
+ of 0.815) and metal substrates reported T = 0.
176
+ - **BEM** checks particle overlap on the volume-corrected meshes the solve uses, so particles about 0.1 nm
177
+ apart no longer produce interpenetrating meshes, and warns when a gap is smaller than the mesh size.
178
+ - **`auto`** skips a backend whose estimate exceeds its own size limit (BEM `max_unknowns`, DDA
179
+ `max_dipoles`, T-matrix `max_modes`, ...) and falls through to the next method, instead of picking it and
180
+ failing at solve time.
181
+ - **`Tabulated`** materials sort their data by wavelength (energy-ordered files are descending, which
182
+ interpolation silently got wrong) and refuse duplicate wavelengths or mismatched column lengths.
183
+
184
+
185
+ ## [0.2.0] - 2026-11-02
186
+
187
+ ### Added
188
+
189
+ - **BEM** (`lightsmith-bem`): PMCHWT surface integral equations on RWG meshes for spheres, spheroids,
190
+ cylinders, layered spheres and disjoint clusters, with near and far fields, on CPU or GPU. `auto` tries
191
+ it after T-matrix for scattering.
192
+ - **BPM** (`lightsmith-bpm`): wide-angle Padé beam propagation for devices, 2D and 3D (semi- and
193
+ full-vectorial), with bends, on CPU or GPU.
194
+ - **FDTD oblique and conical incidence** on layer stacks and periodic structures, up to 85° from the
195
+ normal, with Bloch-periodic boundaries at fixed in-plane wavevector. Scattering accepts any incidence
196
+ direction.
197
+ - **PDK flow** (`lightsmith.pdk`): technologies as JSON (`generic_soi` from open data), parametric cells
198
+ with GDS output, simulation at the port reference planes, fitted and cached compact models, and
199
+ `pdk:<cell>` instances in circuit netlists.
200
+ - **MCP server rewrite** on MCP SDK 2.x: jobs, budgets, resources, prompts, materials tools, and remote
201
+ mode. The `mcp` extra is now `mcp>=2.3,<3`.
202
+ - **3D inverse design** on a full-vector 3D FDFD solver (`lightsmith-fdfd` with `dimension=3` devices):
203
+ exact discrete port modes, TF/SF mode sources, batched BiCGStab on CPU or GPU, and adjoint gradients
204
+ with warm starts across iterations.
205
+ - **Agent benchmark** (`benchmarks/agents/`): 43 graded tasks for agents using the MCP server.
206
+
207
+ ### Changed
208
+
209
+ - The documentation moved to <https://docs.lightsmith.dev/>. The old GitHub Pages address redirects there.
210
+
211
+ ### Fixed
212
+
213
+ - Multilayer Mie: avoid cancellation near zeros of ψₙ, which gave errors up to 12% for coated spheres
214
+ whose interface sits on such a zero.
215
+ - RCWA: grazing diffraction orders (kz = 0) inside uniform layers no longer make the layer S-matrix
216
+ singular.
217
+ - FDTD: runs whose fields grow without bound now raise, also on CPU in float64, where they used to stay
218
+ finite and return cross sections off by many orders of magnitude.
219
+ - Topology optimisation: `OptimizationProblem.options` now merges into the device's options key by key
220
+ within each method, instead of replacing the method's whole dictionary (which dropped `dl_nm`,
221
+ `pml_cells` and the like).
222
+ - `device="auto"` falls back to CPU when CUDA is available but no device is visible
223
+ (`CUDA_VISIBLE_DEVICES=""`), instead of failing with "Invalid device id".
224
+
225
+ ## [0.1.0] - 2026-11-01
226
+
227
+ First public release.
228
+
229
+ ### Added
230
+
231
+ - **One problem spec for every method.** Pydantic models with a `kind` discriminator: `scattering`,
232
+ `layer_stack`, `periodic`, `mode`, `device`, `bands`, `circuit`, `optimization`. Any of them can be
233
+ passed as a model, dict or JSON string. `lightsmith schema` prints the JSON Schema. Lengths are in nm,
234
+ wavelengths are vacuum wavelengths, and the time convention is `exp(-iωt)`.
235
+ - **Entry points** `solve`, `estimate`, `compare`, `choose_method` and `doctor`. `method="auto"` picks
236
+ the preferred applicable solver and explains why the others were skipped.
237
+ - **Solvers.** All are MIT, and all are native unless noted.
238
+ - Scattering: Mie (native, homogeneous and layered spheres, GPU and autodiff), Mie through
239
+ `miepython`, T-matrix through `treams` (`tmatrix` extra), DDA, FDTD, and the quasistatic dipole
240
+ approximation.
241
+ - Thin films and periodic structures: TMM (coherent and incoherent layers, differentiable), RCWA
242
+ (1D/2D lattices, conical incidence, Li and normal-vector factorisation, differentiable), and
243
+ FDTD for periodic and layer-stack problems at normal incidence.
244
+ - Waveguides and devices: FDE (full-vector, bends, PML), EME, and 2D FDFD with adjoint gradients.
245
+ - Photonic crystals: PWE (2D TE/TM and 3D, dense and LOBPCG solvers).
246
+ - Circuits: S-matrix netlist solver with compact models and Touchstone I/O, differentiable.
247
+ - Inverse design: density-based topology optimisation on FDFD (filters, projection, minimum
248
+ feature size, MMA, Adam and L-BFGS-B), exported to polygons and GDS.
249
+ - **Materials.** Bundled CC0 datasets from refractiveindex.info (Au, Ag, Al, Cu, Si, SiO2, TiO2,
250
+ water), online fetch of any database entry, and passive Drude–Lorentz fitting for time-domain solvers.
251
+ - **Layout.** Built-in GDSII reader and writer, extrusion of GDS layers into device problems, and an
252
+ optional gdsfactory bridge (`layout` extra).
253
+ - **Interfaces.** The `lightsmith` CLI (JSON on stdout, JSON errors on stderr) and the `lightsmith-mcp`
254
+ MCP server (`mcp` extra) for AI agents.
255
+ - **Plugins.** The `lightsmith.backends` entry-point group, so GPL-licensed solvers can live in separate
256
+ packages (`lightsmith-adda`, `lightsmith-scattnlay`).
257
+ - **Typing.** A `py.typed` marker; the public API is annotated.
258
+ - **Documentation** site (MkDocs Material), `CITATION.cff` and `.zenodo.json`.
259
+
260
+ ### Notes
261
+
262
+ - The `mcp` extra is pinned to `mcp>=1.2,<2`: the server uses the mcp 1.x `FastMCP` API, which mcp 2.x
263
+ renamed.
264
+
265
+ [Unreleased]: https://github.com/lightsmith-photonics/lightsmith/compare/v0.3.0...HEAD
266
+ [0.3.0]: https://github.com/lightsmith-photonics/lightsmith/compare/v0.2.0...v0.3.0
267
+ [0.2.0]: https://github.com/lightsmith-photonics/lightsmith/compare/v0.1.0...v0.2.0
268
+ [0.1.0]: https://github.com/lightsmith-photonics/lightsmith/releases/tag/v0.1.0
@@ -4,16 +4,16 @@ type: software
4
4
  title: "Lightsmith: an open, GPU-native photonics suite built for AI agents"
5
5
  abstract: >-
6
6
  Lightsmith describes a photonics problem once, as typed JSON, and solves it
7
- with Mie, T-matrix, DDA, FDTD, TMM, RCWA, FDE, EME, FDFD, PWE and S-matrix
8
- circuit solvers on CPU or GPU, with differentiable inverse design. Every
7
+ with Mie, T-matrix, BEM, DDA, FDTD, TMM, RCWA, FDE, EME, BPM, FDFD, PWE and
8
+ S-matrix circuit solvers on CPU or GPU, with differentiable inverse design. Every
9
9
  result uses the same units and conventions and carries provenance, so methods
10
10
  can be cross-checked directly. Python, CLI and MCP interfaces are JSON in,
11
11
  JSON out.
12
12
  authors:
13
13
  - family-names: Feghali
14
14
  given-names: Alexander
15
- version: 0.2.0
16
- date-released: "2026-11-02"
15
+ version: 0.3.0
16
+ date-released: "2026-11-08"
17
17
  license: MIT
18
18
  repository-code: "https://github.com/lightsmith-photonics/lightsmith"
19
19
  url: "https://docs.lightsmith.dev/"
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: lightsmith
3
- Version: 0.2.0
4
- Summary: Open photonics suite: one typed JSON problem spec solved by Mie, T-matrix, DDA, FDTD, TMM, RCWA, FDE, EME, FDFD, PWE and circuit solvers on CPU or GPU, with differentiable inverse design, built for humans and AI agents.
3
+ Version: 0.3.0
4
+ Summary: Open photonics suite: one typed problem description solved by Mie, T-matrix, BEM, DDA, FDTD, TMM, RCWA, FDE, EME, BPM, FDFD, PWE and circuit solvers on CPU or GPU, with differentiable inverse design, built for humans and AI agents.
5
5
  Project-URL: Homepage, https://lightsmith.dev/
6
6
  Project-URL: Documentation, https://docs.lightsmith.dev/
7
7
  Project-URL: Repository, https://github.com/lightsmith-photonics/lightsmith
@@ -45,7 +45,7 @@ Description-Content-Type: text/markdown
45
45
 
46
46
  **The open photonics suite — GPU-native, differentiable, and built for AI agents.**
47
47
 
48
- Describe a photonics problem once, as typed JSON, and solve it with the method that fits: from nanoparticles and thin films to metasurfaces, waveguides, photonic crystals, devices and circuits. Every result comes back in the same units and conventions, with provenance, so methods can be cross-checked directly. Many solvers run on GPU and can be differentiated, which is what powers inverse design.
48
+ Describe a photonics problem once and solve it with whichever method fits: from nanoparticles and thin films to metasurfaces, waveguides, photonic crystals, devices and circuits. Every result comes back in the same units and conventions, with provenance, so methods can be cross-checked directly. Many solvers run on GPU and can be differentiated, which is what powers inverse design.
49
49
 
50
50
  Documentation: <https://docs.lightsmith.dev/>
51
51
 
@@ -85,7 +85,7 @@ res = ls.solve(sim) # auto -> exact Mie for a sphere
85
85
  cmp = ls.compare(sim, ["mie", "dda", "fdtd"]) # cross-check methods
86
86
  ```
87
87
 
88
- The same from the shell, JSON in and out:
88
+ The same from the shell, with the problem saved to a file:
89
89
 
90
90
  ```bash
91
91
  uv run lightsmith solve examples/drude_sphere.json --method dda --device gpu
@@ -114,7 +114,7 @@ FDTD handles oblique and conical incidence on layer stacks and periodic structur
114
114
 
115
115
  ## From components to circuits (`lightsmith.pdk`)
116
116
 
117
- An open design kit: a technology as data (`generic_soi()`: 220 nm Si on 2 µm oxide, open material data only; define others as JSON), parametric cells (straight, circular/Euler bends, taper, MMI 1×2/2×2, directional coupler, ring/racetrack, Y-branch, crossing, grating coupler, MZI) with gdsfactory-style ports and GDS output, and a flow that simulates each component through `solve` (EME, FDFD or whatever `AUTO_ORDER` picks), fits a compact model, caches it by parameter hash and uses it in netlists as `pdk:<cell>`:
117
+ An open design kit: a technology as data (`generic_soi()`: 220 nm Si on 2 µm oxide, open material data only; define your own in Python or load one from a file), parametric cells (straight, circular/Euler bends, taper, MMI 1×2/2×2, directional coupler, ring/racetrack, Y-branch, crossing, grating coupler, MZI) with gdsfactory-style ports and GDS output, and a flow that simulates each component through `solve` (EME, FDFD or whatever `AUTO_ORDER` picks), fits a compact model, caches it by parameter hash and uses it in netlists as `pdk:<cell>`:
118
118
 
119
119
  ```python
120
120
  from lightsmith.pdk import get_component
@@ -2,7 +2,7 @@
2
2
 
3
3
  **The open photonics suite — GPU-native, differentiable, and built for AI agents.**
4
4
 
5
- Describe a photonics problem once, as typed JSON, and solve it with the method that fits: from nanoparticles and thin films to metasurfaces, waveguides, photonic crystals, devices and circuits. Every result comes back in the same units and conventions, with provenance, so methods can be cross-checked directly. Many solvers run on GPU and can be differentiated, which is what powers inverse design.
5
+ Describe a photonics problem once and solve it with whichever method fits: from nanoparticles and thin films to metasurfaces, waveguides, photonic crystals, devices and circuits. Every result comes back in the same units and conventions, with provenance, so methods can be cross-checked directly. Many solvers run on GPU and can be differentiated, which is what powers inverse design.
6
6
 
7
7
  Documentation: <https://docs.lightsmith.dev/>
8
8
 
@@ -42,7 +42,7 @@ res = ls.solve(sim) # auto -> exact Mie for a sphere
42
42
  cmp = ls.compare(sim, ["mie", "dda", "fdtd"]) # cross-check methods
43
43
  ```
44
44
 
45
- The same from the shell, JSON in and out:
45
+ The same from the shell, with the problem saved to a file:
46
46
 
47
47
  ```bash
48
48
  uv run lightsmith solve examples/drude_sphere.json --method dda --device gpu
@@ -71,7 +71,7 @@ FDTD handles oblique and conical incidence on layer stacks and periodic structur
71
71
 
72
72
  ## From components to circuits (`lightsmith.pdk`)
73
73
 
74
- An open design kit: a technology as data (`generic_soi()`: 220 nm Si on 2 µm oxide, open material data only; define others as JSON), parametric cells (straight, circular/Euler bends, taper, MMI 1×2/2×2, directional coupler, ring/racetrack, Y-branch, crossing, grating coupler, MZI) with gdsfactory-style ports and GDS output, and a flow that simulates each component through `solve` (EME, FDFD or whatever `AUTO_ORDER` picks), fits a compact model, caches it by parameter hash and uses it in netlists as `pdk:<cell>`:
74
+ An open design kit: a technology as data (`generic_soi()`: 220 nm Si on 2 µm oxide, open material data only; define your own in Python or load one from a file), parametric cells (straight, circular/Euler bends, taper, MMI 1×2/2×2, directional coupler, ring/racetrack, Y-branch, crossing, grating coupler, MZI) with gdsfactory-style ports and GDS output, and a flow that simulates each component through `solve` (EME, FDFD or whatever `AUTO_ORDER` picks), fits a compact model, caches it by parameter hash and uses it in netlists as `pdk:<cell>`:
75
75
 
76
76
  ```python
77
77
  from lightsmith.pdk import get_component
@@ -0,0 +1,13 @@
1
+ # Top level
2
+
3
+ ::: lightsmith.api
4
+ options:
5
+ members: [solve, estimate, discretization, compare, choose_method, AUTO_ORDER]
6
+
7
+ ::: lightsmith.progress
8
+ options:
9
+ members: [report, reporting, scaled, Cancelled]
10
+
11
+ ::: lightsmith.device
12
+ options:
13
+ members: [doctor, resolve_device, Device]
@@ -13,11 +13,12 @@ agent pushed back on requests that cannot be answered as asked.
13
13
 
14
14
  ## Tasks
15
15
 
16
- 43 tasks cover every problem kind:
16
+ 44 tasks cover every problem kind:
17
17
 
18
18
  | Kind | Tasks |
19
19
  |---|---:|
20
20
  | scattering | 12 |
21
+ | emission | 1 |
21
22
  | layer_stack | 8 |
22
23
  | mode | 7 |
23
24
  | circuit | 5 |
@@ -31,8 +32,8 @@ They fall into four categories:
31
32
  - **Standard** (23): a well-posed question, such as the plasmon peak of a gold sphere in water, an
32
33
  antireflection coating, a Bragg mirror, grating efficiencies, waveguide modes, a 2D MMI, the TM gap of a
33
34
  photonic crystal, the FSR of an MZI or a ring, or a small topology optimisation.
34
- - **Trap** (15): answerable, but the obvious setup is wrong. Examples: a diameter given where the schema
35
- wants a radius; a wavelength given in the medium; energies, wavenumbers, frequencies or µm instead of
35
+ - **Trap** (16): answerable, but the obvious setup is wrong. Examples: a diameter given where the schema
36
+ wants a radius; an emitter's distance given from a particle's surface; a wavelength given in the medium; energies, wavenumbers, frequencies or µm instead of
36
37
  nm; a complex index in the e^{+jωt} convention; light incident from the substrate; a 1 mm slide that must
37
38
  be an incoherent layer; group index versus effective index; normalised frequency a/λ; a material
38
39
  dataset that does not cover the wavelength; cm versus nm in a link budget.
@@ -41,7 +42,7 @@ They fall into four categories:
41
42
  lossless 1×2 splitter with 70 % in each arm.
42
43
  - **Warning** (2): the tools warn about the answer and the agent must pass the warning on.
43
44
 
44
- 11 tasks use grid-based solvers (DDA, RCWA, EME, PWE, inverse design) and are also graded on whether the
45
+ 11 tasks use grid-based solvers (BEM, RCWA, EME, PWE, inverse design) and are also graded on whether the
45
46
  agent estimated before solving.
46
47
 
47
48
  Each task file in `benchmarks/agents/tasks/` holds the prompt, the answer fields with units, a hidden
@@ -114,7 +115,7 @@ uv run --no-sync pytest benchmarks/agents/tests
114
115
  ```
115
116
 
116
117
  The tests check that the task files match `taskdefs.py`, that the graders work on hand-made transcripts,
117
- that the oracle passes all 43 tasks over stdio MCP with no failed tool call, and that the Claude adapter's
118
+ that the oracle passes all 44 tasks over stdio MCP with no failed tool call, and that the Claude adapter's
118
119
  loop works against a scripted stand-in for the API (no key, no cost). They also check that deliberately
119
120
  wrong behaviour fails: numbers off by 25 %, skipped estimates, dropped concerns, no answer, the right
120
121
  numbers without a simulation, every naive problem, and answers to the unphysical requests.
@@ -20,6 +20,7 @@ lightsmith compare SPEC [--methods mie,dda] [--device auto] [-o comparison.json
20
20
  | `backends` | One entry per backend: `name`, `method`, `problem_kinds`, `license`, `gpu`, `differentiable`, `available`, `unavailable_reason`, `citation` |
21
21
  | `schema` | The JSON Schema of every problem kind |
22
22
  | `estimate` | Backend, device, problem size and memory, without solving |
23
+ | `discretization` | What the backend will discretise: grid, mesh, dipole lattice, harmonics, cells ([Discretisation](discretization.md)) |
23
24
  | `solve` | The result model as JSON |
24
25
  | `compare` | `reference`, `results` (one per method) and `relative_difference` |
25
26
 
@@ -0,0 +1,56 @@
1
+ # Discretisation: what a solver will discretise
2
+
3
+ `lightsmith.discretization(problem, method="auto")` reports what a backend will discretise for a problem, before any
4
+ solve: the FDTD Yee grid and its boxes, a device grid and its ports, the DDA dipole lattice, the BEM surface mesh,
5
+ the Mie or T-matrix multipole order, the RCWA harmonics, an FDE cross-section grid, the EME or BPM cells along a
6
+ device, the PWE k-path and plane waves. It calls each backend's own planning code (the code `estimate` and
7
+ `solve` call) and never runs a solver, so it is as cheap as `estimate`. GUIs use it to draw the discretisation,
8
+ and agents use it to check a set-up.
9
+
10
+ ```python
11
+ import lightsmith as ls
12
+
13
+ out = ls.discretization(problem, method="dda")
14
+ out["summary"] # {"dipoles": 2176, "spacing (nm)": 4.98, "dipoles per diameter": 16, ...}
15
+ out["payload"] # {"points_nm": [[x, y, z], ...], "spacing_nm": 4.98, ...}
16
+ ```
17
+
18
+ ```bash
19
+ lightsmith discretization spec.json --method fdtd
20
+ ```
21
+
22
+ The MCP server has the same call as the read-only tool `get_discretization(problem, method)`.
23
+
24
+ ## The envelope
25
+
26
+ Every backend answers with the same keys:
27
+
28
+ | Key | Meaning |
29
+ |---|---|
30
+ | `backend`, `method`, `problem_kind` | The backend that `method` resolves to (as for `solve`) and the problem kind |
31
+ | `layout_kind` | Which payload follows (table below) |
32
+ | `summary` | Labelled key figures, in display order |
33
+ | `payload` | The geometry, in nm and world coordinates |
34
+ | `estimate` | The backend's `estimate` for the same problem (on the CPU) |
35
+ | `warnings` | The planning code's and the estimate's warnings |
36
+ | `error` | The library's refusal of the problem, or `null`. The geometry is still returned where it can be computed, for example for a graded FDTD grid with a Gaussian beam. |
37
+
38
+ A backend the problem does not suit raises, as `solve` would. Backends with nothing to discretise (TMM,
39
+ quasistatic, circuits) return `layout_kind: "none"` and the estimate's figures in `summary`. Plugins can answer
40
+ by overriding `Backend.discretization(problem, device)`.
41
+
42
+ ## Payloads
43
+
44
+ | `layout_kind` | Backends | Payload |
45
+ |---|---|---|
46
+ | `yee_grid` | FDTD scattering, emission | `grid` (`kind`, `shape`, `cells`, `nodes_nm` per axis, min/max spacing, `max_ratio`), `domain_nm`, `pml`, `boxes` (TFSF, total- and scattered-field flux; emission: the radiated-power box), `regions` (from `grid: "auto"` and `mesh_override`), `symmetry` (mirror planes, `planes_nm`). The grid is whole; the run steps one mirror image of it (`estimate.cells`). |
47
+ | `unit_cell` | FDTD periodic, layer stacks | Cell nodes `x_nm`, `y_nm`, `z_nm` (depth below the top of the stack), `planes_nm` (reflection monitor, source, stack top and bottom, transmission monitor), `pml_cells`, layer tops and thicknesses |
48
+ | `device_grid` | FDTD and FDFD devices, inverse design | `nodes_nm` per axis, PML inner faces, `ports` (`axis`, `direction`, `source_nm`, FDTD `monitor_nm`, `window_nm`, `num_modes`), `two_d`; inverse design: `design_regions` (shape, extent, filter radius in cells) |
49
+ | `dipole_lattice` | DDA | `points_nm` (occupied dipoles, subsampled by `stride` beyond 20 000), `material_slot`, `spacing_nm`, `dipoles_per_diameter`, `grid`, `n_dipoles`, `extrapolate` |
50
+ | `surface_mesh` | BEM | `verts_nm`, `tris` (subsampled beyond 40 000), `tri_surface`, `mesh_size_nm`, `n_triangles`, `n_edges` |
51
+ | `multipoles` | Mie (`lightsmith-mie`, `miepython`), T-matrix | Mie: `n_max` and `size_parameter` per wavelength and the rule used; T-matrix: `lmax` per particle, `modes`, `lmax_global` |
52
+ | `harmonics` | RCWA | `harmonics` (m, n), `orders_max`, `layers` (each uniform in z: the problem's own layers) |
53
+ | `cross_section_grid` | FDE | `x_nm`, `y_nm`, spacings, `pml_cells`, `symmetry`, `boundary`, `num_modes` |
54
+ | `cells` | EME, BPM | `axis`, `lo_nm`, `hi_nm`, `cells` (`start_nm`, `stop_nm`; BPM: `steps`, `dz_nm`), the cross-section grid; EME: `modes_per_cell`; BPM: `step_nm` |
55
+ | `plane_waves` | PWE | `k_reduced`, `k_distance`, `k_labels`, per polarisation the solver, plane-wave count, matrix size, FFT grid and (dense) G indices |
56
+ | `none` | TMM, quasistatic, circuits | `note` |
@@ -2,9 +2,8 @@
2
2
 
3
3
  **The open photonics suite — GPU-native, differentiable, and built for AI agents.**
4
4
 
5
- Lightsmith lets you describe a photonics problem once, as typed JSON, and solve it with the method that
6
- fits. It covers nanoparticles, thin films, metasurfaces, waveguides, photonic crystals, devices and
7
- circuits. Every result uses the same units and conventions and records its provenance, so you can
5
+ Lightsmith lets you describe a photonics problem once and solve it with whichever method fits. It covers
6
+ nanoparticles, thin films, metasurfaces, waveguides, photonic crystals, devices and circuits. Every result uses the same units and conventions and records its provenance, so you can
8
7
  cross-check methods directly. Many solvers run on a GPU and can be differentiated, which is what powers
9
8
  inverse design.
10
9
 
@@ -21,7 +20,7 @@ cmp = ls.compare(sim, ["mie", "dda", "fdtd"]) # cross-check methods
21
20
  ```
22
21
 
23
22
  !!! warning "Pre-alpha"
24
- Lightsmith 0.1 is pre-alpha, so the API may still change between minor versions. Each solver page
23
+ Lightsmith 0.2 is pre-alpha, so the API may still change between minor versions. Each solver page
25
24
  lists the validation behind it, with numbers taken from the test suite. Read the `warnings` on every
26
25
  result before you trust its numbers.
27
26
 
@@ -33,12 +32,15 @@ cmp = ls.compare(sim, ["mie", "dda", "fdtd"]) # cross-check methods
33
32
  | [`layer_stack`](problems/layer-stack.md): thin films | [TMM](solvers/tmm.md), [RCWA](solvers/rcwa.md), FDTD | ✅ | TMM, RCWA |
34
33
  | [`periodic`](problems/periodic.md): gratings, metasurfaces | [RCWA](solvers/rcwa.md), FDTD (rectangular lattices) | ✅ | RCWA |
35
34
  | [`mode`](problems/mode.md): waveguide cross-sections | [FDE](solvers/fde.md) | — | — |
36
- | [`device`](problems/device.md): S-parameters between ports | [EME](solvers/eme.md), [BPM](solvers/bpm.md), [FDFD](solvers/fdfd.md) (2D) | BPM, FDFD | FDFD (adjoint) |
35
+ | [`device`](problems/device.md): S-parameters between ports | [EME](solvers/eme.md), [BPM](solvers/bpm.md), [FDFD](solvers/fdfd.md) | BPM, FDFD | FDFD (adjoint) |
37
36
  | [`bands`](problems/bands.md): photonic crystals | [PWE](solvers/pwe.md) | ✅ | dense path |
38
37
  | [`circuit`](problems/circuit.md): netlists of compact models | [S-matrix circuit solver](solvers/circuit.md) | ✅ | ✅ |
39
38
  | [`optimization`](problems/optimization.md): inverse design | [Topology optimisation on FDFD](solvers/inverse.md) | ✅ | — |
40
39
 
41
- ## Three ways in, all JSON
40
+ ## Three ways in
41
+
42
+ All three take the same problem description, so a problem you build in Python can be saved to a file,
43
+ run from the shell, or handed to an agent unchanged.
42
44
 
43
45
  - **Python**: `import lightsmith as ls`, then `ls.solve`, `ls.estimate` and `ls.compare`. See the
44
46
  [quick start](quickstart.md).
@@ -83,7 +83,8 @@ lightsmith doctor
83
83
  ```
84
84
 
85
85
  The output should show the GPU under `"cuda_gpus"`, and `"auto_device"` should name `cuda:0`. With
86
- `device="auto"`, which is the default, solvers that support a GPU use it. Pass `device="cpu"` to force the
86
+ `device="auto"`, which is the default, solvers that support a GPU use it, unless `estimate` says the problem
87
+ will not fit in the GPU's free memory: then the solve runs on the CPU and says so in `warnings`. Pass `device="cpu"` to force the
87
88
  CPU, `device="cuda:1"` to pick a specific GPU, or `device="torch-cpu"` to run the PyTorch code path on
88
89
  the CPU, for example to get gradients without a GPU.
89
90
 
@@ -1,16 +1,16 @@
1
1
  # Materials
2
2
 
3
- You can use a material anywhere a problem asks for one. Every material is a JSON object whose `kind` sets
4
- the model. Permittivities follow the `exp(-iωt)` convention, so loss means `Im(ε) > 0` and `Im(n) > 0`.
3
+ You can use a material anywhere a problem asks for one: pass one of the models below. Permittivities
4
+ follow the `exp(-iωt)` convention, so loss means `Im(ε) > 0` and `Im(n) > 0`.
5
5
 
6
- | `kind` | Model | Fields |
6
+ | Model | Fields | Saved as `kind` |
7
7
  |---|---|---|
8
- | `constant_index` | `ConstantIndex` | `n_real`, `n_imag` (≥ 0) |
9
- | `constant_permittivity` | `ConstantPermittivity` | `eps_real`, `eps_imag` (≥ 0) |
10
- | `drude` | `Drude` | `eps_inf`, `wp_ev`, `gamma_ev`: ε(ω) = ε∞ − ωp² / (ω² + iγω), with energies in eV |
11
- | `drude_lorentz` | `DrudeLorentz` | `eps_inf`, `wp_ev`, `gamma_ev`, `poles: [{delta_eps, omega0_ev, gamma_ev}]` |
12
- | `tabulated` | `Tabulated` | `wavelength_nm`, `n_real`, `n_imag`, `source`: linear interpolation, no extrapolation |
13
- | `library` | `LibraryMaterial` | `name`, `dataset`: a bundled measured dataset (below) |
8
+ | `ConstantIndex` | `n_real`, `n_imag` (≥ 0) | `constant_index` |
9
+ | `ConstantPermittivity` | `eps_real`, `eps_imag` (≥ 0) | `constant_permittivity` |
10
+ | `Drude` | `eps_inf`, `wp_ev`, `gamma_ev`: ε(ω) = ε∞ − ωp² / (ω² + iγω), with energies in eV | `drude` |
11
+ | `DrudeLorentz` | `eps_inf`, `wp_ev`, `gamma_ev`, `poles: [{delta_eps, omega0_ev, gamma_ev}]` | `drude_lorentz` |
12
+ | `Tabulated` | `wavelength_nm`, `n_real`, `n_imag`, `source`: linear interpolation, no extrapolation. Data in any order is sorted by wavelength; duplicate wavelengths are refused. | `tabulated` |
13
+ | `LibraryMaterial` | `name`, `dataset`: a bundled measured dataset (below) | `library` |
14
14
 
15
15
  ## Bundled datasets
16
16
 
@@ -47,7 +47,7 @@ material's default is filled in, so a stored spec stays reproducible.
47
47
  ```python
48
48
  import lightsmith as ls
49
49
 
50
- ls.list_materials("Au") # datasets, ranges, references, ready-made JSON
50
+ ls.list_materials("Au") # datasets, ranges and references
51
51
  gold = ls.LibraryMaterial(name="Au", dataset="McPeak")
52
52
  tab = ls.load_material("Au") # the default dataset as a Tabulated material
53
53
  ```