witwin-maxwell 0.0.1__tar.gz → 0.2.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 (256) hide show
  1. witwin_maxwell-0.2.0/.github/workflows/publish-witwin-maxwell.yml +285 -0
  2. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/.gitignore +4 -0
  3. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/FEATURE_LIST.md +119 -13
  4. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/PKG-INFO +82 -93
  5. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/README.md +76 -91
  6. witwin_maxwell-0.2.0/benchmark/FDFD_PERFORMANCE.md +13 -0
  7. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/RESULTS.md +15 -15
  8. witwin_maxwell-0.2.0/benchmark/fdfd_performance.py +324 -0
  9. witwin_maxwell-0.2.0/docs/dev/fdtd/native_cuda/bench_baseline.py +160 -0
  10. witwin_maxwell-0.2.0/docs/dev/fdtd/native_cuda/kernel_mapping.md +42 -0
  11. witwin_maxwell-0.2.0/docs/dev/fdtd/native_cuda/parity_matrix.md +31 -0
  12. witwin_maxwell-0.2.0/docs/dev/fdtd/native_cuda/profile_scenario.py +24 -0
  13. witwin_maxwell-0.2.0/docs/dev/fdtd/native_cuda/profiling_baseline.md +173 -0
  14. witwin_maxwell-0.2.0/docs/dev/fdtd/native_cuda/snapshot_tool.py +189 -0
  15. witwin_maxwell-0.2.0/docs/dev/grating-tfsf-bloch-pml-notes.md +41 -0
  16. witwin_maxwell-0.2.0/hatch_build.py +17 -0
  17. witwin_maxwell-0.2.0/pyproject.toml +38 -0
  18. witwin_maxwell-0.2.0/scripts/build_fdtd_cuda_prebuilt.py +68 -0
  19. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/TEST_LAYOUT.md +1 -0
  20. witwin_maxwell-0.2.0/tests/api/adapters/gds/test_gds_adapter.py +213 -0
  21. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/api/adapters/tidy3d/test_tidy3d_adapter.py +35 -0
  22. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/api/public/test_public_api.py +7 -5
  23. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/api/public/test_simulation_smoke.py +2 -2
  24. witwin_maxwell-0.2.0/tests/boundaries/absorbers/test_boundary_variants.py +158 -0
  25. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/boundaries/boundary_physics/test_fdtd_boundary_physics.py +134 -0
  26. witwin_maxwell-0.2.0/tests/boundaries/boundary_physics/test_fdtd_pec_material.py +65 -0
  27. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/boundaries/boundary_specs/test_fdtd_boundaries.py +23 -10
  28. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/boundaries/cpml/test_fdtd_cpml.py +12 -12
  29. witwin_maxwell-0.2.0/tests/boundaries/symmetry/test_symmetry_generalization.py +256 -0
  30. witwin_maxwell-0.2.0/tests/core/grid/test_autogrid.py +482 -0
  31. witwin_maxwell-0.2.0/tests/core/grid/test_gridspec_custom.py +283 -0
  32. witwin_maxwell-0.2.0/tests/core/grid/test_nonuniform_placement.py +146 -0
  33. witwin_maxwell-0.2.0/tests/core/grid/test_nonuniform_uniform_equivalence.py +197 -0
  34. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/core/scene/test_scene.py +44 -1
  35. witwin_maxwell-0.2.0/tests/fdfd/test_ams.py +80 -0
  36. witwin_maxwell-0.2.0/tests/fdfd/test_direct_solver.py +100 -0
  37. witwin_maxwell-0.2.0/tests/fdfd/test_krylov.py +130 -0
  38. witwin_maxwell-0.2.0/tests/fdfd/test_matrix_cache.py +102 -0
  39. witwin_maxwell-0.2.0/tests/fdfd/test_preconditioners.py +70 -0
  40. witwin_maxwell-0.2.0/tests/fdfd/test_symmetric_formulation.py +91 -0
  41. witwin_maxwell-0.2.0/tests/fdtd/cuda/_parity_backend.py +30 -0
  42. witwin_maxwell-0.2.0/tests/fdtd/cuda/test_cuda_adjoint_parity.py +1275 -0
  43. witwin_maxwell-0.2.0/tests/fdtd/cuda/test_cuda_common_parity.py +218 -0
  44. witwin_maxwell-0.2.0/tests/fdtd/cuda/test_cuda_cpml_extension_parity.py +346 -0
  45. witwin_maxwell-0.2.0/tests/fdtd/cuda/test_cuda_dispersive_parity.py +168 -0
  46. witwin_maxwell-0.2.0/tests/fdtd/cuda/test_cuda_electric_boundary_parity.py +321 -0
  47. witwin_maxwell-0.2.0/tests/fdtd/cuda/test_cuda_extension_load.py +58 -0
  48. witwin_maxwell-0.2.0/tests/fdtd/cuda/test_cuda_graph.py +37 -0
  49. witwin_maxwell-0.2.0/tests/fdtd/cuda/test_cuda_magnetic_parity.py +256 -0
  50. witwin_maxwell-0.2.0/tests/fdtd/cuda/test_cuda_sources_parity.py +775 -0
  51. witwin_maxwell-0.2.0/tests/fdtd/cuda/test_cuda_spectral_observer_parity.py +193 -0
  52. witwin_maxwell-0.2.0/tests/fdtd/cuda/torch_reference.py +3248 -0
  53. witwin_maxwell-0.2.0/tests/fdtd/test_cuda_graph.py +111 -0
  54. witwin_maxwell-0.2.0/tests/fdtd/test_fdtd_autoshutoff.py +121 -0
  55. witwin_maxwell-0.2.0/tests/gradients/test_fdfd_adjoint.py +137 -0
  56. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/gradients/test_fdtd_adjoint_bridge.py +213 -446
  57. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/gradients/test_fdtd_adjoint_rigorous.py +69 -1
  58. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/gradients/test_fdtd_mode_source_adjoint.py +56 -14
  59. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/materials/compiler/test_material_compiler.py +29 -0
  60. witwin_maxwell-0.2.0/tests/materials/compiler/test_pec_material.py +95 -0
  61. witwin_maxwell-0.2.0/tests/materials/compiler/test_polarized_averaging.py +58 -0
  62. witwin_maxwell-0.2.0/tests/materials/compiler/test_polyslab.py +196 -0
  63. witwin_maxwell-0.2.0/tests/materials/compiler/test_subpixel_gradients.py +58 -0
  64. witwin_maxwell-0.2.0/tests/materials/compiler/test_subpixel_normals.py +34 -0
  65. witwin_maxwell-0.2.0/tests/materials/compiler/test_subpixel_spec.py +67 -0
  66. witwin_maxwell-0.2.0/tests/materials/conductive/test_fdtd_conductive.py +214 -0
  67. witwin_maxwell-0.2.0/tests/monitors/diffraction/test_diffraction_monitor.py +334 -0
  68. witwin_maxwell-0.2.0/tests/monitors/emission/test_dipole_emission_monitor.py +179 -0
  69. witwin_maxwell-0.2.0/tests/monitors/material/test_permittivity_monitor.py +222 -0
  70. witwin_maxwell-0.2.0/tests/monitors/time/test_fdtd_time_monitors.py +255 -0
  71. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/postprocess/scattering/test_mode_overlap.py +17 -11
  72. witwin_maxwell-0.2.0/tests/sources/definitions/test_astigmatic_gaussian_beam.py +203 -0
  73. witwin_maxwell-0.2.0/tests/sources/definitions/test_custom_source_time.py +222 -0
  74. witwin_maxwell-0.2.0/tests/sources/definitions/test_custom_uniform_sources.py +245 -0
  75. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/sources/definitions/test_sources.py +39 -0
  76. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/sources/mode/test_mode_solver_gradients.py +10 -2
  77. witwin_maxwell-0.2.0/tests/sources/tfsf/test_fdtd_grating_tfsf.py +561 -0
  78. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/sources/tfsf/test_fdtd_tfsf.py +24 -24
  79. witwin_maxwell-0.2.0/tests/validation/benchmark/test_fdfd_performance.py +27 -0
  80. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/validation/cross_solver/test_fdfd_vs_fdtd.py +49 -4
  81. witwin_maxwell-0.2.0/tests/validation/physics/test_autogrid_physics.py +160 -0
  82. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/validation/physics/test_fdtd_boundary_tfsf_validation.py +88 -15
  83. witwin_maxwell-0.2.0/tests/validation/physics/test_nonuniform_grid_physics.py +178 -0
  84. witwin_maxwell-0.2.0/tests/validation/physics/test_pec_conformal.py +90 -0
  85. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/__init__.py +62 -3
  86. witwin_maxwell-0.2.0/witwin/maxwell/adapters/gds.py +203 -0
  87. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/adapters/tidy3d.py +14 -2
  88. witwin_maxwell-0.2.0/witwin/maxwell/adjoint_inputs.py +66 -0
  89. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/compiler/__init__.py +2 -1
  90. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/compiler/materials.py +157 -29
  91. witwin_maxwell-0.2.0/witwin/maxwell/compiler/monitors.py +164 -0
  92. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/compiler/sources.py +94 -2
  93. witwin_maxwell-0.2.0/witwin/maxwell/fdfd/adjoint/__init__.py +3 -0
  94. witwin_maxwell-0.2.0/witwin/maxwell/fdfd/adjoint/bridge.py +178 -0
  95. witwin_maxwell-0.2.0/witwin/maxwell/fdfd/ams.py +300 -0
  96. witwin_maxwell-0.2.0/witwin/maxwell/fdfd/krylov.py +280 -0
  97. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdfd/solver.py +393 -158
  98. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/adjoint/bridge.py +22 -55
  99. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/adjoint/core.py +486 -1163
  100. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/adjoint/dispatch.py +127 -105
  101. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/adjoint/reference.py +130 -157
  102. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/adjoint/reverse_common.py +19 -31
  103. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/boundary/bloch.py +90 -0
  104. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/boundary/common.py +3 -0
  105. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/boundary/cpml.py +188 -112
  106. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/boundary/runtime.py +209 -0
  107. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/checkpoint.py +7 -2
  108. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/coords.py +32 -0
  109. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/__init__.py +11 -0
  110. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/backend.py +2520 -0
  111. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/build.py +242 -0
  112. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/extension.cpp +1235 -0
  113. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/kernels/adjoint.cu +3244 -0
  114. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/kernels/boundary.cu +354 -0
  115. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/kernels/common.cu +63 -0
  116. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/kernels/common.cuh +82 -0
  117. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/kernels/dispersive.cu +475 -0
  118. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/kernels/electric.cu +2298 -0
  119. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/kernels/magnetic.cu +981 -0
  120. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/kernels/observers.cu +350 -0
  121. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/kernels/projection.cu +214 -0
  122. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/kernels/sources.cu +1485 -0
  123. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/kernels/spectral.cu +300 -0
  124. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/launch.h +16 -0
  125. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/runtime/__init__.py +6 -0
  126. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/runtime/dispatcher.py +6 -0
  127. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/runtime/graph.py +33 -0
  128. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/runtime/parity.py +9 -0
  129. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/cuda/tensors.h +22 -0
  130. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/dispersion.py +48 -0
  131. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/excitation/injection.py +295 -33
  132. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/excitation/modes.py +28 -8
  133. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/excitation/spatial.py +134 -31
  134. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/excitation/temporal.py +170 -59
  135. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/excitation/tfsf_apply.py +5 -0
  136. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/excitation/tfsf_common.py +98 -53
  137. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/excitation/tfsf_specs.py +49 -29
  138. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/excitation/tfsf_state.py +219 -32
  139. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/meshing/__init__.py +3 -0
  140. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/meshing/autogrid.py +313 -0
  141. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/observers.py +336 -1
  142. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/runtime/__init__.py +4 -0
  143. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/runtime/initialization.py +18 -14
  144. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/runtime/materials.py +83 -18
  145. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/runtime/module_cache.py +31 -0
  146. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/runtime/spectral.py +119 -0
  147. witwin_maxwell-0.2.0/witwin/maxwell/fdtd/runtime/stepping.py +1213 -0
  148. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/solver.py +55 -32
  149. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/media.py +26 -0
  150. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/monitors.py +250 -0
  151. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/postprocess/__init__.py +5 -0
  152. witwin_maxwell-0.2.0/witwin/maxwell/postprocess/diffraction.py +219 -0
  153. witwin_maxwell-0.2.0/witwin/maxwell/postprocess/emission.py +67 -0
  154. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/postprocess/modal.py +0 -3
  155. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/result.py +174 -7
  156. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/scene.py +351 -40
  157. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/simulation.py +55 -0
  158. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/sources.py +379 -5
  159. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/visualization/__init__.py +9 -1
  160. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/visualization/interactive.py +4 -1
  161. witwin_maxwell-0.0.1/.claude/settings.json +0 -16
  162. witwin_maxwell-0.0.1/.github/workflows/publish-witwin-maxwell.yml +0 -93
  163. witwin_maxwell-0.0.1/pyproject.toml +0 -23
  164. witwin_maxwell-0.0.1/witwin/maxwell/compiler/monitors.py +0 -73
  165. witwin_maxwell-0.0.1/witwin/maxwell/fdtd/adjoint/.kernels_runtime_1773795042135987100_57071.slang +0 -2090
  166. witwin_maxwell-0.0.1/witwin/maxwell/fdtd/adjoint/.kernels_runtime_1773800541701589400_57074.slang +0 -2090
  167. witwin_maxwell-0.0.1/witwin/maxwell/fdtd/adjoint/kernels.slang +0 -2090
  168. witwin_maxwell-0.0.1/witwin/maxwell/fdtd/boundary/helpers.slang +0 -218
  169. witwin_maxwell-0.0.1/witwin/maxwell/fdtd/boundary/projection.slang +0 -134
  170. witwin_maxwell-0.0.1/witwin/maxwell/fdtd/boundary/runtime.py +0 -83
  171. witwin_maxwell-0.0.1/witwin/maxwell/fdtd/boundary/update.slang +0 -1866
  172. witwin_maxwell-0.0.1/witwin/maxwell/fdtd/coords.py +0 -45
  173. witwin_maxwell-0.0.1/witwin/maxwell/fdtd/fdtd.slang +0 -9
  174. witwin_maxwell-0.0.1/witwin/maxwell/fdtd/kernels/common.slang +0 -54
  175. witwin_maxwell-0.0.1/witwin/maxwell/fdtd/kernels/dispersive.slang +0 -375
  176. witwin_maxwell-0.0.1/witwin/maxwell/fdtd/kernels/magnetic.slang +0 -223
  177. witwin_maxwell-0.0.1/witwin/maxwell/fdtd/kernels/sources.slang +0 -640
  178. witwin_maxwell-0.0.1/witwin/maxwell/fdtd/kernels/spectral.slang +0 -178
  179. witwin_maxwell-0.0.1/witwin/maxwell/fdtd/runtime/module_cache.py +0 -49
  180. witwin_maxwell-0.0.1/witwin/maxwell/fdtd/runtime/stepping.py +0 -699
  181. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/COPYING +0 -0
  182. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/assets/teapot.obj +0 -0
  183. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/__init__.py +0 -0
  184. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/__main__.py +0 -0
  185. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/cache.py +0 -0
  186. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/metrics.py +0 -0
  187. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/models.py +0 -0
  188. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/paths.py +0 -0
  189. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/plotting.py +0 -0
  190. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/report.py +0 -0
  191. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/runner.py +0 -0
  192. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/scenes/__init__.py +0 -0
  193. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/scenes/_common.py +0 -0
  194. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/scenes/dipole/__init__.py +0 -0
  195. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/scenes/dipole/dipole_dielectric_box.py +0 -0
  196. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/scenes/dipole/dipole_dielectric_sphere.py +0 -0
  197. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/scenes/dipole/dipole_ey.py +0 -0
  198. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/scenes/dipole/dipole_offcenter.py +0 -0
  199. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/scenes/dipole/dipole_two_freq.py +0 -0
  200. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/scenes/dipole/dipole_vacuum.py +0 -0
  201. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/scenes/dipole/high_eps_box.py +0 -0
  202. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/scenes/dipole/lorentz_resonator.py +0 -0
  203. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/scenes/dipole/multi_dielectric.py +0 -0
  204. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/scenes/planewave/__init__.py +0 -0
  205. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/scenes/planewave/dielectric_slab.py +0 -0
  206. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/scenes/planewave/dielectric_sphere.py +0 -0
  207. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/scenes/planewave/metal_sphere.py +0 -0
  208. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/scenes/planewave/planewave_dielectric_sphere.py +0 -0
  209. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/scenes/planewave/planewave_vacuum.py +0 -0
  210. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/benchmark/tidy3d_scene.py +0 -0
  211. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/__init__.py +0 -0
  212. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/assets/cube.obj +0 -0
  213. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/assets/teapot.obj +0 -0
  214. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/conftest.py +0 -0
  215. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/core/geometry/test_mesh_geometry.py +0 -0
  216. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/core/grid/test_fdtd_coords.py +0 -0
  217. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/gradients/README.md +0 -0
  218. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/gradients/__init__.py +0 -0
  219. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/gradients/fdtd_adjoint_baselines.py +0 -0
  220. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/materials/compiler/test_fdfd_material_support.py +0 -0
  221. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/materials/dispersive/test_fdtd_dispersive.py +0 -0
  222. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/monitors/observers/test_fdtd_observers.py +0 -0
  223. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/postprocess/directivity/test_directivity.py +0 -0
  224. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/postprocess/evaluation/test_fdtd_evaluation.py +0 -0
  225. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/postprocess/rcs/test_postprocess.py +0 -0
  226. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/postprocess/scattering/test_scattering_parameters.py +0 -0
  227. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/sources/incident/test_fdtd_incident.py +0 -0
  228. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/sources/mode/test_fdtd_mode_source.py +0 -0
  229. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/sources/point/test_fdtd_source_normalization.py +0 -0
  230. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/sources/point/test_fdtd_sources.py +0 -0
  231. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/validation/benchmark/test_benchmark_system.py +0 -0
  232. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/validation/physics/test_fdtd_physics_correctness.py +0 -0
  233. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/tests/validation/physics/test_postprocess_end_to_end_validation.py +0 -0
  234. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/adapters/__init__.py +0 -0
  235. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdfd/__init__.py +0 -0
  236. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdfd/plotting.py +0 -0
  237. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdfd/postprocess.py +0 -0
  238. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/__init__.py +0 -0
  239. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/adjoint/__init__.py +0 -0
  240. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/adjoint/profiler.py +0 -0
  241. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/adjoint/seeds.py +0 -0
  242. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/boundary/__init__.py +0 -0
  243. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/evaluation.py +0 -0
  244. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/excitation/__init__.py +0 -0
  245. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/io.py +0 -0
  246. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/material_pullback.py +0 -0
  247. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/plotting.py +0 -0
  248. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/fdtd/postprocess.py +0 -0
  249. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/materials.py +0 -0
  250. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/ports.py +0 -0
  251. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/postprocess/RCS.py +0 -0
  252. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/postprocess/directivity.py +0 -0
  253. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/postprocess/nfft.py +0 -0
  254. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/postprocess/scattering_parameters.py +0 -0
  255. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/postprocess/stratton_chu.py +0 -0
  256. {witwin_maxwell-0.0.1 → witwin_maxwell-0.2.0}/witwin/maxwell/visualization/plots.py +0 -0
@@ -0,0 +1,285 @@
1
+ name: Build and publish witwin-maxwell
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ - "codex/**"
8
+ pull_request:
9
+ release:
10
+ types: [published]
11
+ workflow_dispatch:
12
+
13
+ jobs:
14
+ validate_release:
15
+ if: github.event_name != 'release' || (startsWith(github.event.release.tag_name, 'witwin-maxwell-v') && !github.event.release.prerelease)
16
+ name: Validate release
17
+ runs-on: ubuntu-latest
18
+ outputs:
19
+ package_dir: ${{ steps.package_dir.outputs.path }}
20
+
21
+ steps:
22
+ - name: Check out repository
23
+ uses: actions/checkout@v4
24
+
25
+ - name: Set up Python
26
+ uses: actions/setup-python@v5
27
+ with:
28
+ python-version: "3.11"
29
+
30
+ - name: Resolve package directory
31
+ id: package_dir
32
+ shell: bash
33
+ run: |
34
+ if [ -f pyproject.toml ]; then
35
+ echo "path=." >> "$GITHUB_OUTPUT"
36
+ elif [ -f maxwell/pyproject.toml ]; then
37
+ echo "path=maxwell" >> "$GITHUB_OUTPUT"
38
+ else
39
+ echo "Unable to find pyproject.toml for the witwin-maxwell package." >&2
40
+ exit 1
41
+ fi
42
+
43
+ - name: Validate release tag and package version
44
+ if: github.event_name == 'release'
45
+ shell: bash
46
+ env:
47
+ PACKAGE_DIR: ${{ steps.package_dir.outputs.path }}
48
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
49
+ run: |
50
+ python - <<'PY'
51
+ import os
52
+ import re
53
+ import sys
54
+ import tomllib
55
+ from pathlib import Path
56
+
57
+ tag = os.environ["RELEASE_TAG"]
58
+ match = re.fullmatch(r"witwin-maxwell-v(?P<version>[0-9A-Za-z.+_-]+)", tag)
59
+ if match is None:
60
+ print(f"Release tag '{tag}' must match 'witwin-maxwell-v<version>'.", file=sys.stderr)
61
+ raise SystemExit(1)
62
+
63
+ expected_version = match.group("version")
64
+ pyproject_path = Path(os.environ["PACKAGE_DIR"]) / "pyproject.toml"
65
+ data = tomllib.loads(pyproject_path.read_text(encoding="utf-8"))
66
+
67
+ project = data["project"]
68
+ package_name = project["name"]
69
+ package_version = project["version"]
70
+
71
+ if package_name != "witwin-maxwell":
72
+ print(f"Expected package name 'witwin-maxwell', found '{package_name}'.", file=sys.stderr)
73
+ raise SystemExit(1)
74
+
75
+ if package_version != expected_version:
76
+ print(
77
+ f"Release tag version '{expected_version}' does not match pyproject version '{package_version}'.",
78
+ file=sys.stderr,
79
+ )
80
+ raise SystemExit(1)
81
+
82
+ print(f"Validated {package_name} {package_version} from {pyproject_path}.")
83
+ PY
84
+
85
+ build_cuda_wheels:
86
+ name: Build CUDA wheel / ${{ matrix.os }} / py${{ matrix.python_version }}
87
+ needs: validate_release
88
+ runs-on: ${{ matrix.os }}
89
+ strategy:
90
+ fail-fast: false
91
+ matrix:
92
+ os: [ubuntu-22.04, windows-2022]
93
+ python_version: ["3.10", "3.11", "3.12"]
94
+
95
+ steps:
96
+ - name: Check out repository
97
+ uses: actions/checkout@v4
98
+
99
+ - name: Set up Python
100
+ uses: actions/setup-python@v5
101
+ with:
102
+ python-version: ${{ matrix.python_version }}
103
+
104
+ - name: Free disk space (Linux)
105
+ if: runner.os == 'Linux'
106
+ shell: bash
107
+ run: |
108
+ echo "Disk before cleanup:"; df -h /
109
+ sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/lib/android \
110
+ /usr/local/share/boost /opt/hostedtoolcache/CodeQL \
111
+ /usr/local/share/powershell /usr/share/swift || true
112
+ sudo docker image prune --all --force || true
113
+ echo "Disk after cleanup:"; df -h /
114
+
115
+ - name: Install CUDA Toolkit
116
+ uses: Jimver/cuda-toolkit@v0.2.29
117
+ with:
118
+ cuda: "12.5.0"
119
+ method: local
120
+ log-file-suffix: "${{ runner.os }}-py${{ matrix.python_version }}"
121
+
122
+ - name: Set up MSVC
123
+ if: runner.os == 'Windows'
124
+ uses: ilammy/msvc-dev-cmd@v1
125
+ with:
126
+ arch: x64
127
+
128
+ - name: Export Windows CUDA_HOME
129
+ if: runner.os == 'Windows'
130
+ shell: pwsh
131
+ run: |
132
+ $cudaRoot = $env:CUDA_PATH
133
+ if (-not $cudaRoot) {
134
+ $nvcc = (Get-Command nvcc -ErrorAction Stop).Source
135
+ $cudaRoot = Split-Path (Split-Path $nvcc -Parent) -Parent
136
+ }
137
+ "CUDA_HOME=$cudaRoot" >> $env:GITHUB_ENV
138
+ "CUDA_PATH=$cudaRoot" >> $env:GITHUB_ENV
139
+ "CUDA_ROOT=$cudaRoot" >> $env:GITHUB_ENV
140
+ "CUDA_BIN_PATH=$cudaRoot" >> $env:GITHUB_ENV
141
+
142
+ - name: Show toolchain
143
+ shell: bash
144
+ run: |
145
+ python --version
146
+ nvcc --version
147
+ command -v cl || true
148
+
149
+ - name: Install CUDA extension build dependencies
150
+ run: |
151
+ python -m pip install --upgrade pip setuptools wheel ninja numpy
152
+ python -m pip install torch==2.6.0 --index-url https://download.pytorch.org/whl/cu124
153
+ python -m pip install build
154
+
155
+ - name: Build packaged FDTD CUDA extension
156
+ env:
157
+ MAX_JOBS: "2"
158
+ TORCH_CUDA_ARCH_LIST: "7.0;8.0;8.6;8.9;9.0+PTX"
159
+ WITWIN_MAXWELL_FDTD_CUDA_BUILD_DIR: ${{ runner.temp }}/witwin_maxwell_fdtd_cuda
160
+ run: |
161
+ python scripts/build_fdtd_cuda_prebuilt.py --verbose
162
+
163
+ - name: Build platform wheel
164
+ shell: bash
165
+ env:
166
+ PACKAGE_DIR: ${{ needs.validate_release.outputs.package_dir }}
167
+ run: |
168
+ python -m build --wheel "$PACKAGE_DIR"
169
+
170
+ - name: Normalize Linux wheel platform tag
171
+ if: runner.os == 'Linux'
172
+ shell: bash
173
+ env:
174
+ PACKAGE_DIR: ${{ needs.validate_release.outputs.package_dir }}
175
+ run: |
176
+ # PyPI rejects the raw linux_x86_64 tag; the extension is built on the
177
+ # ubuntu-22.04 runner (glibc 2.35), so retag to the matching manylinux
178
+ # tag. torch/CUDA runtime libraries are runtime dependencies and stay
179
+ # unbundled, so no auditwheel repair is required.
180
+ shopt -s nullglob
181
+ for whl in "$PACKAGE_DIR"/dist/*-linux_x86_64.whl; do
182
+ echo "Retagging $whl"
183
+ python -m wheel tags --platform-tag manylinux_2_35_x86_64 --remove "$whl"
184
+ done
185
+ ls -l "$PACKAGE_DIR"/dist
186
+
187
+ - name: Smoke install prebuilt wheel
188
+ shell: bash
189
+ env:
190
+ PACKAGE_DIR: ${{ needs.validate_release.outputs.package_dir }}
191
+ WITWIN_MAXWELL_FDTD_CUDA_PREBUILT: "1"
192
+ WITWIN_MAXWELL_FDTD_CUDA_BUILD_DIR: ${{ runner.temp }}/missing_prebuilt_build_dir
193
+ run: |
194
+ python -m pip uninstall -y witwin-maxwell || true
195
+ python -m pip install --no-deps "$PACKAGE_DIR"/dist/*.whl
196
+ python - <<'PY'
197
+ import importlib.util
198
+ import site
199
+ from pathlib import Path
200
+
201
+ candidates = []
202
+ for root in site.getsitepackages() + [site.getusersitepackages()]:
203
+ candidates.append(Path(root) / "witwin" / "maxwell" / "fdtd" / "cuda" / "build.py")
204
+ build_path = next((path for path in candidates if path.exists()), None)
205
+ assert build_path is not None, f"installed build.py not found in {candidates}"
206
+
207
+ spec = importlib.util.spec_from_file_location("witwin_maxwell_fdtd_cuda_build", build_path)
208
+ module = importlib.util.module_from_spec(spec)
209
+ spec.loader.exec_module(module)
210
+
211
+ path = module.prebuilt_extension_path()
212
+ assert path.exists(), f"missing packaged prebuilt extension: {path}"
213
+ extension = module.build_extension()
214
+ print(f"Loaded packaged FDTD CUDA extension from {extension.__file__}")
215
+ PY
216
+
217
+ - name: Upload wheel artifact
218
+ uses: actions/upload-artifact@v4
219
+ with:
220
+ name: wheel-${{ matrix.os }}-py${{ matrix.python_version }}
221
+ path: ${{ needs.validate_release.outputs.package_dir }}/dist/*.whl
222
+ if-no-files-found: error
223
+
224
+ build_sdist:
225
+ name: Build source distribution
226
+ needs: validate_release
227
+ runs-on: ubuntu-latest
228
+
229
+ steps:
230
+ - name: Check out repository
231
+ uses: actions/checkout@v4
232
+
233
+ - name: Set up Python
234
+ uses: actions/setup-python@v5
235
+ with:
236
+ python-version: "3.11"
237
+
238
+ - name: Build distributions
239
+ shell: bash
240
+ env:
241
+ PACKAGE_DIR: ${{ needs.validate_release.outputs.package_dir }}
242
+ run: |
243
+ python -m pip install --upgrade pip build
244
+ python -m build --sdist "$PACKAGE_DIR"
245
+
246
+ - name: Upload source distribution artifact
247
+ uses: actions/upload-artifact@v4
248
+ with:
249
+ name: sdist
250
+ path: ${{ needs.validate_release.outputs.package_dir }}/dist/*.tar.gz
251
+ if-no-files-found: error
252
+
253
+ publish:
254
+ name: Publish to PyPI
255
+ if: github.event_name == 'release'
256
+ needs:
257
+ - build_cuda_wheels
258
+ - build_sdist
259
+ runs-on: ubuntu-latest
260
+ permissions:
261
+ contents: read
262
+ id-token: write
263
+ environment:
264
+ name: pypi
265
+ url: https://pypi.org/project/witwin-maxwell/
266
+
267
+ steps:
268
+ - name: Download wheel artifacts
269
+ uses: actions/download-artifact@v4
270
+ with:
271
+ pattern: wheel-*
272
+ path: dist
273
+ merge-multiple: true
274
+
275
+ - name: Download source distribution artifact
276
+ uses: actions/download-artifact@v4
277
+ with:
278
+ name: sdist
279
+ path: dist
280
+
281
+ - name: Publish distributions to PyPI
282
+ uses: pypa/gh-action-pypi-publish@release/v1
283
+ with:
284
+ packages-dir: dist
285
+ skip-existing: true
@@ -172,6 +172,9 @@ venv.bak/
172
172
  # mkdocs documentation
173
173
  /site
174
174
  .slangtorch_cache/
175
+ .*_runtime_*.slang
176
+ witwin/maxwell/fdtd/cuda/prebuilt/*.pyd
177
+ witwin/maxwell/fdtd/cuda/prebuilt/*.so
175
178
  .fdtd_runtime_*.slang
176
179
  .adjoint_kernels_runtime_*.slang
177
180
  *.png
@@ -179,6 +182,7 @@ venv.bak/
179
182
  *.npz
180
183
 
181
184
  settings.local.json
185
+ .claude/
182
186
 
183
187
  # mypy
184
188
  .mypy_cache/
@@ -21,10 +21,16 @@ This document tracks the current user-visible capabilities of the `maxwell` pack
21
21
 
22
22
  - `Domain` with explicit 3D bounds and `from_domain_range(...)`
23
23
  - `GridSpec.uniform(...)` for isotropic grids
24
- - `GridSpec.anisotropic(...)` for nonuniform `dx`, `dy`, `dz`
25
- - `GridSpec.spacing` always returns `(dx, dy, dz)`, with `GridSpec.is_uniform` for uniform-grid checks
24
+ - `GridSpec.anisotropic(...)` for per-axis constant `dx`, `dy`, `dz`
25
+ - `GridSpec.custom(x_coords, y_coords, z_coords)` for nonuniform (graded) Yee grids from explicit node coordinates: any 1D float array-likes (list / NumPy / torch), validated per axis (strictly increasing, finite, at least two nodes) and stored as read-only float64 masters; a uniform axis is expressed by uniformly spaced coords, and the `Domain` bounds must equal the coordinate extents
26
+ - `GridSpec.auto(min_steps_per_wavelength=..., wavelength=None, max_ratio=..., override_structures=..., layer_refinement=...)` for adaptive (AutoGrid) meshing: at prepare time every structure and `MaterialRegion` AABB face snaps to a cell boundary, each face-bounded interval is stepped at `wavelength / (n_max * min_steps_per_wavelength)` using the maximum overlapping refractive index at the meshing wavelength (material regions contribute `sqrt(max(eps_bounds) * max(mu_bounds))`), intervals are filled with uniform or geometrically graded cells with a global adjacent-cell ratio bound of `max_ratio`, and the result materializes through the same nonuniform-grid path as `GridSpec.custom` (single downstream representation); the meshing wavelength defaults to the highest source frequency in the scene, or an explicit `wavelength=`
27
+ - `MeshOverrideStructure(geometry, dl)` mesh overrides for `GridSpec.auto`: a scalar or per-axis `(dx, dy, dz)` maximum step enforced inside the geometry's axis-aligned bounding box
28
+ - `LayerRefinementSpec(min_cells=..., axes=None)` for `GridSpec.auto`: any structure-bounded interval thinner than `min_cells` local target steps receives at least `min_cells` cells along the covered axes
29
+ - `GridSpec.is_custom`, `GridSpec.is_auto`, `GridSpec.min_spacing`, and `GridSpec.axis_coords(...)` for nonuniform-grid introspection
30
+ - `GridSpec.spacing` returns `(dx, dy, dz)` for uniform specs, with `GridSpec.is_uniform` for uniform-grid checks; both raise on `GridSpec.custom` and `GridSpec.auto`, as do the scalar `Scene.dx/dy/dz` / `Scene.grid_spacing` properties (use `scene.x/y/z`, the half-grid coordinates, or `grid.min_spacing` instead)
26
31
  - `BoundarySpec.none()`, `BoundarySpec.pml(...)`, `BoundarySpec.periodic()`, `BoundarySpec.bloch(...)`, `BoundarySpec.pec()`, and `BoundarySpec.pmc()`
27
32
  - Per-face boundary configuration through `BoundarySpec.faces(...)` and direct `BoundarySpec(kind=..., x=..., x_low=..., ...)` overrides, including global defaults plus per-axis or per-face specialization
33
+ - `BoundarySpec.bloch_wavevector="auto"` marker for solver-resolved Bloch phase workflows during FDTD preparation
28
34
  - Public `BoundaryKind` literal type for boundary-mode selection across declarative scene APIs
29
35
  - Shared `witwin.core.Structure` records pairing geometry and material, with `priority`, `enabled`, and `tags`
30
36
  - `Geometry.with_material(...)` convenience path returns a shared `Structure`
@@ -33,14 +39,17 @@ This document tracks the current user-visible capabilities of the `maxwell` pack
33
39
  - Scene-level modal port assembly with `Scene.add_port(...)`, plus `Scene.resolved_sources()` / `Scene.resolved_monitors()` to materialize first-class `ModePort` objects into the standard `Scene -> Simulation -> Result` workflow
34
40
  - `Scene.clone(...)` for scene-preserving validation, benchmarking, and device-transfer workflows
35
41
  - `Scene(...)` defaults to `device="cuda"` and requires an explicit `device="cpu"` override for scene-only CPU workflows
36
- - Optional low-face symmetry specification on `Scene(symmetry=(..., ..., ...))` with per-axis `None` / `"PEC"` / `"PMC"`
37
- - Optional subpixel material averaging via `Scene(subpixel_samples=...)`, accepting only `int` or `(sx, sy, sz)`
42
+ - Optional domain symmetry on `Scene(symmetry=(..., ..., ...))` with per-axis `None` / `"PEC"` / `"PMC"` on either domain face, via bare mode strings (low face by default) or explicit `(mode, face)` pairs such as `("PEC", "high")`, folding the domain about any axis at either face with matching result-side expansion
43
+ - Optional subpixel material averaging via `Scene(subpixel_samples=...)`, accepting `int`, `(sx, sy, sz)`, or a `SubpixelSpec(samples=..., averaging=..., pec=...)` policy object; the bare `int` / tuple form keeps the legacy arithmetic / staircase behavior bitwise unchanged
44
+ - `SubpixelSpec(averaging="polarized")` enables Kottke normal-projection subpixel averaging (harmonic permittivity/permeability along the SDF interface normal, arithmetic tangentially) for `eps` and `mu` components, flowing through both FDFD and FDTD from the shared material compiler
45
+ - `SubpixelSpec(pec="conformal")` enables stable partial-fill conformal PEC edge treatment for in-domain `Material.pec()` structures in FDTD
38
46
  - Solver-side compiled scene inspection via `Simulation.prepare()`, where `prepared.solver.scene` materializes Yee-grid dimensions, lazy meshgrid allocation, material compilation, and orthogonal material cross sections without storing that state on the public `Scene`
39
47
 
40
48
  ## Geometry
41
49
 
42
50
  - Analytic geometry primitives:
43
51
  `Box`, `Sphere`, `Cylinder`, `Ellipsoid`, `Cone`, `Pyramid`, `Prism`, `Torus`, `HollowBox`
52
+ - Extruded polygon geometry via `PolySlab(vertices, bounds, axis, sidewall_angle, reference_plane)` with Tidy3D-style linear sidewall taper and even-odd interior rule for non-convex cross-sections, plus `ComplexPolySlab(loops, ...)` for self-intersecting and multi-loop (hole-carving) cross-sections
44
53
  - Shared core geometry constructors use `position=...` consistently across analytic primitives, `Mesh`, and `SMPLBody`
45
54
  - Shared core geometry constructors default to `device=None`, while `Scene(...)` owns device placement and defaults to CUDA
46
55
  - Rotation support for applicable analytic geometries
@@ -70,12 +79,16 @@ This document tracks the current user-visible capabilities of the `maxwell` pack
70
79
  - Structure overlap resolution uses `Structure.priority` first, then append order among equal-priority structures
71
80
  - Occupancy-based material blending on the scene grid, with SDF-driven soft occupancy for shared `Box`, `Sphere`, `Cylinder`, `Torus`, and `HollowBox`
72
81
  - Phase-1.5 primitive SDF coverage for shared `Ellipsoid`, `Cone`, `Pyramid`, and `Prism`
82
+ - Differentiable SDF occupancy for `PolySlab` and `ComplexPolySlab`, with gradients through polygon vertices, axis bounds, and sidewall angle
73
83
  - Differentiable mesh occupancy compilation through shared mesh signed-distance evaluation, including Slang-accelerated CUDA forward/backward distance-sign queries for watertight solid fill, geometry-state-aware static mesh SDF caching, cached BVH acceleration for larger static CUDA meshes, and shared surface-band modes
74
84
  - Supersampled voxel averaging for smoother material interfaces on partial cells
85
+ - Polarized (Kottke normal-projection) subpixel averaging for `eps` and `mu`, using SDF-gradient interface normals estimated by central finite differences on the node grid (differentiable in geometry parameters), reducing normal-field error at high-contrast interfaces
86
+ - In-domain perfect-electric-conductor material via `Material.pec(name=None)` / `Material.is_pec`, compiled to a differentiable union PEC occupancy grid and enforced in FDTD through per-edge open-fraction coefficient scaling (`staircase` hard edge or `conformal` stable partial fill)
75
87
 
76
88
  ## Sources
77
89
 
78
90
  - `CW`, `GaussianPulse`, and `RickerWavelet` source-time definitions
91
+ - `CustomSourceTime` arbitrary temporal waveform from a sampled `(times, amplitudes)` table or a callable `fn`, evaluated on the solver time grid through the Python scalar injection path (no CUDA kernel change)
79
92
  - `PointDipole` source definition with `source_time` and selectable `profile="gaussian"|"ideal"`
80
93
  - `PointDipole`, `ModeSource`, `ModeMonitor`, and `ModePort` use `position=...` as the public spatial-location argument
81
94
  - `PointDipole` width compensation keeps narrow-source injected strength consistent with the default regularization width in FDTD/FDFD workflows
@@ -83,15 +96,53 @@ This document tracks the current user-visible capabilities of the `maxwell` pack
83
96
  - `PlaneWave` soft source for analytical plane-wave injection on an auto-placed source plane
84
97
  - `PlaneWave` soft source uses a single-plane directional `E/H` equivalent-current injector with calibrated Tidy3D-style incident-power scaling
85
98
  - `GaussianBeam` soft source for analytical Gaussian-beam injection with configurable waist and focus
99
+ - `AstigmaticGaussianBeam` soft source for elliptical Gaussian-beam injection with independent per-axis waist `(w0_u, w0_v)` and per-axis focal offsets `focus_u`/`focus_v`, reducing exactly to `GaussianBeam` for isotropic inputs and reusing the same soft and TFSF injection paths
100
+ - `UniformCurrentSource(size, polarization, source_time, center=...)` for a uniform additive electric current filling an axis-aligned box region; radiated power scales as the square of the drive amplitude
101
+ - `CustomCurrentSource(current_dataset, source_time)` injects an arbitrary volume electric-current (`Jx/Jy/Jz`) and magnetic-current (`Mx/My/Mz`) distribution from a `CurrentDataset` (rectilinear coordinate arrays plus per-component tensors), trilinearly interpolated onto the Yee grid
102
+ - `CustomFieldSource(field_dataset, source_time)` replays a tangential `E/H` distribution on a plane by converting it into equivalent surface currents `J = n x H`, `M = -n x E` (normal along the single-sample `FieldDataset` axis), reproducing the corresponding directional plane wave
86
103
  - Experimental `ModeSource` soft source for axis-aligned FDTD waveguide launching, using a full-vector generalized 2D eigenmode solve for forward source-plane assembly on real isotropic apertures, dense and sparse forward backends for that generalized solve, and a retained experimental torch-differentiable scalar eigensolve path for current trainable FDTD scenes
87
- - Experimental `TFSF(bounds=...)` injection descriptor for `PlaneWave` and `GaussianBeam`, with validated axis-aligned `PlaneWave` support for `CW` and `GaussianPulse`, and validated CW oblique `PlaneWave` support
88
- - CUDA `PlaneWave` TFSF forward stepping uses Slang auxiliary-line updates and fused patch-application kernels to reduce per-step launch overhead
104
+ - Experimental `TFSF(bounds=...)` injection descriptor for `PlaneWave`, `GaussianBeam`, and `AstigmaticGaussianBeam`, with validated axis-aligned `PlaneWave` support for `CW` and `GaussianPulse`, and validated CW oblique `PlaneWave` support
105
+ - Experimental `TFSF.slab(axis="z", bounds=...)` injection descriptor for grating-oriented CW `PlaneWave` workflows, spanning the transverse Bloch unit cell during solver preparation for periodic grating illumination
106
+ - CUDA `PlaneWave` TFSF forward stepping uses native CUDA auxiliary-line updates and fused patch-application kernels to reduce per-step launch overhead
89
107
  - `GaussianBeam` `TFSF` remains experimental and currently uses the analytical profile provider rather than the future angular-spectrum / discrete-face engine
90
108
  - Polarization specified by field name (`"Ex"`, `"Ey"`, `"Ez"`) or explicit 3-vector
91
109
  - Source amplitude and phase carried by `source_time`; spatial sources keep width / beam parameters and optional name
92
110
  - Multiple sources per scene
93
111
  - Source compilation uses `compile_fdfd_sources(...)` / `compile_fdtd_sources(...)` list-based interfaces across both solvers
94
112
 
113
+ ## Grating TFSF Example
114
+
115
+ ```python
116
+ import witwin.maxwell as mw
117
+
118
+ scene = mw.Scene(
119
+ domain=mw.Domain(bounds=((-0.5, 0.5), (-0.5, 0.5), (-1.0, 1.0))),
120
+ grid=mw.GridSpec.uniform(0.05),
121
+ boundary=mw.BoundarySpec.faces(
122
+ default="pml",
123
+ num_layers=12,
124
+ strength=1.0,
125
+ x="bloch",
126
+ y="bloch",
127
+ z="pml",
128
+ bloch_wavevector="auto",
129
+ ),
130
+ )
131
+
132
+ scene.add_source(
133
+ mw.PlaneWave(
134
+ direction=(0.25, 0.0, 0.9682458366),
135
+ polarization=(1.0, 0.0, -0.2581988897),
136
+ source_time=mw.CW(frequency=200e12),
137
+ injection=mw.TFSF.slab(axis="z", bounds=(-0.4, 0.4)),
138
+ )
139
+ )
140
+
141
+ scene.add_monitor(mw.FluxMonitor("transmission", axis="z", position=0.7))
142
+
143
+ result = mw.Simulation.fdtd(scene, frequencies=[200e12]).run()
144
+ ```
145
+
95
146
  ## Monitors
96
147
 
97
148
  - `PointMonitor` for point sampling of selected electric or magnetic field components
@@ -99,7 +150,12 @@ This document tracks the current user-visible capabilities of the `maxwell` pack
99
150
  - `FinitePlaneMonitor` for first-class finite rectangular plane sampling with explicit `position=(x, y, z)` and `size=(sx, sy, sz)` on a zero-thickness axis
100
151
  - `ClosedSurfaceMonitor` for first-class finite closed Huygens-surface workflows, including `ClosedSurfaceMonitor.box(...)` and custom multi-face axis-aligned surfaces built from `FinitePlaneMonitor` faces
101
152
  - `FluxMonitor` for plane-integrated power / flux extraction from tangential `E/H` fields
153
+ - `FieldTimeMonitor` for raw time-domain FDTD field recording (point, plane, or volume region) with `start` / `stop` / `interval` sampling controls, returning the sample-time tensor `t` and per-component GPU buffers through `Result.monitor(...)`
154
+ - `FluxTimeMonitor` for instantaneous time-domain Poynting flux (`E x H`) recorded on an axis-aligned plane with `start` / `stop` / `interval` sampling controls, returning the sample-time tensor `t` and the flux time series through `Result.monitor(...)`
102
155
  - Experimental `ModeMonitor` for first-class modal decomposition on an axis-aligned port plane, reusing the current `ModeSource` mode specification and returning forward / backward modal amplitudes and power through `Result.monitor(...)`
156
+ - Experimental `DiffractionMonitor` for grating diffraction-order decomposition on an axis-aligned periodic unit-cell plane, returning per-order `(m, n)` complex tangential amplitudes, per-order Poynting power, propagating / evanescent flags, and diffraction angles through `Result.monitor(...)`, with reciprocal lattice and light-cone cutoff derived from the transverse periods and the resolved Bloch wavevector
157
+ - `PermittivityMonitor` and `MediumMonitor` for first-class point / plane / volume sampling of the compiled material properties (`eps`, plus `mu` and `sigma_e` for `MediumMonitor`), resolved from the compiled material tensors at result time through `Result.monitor(...)` without requesting any time stepping or extra DFT frequencies
158
+ - Experimental `DipoleEmissionMonitor` for the power a named `PointDipole` delivers to the field (`P = -(1/2) Re(conj(J) . E)`), formed from the co-located electric-field DFT at the dipole cell and the injected source current spectrum, returning per-frequency `power_delivered` through `Result.monitor(...)`; combine a structured run with a vacuum run through `maxwell.postprocess.purcell_factor(...)` to obtain the Purcell factor / local density of states
103
159
  - Optional per-monitor `frequencies=` on plane and modal monitors / ports
104
160
  - Named monitor results returned through the unified `Result` object
105
161
  - Multi-component plane monitors with aggregated `Result.monitor(...)` payloads and collocated tangential grids for postprocessing workflows
@@ -124,9 +180,18 @@ This document tracks the current user-visible capabilities of the `maxwell` pack
124
180
  - Axis-aligned diagonal electric anisotropy and diagonal `sigma_e_tensor` support in the Yee-grid operator
125
181
  - Per-face `none` / `pml` boundary selection, including one-sided and mixed-axis PML layouts
126
182
  - Explicit fast-fail validation for unsupported magnetic response and Kerr media
127
- - Configurable GMRES settings via `GMRES(max_iter, tol, restart, solver_type)`
183
+ - Configurable GMRES settings via `GMRES(max_iter, tol, restart, solver_type, preconditioner)`
184
+ - GPU-native preconditioners for the iterative solvers: `none`, `jacobi` (default), `ssor` (relaxation via `GMRES(ssor_omega=...)`, default 0.8), `ilu` (ILU(0); unstable on the indefinite curl-curl operator — see `benchmark/FDFD_PERFORMANCE.md`), and `ams` (experimental in-repo Hiptmair–Xu auxiliary-space preconditioner with geometric multigrid; measured non-contractive on the indefinite time-harmonic operator — see the module docstring for its scope)
185
+ - Double-precision iterative solves via `GMRES(precision="double")`: the Krylov recurrences and preconditioner run in complex128 while assembly and returned fields stay complex64; removes the float32 round-off stagnation (measured: `sqmr`+`ssor` converges to 1e-7 at 48³ where single precision stalls at ~2e-2)
186
+ - Supported `solver_type` values: `gmres`, `cg`, `direct`, plus in-repo GPU Krylov engines `bicgstab`, `tfqmr`, `idr` (IDR(s)), and `sqmr` (simplified QMR; exploits the complex-symmetric system)
187
+ - The FDFD system is assembled in a symmetrized UPML formulation (exactly complex-symmetric via a diagonal similarity), which also measures far lower PML reflection than the previous discretization; the adjoint solve reuses the forward factorization/preconditioner as a consequence
188
+ - `direct` solver backed by NVIDIA cuDSS (`pip install witwin-maxwell[direct]`): factorize-once / solve-many with the factorization cached on the prepared solver and reused across source changes; complex64 LU plus iterative refinement
189
+ - Direct-solve reuse composes with `solver.set_frequency(...)`, which releases the stale factorization automatically
128
190
  - Typed FDFD solver configuration through `FDFDConfig(solver=..., enable_plot=..., verbose=...)`
129
191
  - Prepared execution via `Simulation.prepare()` before running
192
+ - Differentiable FDFD: scenes with trainable parameters (SceneModule parameters, `MaterialRegion` densities, trainable geometry tensors) route through an adjoint gradient bridge, so `loss.backward()` on `Result` fields propagates to material and geometry inputs; the adjoint solve reuses the cached system state (with the direct backend, a cached transpose factorization)
193
+ - System-matrix caching on the prepared solver: repeated `solve()` calls reuse the assembled matrix across source changes
194
+ - Frequency switching on the prepared solver via `solver.set_frequency(...)`, reusing compiled material components when all materials are non-dispersive
130
195
  - Unified `Result` output containing `Ex`, `Ey`, and `Ez`
131
196
  - Solver stats including convergence flag, solver info, residual, and solver configuration
132
197
 
@@ -134,19 +199,27 @@ This document tracks the current user-visible capabilities of the `maxwell` pack
134
199
 
135
200
  - Time-domain simulation through `Simulation.fdtd(...)`
136
201
  - CUDA-only solver execution; `Simulation.fdtd(...)` requires `Scene(device="cuda")`
202
+ - Compiled native CUDA kernels are the only FDTD runtime backend; the Torch reference path has been retired from the runtime and relocated to the CUDA parity tests
137
203
  - Single- or multi-frequency DFT extraction through `frequency=` or `frequencies=[...]`
138
204
  - Source temporal frequency (`source_time.frequency`) remains distinct from simulation / monitor extraction frequencies; Maxwell does not infer extraction frequencies implicitly
139
205
  - ADE-based electric and magnetic dispersive-material updates for Debye, Drude, and Lorentz media
206
+ - Static isotropic or diagonal electric conductivity (`sigma_e`) in the time-domain update, folded into the per-component lossy-dielectric `Ca`/`Cb` coefficients via the standard semi-implicit trapezoidal scheme so simple lossy dielectrics no longer require a fitted Drude pole
140
207
  - Axis-aligned diagonal anisotropy support for electric and magnetic material tensors on the Yee grid
208
+ - Nonuniform (`GridSpec.custom`) Yee grids run on the single native CUDA kernel path through per-axis primal/dual spacing arrays, so a uniform grid is just the constant-array special case (a `GridSpec.custom` built from a uniform scene's node masters reproduces the `GridSpec.uniform` run bitwise); covers all field-update variants (standard, CPML dense/compressed, Bloch, mixed Bloch+PML), physical-depth-graded CPML profiles with per-side layer thicknesses, per-face local-cell Mur deltas, physically placed sources and monitors via the float64 coordinate masters, and `dt` from the per-axis minimum spacing
209
+ - The reverse-time FDTD adjoint is the exact transpose of the nonuniform forward stencils (each reverse term reuses the same per-axis spacing element as its forward counterpart), so design-region gradients work unchanged on graded meshes
141
210
  - Instantaneous isotropic electric Kerr nonlinearity with GPU-resident dynamic update coefficients
142
211
  - Automatic run length estimation with `TimeConfig.auto(...)`
143
212
  - Explicit run-step control with `TimeConfig(time_steps=...)`
213
+ - Opt-in auto-shutoff early termination stops the forward loop once relative electric-field energy decays below `Simulation.fdtd(..., shutoff=..., shutoff_check_interval=100)` (default `shutoff=0.0` disables it), with a settling/DFT/observer-aware floor so continuously driven CW and spectral runs are never truncated, plus a planned-window normalization restore so an early-stopped run's DFT/monitor spectra match the full-length run; `Result.stats()` reports `shutoff`, `shutoff_triggered`, `shutoff_step`, and `steps_run`
144
214
  - Automatic `dt` tightening for broadband source-time objects such as `GaussianPulse` and `RickerWavelet`, and for electric or magnetic dispersive material poles such as `Drude`, `Debye`, and `Lorentz` media
145
215
  - CPML absorber configuration through `BoundarySpec.pml(...)` plus typed `Simulation.fdtd(...)` config (`absorber=...`, `cpml_config=...`)
146
216
  - CPML auxiliary `psi` storage auto-selects between a dense fast path and slab-allocated low-memory storage, with `cpml_config={"memory_mode": "auto"|"dense"|"slab"}` and optional `dense_memory_limit_mib` tuning
217
+ - Additional PML-face absorber variants selectable through `Simulation.fdtd(..., absorber=...)`: `"absorber"` (adiabatic graded-conductivity layer with no auxiliary `psi` memory) and `"stablepml"` (a CPML profile tuned for late-time stability with a higher grading order and larger complex-frequency shift), alongside the existing `"cpml"` and `"pml"` options
218
+ - First-order Mur absorbing boundary as a per-face `BoundarySpec.mur()` kind, applied by a native CUDA kernel after the electric update that updates persistent per-face boundary buffers in place (no per-step host arithmetic or allocation, so it is captured into the tail CUDA graph)
147
219
  - Non-absorbing FDTD boundary conditions: periodic, Bloch phase-shifted periodic, PEC, and PMC
148
220
  - Per-face FDTD boundary selection across `pml`, `periodic`, `pec`, `pmc`, and `none`, including mixed-axis combinations such as periodic-in-`y` plus PML-in-`x/z`
149
- - Mixed low-face symmetry plus high-face absorber workflows through `Scene(symmetry=...)` with `BoundarySpec.pml(...)`
221
+ - Mixed x/y Bloch + z PML FDTD forward stepping for grating-oriented CW `PlaneWave` TFSF slabs, including explicit Bloch wavevectors and solver-resolved automatic Bloch phase from the incident CW plane wave
222
+ - Any-axis / either-face domain symmetry (PEC/PMC image plane on the chosen `low` or `high` face) combined with absorbing boundaries through `Scene(symmetry=...)` with `BoundarySpec.pml(...)`; point-like sources in the folded-away half are rejected with a clear error
150
223
  - Spectral window and normalization configuration through `SpectralSampler(window=..., normalize_source=...)`
151
224
  - Pulse-driven spectral extraction starts at the transient without steady-state apodization for `GaussianPulse` and `RickerWavelet`, while CW extraction still skips startup transients
152
225
  - Optional prepared execution via `Simulation.prepare()`
@@ -162,6 +235,12 @@ This document tracks the current user-visible capabilities of the `maxwell` pack
162
235
  - Internal checkpoint/replay support for adjoint-enabled FDTD runs, including CPML auxiliary state replay, TFSF auxiliary-line replay, and Bloch real/imag field checkpoints
163
236
  - Adjoint gradient pullback from Yee-grid electric permittivity coefficients back through `Scene.compile_material_tensors()` into trainable material-graph inputs
164
237
  - Solver stats including time steps, `dt`, absorber, requested frequencies, per-frequency DFT sample counts, elapsed time, milliseconds per step, and steps per second
238
+ - Native CUDA extension builds on Windows can discover and load the Visual Studio x64 build environment automatically for accelerated FDTD kernels
239
+ - Native CUDA extension platform wheels include the packaged FDTD CUDA extension, so ordinary `pip install witwin-maxwell` users can load the accelerated FDTD runtime without compiling locally
240
+ - Native CUDA extension builds resolve conda-distributed torch import libraries automatically, and `WITWIN_MAXWELL_FDTD_CUDA_PREBUILT=1` loads an already-built extension from the configured build directory without invoking the build toolchain (required under profilers such as Nsight Systems)
241
+ - Native CUDA CPML field updates skip full-volume coefficient reads when the decay/curl coefficient tensors are spatially uniform, detected automatically once per solve (about 1.4x faster forward stepping on homogeneous scenes)
242
+ - Optional CUDA-graph capture of the per-step FDTD work via `Simulation.fdtd(..., cuda_graph=True)`: the magnetic/electric Yee updates (with CPML) are captured as one graph, and the post-source tail (PEC clamp, Mur ABC, and a GPU-driven running DFT) as a second graph, collapsing per-step kernel-launch and host overhead. The running DFT is driven from a precomputed device weight table indexed by a device step counter (no per-step host arithmetic or host->device transfer), so it captures cleanly and stays bit-identical to the host path (single- and multi-frequency). Bit-exact against the non-graph path, opt-in, and automatically declined for TFSF / magnetic-source / complex-field / Kerr / dispersive scenes whose per-step work carries host input. Most effective in the launch-bound small/adaptive-grid regime (measured ~3.7x/step on a ~1.25e5-cell AutoGrid scene, bringing AutoGrid to ~10.9x faster than the fine-uniform reference -- its full cell-count ratio -- and negligible on large compute-bound uniform grids); `Result.stats()["cuda_graph_active"]` / `["tail_graph_active"]` report whether capture engaged
243
+ - The native CUDA module surface accepts strided tensor views, so reverse-time adjoint checks run on native CUDA reverse kernels for standard, CPML, Bloch, and dispersive scenes, validated against the relocated Torch reference; TFSF adjoint uses the native reference composition
165
244
  - FDTD result stats include CPML auxiliary-memory mode and allocated-versus-dense `psi` byte counts
166
245
  - Support for odd grid sizes in Yee-component field outputs
167
246
 
@@ -195,6 +274,8 @@ This document tracks the current user-visible capabilities of the `maxwell` pack
195
274
  - `maxwell.postprocess.compute_directivity(...)` for radiation intensity, total radiated power, directivity, gain, radiation efficiency, and 3 dB beamwidth extraction from NFFT far fields
196
275
  - `maxwell.postprocess.compute_s_parameters(...)` for broadband `S11` / `S21` extraction from flux-monitor results using reference-run or explicit incident-power normalization
197
276
  - Experimental `maxwell.postprocess.compute_mode_overlap(...)` for plane-monitor or first-class `ModeMonitor` / `ModePort` modal decomposition against an axis-aligned scalar `ModeSource` reference, returning forward/backward modal amplitudes and power fractions
277
+ - Experimental `maxwell.postprocess.purcell_factor(structured, vacuum, name)` for the vacuum-normalized Purcell factor / local density of states of a `DipoleEmissionMonitor`, validated under `tests/monitors/emission/test_dipole_emission_monitor.py` against the analytic dipole-near-PEC-mirror curve (perpendicular orientation) and unity vacuum emission
278
+ - Experimental `maxwell.postprocess.compute_diffraction_orders(...)` and `enumerate_diffraction_orders(...)` for grating diffraction-order decomposition on a periodic unit-cell plane; regression-tested under `tests/monitors/diffraction/test_diffraction_monitor.py` for order-cutoff / light-cone physics, Parseval consistency between the summed order powers and the direct plane-flux integral, specular dominance at normal incidence, grating-driven redistribution of transmitted power into the `+/-1` orders, and cross-validation of the transmission/reflection coefficients against the independent Yee-grid `FluxMonitor` primitive (with an `xfail` tripwire documenting that absolute `T + R = 1` energy conservation is not recoverable under the FDTD spectral-monitor CW normalization)
198
279
  - End-to-end validation coverage for first-class finite closed-surface Huygens workflows in homogeneous free space: rectangular-box dipole near-field reconstruction/directivity, non-rectangular orthogonal-surface dipole directivity, and TFSF Rayleigh-sphere bistatic RCS are regression-tested against analytic or direct-FDTD references under `tests/validation/physics/test_postprocess_end_to_end_validation.py`
199
280
  - First-class closed-surface postprocessing now rejects layered or otherwise inhomogeneous exterior media explicitly instead of silently applying a free-space Green's function outside its validity range
200
281
 
@@ -206,6 +287,12 @@ This document tracks the current user-visible capabilities of the `maxwell` pack
206
287
  - `PlaneWave` export places the source inside the physical interior and uses Tidy3D's infinite-plane aperture convention instead of a finite rectangular source patch
207
288
  - Supported mappings: Domain, GridSpec, BoundarySpec (uniform or per-face PML/periodic/PEC/PMC/Bloch export), Structure (Box/Sphere/Cylinder/Cone), Material (simple conductive / Drude / Lorentz / Debye / mixed PoleResidue with `mu_r = 1`), PointDipole, PlaneWave, GaussianBeam, PointMonitor, PlaneMonitor, FinitePlaneMonitor, FluxMonitor, symmetry
208
289
 
290
+ ## GDS Adapter
291
+
292
+ - `maxwell.adapters.gds.from_gds(path, layer=..., bounds=..., ...)` imports GDS layout polygons as `PolySlab` geometries with cell selection (explicit name or unique top-level cell), layer/datatype filtering, recursive reference flattening, extrusion parameters (`axis`, `bounds`, `sidewall_angle`, `reference_plane`), and unit conversion from the file's user unit to metres (overridable via `length_scale`)
293
+ - `maxwell.adapters.gds.to_gds_file(geometries, path, ...)` writes `PolySlab` / `ComplexPolySlab` cross-sections as GDS polygons on a chosen layer/datatype (multi-loop geometry is even-odd merged so holes survive as keyhole cuts), with the library unit derived from `length_scale` (micrometre user units by default)
294
+ - Adapter module at `maxwell/adapters/gds.py` with optional `gdstk` import
295
+
209
296
  ## Tidy3D Benchmarking
210
297
 
211
298
  - `benchmark/` package as the unified Maxwell-vs-Tidy3D benchmarking entrypoint
@@ -223,6 +310,12 @@ This document tracks the current user-visible capabilities of the `maxwell` pack
223
310
  - Auto-updated benchmark summary in `benchmark/RESULTS.md`, grouped by benchmark scene folder with per-metric better-direction and target-range guidance
224
311
  - Plane-wave benchmark runs enable source-spectrum normalization on the Maxwell side so pulsed `PlaneWave` scenarios compare against the same frequency-domain reference convention as the Tidy3D export
225
312
 
313
+ ## Performance Benchmarking
314
+
315
+ - FDFD solver performance benchmark via `python -m benchmark.fdfd_performance`, sweeping cubic grid sizes (default 32³ through 128³) on a canonical dipole + dielectric-cube scene, with `--solver`/`--precond`/`--precision` axes
316
+ - Per-size metrics: matrix assembly time, solve time, operator matvec count, convergence flag, explicit relative residual, and CuPy peak-GPU-memory high-water mark
317
+ - Results written to `benchmark/FDFD_PERFORMANCE.md` with raw JSON runs archived under `benchmark/cache/fdfd_performance/`
318
+
226
319
  ## Validation and Reference Utilities
227
320
 
228
321
  - Shared material compiler used by scene construction and backend preparation
@@ -234,15 +327,26 @@ This document tracks the current user-visible capabilities of the `maxwell` pack
234
327
 
235
328
  ## Known Limitations
236
329
 
237
- - Current subpixel material smoothing uses scalar arithmetic averaging on the scene grid
238
- - Yee-edge tangential versus normal permittivity averaging is not yet implemented
239
- - High-contrast interfaces can therefore show larger normal-field error than a true edge-aware subpixel scheme
330
+ - Nonuniform (`GridSpec.custom`) grids are FDTD-only in v1: FDFD and Tidy3D export both raise `NotImplementedError` for custom grids; `GridSpec.auto` resolves to a nonuniform grid at prepare time and inherits the same restrictions (FDFD unsupported, TFSF/mode-plane locally-uniform rules apply)
331
+ - On nonuniform grids, TFSF-kind injections (`PlaneWave` TFSF box, grating TFSF slab) require locally uniform spacing along all three axes over the injection region expanded by one cell, and `ModeSource` / `ModeMonitor` / `ModePort` require locally uniform transverse spacing across the mode plane; both are validated with explicit errors. Soft (non-TFSF) surface sources and `PointDipole` are fully generalized, but the soft `PlaneWave` numerical-dispersion phase correction uses the per-axis minimum spacing (exact on uniform grids, an approximation on graded ones)
332
+ - Subpixel material averaging (`Scene(subpixel_samples=...)` with more than one sample) is not yet generalized to nonuniform grids and fails through the scalar `Scene.dx` accessor
333
+ - Polarized subpixel averaging is applied to `eps` and `mu` only; `sigma_e`, Kerr `chi3`, and dispersive-pole weights stay arithmetic (the normal-projection rule is not well defined for conductivity/nonlinearity, and only the static base permittivity/permeability becomes normal-aware for dispersive media)
334
+ - The polarized rule is baked at grid nodes and both runtimes keep their existing arithmetic node-to-Yee-edge averaging, so a residual O(dx) half-cell smoothing of the normal-aware correction remains versus evaluating the rule exactly at each Yee-edge location; this residual is far below the arithmetic/staircase error it replaces
335
+ - Conformal PEC (`SubpixelSpec(pec="conformal")`) is FDTD-only: FDFD raises `NotImplementedError` for in-domain PEC materials, and the FDTD scheme is the stable partial-fill (edge-fraction E-suppression) variant of the Dey-Mittra family; classical area-scaled Dey-Mittra (H-side `1/A_open` with an area floor), contour-path H-loop averaging, and surface-impedance boundaries remain future work
336
+ - Subpixel averaging normals and PEC fill fractions reuse per-structure signed-distance fields, so accuracy is bounded by SDF quality for primitives with kinked distance fields (faces/edges/corners)
240
337
  - Maxwell supports axis-aligned diagonal anisotropy through `DiagonalTensor3`, but `Material.orientation` and full `Tensor3x3` rotation / off-diagonal tensors remain unsupported
241
338
  - Kerr media cannot be combined with dispersive or anisotropic materials in the same scene in v1
339
+ - Experimental `DiffractionMonitor` is v1-limited: it assumes the monitor plane spans one full transverse unit cell (periods taken from the transverse domain lengths), targets FDTD `CW` grating scenes with transverse Bloch/periodic boundaries, and reports per-order power as a share of the transmitted plane flux. Absolute per-order diffraction efficiency normalized against a separately measured incident power is not asserted, because the FDTD spectral-monitor CW normalization is steady-state/ratio-based rather than an absolute cross-run power balance
340
+ - Experimental `DipoleEmissionMonitor` is v1-limited: it reports `power_delivered` from the single co-located dipole cell (a point approximation of the profile-weighted current integral) and requires FDTD `PointDipole` sources; the Purcell factor is only obtained by explicitly normalizing against a separate vacuum run through `maxwell.postprocess.purcell_factor(...)`, because the discrete effective source volume that sets the absolute power scale has no reliable closed form, so a lone run returns `purcell_factor=None`
242
341
  - FDFD supports electric anisotropy only; static magnetic media and magnetic dispersion still fail explicitly
243
- - FDTD rejects static conductive `sigma_e` materials explicitly; use FDFD for frequency-domain conductivity or Maxwell dispersive poles for time-domain media
244
- - Mixed Bloch boundary configurations currently fail explicitly in FDTD; use homogeneous `BoundarySpec.bloch(...)` or avoid Bloch on mixed boundary layouts
342
+ - FDTD supports static electric conductivity (`sigma_e`) in the forward update but still lacks static magnetic conductivity (`sigma_m`), and the FDTD adjoint bridge rejects `sigma_e` media because the reverse-time kernels do not model the conduction-loss decay
343
+ - Mixed Bloch boundary configurations outside the supported x/y Bloch + z PML grating FDTD path still fail explicitly
344
+ - TFSF slab runtime support is currently limited to CW `PlaneWave` grating slabs with `axis="z"`; non-Bloch slabs, non-`PlaneWave` slab sources, and broadband automatic fixed-angle Bloch workflows fail explicitly because automatic Bloch phase is single-frequency metadata
345
+ - Automatic Bloch wavevectors are solver-preparation metadata and are rejected by unresolved Tidy3D export
245
346
  - FDFD currently supports per-face boundary mixing only for `none` and `pml`
347
+ - Domain symmetry (`Scene(symmetry=...)`) is FDTD-only (FDFD rejects it), applies a single image plane per axis at the chosen `low`/`high` face, and requires the user to supply the pre-folded half/quarter domain with a physically symmetric source layout; the symmetry-plane face must be `none` or `pml`. Tidy3D export encodes symmetry about the domain center only and drops the per-face (`low`/`high`) selection
348
+ - The first-order `BoundarySpec.mur()` absorbing boundary leaves a higher reflected residual than a PML absorber (single-snapshot residual energy roughly an order of magnitude above a reflecting PEC box, versus about two orders for PML), applies only to the real electric field so it cannot be combined with Bloch complex-field runs, and has no second-order variant in v1
349
+ - The `"absorber"` and `"stablepml"` variants share the existing PML face plumbing (`BoundarySpec.pml(...)`); `"stablepml"` overrides the CPML grading/alpha profile, so a user-supplied `cpml_config` does not override the stable-profile grading keys
246
350
  - Tidy3D export and the FDTD adjoint bridge reject anisotropy, magnetic dispersion, and Kerr media explicitly in v1
247
351
  - Experimental `ModeSource`, `ModeMonitor`, and `ModePort` are currently limited to FDTD `CW` soft injection / monitoring on an axis-aligned plane and no Tidy3D mode-source export support; forward mode solving now uses a full-vector generalized eigenproblem on real isotropic source apertures and can handle non-unit `mu_r`, but the differentiable path still inherits the older scalar restrictions, and the broader modal stack is still missing complex/lossy, anisotropic, bent, angled, and RF-style wave-port coverage
248
352
  - Experimental `compute_mode_overlap(...)` currently expects aligned tangential `E/H` fields on the target port plane and inherits the same axis-aligned modal-source assumptions as the current `ModeSource` implementation
@@ -250,3 +354,5 @@ This document tracks the current user-visible capabilities of the `maxwell` pack
250
354
  - First-class closed-surface postprocessing currently requires a homogeneous exterior medium immediately outside every face; layered or otherwise inhomogeneous exteriors are rejected explicitly
251
355
  - Closed-surface validation currently covers axis-aligned planar faces, including rectangular Huygens boxes and non-rectangular orthogonal polyhedra; curved/non-planar closed surfaces still need a separate workflow and validation path
252
356
  - Benchmark soft-plane-wave absolute calibration still needs separate validation/debugging and remains a known open correctness issue
357
+ - `UniformCurrentSource`, `CustomCurrentSource`, and `CustomFieldSource` are v1 forward-only: the FDTD adjoint bridge rejects them (no source pullback is implemented). `CustomFieldSource` additionally requires a planar (single-sample-axis) `FieldDataset`, injects toward `+normal` only, and reproduces the plane wave to discretization-limited tolerance (finite-aperture edge diffraction and half-cell E/H staggering leave a small backward and cross-polarized residual)
358
+ - `CustomSourceTime` v1 is limited to the Python scalar soft/uniform injection path: it is supported on `PointDipole` but rejected on `PlaneWave`, `GaussianBeam`, `AstigmaticGaussianBeam` (which require the native time-shifted kernel), and on `ModeSource` (CW-only); callable `fn` waveforms need an explicit `characteristic_frequency` and are not supported in the FDTD adjoint (only sampled `(times, amplitudes)` tables are), and custom-waveform samples are not differentiable