@photivra/engine 2.18.0 → 2.20.0

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 (335) hide show
  1. package/CHANGELOG.md +179 -1
  2. package/CITATION.cff +1 -1
  3. package/NODE_SUPPORT.md +7 -5
  4. package/README.md +6 -6
  5. package/SECURITY.md +1 -1
  6. package/THIRD_PARTY.md +14 -10
  7. package/dist/capture/dng-lens-correction-opcodes.d.ts +32 -0
  8. package/dist/capture/dng-lens-correction-opcodes.js +119 -0
  9. package/dist/capture/dng-lens-correction-opcodes.js.map +1 -0
  10. package/dist/capture/focus-control.js +2 -75
  11. package/dist/capture/focus-control.js.map +1 -1
  12. package/dist/capture/native-environment-lean.d.ts +1 -0
  13. package/dist/capture/native-environment-lean.js +2 -6
  14. package/dist/capture/native-environment-lean.js.map +1 -1
  15. package/dist/capture/native-environment-optical-stage.d.ts +1 -0
  16. package/dist/capture/native-environment-optical-stage.js +2 -5
  17. package/dist/capture/native-environment-optical-stage.js.map +1 -1
  18. package/dist/capture/native-environment-raw.js +1 -5
  19. package/dist/capture/native-environment-raw.js.map +1 -1
  20. package/dist/capture/native-raw-dng.d.ts +6 -0
  21. package/dist/capture/native-raw-dng.js +16 -2
  22. package/dist/capture/native-raw-dng.js.map +1 -1
  23. package/dist/capture/release-sequence.js +2 -47
  24. package/dist/capture/release-sequence.js.map +1 -1
  25. package/dist/capture/sensor-raw-producer.js +3 -5
  26. package/dist/capture/sensor-raw-producer.js.map +1 -1
  27. package/dist/color/white-balance.d.ts +2 -0
  28. package/dist/color/white-balance.js +3 -56
  29. package/dist/color/white-balance.js.map +1 -1
  30. package/dist/composition/image-formation-plan.d.ts +1 -0
  31. package/dist/composition/image-formation-plan.js +3 -49
  32. package/dist/composition/image-formation-plan.js.map +1 -1
  33. package/dist/core/evidence-provenance.js +1 -16
  34. package/dist/core/evidence-provenance.js.map +1 -1
  35. package/dist/core/record-validation.d.ts +54 -0
  36. package/dist/core/record-validation.js +176 -0
  37. package/dist/core/record-validation.js.map +1 -1
  38. package/dist/core/scientific-assurance.js +1 -18
  39. package/dist/core/scientific-assurance.js.map +1 -1
  40. package/dist/core/shared-helpers.d.ts +35 -0
  41. package/dist/core/shared-helpers.js +38 -0
  42. package/dist/core/shared-helpers.js.map +1 -0
  43. package/dist/core/spectral-composition.js +1 -36
  44. package/dist/core/spectral-composition.js.map +1 -1
  45. package/dist/core/spectral.js +1 -19
  46. package/dist/core/spectral.js.map +1 -1
  47. package/dist/core/version.d.ts +1 -1
  48. package/dist/core/version.js +1 -1
  49. package/dist/core/version.js.map +1 -1
  50. package/dist/equipment/exposure-capabilities.d.ts +1 -0
  51. package/dist/equipment/exposure-capabilities.js +2 -36
  52. package/dist/equipment/exposure-capabilities.js.map +1 -1
  53. package/dist/equipment/generic-lens-catalogue.d.ts +8 -2
  54. package/dist/equipment/generic-lens-catalogue.js +31 -2
  55. package/dist/equipment/generic-lens-catalogue.js.map +1 -1
  56. package/dist/equipment/generic-tier-assets.js +2 -3
  57. package/dist/equipment/generic-tier-assets.js.map +1 -1
  58. package/dist/equipment/generic-tier-presets.js +2 -3
  59. package/dist/equipment/generic-tier-presets.js.map +1 -1
  60. package/dist/equipment/iso-capabilities.js +2 -49
  61. package/dist/equipment/iso-capabilities.js.map +1 -1
  62. package/dist/equipment/metering-capabilities.js +1 -26
  63. package/dist/equipment/metering-capabilities.js.map +1 -1
  64. package/dist/equipment/release-capabilities.js +1 -53
  65. package/dist/equipment/release-capabilities.js.map +1 -1
  66. package/dist/exposure/auto-iso-slowest-shutter.js +1 -7
  67. package/dist/exposure/auto-iso-slowest-shutter.js.map +1 -1
  68. package/dist/exposure/exposure-duration-control.js +1 -16
  69. package/dist/exposure/exposure-duration-control.js.map +1 -1
  70. package/dist/exposure/exposure-mode-resolver.js +1 -17
  71. package/dist/exposure/exposure-mode-resolver.js.map +1 -1
  72. package/dist/exposure/filtered-exposure-time.d.ts +93 -0
  73. package/dist/exposure/filtered-exposure-time.js +129 -0
  74. package/dist/exposure/filtered-exposure-time.js.map +1 -0
  75. package/dist/exposure/flash-ttl.d.ts +1 -0
  76. package/dist/exposure/flash-ttl.js +1 -1
  77. package/dist/exposure/flash-ttl.js.map +1 -1
  78. package/dist/exposure/flash.js +1 -49
  79. package/dist/exposure/flash.js.map +1 -1
  80. package/dist/exposure/metering-scene-radiance.js +1 -25
  81. package/dist/exposure/metering-scene-radiance.js.map +1 -1
  82. package/dist/exposure/metering-target.js +1 -30
  83. package/dist/exposure/metering-target.js.map +1 -1
  84. package/dist/exposure/metering-temporal.js +1 -8
  85. package/dist/exposure/metering-temporal.js.map +1 -1
  86. package/dist/exposure/metering.js +1 -72
  87. package/dist/exposure/metering.js.map +1 -1
  88. package/dist/exposure/program-line.js +1 -45
  89. package/dist/exposure/program-line.js.map +1 -1
  90. package/dist/facade/develop-joined-parts.d.ts +29 -0
  91. package/dist/facade/develop-joined-parts.js +33 -0
  92. package/dist/facade/develop-joined-parts.js.map +1 -0
  93. package/dist/facade/display-view-gpu.d.ts +7 -4
  94. package/dist/facade/display-view-gpu.js +4 -4
  95. package/dist/facade/display-view-gpu.js.map +1 -1
  96. package/dist/facade/display-view-lens-signal.d.ts +1 -1
  97. package/dist/facade/display-view-lens-signal.js +5 -3
  98. package/dist/facade/display-view-lens-signal.js.map +1 -1
  99. package/dist/facade/display-view.d.ts +3 -1
  100. package/dist/facade/display-view.js +1 -1
  101. package/dist/facade/display-view.js.map +1 -1
  102. package/dist/facade/fast-methods.d.ts +50 -0
  103. package/dist/facade/fast-methods.js +50 -0
  104. package/dist/facade/fast-methods.js.map +1 -0
  105. package/dist/facade/fast-resolution.d.ts +12 -0
  106. package/dist/facade/fast-resolution.js +18 -0
  107. package/dist/facade/fast-resolution.js.map +1 -0
  108. package/dist/facade/generic-lens-capture.d.ts +6 -3
  109. package/dist/facade/generic-lens-capture.js +6 -3
  110. package/dist/facade/generic-lens-capture.js.map +1 -1
  111. package/dist/facade/simulate-capture.d.ts +88 -16
  112. package/dist/facade/simulate-capture.js +279 -153
  113. package/dist/facade/simulate-capture.js.map +1 -1
  114. package/dist/facade/simulate-display-view.d.ts +3 -2
  115. package/dist/facade/simulate-display-view.js +22 -12
  116. package/dist/facade/simulate-display-view.js.map +1 -1
  117. package/dist/gpu/chart-composite-gpu.js +1 -3
  118. package/dist/gpu/chart-composite-gpu.js.map +1 -1
  119. package/dist/gpu/chart-radiance-gpu.js +1 -5
  120. package/dist/gpu/chart-radiance-gpu.js.map +1 -1
  121. package/dist/gpu/display-view-quality-gpu.d.ts +13 -1
  122. package/dist/gpu/display-view-quality-gpu.js +4 -8
  123. package/dist/gpu/display-view-quality-gpu.js.map +1 -1
  124. package/dist/gpu/display-view-speed-gpu.js +3 -25
  125. package/dist/gpu/display-view-speed-gpu.js.map +1 -1
  126. package/dist/gpu/sensor-stage-gpu.js +1 -5
  127. package/dist/gpu/sensor-stage-gpu.js.map +1 -1
  128. package/dist/gpu/webgpu-runtime.d.ts +2 -0
  129. package/dist/gpu/webgpu-runtime.js +3 -0
  130. package/dist/gpu/webgpu-runtime.js.map +1 -1
  131. package/dist/index.d.ts +11 -1
  132. package/dist/index.js +8 -0
  133. package/dist/index.js.map +1 -1
  134. package/dist/motion/camera-rotation.js +1 -6
  135. package/dist/motion/camera-rotation.js.map +1 -1
  136. package/dist/motion/capture-rotation-inverse-mapping.d.ts +12 -0
  137. package/dist/motion/capture-rotation-inverse-mapping.js +2 -2
  138. package/dist/motion/capture-rotation-inverse-mapping.js.map +1 -1
  139. package/dist/motion/capture-rotation-temporal-quadrature.d.ts +1 -0
  140. package/dist/motion/capture-rotation-temporal-quadrature.js +1 -1
  141. package/dist/motion/capture-rotation-temporal-quadrature.js.map +1 -1
  142. package/dist/motion/capture-rotation-trajectory.js +2 -17
  143. package/dist/motion/capture-rotation-trajectory.js.map +1 -1
  144. package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts +1 -0
  145. package/dist/motion/capture-translation-parallax-temporal-quadrature.js +3 -14
  146. package/dist/motion/capture-translation-parallax-temporal-quadrature.js.map +1 -1
  147. package/dist/motion/extended-object-projection.js +5 -40
  148. package/dist/motion/extended-object-projection.js.map +1 -1
  149. package/dist/optics/aperture-diameter.d.ts +47 -0
  150. package/dist/optics/aperture-diameter.js +50 -0
  151. package/dist/optics/aperture-diameter.js.map +1 -0
  152. package/dist/optics/atmospheric-haze.js +1 -7
  153. package/dist/optics/atmospheric-haze.js.map +1 -1
  154. package/dist/optics/brown-conrady-distortion.js +1 -7
  155. package/dist/optics/brown-conrady-distortion.js.map +1 -1
  156. package/dist/optics/complex-pupil-psf.d.ts +1 -0
  157. package/dist/optics/complex-pupil-psf.js +2 -84
  158. package/dist/optics/complex-pupil-psf.js.map +1 -1
  159. package/dist/optics/detail-limit.d.ts +182 -0
  160. package/dist/optics/detail-limit.js +336 -0
  161. package/dist/optics/detail-limit.js.map +1 -0
  162. package/dist/optics/focus-state.js +1 -11
  163. package/dist/optics/focus-state.js.map +1 -1
  164. package/dist/optics/front-of-lens-filter.d.ts +5 -0
  165. package/dist/optics/front-of-lens-filter.js +3 -65
  166. package/dist/optics/front-of-lens-filter.js.map +1 -1
  167. package/dist/optics/generic-lens-psf.d.ts +18 -2
  168. package/dist/optics/generic-lens-psf.js +25 -2
  169. package/dist/optics/generic-lens-psf.js.map +1 -1
  170. package/dist/optics/generic-nd-filter-presets.d.ts +12 -0
  171. package/dist/optics/generic-nd-filter-presets.js +48 -0
  172. package/dist/optics/generic-nd-filter-presets.js.map +1 -0
  173. package/dist/optics/illumination-vignetting.js +1 -6
  174. package/dist/optics/illumination-vignetting.js.map +1 -1
  175. package/dist/optics/lens-psf-profile.d.ts +4 -1
  176. package/dist/optics/lens-psf-profile.js +12 -111
  177. package/dist/optics/lens-psf-profile.js.map +1 -1
  178. package/dist/optics/longitudinal-chromatic-aberration.js +1 -7
  179. package/dist/optics/longitudinal-chromatic-aberration.js.map +1 -1
  180. package/dist/optics/pupil-vignetting.js +1 -7
  181. package/dist/optics/pupil-vignetting.js.map +1 -1
  182. package/dist/optics/radial-distortion.js +1 -6
  183. package/dist/optics/radial-distortion.js.map +1 -1
  184. package/dist/optics/scene-to-sensor-irradiance.d.ts +13 -0
  185. package/dist/optics/scene-to-sensor-irradiance.js +11 -96
  186. package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
  187. package/dist/optics/stray-light.d.ts +1 -0
  188. package/dist/optics/stray-light.js +1 -1
  189. package/dist/optics/stray-light.js.map +1 -1
  190. package/dist/optics/zernike-wavefront.js +1 -7
  191. package/dist/optics/zernike-wavefront.js.map +1 -1
  192. package/dist/output/capture-geometry.js +1 -8
  193. package/dist/output/capture-geometry.js.map +1 -1
  194. package/dist/output/crop-to-match-focal-length.d.ts +62 -0
  195. package/dist/output/crop-to-match-focal-length.js +63 -0
  196. package/dist/output/crop-to-match-focal-length.js.map +1 -0
  197. package/dist/output/developed-lens-corrections.d.ts +62 -0
  198. package/dist/output/developed-lens-corrections.js +135 -0
  199. package/dist/output/developed-lens-corrections.js.map +1 -0
  200. package/dist/output/generic-lens-corrections.d.ts +5 -7
  201. package/dist/output/generic-lens-corrections.js +11 -10
  202. package/dist/output/generic-lens-corrections.js.map +1 -1
  203. package/dist/output/geometric-transforms.js +1 -4
  204. package/dist/output/geometric-transforms.js.map +1 -1
  205. package/dist/output/lens-corrections.d.ts +12 -2
  206. package/dist/output/lens-corrections.js +22 -7
  207. package/dist/output/lens-corrections.js.map +1 -1
  208. package/dist/output/native-capture-sdr.d.ts +2 -2
  209. package/dist/output/native-capture-sdr.js +3 -2
  210. package/dist/output/native-capture-sdr.js.map +1 -1
  211. package/dist/output/print-contrast-reference.js +1 -1
  212. package/dist/output/print-contrast-reference.js.map +1 -1
  213. package/dist/output/print-size-blur-noise.d.ts +110 -0
  214. package/dist/output/print-size-blur-noise.js +138 -0
  215. package/dist/output/print-size-blur-noise.js.map +1 -0
  216. package/dist/processing/development-detail.d.ts +29 -0
  217. package/dist/processing/development-detail.js +128 -107
  218. package/dist/processing/development-detail.js.map +1 -1
  219. package/dist/schema/illumination-temporal.js +3 -72
  220. package/dist/schema/illumination-temporal.js.map +1 -1
  221. package/dist/schema/illumination.d.ts +1 -0
  222. package/dist/schema/illumination.js +2 -65
  223. package/dist/schema/illumination.js.map +1 -1
  224. package/dist/schema/scene-radiance-temporal.js +2 -14
  225. package/dist/schema/scene-radiance-temporal.js.map +1 -1
  226. package/dist/schema/scene-radiance.js +2 -60
  227. package/dist/schema/scene-radiance.js.map +1 -1
  228. package/dist/schema/validation.d.ts +2 -0
  229. package/dist/schema/validation.js +2 -17
  230. package/dist/schema/validation.js.map +1 -1
  231. package/dist/sensor/accumulated-charge.js +2 -59
  232. package/dist/sensor/accumulated-charge.js.map +1 -1
  233. package/dist/sensor/architecture.js +1 -16
  234. package/dist/sensor/architecture.js.map +1 -1
  235. package/dist/sensor/camera-saturation-capacity.d.ts +1 -0
  236. package/dist/sensor/camera-saturation-capacity.js +3 -55
  237. package/dist/sensor/camera-saturation-capacity.js.map +1 -1
  238. package/dist/sensor/capture-color-sampling-binding.js +1 -26
  239. package/dist/sensor/capture-color-sampling-binding.js.map +1 -1
  240. package/dist/sensor/capture-mode-timing.js +1 -39
  241. package/dist/sensor/capture-mode-timing.js.map +1 -1
  242. package/dist/sensor/capture-mode.js +1 -23
  243. package/dist/sensor/capture-mode.js.map +1 -1
  244. package/dist/sensor/color-sampling.js +1 -26
  245. package/dist/sensor/color-sampling.js.map +1 -1
  246. package/dist/sensor/constant-rate-temporal-integration.js +2 -46
  247. package/dist/sensor/constant-rate-temporal-integration.js.map +1 -1
  248. package/dist/sensor/dark-current.js +2 -45
  249. package/dist/sensor/dark-current.js.map +1 -1
  250. package/dist/sensor/eqe-electron-rate.js +2 -41
  251. package/dist/sensor/eqe-electron-rate.js.map +1 -1
  252. package/dist/sensor/exposure-window.d.ts +7 -0
  253. package/dist/sensor/exposure-window.js +9 -24
  254. package/dist/sensor/exposure-window.js.map +1 -1
  255. package/dist/sensor/iso-gain.js +1 -7
  256. package/dist/sensor/iso-gain.js.map +1 -1
  257. package/dist/sensor/iso-signal-chain.js +1 -43
  258. package/dist/sensor/iso-signal-chain.js.map +1 -1
  259. package/dist/sensor/optical-stack.js +1 -25
  260. package/dist/sensor/optical-stack.js.map +1 -1
  261. package/dist/sensor/photon-energy.js +1 -26
  262. package/dist/sensor/photon-energy.js.map +1 -1
  263. package/dist/sensor/physical-charge-capacity.js +3 -77
  264. package/dist/sensor/physical-charge-capacity.js.map +1 -1
  265. package/dist/sensor/radiometry-readiness.js +2 -23
  266. package/dist/sensor/radiometry-readiness.js.map +1 -1
  267. package/dist/sensor/raw-readout.d.ts +3 -0
  268. package/dist/sensor/raw-readout.js +4 -66
  269. package/dist/sensor/raw-readout.js.map +1 -1
  270. package/dist/sensor/raw-reconstruction.js +2 -64
  271. package/dist/sensor/raw-reconstruction.js.map +1 -1
  272. package/dist/sensor/readout-exposure-linkage.js +1 -9
  273. package/dist/sensor/readout-exposure-linkage.js.map +1 -1
  274. package/dist/sensor/readout-timing.js +4 -79
  275. package/dist/sensor/readout-timing.js.map +1 -1
  276. package/dist/sensor/response-application-compatibility.d.ts +2 -0
  277. package/dist/sensor/response-application-compatibility.js +4 -35
  278. package/dist/sensor/response-application-compatibility.js.map +1 -1
  279. package/dist/sensor/response-operating-range.d.ts +1 -0
  280. package/dist/sensor/response-operating-range.js +3 -79
  281. package/dist/sensor/response-operating-range.js.map +1 -1
  282. package/dist/sensor/responsivity-photocurrent.js +4 -114
  283. package/dist/sensor/responsivity-photocurrent.js.map +1 -1
  284. package/dist/sensor/sampling-aperture.js +1 -25
  285. package/dist/sensor/sampling-aperture.js.map +1 -1
  286. package/dist/sensor/sensor-characteristics.d.ts +137 -0
  287. package/dist/sensor/sensor-characteristics.js +115 -0
  288. package/dist/sensor/sensor-characteristics.js.map +1 -0
  289. package/dist/sensor/spatial-sample-reduction.js +3 -24
  290. package/dist/sensor/spatial-sample-reduction.js.map +1 -1
  291. package/dist/sensor/spatial-sampling-quadrature.js +1 -3
  292. package/dist/sensor/spatial-sampling-quadrature.js.map +1 -1
  293. package/dist/sensor/spatio-spectral-reduction.js +1 -18
  294. package/dist/sensor/spatio-spectral-reduction.js.map +1 -1
  295. package/dist/sensor/spectral-coverage.d.ts +10 -1
  296. package/dist/sensor/spectral-coverage.js +1 -1
  297. package/dist/sensor/spectral-coverage.js.map +1 -1
  298. package/dist/sensor/spectral-quadrature.js +3 -41
  299. package/dist/sensor/spectral-quadrature.js.map +1 -1
  300. package/dist/sensor/spectral-response.js +1 -47
  301. package/dist/sensor/spectral-response.js.map +1 -1
  302. package/dist/sensor/temporal-photo-signal.d.ts +3 -0
  303. package/dist/sensor/temporal-photo-signal.js +5 -2
  304. package/dist/sensor/temporal-photo-signal.js.map +1 -1
  305. package/dist/stabilization/camera-shake.js +1 -6
  306. package/dist/stabilization/camera-shake.js.map +1 -1
  307. package/dist/stabilization/system.d.ts +9 -0
  308. package/dist/stabilization/system.js +7 -86
  309. package/dist/stabilization/system.js.map +1 -1
  310. package/docs/AGENT_GUIDE.md +5 -0
  311. package/docs/API_REFERENCE.md +116 -3
  312. package/docs/QUICK_START.md +178 -14
  313. package/docs/USAGE.md +111 -3
  314. package/docs/api/capture-native-raw-dng.md +6 -0
  315. package/docs/api/core-version.md +1 -1
  316. package/docs/api/equipment-generic-lens-catalogue.md +7 -2
  317. package/docs/api/exports.json +203 -3
  318. package/docs/api/exposure-filtered-exposure-time.md +105 -0
  319. package/docs/api/facade-develop-joined-parts.md +32 -0
  320. package/docs/api/facade-display-view-gpu.md +5 -2
  321. package/docs/api/facade-fast-methods.md +91 -0
  322. package/docs/api/facade-simulate-capture.md +72 -16
  323. package/docs/api/facade-simulate-display-view.md +3 -2
  324. package/docs/api/optics-aperture-diameter.md +51 -0
  325. package/docs/api/optics-detail-limit.md +203 -0
  326. package/docs/api/optics-generic-nd-filter-presets.md +34 -0
  327. package/docs/api/optics-lens-psf-profile.md +3 -1
  328. package/docs/api/output-crop-to-match-focal-length.md +67 -0
  329. package/docs/api/output-developed-lens-corrections.md +12 -0
  330. package/docs/api/output-generic-lens-corrections.md +3 -10
  331. package/docs/api/output-lens-corrections.md +11 -1
  332. package/docs/api/output-print-size-blur-noise.md +115 -0
  333. package/docs/api/sensor-sensor-characteristics.md +105 -0
  334. package/llms.txt +5 -0
  335. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"brown-conrady-distortion.js","sourceRoot":"","sources":["../../src/optics/brown-conrady-distortion.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Generic Brown-Conrady lens distortion: radial (k1, k2, k3) plus tangential/decentering (p1, p2)\n * terms on normalized image-plane coordinates (x, y) = point / normalizationRadiusMm, r^2 = x^2 + y^2:\n * x_d = x (1 + k1 r^2 + k2 r^4 + k3 r^6) + 2 p1 x y + p2 (r^2 + 2 x^2)\n * y_d = y (1 + k1 r^2 + k2 r^4 + k3 r^6) + p1 (r^2 + 2 y^2) + 2 p2 x y\n * In vector form the tangential term is r^2 P + 2 (P . u) u with P = (p2, p1), so (p1, p2) rotate as\n * a vector with the image.\n *\n * Sources: Conrady 1919 (MNRAS 79:384, decentred lens systems); Brown 1966\n * (Photogrammetric Engineering 32:444, \"Decentering distortion of lenses\"); Brown 1971 (Photogramm.\n * Eng. 37:855, close-range camera calibration). The coefficient layout follows the widely used\n * Brown-Conrady convention (for example Heikkila & Silven 1997, CVPR). The coefficient names match\n * that convention, but the values only mean something together with the declared normalization\n * radius.\n *\n * Validity checks (matching the radial-distortion validator):\n * - The radial part must be strictly monotonic over the envelope (the valid radius range).\n * - The Jacobian determinant must stay positive at a dense, fixed polar grid of samples over the\n * envelope disk.\n * - The mapped envelope boundary must have strictly increasing polar angle, so it is a simple\n * star-shaped curve.\n * A smooth, locally invertible map of a closed disk that is one-to-one on its boundary is one-to-one\n * everywhere. So these conditions make the inverse single-valued. Note that the Jacobian and boundary\n * conditions are checked at samples, not proven between them.\n *\n * The inverse uses damped Newton iteration, starting from the radial-only inverse.\n * @see docs/PHYSICS_FOUNDATION.md for the equations, units, coordinate conventions, known blockers\n * and support limits.\n */\n\nimport {\n approximationResult,\n type CalculationResult\n} from \"../core/calculation-result.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport {\n calculateInverseRadialSourcePointValue,\n validateRadialDistortionProfile,\n type LensFieldPointMm,\n type ValidatedRadialProfile\n} from \"./radial-distortion.js\";\nimport { requireInputKeys } from \"../core/record-validation.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\n\nexport interface BrownConradyDistortionCoefficients {\n /** Radial r^2 coefficient. */\n k1: number;\n /** Radial r^4 coefficient. */\n k2: number;\n /** Radial r^6 coefficient. */\n k3: number;\n /** Tangential (decentering) coefficient p1 (couples to y; see module equation). */\n p1: number;\n /** Tangential (decentering) coefficient p2 (couples to x; see module equation). */\n p2: number;\n}\n\nexport interface BrownConradyDistortionProfile {\n /** Physical image-plane radius used to normalize field position, in mm. */\n normalizationRadiusMm: number;\n /** Maximum undistorted normalized radius of the operating envelope. */\n maximumNormalizedRadius: number;\n coefficients: BrownConradyDistortionCoefficients;\n}\n\nexport interface CalculateBrownConradyDistortionMappingInput {\n /** Ideal/undistorted image-plane point, in mm. */\n imagePointMm: LensFieldPointMm;\n profile: BrownConradyDistortionProfile;\n}\n\nexport interface CalculateInverseBrownConradyDistortionMappingInput {\n /** Distorted image-plane point to map back to ideal coordinates, in mm. */\n distortedImagePointMm: LensFieldPointMm;\n profile: BrownConradyDistortionProfile;\n}\n\nexport interface BrownConradyDistortionMapping {\n direction: \"undistorted-to-distorted\";\n sourceImagePointMm: LensFieldPointMm;\n mappedImagePointMm: LensFieldPointMm;\n sourceNormalizedRadius: number;\n /** Determinant of d(mapped)/d(source) at the source point (dimensionless area scale). */\n jacobianDeterminant: number;\n deltaMm: { x: number; y: number; distance: number };\n profileMinimumJacobianDeterminant: number;\n}\n\nexport interface InverseBrownConradyDistortionMapping {\n direction: \"distorted-to-undistorted\";\n distortedImagePointMm: LensFieldPointMm;\n sourceImagePointMm: LensFieldPointMm;\n sourceNormalizedRadius: number;\n jacobianDeterminantAtSource: number;\n newtonIterations: number;\n /** Forward-mapping residual of the solved source point, in mm. */\n residualMm: number;\n deltaMm: { x: number; y: number; distance: number };\n profileMinimumJacobianDeterminant: number;\n}\n\ninterface ValidatedBrownConradyProfile {\n radial: ValidatedRadialProfile;\n coefficients: BrownConradyDistortionCoefficients;\n minimumJacobianDeterminant: number;\n}\n\nconst VALIDATION_RINGS = 64;\nconst VALIDATION_AZIMUTHS = 256;\nconst MAXIMUM_NEWTON_ITERATIONS = 100;\n\nfunction requireFinite(name: string, value: unknown): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n throw new InvalidScientificInputError(`${name} must be finite.`);\n }\n return value;\n}\n\nfunction requirePoint(name: string, point: unknown): LensFieldPointMm {\n if (typeof point !== \"object\" || point === null) {\n throw new InvalidConfigurationError(\n `${name} must be an object with finite numeric x and y coordinates.`\n );\n }\n const record = point as Record<string, unknown>;\n return {\n x: requireFinite(`${name}.x`, record.x),\n y: requireFinite(`${name}.y`, record.y)\n };\n}\n\n/** Forward map on normalized coordinates. */\nfunction forwardNormalized(\n x: number,\n y: number,\n c: BrownConradyDistortionCoefficients\n): { x: number; y: number } {\n const r2 = x * x + y * y;\n const radial = 1 + r2 * (c.k1 + r2 * (c.k2 + r2 * c.k3));\n return {\n x: x * radial + 2 * c.p1 * x * y + c.p2 * (r2 + 2 * x * x),\n y: y * radial + c.p1 * (r2 + 2 * y * y) + 2 * c.p2 * x * y\n };\n}\n\n/** Jacobian [[a, b], [c, d]] of the normalized forward map. */\nfunction jacobianNormalized(\n x: number,\n y: number,\n c: BrownConradyDistortionCoefficients\n): { a: number; b: number; c: number; d: number } {\n const r2 = x * x + y * y;\n const s = 1 + r2 * (c.k1 + r2 * (c.k2 + r2 * c.k3));\n const ds = c.k1 + r2 * (2 * c.k2 + 3 * c.k3 * r2);\n const off = 2 * x * y * ds + 2 * c.p1 * x + 2 * c.p2 * y;\n return {\n a: s + 2 * x * x * ds + 2 * c.p1 * y + 6 * c.p2 * x,\n b: off,\n c: off,\n d: s + 2 * y * y * ds + 6 * c.p1 * y + 2 * c.p2 * x\n };\n}\n\nfunction determinant(j: { a: number; b: number; c: number; d: number }): number {\n return j.a * j.d - j.b * j.c;\n}\n\nfunction validateProfile(\n profile: BrownConradyDistortionProfile\n): ValidatedBrownConradyProfile {\n if (typeof profile !== \"object\" || profile === null) {\n throw new InvalidConfigurationError(\"profile must be an object.\");\n }\n if (typeof profile.coefficients !== \"object\" || profile.coefficients === null) {\n throw new InvalidConfigurationError(\"profile.coefficients must be an object.\");\n }\n const coefficients: BrownConradyDistortionCoefficients = {\n k1: requireFinite(\"profile.coefficients.k1\", profile.coefficients.k1),\n k2: requireFinite(\"profile.coefficients.k2\", profile.coefficients.k2),\n k3: requireFinite(\"profile.coefficients.k3\", profile.coefficients.k3),\n p1: requireFinite(\"profile.coefficients.p1\", profile.coefficients.p1),\n p2: requireFinite(\"profile.coefficients.p2\", profile.coefficients.p2)\n };\n const radial = validateRadialDistortionProfile({\n normalizationRadiusMm: profile.normalizationRadiusMm,\n maximumNormalizedRadius: profile.maximumNormalizedRadius,\n coefficients: {\n k1: coefficients.k1,\n k2: coefficients.k2,\n k3: coefficients.k3\n }\n });\n\n const maximum = radial.maximumNormalizedRadius;\n let minimumJacobianDeterminant = Number.POSITIVE_INFINITY;\n for (let ring = 0; ring <= VALIDATION_RINGS; ring += 1) {\n const rho = (maximum * ring) / VALIDATION_RINGS;\n const azimuths = ring === 0 ? 1 : VALIDATION_AZIMUTHS;\n for (let index = 0; index < azimuths; index += 1) {\n const phi = (2 * Math.PI * index) / VALIDATION_AZIMUTHS;\n const det = determinant(\n jacobianNormalized(rho * Math.cos(phi), rho * Math.sin(phi), coefficients)\n );\n minimumJacobianDeterminant = Math.min(minimumJacobianDeterminant, det);\n }\n }\n if (!Number.isFinite(minimumJacobianDeterminant) || minimumJacobianDeterminant <= 0) {\n throw new InvalidScientificInputError(\n \"Brown-Conrady profile must keep a positive Jacobian determinant over maximumNormalizedRadius so the mapping stays locally invertible.\"\n );\n }\n\n // The mapped boundary must be star-shaped about the mapped centre (the origin): its polar angle\n // must increase strictly around the circle, so the boundary curve is simple.\n let previous: number | undefined;\n let accumulated = 0;\n for (let index = 0; index <= VALIDATION_AZIMUTHS; index += 1) {\n const phi = (2 * Math.PI * index) / VALIDATION_AZIMUTHS;\n const mapped = forwardNormalized(\n maximum * Math.cos(phi),\n maximum * Math.sin(phi),\n coefficients\n );\n const angle = Math.atan2(mapped.y, mapped.x);\n if (previous !== undefined) {\n let step = angle - previous;\n if (step <= -Math.PI) step += 2 * Math.PI;\n if (step > Math.PI) step -= 2 * Math.PI;\n if (!(step > 0)) {\n throw new InvalidScientificInputError(\n \"Brown-Conrady profile maps the envelope boundary to a curve that is not star-shaped about the optical axis; the inverse would not be single-valued.\"\n );\n }\n accumulated += step;\n }\n previous = angle;\n }\n if (Math.abs(accumulated - 2 * Math.PI) > 1e-9) {\n throw new InvalidScientificInputError(\n \"Brown-Conrady profile boundary must wind exactly once around the optical axis.\"\n );\n }\n\n return { radial, coefficients, minimumJacobianDeterminant };\n}\n\nfunction assumptions(): readonly string[] {\n return [\n \"Generic Brown-Conrady radial (k1, k2, k3) plus tangential/decentering (p1, p2) polynomial field mapping\",\n \"Coordinates are normalized by the caller-declared normalizationRadiusMm; the optical axis maps to itself\",\n \"Validity: monotonic radial part, positive Jacobian at a 64-ring x 256-azimuth polar sample and a strictly star-shaped mapped boundary; checked at samples, not proven between them\",\n \"Coefficients are generic caller inputs and do not represent a named lens unless separately calibrated with defensible provenance\",\n \"Thin-prism, anamorphic and higher-order decentering terms are not modeled\"\n ];\n}\n\n/** @internal Opaque validated profile for repeated in-package evaluation. */\nexport type ValidatedBrownConradyDistortionProfile = ValidatedBrownConradyProfile;\n\n/** @internal Validates one profile for repeated evaluation (geometric mapping, ray queries). */\nexport function validateBrownConradyDistortionProfile(\n profile: BrownConradyDistortionProfile\n): ValidatedBrownConradyDistortionProfile {\n return validateProfile(profile);\n}\n\n/** @internal Forward map in mm with its Jacobian d(distorted)/d(ideal), row-major. */\nexport function brownConradyForwardValue(\n profile: ValidatedBrownConradyDistortionProfile,\n point: LensFieldPointMm\n): { mappedImagePointMm: LensFieldPointMm; jacobian: readonly [number, number, number, number] } {\n const scale = profile.radial.normalizationRadiusMm;\n const x = point.x / scale;\n const y = point.y / scale;\n if (Math.hypot(x, y) > profile.radial.maximumNormalizedRadius) {\n throw new InvalidScientificInputError(\n \"Point lies outside the Brown-Conrady profile maximumNormalizedRadius.\"\n );\n }\n const mapped = forwardNormalized(x, y, profile.coefficients);\n const j = jacobianNormalized(x, y, profile.coefficients);\n return {\n mappedImagePointMm: { x: mapped.x * scale, y: mapped.y * scale },\n jacobian: [j.a, j.b, j.c, j.d]\n };\n}\n\n/** @internal Inverse map in mm (distorted to ideal). */\nexport function brownConradyInverseValue(\n profile: ValidatedBrownConradyDistortionProfile,\n point: LensFieldPointMm\n): LensFieldPointMm {\n const solved = solveInverseBrownConrady(profile, point);\n const scale = profile.radial.normalizationRadiusMm;\n return { x: solved.x * scale, y: solved.y * scale };\n}\n\nfunction solveInverseBrownConrady(\n profile: ValidatedBrownConradyProfile,\n point: LensFieldPointMm\n): { x: number; y: number; iterations: number; residual: number; sourceNormalizedRadius: number } {\n const scale = profile.radial.normalizationRadiusMm;\n const maximum = profile.radial.maximumNormalizedRadius;\n const tx = point.x / scale;\n const ty = point.y / scale;\n const tolerance = 1e-12 * Math.max(1, Math.hypot(tx, ty));\n\n // Starting point: the radial-only inverse if inside its mapped envelope, otherwise the target itself.\n let x = tx;\n let y = ty;\n if (Math.hypot(tx, ty) <= profile.radial.maximumMappedNormalizedRadius) {\n const seed = calculateInverseRadialSourcePointValue(\n point,\n profile.radial,\n \"distortedImagePointMm\"\n ).sourceImagePointMm;\n x = seed.x / scale;\n y = seed.y / scale;\n }\n\n let iterations = 0;\n let residual = Number.POSITIVE_INFINITY;\n for (; iterations < MAXIMUM_NEWTON_ITERATIONS; iterations += 1) {\n const f = forwardNormalized(x, y, profile.coefficients);\n const rx = f.x - tx;\n const ry = f.y - ty;\n residual = Math.hypot(rx, ry);\n if (residual <= tolerance) {\n break;\n }\n const j = jacobianNormalized(x, y, profile.coefficients);\n const det = determinant(j);\n if (!(Math.abs(det) > 0) || !Number.isFinite(det)) {\n break;\n }\n const stepX = (j.d * rx - j.b * ry) / det;\n const stepY = (-j.c * rx + j.a * ry) / det;\n // Damping: halve the step until the residual decreases (at most 30 halvings).\n let lambda = 1;\n let accepted = false;\n for (let halving = 0; halving < 30; halving += 1) {\n const nx = x - lambda * stepX;\n const ny = y - lambda * stepY;\n const g = forwardNormalized(nx, ny, profile.coefficients);\n if (Math.hypot(g.x - tx, g.y - ty) < residual) {\n x = nx;\n y = ny;\n accepted = true;\n break;\n }\n lambda /= 2;\n }\n if (!accepted) {\n break;\n }\n }\n\n const sourceNormalizedRadius = Math.hypot(x, y);\n if (\n !(residual <= tolerance) ||\n sourceNormalizedRadius > maximum * (1 + 1e-12)\n ) {\n throw new InvalidScientificInputError(\n \"distortedImagePointMm lies outside the mapped Brown-Conrady profile operating envelope.\"\n );\n }\n\n return { x, y, iterations, residual, sourceNormalizedRadius };\n}\n\n/** Applies the Brown-Conrady forward mapping to one ideal image-plane point. */\nexport function calculateBrownConradyDistortionMapping(\n input: CalculateBrownConradyDistortionMappingInput\n): CalculationResult<BrownConradyDistortionMapping> {\n requireInputKeys(input, \"calculateBrownConradyDistortionMapping\", [\"imagePointMm\", \"profile\"]);\n const point = requirePoint(\"imagePointMm\", input.imagePointMm);\n const profile = validateProfile(input.profile);\n const scale = profile.radial.normalizationRadiusMm;\n const x = point.x / scale;\n const y = point.y / scale;\n const sourceNormalizedRadius = Math.hypot(x, y);\n if (sourceNormalizedRadius > profile.radial.maximumNormalizedRadius) {\n throw new InvalidScientificInputError(\n \"imagePointMm lies outside the Brown-Conrady profile maximumNormalizedRadius.\"\n );\n }\n const mapped = forwardNormalized(x, y, profile.coefficients);\n const mappedImagePointMm = { x: mapped.x * scale, y: mapped.y * scale };\n const dx = mappedImagePointMm.x - point.x;\n const dy = mappedImagePointMm.y - point.y;\n return approximationResult(\n {\n direction: \"undistorted-to-distorted\",\n sourceImagePointMm: point,\n mappedImagePointMm,\n sourceNormalizedRadius,\n jacobianDeterminant: determinant(jacobianNormalized(x, y, profile.coefficients)),\n deltaMm: { x: dx, y: dy, distance: Math.hypot(dx, dy) },\n profileMinimumJacobianDeterminant: profile.minimumJacobianDeterminant\n },\n \"generic-brown-conrady-lens-distortion\",\n \"1.0.0\",\n assumptions()\n );\n}\n\n/**\n * Inverse-maps one distorted image-plane point to its ideal source point, for destination-to-source\n * resampling. Damped Newton iteration starts from the radial-only inverse. The solution must lie\n * inside the declared envelope and must reproduce the distorted point within a relative tolerance of\n * 1e-12.\n */\nexport function calculateInverseBrownConradyDistortionMapping(\n input: CalculateInverseBrownConradyDistortionMappingInput\n): CalculationResult<InverseBrownConradyDistortionMapping> {\n requireInputKeys(input, \"calculateInverseBrownConradyDistortionMapping\", [\"distortedImagePointMm\", \"profile\"]);\n const point = requirePoint(\"distortedImagePointMm\", input.distortedImagePointMm);\n const profile = validateProfile(input.profile);\n const solved = solveInverseBrownConrady(profile, point);\n const scale = profile.radial.normalizationRadiusMm;\n const { x, y, iterations, residual, sourceNormalizedRadius } = solved;\n const sourceImagePointMm = { x: x * scale, y: y * scale };\n const dx = sourceImagePointMm.x - point.x;\n const dy = sourceImagePointMm.y - point.y;\n return approximationResult(\n {\n direction: \"distorted-to-undistorted\",\n distortedImagePointMm: point,\n sourceImagePointMm,\n sourceNormalizedRadius,\n jacobianDeterminantAtSource: determinant(\n jacobianNormalized(x, y, profile.coefficients)\n ),\n newtonIterations: iterations,\n residualMm: residual * scale,\n deltaMm: { x: dx, y: dy, distance: Math.hypot(dx, dy) },\n profileMinimumJacobianDeterminant: profile.minimumJacobianDeterminant\n },\n \"generic-inverse-brown-conrady-lens-distortion\",\n \"1.0.0\",\n [\n ...assumptions(),\n `Inverse uses damped Newton iteration (at most ${MAXIMUM_NEWTON_ITERATIONS} steps) seeded by the radial-only inverse, accepted at a normalized residual of 1e-12`\n ]\n );\n}\n"]}
1
+ {"version":3,"file":"brown-conrady-distortion.js","sourceRoot":"","sources":["../../src/optics/brown-conrady-distortion.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Generic Brown-Conrady lens distortion: radial (k1, k2, k3) plus tangential/decentering (p1, p2)\n * terms on normalized image-plane coordinates (x, y) = point / normalizationRadiusMm, r^2 = x^2 + y^2:\n * x_d = x (1 + k1 r^2 + k2 r^4 + k3 r^6) + 2 p1 x y + p2 (r^2 + 2 x^2)\n * y_d = y (1 + k1 r^2 + k2 r^4 + k3 r^6) + p1 (r^2 + 2 y^2) + 2 p2 x y\n * In vector form the tangential term is r^2 P + 2 (P . u) u with P = (p2, p1), so (p1, p2) rotate as\n * a vector with the image.\n *\n * Sources: Conrady 1919 (MNRAS 79:384, decentred lens systems); Brown 1966\n * (Photogrammetric Engineering 32:444, \"Decentering distortion of lenses\"); Brown 1971 (Photogramm.\n * Eng. 37:855, close-range camera calibration). The coefficient layout follows the widely used\n * Brown-Conrady convention (for example Heikkila & Silven 1997, CVPR). The coefficient names match\n * that convention, but the values only mean something together with the declared normalization\n * radius.\n *\n * Validity checks (matching the radial-distortion validator):\n * - The radial part must be strictly monotonic over the envelope (the valid radius range).\n * - The Jacobian determinant must stay positive at a dense, fixed polar grid of samples over the\n * envelope disk.\n * - The mapped envelope boundary must have strictly increasing polar angle, so it is a simple\n * star-shaped curve.\n * A smooth, locally invertible map of a closed disk that is one-to-one on its boundary is one-to-one\n * everywhere. So these conditions make the inverse single-valued. Note that the Jacobian and boundary\n * conditions are checked at samples, not proven between them.\n *\n * The inverse uses damped Newton iteration, starting from the radial-only inverse.\n * @see docs/PHYSICS_FOUNDATION.md for the equations, units, coordinate conventions, known blockers\n * and support limits.\n */\n\nimport {\n approximationResult,\n type CalculationResult\n} from \"../core/calculation-result.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport {\n calculateInverseRadialSourcePointValue,\n validateRadialDistortionProfile,\n type LensFieldPointMm,\n type ValidatedRadialProfile\n} from \"./radial-distortion.js\";\nimport { requireInputKeys, requireNamedFinite as requireFinite } from \"../core/record-validation.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\n\nexport interface BrownConradyDistortionCoefficients {\n /** Radial r^2 coefficient. */\n k1: number;\n /** Radial r^4 coefficient. */\n k2: number;\n /** Radial r^6 coefficient. */\n k3: number;\n /** Tangential (decentering) coefficient p1 (couples to y; see module equation). */\n p1: number;\n /** Tangential (decentering) coefficient p2 (couples to x; see module equation). */\n p2: number;\n}\n\nexport interface BrownConradyDistortionProfile {\n /** Physical image-plane radius used to normalize field position, in mm. */\n normalizationRadiusMm: number;\n /** Maximum undistorted normalized radius of the operating envelope. */\n maximumNormalizedRadius: number;\n coefficients: BrownConradyDistortionCoefficients;\n}\n\nexport interface CalculateBrownConradyDistortionMappingInput {\n /** Ideal/undistorted image-plane point, in mm. */\n imagePointMm: LensFieldPointMm;\n profile: BrownConradyDistortionProfile;\n}\n\nexport interface CalculateInverseBrownConradyDistortionMappingInput {\n /** Distorted image-plane point to map back to ideal coordinates, in mm. */\n distortedImagePointMm: LensFieldPointMm;\n profile: BrownConradyDistortionProfile;\n}\n\nexport interface BrownConradyDistortionMapping {\n direction: \"undistorted-to-distorted\";\n sourceImagePointMm: LensFieldPointMm;\n mappedImagePointMm: LensFieldPointMm;\n sourceNormalizedRadius: number;\n /** Determinant of d(mapped)/d(source) at the source point (dimensionless area scale). */\n jacobianDeterminant: number;\n deltaMm: { x: number; y: number; distance: number };\n profileMinimumJacobianDeterminant: number;\n}\n\nexport interface InverseBrownConradyDistortionMapping {\n direction: \"distorted-to-undistorted\";\n distortedImagePointMm: LensFieldPointMm;\n sourceImagePointMm: LensFieldPointMm;\n sourceNormalizedRadius: number;\n jacobianDeterminantAtSource: number;\n newtonIterations: number;\n /** Forward-mapping residual of the solved source point, in mm. */\n residualMm: number;\n deltaMm: { x: number; y: number; distance: number };\n profileMinimumJacobianDeterminant: number;\n}\n\ninterface ValidatedBrownConradyProfile {\n radial: ValidatedRadialProfile;\n coefficients: BrownConradyDistortionCoefficients;\n minimumJacobianDeterminant: number;\n}\n\nconst VALIDATION_RINGS = 64;\nconst VALIDATION_AZIMUTHS = 256;\nconst MAXIMUM_NEWTON_ITERATIONS = 100;\n\nfunction requirePoint(name: string, point: unknown): LensFieldPointMm {\n if (typeof point !== \"object\" || point === null) {\n throw new InvalidConfigurationError(\n `${name} must be an object with finite numeric x and y coordinates.`\n );\n }\n const record = point as Record<string, unknown>;\n return {\n x: requireFinite(`${name}.x`, record.x),\n y: requireFinite(`${name}.y`, record.y)\n };\n}\n\n/** Forward map on normalized coordinates. */\nfunction forwardNormalized(\n x: number,\n y: number,\n c: BrownConradyDistortionCoefficients\n): { x: number; y: number } {\n const r2 = x * x + y * y;\n const radial = 1 + r2 * (c.k1 + r2 * (c.k2 + r2 * c.k3));\n return {\n x: x * radial + 2 * c.p1 * x * y + c.p2 * (r2 + 2 * x * x),\n y: y * radial + c.p1 * (r2 + 2 * y * y) + 2 * c.p2 * x * y\n };\n}\n\n/** Jacobian [[a, b], [c, d]] of the normalized forward map. */\nfunction jacobianNormalized(\n x: number,\n y: number,\n c: BrownConradyDistortionCoefficients\n): { a: number; b: number; c: number; d: number } {\n const r2 = x * x + y * y;\n const s = 1 + r2 * (c.k1 + r2 * (c.k2 + r2 * c.k3));\n const ds = c.k1 + r2 * (2 * c.k2 + 3 * c.k3 * r2);\n const off = 2 * x * y * ds + 2 * c.p1 * x + 2 * c.p2 * y;\n return {\n a: s + 2 * x * x * ds + 2 * c.p1 * y + 6 * c.p2 * x,\n b: off,\n c: off,\n d: s + 2 * y * y * ds + 6 * c.p1 * y + 2 * c.p2 * x\n };\n}\n\nfunction determinant(j: { a: number; b: number; c: number; d: number }): number {\n return j.a * j.d - j.b * j.c;\n}\n\nfunction validateProfile(\n profile: BrownConradyDistortionProfile\n): ValidatedBrownConradyProfile {\n if (typeof profile !== \"object\" || profile === null) {\n throw new InvalidConfigurationError(\"profile must be an object.\");\n }\n if (typeof profile.coefficients !== \"object\" || profile.coefficients === null) {\n throw new InvalidConfigurationError(\"profile.coefficients must be an object.\");\n }\n const coefficients: BrownConradyDistortionCoefficients = {\n k1: requireFinite(\"profile.coefficients.k1\", profile.coefficients.k1),\n k2: requireFinite(\"profile.coefficients.k2\", profile.coefficients.k2),\n k3: requireFinite(\"profile.coefficients.k3\", profile.coefficients.k3),\n p1: requireFinite(\"profile.coefficients.p1\", profile.coefficients.p1),\n p2: requireFinite(\"profile.coefficients.p2\", profile.coefficients.p2)\n };\n const radial = validateRadialDistortionProfile({\n normalizationRadiusMm: profile.normalizationRadiusMm,\n maximumNormalizedRadius: profile.maximumNormalizedRadius,\n coefficients: {\n k1: coefficients.k1,\n k2: coefficients.k2,\n k3: coefficients.k3\n }\n });\n\n const maximum = radial.maximumNormalizedRadius;\n let minimumJacobianDeterminant = Number.POSITIVE_INFINITY;\n for (let ring = 0; ring <= VALIDATION_RINGS; ring += 1) {\n const rho = (maximum * ring) / VALIDATION_RINGS;\n const azimuths = ring === 0 ? 1 : VALIDATION_AZIMUTHS;\n for (let index = 0; index < azimuths; index += 1) {\n const phi = (2 * Math.PI * index) / VALIDATION_AZIMUTHS;\n const det = determinant(\n jacobianNormalized(rho * Math.cos(phi), rho * Math.sin(phi), coefficients)\n );\n minimumJacobianDeterminant = Math.min(minimumJacobianDeterminant, det);\n }\n }\n if (!Number.isFinite(minimumJacobianDeterminant) || minimumJacobianDeterminant <= 0) {\n throw new InvalidScientificInputError(\n \"Brown-Conrady profile must keep a positive Jacobian determinant over maximumNormalizedRadius so the mapping stays locally invertible.\"\n );\n }\n\n // The mapped boundary must be star-shaped about the mapped centre (the origin): its polar angle\n // must increase strictly around the circle, so the boundary curve is simple.\n let previous: number | undefined;\n let accumulated = 0;\n for (let index = 0; index <= VALIDATION_AZIMUTHS; index += 1) {\n const phi = (2 * Math.PI * index) / VALIDATION_AZIMUTHS;\n const mapped = forwardNormalized(\n maximum * Math.cos(phi),\n maximum * Math.sin(phi),\n coefficients\n );\n const angle = Math.atan2(mapped.y, mapped.x);\n if (previous !== undefined) {\n let step = angle - previous;\n if (step <= -Math.PI) step += 2 * Math.PI;\n if (step > Math.PI) step -= 2 * Math.PI;\n if (!(step > 0)) {\n throw new InvalidScientificInputError(\n \"Brown-Conrady profile maps the envelope boundary to a curve that is not star-shaped about the optical axis; the inverse would not be single-valued.\"\n );\n }\n accumulated += step;\n }\n previous = angle;\n }\n if (Math.abs(accumulated - 2 * Math.PI) > 1e-9) {\n throw new InvalidScientificInputError(\n \"Brown-Conrady profile boundary must wind exactly once around the optical axis.\"\n );\n }\n\n return { radial, coefficients, minimumJacobianDeterminant };\n}\n\nfunction assumptions(): readonly string[] {\n return [\n \"Generic Brown-Conrady radial (k1, k2, k3) plus tangential/decentering (p1, p2) polynomial field mapping\",\n \"Coordinates are normalized by the caller-declared normalizationRadiusMm; the optical axis maps to itself\",\n \"Validity: monotonic radial part, positive Jacobian at a 64-ring x 256-azimuth polar sample and a strictly star-shaped mapped boundary; checked at samples, not proven between them\",\n \"Coefficients are generic caller inputs and do not represent a named lens unless separately calibrated with defensible provenance\",\n \"Thin-prism, anamorphic and higher-order decentering terms are not modeled\"\n ];\n}\n\n/** @internal Opaque validated profile for repeated in-package evaluation. */\nexport type ValidatedBrownConradyDistortionProfile = ValidatedBrownConradyProfile;\n\n/** @internal Validates one profile for repeated evaluation (geometric mapping, ray queries). */\nexport function validateBrownConradyDistortionProfile(\n profile: BrownConradyDistortionProfile\n): ValidatedBrownConradyDistortionProfile {\n return validateProfile(profile);\n}\n\n/** @internal Forward map in mm with its Jacobian d(distorted)/d(ideal), row-major. */\nexport function brownConradyForwardValue(\n profile: ValidatedBrownConradyDistortionProfile,\n point: LensFieldPointMm\n): { mappedImagePointMm: LensFieldPointMm; jacobian: readonly [number, number, number, number] } {\n const scale = profile.radial.normalizationRadiusMm;\n const x = point.x / scale;\n const y = point.y / scale;\n if (Math.hypot(x, y) > profile.radial.maximumNormalizedRadius) {\n throw new InvalidScientificInputError(\n \"Point lies outside the Brown-Conrady profile maximumNormalizedRadius.\"\n );\n }\n const mapped = forwardNormalized(x, y, profile.coefficients);\n const j = jacobianNormalized(x, y, profile.coefficients);\n return {\n mappedImagePointMm: { x: mapped.x * scale, y: mapped.y * scale },\n jacobian: [j.a, j.b, j.c, j.d]\n };\n}\n\n/** @internal Inverse map in mm (distorted to ideal). */\nexport function brownConradyInverseValue(\n profile: ValidatedBrownConradyDistortionProfile,\n point: LensFieldPointMm\n): LensFieldPointMm {\n const solved = solveInverseBrownConrady(profile, point);\n const scale = profile.radial.normalizationRadiusMm;\n return { x: solved.x * scale, y: solved.y * scale };\n}\n\nfunction solveInverseBrownConrady(\n profile: ValidatedBrownConradyProfile,\n point: LensFieldPointMm\n): { x: number; y: number; iterations: number; residual: number; sourceNormalizedRadius: number } {\n const scale = profile.radial.normalizationRadiusMm;\n const maximum = profile.radial.maximumNormalizedRadius;\n const tx = point.x / scale;\n const ty = point.y / scale;\n const tolerance = 1e-12 * Math.max(1, Math.hypot(tx, ty));\n\n // Starting point: the radial-only inverse if inside its mapped envelope, otherwise the target itself.\n let x = tx;\n let y = ty;\n if (Math.hypot(tx, ty) <= profile.radial.maximumMappedNormalizedRadius) {\n const seed = calculateInverseRadialSourcePointValue(\n point,\n profile.radial,\n \"distortedImagePointMm\"\n ).sourceImagePointMm;\n x = seed.x / scale;\n y = seed.y / scale;\n }\n\n let iterations = 0;\n let residual = Number.POSITIVE_INFINITY;\n for (; iterations < MAXIMUM_NEWTON_ITERATIONS; iterations += 1) {\n const f = forwardNormalized(x, y, profile.coefficients);\n const rx = f.x - tx;\n const ry = f.y - ty;\n residual = Math.hypot(rx, ry);\n if (residual <= tolerance) {\n break;\n }\n const j = jacobianNormalized(x, y, profile.coefficients);\n const det = determinant(j);\n if (!(Math.abs(det) > 0) || !Number.isFinite(det)) {\n break;\n }\n const stepX = (j.d * rx - j.b * ry) / det;\n const stepY = (-j.c * rx + j.a * ry) / det;\n // Damping: halve the step until the residual decreases (at most 30 halvings).\n let lambda = 1;\n let accepted = false;\n for (let halving = 0; halving < 30; halving += 1) {\n const nx = x - lambda * stepX;\n const ny = y - lambda * stepY;\n const g = forwardNormalized(nx, ny, profile.coefficients);\n if (Math.hypot(g.x - tx, g.y - ty) < residual) {\n x = nx;\n y = ny;\n accepted = true;\n break;\n }\n lambda /= 2;\n }\n if (!accepted) {\n break;\n }\n }\n\n const sourceNormalizedRadius = Math.hypot(x, y);\n if (\n !(residual <= tolerance) ||\n sourceNormalizedRadius > maximum * (1 + 1e-12)\n ) {\n throw new InvalidScientificInputError(\n \"distortedImagePointMm lies outside the mapped Brown-Conrady profile operating envelope.\"\n );\n }\n\n return { x, y, iterations, residual, sourceNormalizedRadius };\n}\n\n/** Applies the Brown-Conrady forward mapping to one ideal image-plane point. */\nexport function calculateBrownConradyDistortionMapping(\n input: CalculateBrownConradyDistortionMappingInput\n): CalculationResult<BrownConradyDistortionMapping> {\n requireInputKeys(input, \"calculateBrownConradyDistortionMapping\", [\"imagePointMm\", \"profile\"]);\n const point = requirePoint(\"imagePointMm\", input.imagePointMm);\n const profile = validateProfile(input.profile);\n const scale = profile.radial.normalizationRadiusMm;\n const x = point.x / scale;\n const y = point.y / scale;\n const sourceNormalizedRadius = Math.hypot(x, y);\n if (sourceNormalizedRadius > profile.radial.maximumNormalizedRadius) {\n throw new InvalidScientificInputError(\n \"imagePointMm lies outside the Brown-Conrady profile maximumNormalizedRadius.\"\n );\n }\n const mapped = forwardNormalized(x, y, profile.coefficients);\n const mappedImagePointMm = { x: mapped.x * scale, y: mapped.y * scale };\n const dx = mappedImagePointMm.x - point.x;\n const dy = mappedImagePointMm.y - point.y;\n return approximationResult(\n {\n direction: \"undistorted-to-distorted\",\n sourceImagePointMm: point,\n mappedImagePointMm,\n sourceNormalizedRadius,\n jacobianDeterminant: determinant(jacobianNormalized(x, y, profile.coefficients)),\n deltaMm: { x: dx, y: dy, distance: Math.hypot(dx, dy) },\n profileMinimumJacobianDeterminant: profile.minimumJacobianDeterminant\n },\n \"generic-brown-conrady-lens-distortion\",\n \"1.0.0\",\n assumptions()\n );\n}\n\n/**\n * Inverse-maps one distorted image-plane point to its ideal source point, for destination-to-source\n * resampling. Damped Newton iteration starts from the radial-only inverse. The solution must lie\n * inside the declared envelope and must reproduce the distorted point within a relative tolerance of\n * 1e-12.\n */\nexport function calculateInverseBrownConradyDistortionMapping(\n input: CalculateInverseBrownConradyDistortionMappingInput\n): CalculationResult<InverseBrownConradyDistortionMapping> {\n requireInputKeys(input, \"calculateInverseBrownConradyDistortionMapping\", [\"distortedImagePointMm\", \"profile\"]);\n const point = requirePoint(\"distortedImagePointMm\", input.distortedImagePointMm);\n const profile = validateProfile(input.profile);\n const solved = solveInverseBrownConrady(profile, point);\n const scale = profile.radial.normalizationRadiusMm;\n const { x, y, iterations, residual, sourceNormalizedRadius } = solved;\n const sourceImagePointMm = { x: x * scale, y: y * scale };\n const dx = sourceImagePointMm.x - point.x;\n const dy = sourceImagePointMm.y - point.y;\n return approximationResult(\n {\n direction: \"distorted-to-undistorted\",\n distortedImagePointMm: point,\n sourceImagePointMm,\n sourceNormalizedRadius,\n jacobianDeterminantAtSource: determinant(\n jacobianNormalized(x, y, profile.coefficients)\n ),\n newtonIterations: iterations,\n residualMm: residual * scale,\n deltaMm: { x: dx, y: dy, distance: Math.hypot(dx, dy) },\n profileMinimumJacobianDeterminant: profile.minimumJacobianDeterminant\n },\n \"generic-inverse-brown-conrady-lens-distortion\",\n \"1.0.0\",\n [\n ...assumptions(),\n `Inverse uses damped Newton iteration (at most ${MAXIMUM_NEWTON_ITERATIONS} steps) seeded by the radial-only inverse, accepted at a normalized residual of 1e-12`\n ]\n );\n}\n"]}
@@ -149,6 +149,7 @@ export interface LensComplexPupilPsfSampling {
149
149
  samplingFactorQX: number | null;
150
150
  samplingFactorQY: number | null;
151
151
  }
152
+ export declare function positiveModulo(value: number, size: number): number;
152
153
  /**
153
154
  * Evaluates a declared complex pupil with explicit amplitude, phase and sampling support. Returns the
154
155
  * normalized PSF shape, and the pupil throughput as a separate quantity.
@@ -17,75 +17,8 @@ import { InvalidConfigurationError } from "../core/configuration-error.js";
17
17
  import { parseEvidenceList } from "../core/evidence-provenance.js";
18
18
  import { InvalidScientificInputError } from "../core/validation.js";
19
19
  import { parseFocusPlane } from "./focus-state.js";
20
- import { requireInputKeys, rejectUnknownFields, rejectUnknownVariantFields, UNCERTAINTY_VARIANT_FIELDS } from "../core/record-validation.js";
20
+ import { requireInputKeys, rejectUnknownVariantFields, UNCERTAINTY_VARIANT_FIELDS, requireConfigRecord as requireRecord, requireTrimmedConfigString as requireNonEmptyString, requireConfigFinite as requireFinite, parseConfigScientificStatus as parseStatus, requireConfigNonNegativeSafeInteger as requireNonNegativeSafeInteger, requireConfigPositiveSafeInteger as requirePositiveSafeInteger, parseConfigLimitations as parseLimitations, requireConfigFiniteAboveZero as requirePositiveFinite, requireConfigUnitInterval as requireUnitInterval } from "../core/record-validation.js";
21
21
  export const LENS_COMPLEX_PUPIL_PROFILE_SCHEMA_VERSION = "0.1.0";
22
- function requireRecord(value, path, allowedKeys) {
23
- if (typeof value !== "object" ||
24
- value === null ||
25
- Array.isArray(value)) {
26
- throw new InvalidConfigurationError(path + " must be an object.");
27
- }
28
- if (allowedKeys !== null)
29
- rejectUnknownFields(value, allowedKeys, path);
30
- return value;
31
- }
32
- function requireNonEmptyString(value, path) {
33
- if (typeof value !== "string" ||
34
- value.trim().length === 0) {
35
- throw new InvalidConfigurationError(path +
36
- " must be a non-empty string.");
37
- }
38
- return value.trim();
39
- }
40
- function requireFinite(value, path) {
41
- if (typeof value !== "number" ||
42
- !Number.isFinite(value)) {
43
- throw new InvalidConfigurationError(path + " must be finite.");
44
- }
45
- return value;
46
- }
47
- function requirePositiveFinite(value, path) {
48
- const parsed = requireFinite(value, path);
49
- if (parsed <= 0) {
50
- throw new InvalidConfigurationError(path +
51
- " must be greater than zero.");
52
- }
53
- return parsed;
54
- }
55
- function requireUnitInterval(value, path) {
56
- const parsed = requireFinite(value, path);
57
- if (parsed < 0 ||
58
- parsed > 1) {
59
- throw new InvalidConfigurationError(path +
60
- " must lie from zero through one.");
61
- }
62
- return parsed;
63
- }
64
- function requirePositiveSafeInteger(value, path) {
65
- if (typeof value !== "number" ||
66
- !Number.isSafeInteger(value) ||
67
- value <= 0) {
68
- throw new InvalidConfigurationError(path +
69
- " must be a positive safe integer.");
70
- }
71
- return value;
72
- }
73
- function requireNonNegativeSafeInteger(value, path) {
74
- if (typeof value !== "number" ||
75
- !Number.isSafeInteger(value) ||
76
- value < 0) {
77
- throw new InvalidConfigurationError(path +
78
- " must be a non-negative safe integer.");
79
- }
80
- return value;
81
- }
82
- function parseStatus(value, path) {
83
- if (value !== "calibrated" &&
84
- value !== "approximation") {
85
- throw new InvalidConfigurationError(path + " is invalid.");
86
- }
87
- return value;
88
- }
89
22
  function parseUncertainty(value, path) {
90
23
  const record = requireRecord(value, path, null);
91
24
  rejectUnknownVariantFields(record, "kind", UNCERTAINTY_VARIANT_FIELDS, path);
@@ -111,21 +44,6 @@ function parseUncertainty(value, path) {
111
44
  }
112
45
  throw new InvalidConfigurationError(path + ".kind is invalid.");
113
46
  }
114
- function parseLimitations(value, path) {
115
- if (!Array.isArray(value)) {
116
- throw new InvalidConfigurationError(path + " must be an array.");
117
- }
118
- const parsed = value.map((entry, index) => requireNonEmptyString(entry, path +
119
- "[" +
120
- index +
121
- "]"));
122
- if (new Set(parsed).size !==
123
- parsed.length) {
124
- throw new InvalidConfigurationError(path +
125
- " must not contain duplicates.");
126
- }
127
- return parsed;
128
- }
129
47
  function parseGrid(value) {
130
48
  const record = requireRecord(value, "lensComplexPupil.grid", ["widthSamples", "heightSamples", "centerSampleX", "centerSampleY", "relativeAmplitude", "opticalPathDifferenceMicrometers", "pupilSamplePitchMmX", "pupilSamplePitchMmY"]);
131
49
  const widthSamples = requirePositiveSafeInteger(record.widthSamples, "lensComplexPupil.grid.widthSamples");
@@ -401,7 +319,7 @@ function twiddleTable(size) {
401
319
  }
402
320
  return { cos, sin };
403
321
  }
404
- function positiveModulo(value, size) {
322
+ export function positiveModulo(value, size) {
405
323
  const remainder = value % size;
406
324
  return remainder < 0 ? remainder + size : remainder;
407
325
  }
@@ -1 +1 @@
1
- {"version":3,"file":"complex-pupil-psf.js","sourceRoot":"","sources":["../../src/optics/complex-pupil-psf.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * PSF (point-spread function) from a declared complex pupil: amplitude and phase sampled on a grid.\n *\n * The profile parser validates untrusted input and returns the normalized typed contract. Unknown\n * enum values, missing required fields and incompatible scientific data are rejected.\n *\n * The complex pupil is evaluated by summing the declared amplitude and phase over a bounded, regular\n * pupil grid. The PSF shape is normalized separately from the pupil throughput. A single blur radius\n * cannot stand in for coherent phase, pupil energy, or the wavelength and field range where the\n * profile applies. Numeric profiles need provenance showing the data is owned or reusable.\n * @see docs/PSF_FOUNDATION.md for the equations, units, coordinate conventions, known blockers and\n * support limits.\n */\n\nimport {\n approximationResult,\n type CalculationResult\n} from \"../core/calculation-result.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport {\n parseEvidenceList,\n type EvidenceProvenance\n} from \"../core/evidence-provenance.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport {\n parseFocusPlane,\n type FocusPlane\n} from \"./focus-state.js\";\nimport type {\n LensPsfKernel,\n LensPsfScientificStatus,\n LensPsfUncertainty\n} from \"./lens-psf-profile.js\";\nimport { requireInputKeys, rejectUnknownFields, rejectUnknownVariantFields, UNCERTAINTY_VARIANT_FIELDS } from \"../core/record-validation.js\";\n\ntype UnknownRecord = Record<string, unknown>;\n\nexport const LENS_COMPLEX_PUPIL_PROFILE_SCHEMA_VERSION =\n \"0.1.0\" as const;\n\nexport interface LensComplexPupilGrid {\n widthSamples: number;\n heightSamples: number;\n pupilSamplePitchMmX: number;\n pupilSamplePitchMmY: number;\n centerSampleX: number;\n centerSampleY: number;\n relativeAmplitude:\n readonly number[];\n opticalPathDifferenceMicrometers:\n readonly number[];\n}\n\nexport interface LensComplexPupilProfile {\n schemaVersion:\n typeof LENS_COMPLEX_PUPIL_PROFILE_SCHEMA_VERSION;\n profileId: string;\n profileVersion: string;\n scientificStatus:\n LensPsfScientificStatus;\n opticalDomain:\n \"lens-primary-optical-path-only\";\n representation:\n \"complex-pupil-amplitude-plus-opd\";\n pupilCoordinateSystem:\n \"pupil-plane-metric-aligned-to-image-plane\";\n imageFieldAxes:\n \"+X right, +Y up\";\n amplitudeMeaning:\n \"relative-complex-pupil-amplitude-shape\";\n wavefrontMeaning:\n \"optical-path-difference-micrometers\";\n throughputOwnership:\n \"separate-relative-pupil-throughput-factor\";\n kernelEnergyNormalization:\n \"unit-energy-shape\";\n propagationModel:\n \"scalar-fraunhofer-discrete-reference\";\n context: {\n focalLengthMm: number;\n focus: FocusPlane;\n apertureFNumber: number;\n fieldPointMm: {\n x: number;\n y: number;\n };\n wavelengthNm: number;\n signedDefocusImagePlaneMicrometers:\n number;\n };\n responseIncludes: {\n diffraction: true;\n aberration: boolean;\n defocus: boolean;\n pupilClippingShape:\n boolean;\n };\n relativePupilThroughputFactor:\n number;\n grid: LensComplexPupilGrid;\n sensorOpticalStackIncluded:\n false;\n sensorSamplingIncluded:\n false;\n reconstructionIncluded:\n false;\n strayLightIncluded: false;\n evidence:\n readonly EvidenceProvenance[];\n uncertainty:\n LensPsfUncertainty;\n limitations: readonly string[];\n}\n\nexport interface CalculateLensComplexPupilPsfInput {\n profile:\n LensComplexPupilProfile;\n /** Physical propagation distance from pupil to image, in mm. If omitted, the\n * nominal focal-plane reference is used. At finite focus the caller must\n * resolve the supported principal-plane geometry; profile metadata does not. */\n propagationDistanceMm?: number;\n}\n\nexport interface LensComplexPupilPsf {\n propagationDistanceMm: number;\n propagationDistanceSource: \"explicit\" | \"nominal-focal-plane-reference\";\n profileId: string;\n profileVersion: string;\n scientificStatus:\n LensPsfScientificStatus;\n context:\n LensComplexPupilProfile[\"context\"];\n kernel: LensPsfKernel;\n /** Nyquist sampling diagnostics and the applied zero padding. */\n sampling: LensComplexPupilPsfSampling;\n relativePupilThroughputFactor:\n number;\n throughputOwnership:\n \"separate-relative-pupil-throughput-factor\";\n diffractionAndAberrationJointlyEvaluated:\n true;\n pupilClippingShapeIncluded:\n boolean;\n pupilClippingThroughputAppliedToKernel:\n false;\n scalarFraunhoferReference:\n true;\n full2dOrientationPreserved:\n true;\n geometricDistortionModified:\n false;\n lateralChromaticPositionShiftApplied:\n false;\n sensorOpticalStackIncluded:\n false;\n sensorSamplingIncluded: false;\n reconstructionIncluded: false;\n strayLightIncluded: false;\n scalarSharpnessScoreProduced:\n false;\n componentEvidence: {\n pupilProfile:\n readonly EvidenceProvenance[];\n };\n uncertainty:\n LensPsfUncertainty;\n}\n\nfunction requireRecord(\n value: unknown,\n path: string,\n allowedKeys: readonly string[] | null\n): UnknownRecord {\n if (\n typeof value !== \"object\" ||\n value === null ||\n Array.isArray(value)\n ) {\n throw new InvalidConfigurationError(\n path + \" must be an object.\"\n );\n }\n if (allowedKeys !== null) rejectUnknownFields(value, allowedKeys, path);\n return value as UnknownRecord;\n}\n\nfunction requireNonEmptyString(\n value: unknown,\n path: string\n): string {\n if (\n typeof value !== \"string\" ||\n value.trim().length === 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must be a non-empty string.\"\n );\n }\n return value.trim();\n}\n\nfunction requireFinite(\n value: unknown,\n path: string\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value)\n ) {\n throw new InvalidConfigurationError(\n path + \" must be finite.\"\n );\n }\n return value;\n}\n\nfunction requirePositiveFinite(\n value: unknown,\n path: string\n): number {\n const parsed =\n requireFinite(value, path);\n if (parsed <= 0) {\n throw new InvalidConfigurationError(\n path +\n \" must be greater than zero.\"\n );\n }\n return parsed;\n}\n\nfunction requireUnitInterval(\n value: unknown,\n path: string\n): number {\n const parsed =\n requireFinite(value, path);\n if (\n parsed < 0 ||\n parsed > 1\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must lie from zero through one.\"\n );\n }\n return parsed;\n}\n\nfunction requirePositiveSafeInteger(\n value: unknown,\n path: string\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isSafeInteger(value) ||\n value <= 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must be a positive safe integer.\"\n );\n }\n return value;\n}\n\nfunction requireNonNegativeSafeInteger(\n value: unknown,\n path: string\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isSafeInteger(value) ||\n value < 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must be a non-negative safe integer.\"\n );\n }\n return value;\n}\n\nfunction parseStatus(\n value: unknown,\n path: string\n): LensPsfScientificStatus {\n if (\n value !== \"calibrated\" &&\n value !== \"approximation\"\n ) {\n throw new InvalidConfigurationError(\n path + \" is invalid.\"\n );\n }\n return value;\n}\n\nfunction parseUncertainty(\n value: unknown,\n path: string\n): LensPsfUncertainty {\n const record =\n requireRecord(value, path, null);\n rejectUnknownVariantFields(record, \"kind\", UNCERTAINTY_VARIANT_FIELDS, path);\n if (record.kind === \"relative\") {\n const fraction =\n requireFinite(\n record.fraction,\n path + \".fraction\"\n );\n if (fraction < 0) {\n throw new InvalidConfigurationError(\n path +\n \".fraction must be nonnegative.\"\n );\n }\n return {\n kind: \"relative\",\n fraction,\n basis:\n requireNonEmptyString(\n record.basis,\n path + \".basis\"\n )\n };\n }\n if (\n record.kind ===\n \"not-quantified\"\n ) {\n return {\n kind: \"not-quantified\",\n limitation:\n requireNonEmptyString(\n record.limitation,\n path +\n \".limitation\"\n )\n };\n }\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n}\n\nfunction parseLimitations(\n value: unknown,\n path: string\n): readonly string[] {\n if (!Array.isArray(value)) {\n throw new InvalidConfigurationError(\n path + \" must be an array.\"\n );\n }\n const parsed =\n value.map(\n (entry, index) =>\n requireNonEmptyString(\n entry,\n path +\n \"[\" +\n index +\n \"]\"\n )\n );\n if (\n new Set(parsed).size !==\n parsed.length\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must not contain duplicates.\"\n );\n }\n return parsed;\n}\n\nfunction parseGrid(\n value: unknown\n): LensComplexPupilGrid {\n const record =\n requireRecord(\n value,\n \"lensComplexPupil.grid\", [\"widthSamples\", \"heightSamples\", \"centerSampleX\", \"centerSampleY\", \"relativeAmplitude\", \"opticalPathDifferenceMicrometers\", \"pupilSamplePitchMmX\", \"pupilSamplePitchMmY\"]\n );\n const widthSamples =\n requirePositiveSafeInteger(\n record.widthSamples,\n \"lensComplexPupil.grid.widthSamples\"\n );\n const heightSamples =\n requirePositiveSafeInteger(\n record.heightSamples,\n \"lensComplexPupil.grid.heightSamples\"\n );\n const total =\n widthSamples *\n heightSamples;\n if (\n !Number.isSafeInteger(total) ||\n total > 4096\n ) {\n throw new InvalidConfigurationError(\n \"lensComplexPupil grid must contain at most 4096 samples.\"\n );\n }\n const centerSampleX =\n requireNonNegativeSafeInteger(\n record.centerSampleX,\n \"lensComplexPupil.grid.centerSampleX\"\n );\n const centerSampleY =\n requireNonNegativeSafeInteger(\n record.centerSampleY,\n \"lensComplexPupil.grid.centerSampleY\"\n );\n if (\n centerSampleX >=\n widthSamples ||\n centerSampleY >=\n heightSamples\n ) {\n throw new InvalidConfigurationError(\n \"lensComplexPupil grid center must lie within the pupil array.\"\n );\n }\n if (\n !Array.isArray(\n record.relativeAmplitude\n ) ||\n record.relativeAmplitude\n .length !== total\n ) {\n throw new InvalidConfigurationError(\n \"lensComplexPupil.grid.relativeAmplitude length must equal widthSamples × heightSamples.\"\n );\n }\n if (\n !Array.isArray(\n record\n .opticalPathDifferenceMicrometers\n ) ||\n record\n .opticalPathDifferenceMicrometers\n .length !== total\n ) {\n throw new InvalidConfigurationError(\n \"lensComplexPupil.grid.opticalPathDifferenceMicrometers length must equal widthSamples × heightSamples.\"\n );\n }\n\n const relativeAmplitude =\n record.relativeAmplitude.map(\n (entry, index) =>\n requireUnitInterval(\n entry,\n \"lensComplexPupil.grid.relativeAmplitude[\" +\n index +\n \"]\"\n )\n );\n if (\n !relativeAmplitude.some(\n (value) =>\n value > 0\n )\n ) {\n throw new InvalidConfigurationError(\n \"lensComplexPupil must contain at least one non-zero pupil-amplitude sample.\"\n );\n }\n const opd =\n record\n .opticalPathDifferenceMicrometers\n .map(\n (entry, index) =>\n requireFinite(\n entry,\n \"lensComplexPupil.grid.opticalPathDifferenceMicrometers[\" +\n index +\n \"]\"\n )\n );\n\n return {\n widthSamples,\n heightSamples,\n pupilSamplePitchMmX:\n requirePositiveFinite(\n record\n .pupilSamplePitchMmX,\n \"lensComplexPupil.grid.pupilSamplePitchMmX\"\n ),\n pupilSamplePitchMmY:\n requirePositiveFinite(\n record\n .pupilSamplePitchMmY,\n \"lensComplexPupil.grid.pupilSamplePitchMmY\"\n ),\n centerSampleX,\n centerSampleY,\n relativeAmplitude,\n opticalPathDifferenceMicrometers:\n opd\n };\n}\n\n/**\n * Validates an untrusted declaration and returns the normalized typed contract. Unknown enum values,\n * missing required fields and incompatible scientific data are rejected here.\n *\n * The complex pupil is evaluated by summing the declared amplitude and phase over a bounded, regular\n * pupil grid. The PSF shape is normalized separately from the pupil throughput. A single blur radius\n * cannot stand in for coherent phase, pupil energy, or the wavelength and field range where the\n * profile applies. Numeric profiles need provenance showing the data is owned or reusable.\n * @param value - unknown. Untrusted input; TypeScript types alone are not validation.\n * @returns LensComplexPupilProfile. The result states its shape and scientific status; a successful call does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the root export and exact type graph.\n */\nexport function parseLensComplexPupilProfile(\n value: unknown\n): LensComplexPupilProfile {\n const record =\n requireRecord(\n value,\n \"lensComplexPupil\", [\"schemaVersion\", \"opticalDomain\", \"representation\", \"pupilCoordinateSystem\", \"imageFieldAxes\", \"amplitudeMeaning\", \"wavefrontMeaning\", \"throughputOwnership\", \"kernelEnergyNormalization\", \"propagationModel\", \"sensorOpticalStackIncluded\", \"sensorSamplingIncluded\", \"reconstructionIncluded\", \"strayLightIncluded\", \"scientificStatus\", \"uncertainty\", \"context\", \"responseIncludes\", \"profileId\", \"profileVersion\", \"relativePupilThroughputFactor\", \"grid\", \"evidence\", \"limitations\"]\n );\n if (\n record.schemaVersion !==\n LENS_COMPLEX_PUPIL_PROFILE_SCHEMA_VERSION\n ) {\n throw new InvalidConfigurationError(\n 'lensComplexPupil.schemaVersion must be \"' +\n LENS_COMPLEX_PUPIL_PROFILE_SCHEMA_VERSION +\n '\".'\n );\n }\n if (\n record.opticalDomain !==\n \"lens-primary-optical-path-only\" ||\n record.representation !==\n \"complex-pupil-amplitude-plus-opd\" ||\n record.pupilCoordinateSystem !==\n \"pupil-plane-metric-aligned-to-image-plane\" ||\n record.imageFieldAxes !==\n \"+X right, +Y up\" ||\n record.amplitudeMeaning !==\n \"relative-complex-pupil-amplitude-shape\" ||\n record.wavefrontMeaning !==\n \"optical-path-difference-micrometers\" ||\n record.throughputOwnership !==\n \"separate-relative-pupil-throughput-factor\" ||\n record.kernelEnergyNormalization !==\n \"unit-energy-shape\" ||\n record.propagationModel !==\n \"scalar-fraunhofer-discrete-reference\"\n ) {\n throw new InvalidConfigurationError(\n \"lensComplexPupil representation/coordinate/energy semantics are invalid.\"\n );\n }\n if (\n record.sensorOpticalStackIncluded !==\n false ||\n record.sensorSamplingIncluded !==\n false ||\n record.reconstructionIncluded !==\n false ||\n record.strayLightIncluded !==\n false\n ) {\n throw new InvalidConfigurationError(\n \"V1 complex pupil profiles must exclude sensor/reconstruction/stray-light effects.\"\n );\n }\n const status =\n parseStatus(\n record.scientificStatus,\n \"lensComplexPupil.scientificStatus\"\n );\n const uncertainty =\n parseUncertainty(\n record.uncertainty,\n \"lensComplexPupil.uncertainty\"\n );\n if (\n status === \"calibrated\" &&\n uncertainty.kind ===\n \"not-quantified\"\n ) {\n throw new InvalidConfigurationError(\n \"Calibrated complex-pupil profiles must declare quantified relative uncertainty.\"\n );\n }\n const context =\n requireRecord(\n record.context,\n \"lensComplexPupil.context\", [\"fieldPointMm\", \"focalLengthMm\", \"focus\", \"apertureFNumber\", \"wavelengthNm\", \"signedDefocusImagePlaneMicrometers\"]\n );\n const field =\n requireRecord(\n context.fieldPointMm,\n \"lensComplexPupil.context.fieldPointMm\", [\"x\", \"y\"]\n );\n const response =\n requireRecord(\n record.responseIncludes,\n \"lensComplexPupil.responseIncludes\", [\"diffraction\", \"aberration\", \"defocus\", \"pupilClippingShape\"]\n );\n if (\n response.diffraction !==\n true ||\n typeof response.aberration !==\n \"boolean\" ||\n typeof response.defocus !==\n \"boolean\" ||\n typeof response.pupilClippingShape !==\n \"boolean\"\n ) {\n throw new InvalidConfigurationError(\n \"lensComplexPupil.responseIncludes is invalid; diffraction must be included in this pupil propagation path.\"\n );\n }\n\n return {\n schemaVersion:\n LENS_COMPLEX_PUPIL_PROFILE_SCHEMA_VERSION,\n profileId:\n requireNonEmptyString(\n record.profileId,\n \"lensComplexPupil.profileId\"\n ),\n profileVersion:\n requireNonEmptyString(\n record.profileVersion,\n \"lensComplexPupil.profileVersion\"\n ),\n scientificStatus:\n status,\n opticalDomain:\n \"lens-primary-optical-path-only\",\n representation:\n \"complex-pupil-amplitude-plus-opd\",\n pupilCoordinateSystem:\n \"pupil-plane-metric-aligned-to-image-plane\",\n imageFieldAxes:\n \"+X right, +Y up\",\n amplitudeMeaning:\n \"relative-complex-pupil-amplitude-shape\",\n wavefrontMeaning:\n \"optical-path-difference-micrometers\",\n throughputOwnership:\n \"separate-relative-pupil-throughput-factor\",\n kernelEnergyNormalization:\n \"unit-energy-shape\",\n propagationModel:\n \"scalar-fraunhofer-discrete-reference\",\n context: {\n focalLengthMm:\n requirePositiveFinite(\n context.focalLengthMm,\n \"lensComplexPupil.context.focalLengthMm\"\n ),\n focus:\n parseFocusPlane(\n context.focus\n ),\n apertureFNumber:\n requirePositiveFinite(\n context.apertureFNumber,\n \"lensComplexPupil.context.apertureFNumber\"\n ),\n fieldPointMm: {\n x:\n requireFinite(\n field.x,\n \"lensComplexPupil.context.fieldPointMm.x\"\n ),\n y:\n requireFinite(\n field.y,\n \"lensComplexPupil.context.fieldPointMm.y\"\n )\n },\n wavelengthNm:\n requirePositiveFinite(\n context.wavelengthNm,\n \"lensComplexPupil.context.wavelengthNm\"\n ),\n signedDefocusImagePlaneMicrometers:\n requireFinite(\n context\n .signedDefocusImagePlaneMicrometers,\n \"lensComplexPupil.context.signedDefocusImagePlaneMicrometers\"\n )\n },\n responseIncludes: {\n diffraction: true,\n aberration:\n response.aberration as boolean,\n defocus:\n response.defocus as boolean,\n pupilClippingShape:\n response\n .pupilClippingShape as boolean\n },\n relativePupilThroughputFactor:\n requireUnitInterval(\n record\n .relativePupilThroughputFactor,\n \"lensComplexPupil.relativePupilThroughputFactor\"\n ),\n grid:\n parseGrid(record.grid),\n sensorOpticalStackIncluded:\n false,\n sensorSamplingIncluded:\n false,\n reconstructionIncluded:\n false,\n strayLightIncluded:\n false,\n evidence:\n parseEvidenceList(\n record.evidence,\n \"lensComplexPupil.evidence\"\n ),\n uncertainty,\n limitations:\n parseLimitations(\n record.limitations,\n \"lensComplexPupil.limitations\"\n )\n };\n}\n\ninterface ComplexValue {\n re: number;\n im: number;\n}\n\nfunction pupilComplexValue(\n amplitude: number,\n opdMicrometers: number,\n wavelengthMicrometers:\n number\n): ComplexValue {\n const phase =\n 2 *\n Math.PI *\n opdMicrometers /\n wavelengthMicrometers;\n return {\n re:\n amplitude *\n Math.cos(phase),\n im:\n amplitude *\n Math.sin(phase)\n };\n}\n\nexport interface LensComplexPupilPsfSampling {\n criterion: \"discrete-intensity-alias-free-goodman-q-above-2\";\n /** Number of pupil samples spanned by non-zero amplitude, per axis. */\n pupilSupportSamplesX: number;\n pupilSupportSamplesY: number;\n /**\n * Sampled pupil diameter D = (support samples - 1) x pupil pitch: the\n * centre-to-centre span of the outermost non-zero samples, in millimetres.\n */\n pupilSupportDiameterMmX: number;\n pupilSupportDiameterMmY: number;\n /**\n * Widest support allowed by the declared f-number at the resolved propagation distance:\n * propagationDistanceMm / apertureFNumber, in millimetres. For the nominal focal-plane reference\n * this is focalLengthMm / apertureFNumber.\n */\n declaredPupilDiameterMm: number;\n /** Declared pupil grid size before zero padding. */\n pupilGridWidthSamples: number;\n pupilGridHeightSamples: number;\n /** DFT size after zero padding; equals the output kernel size. */\n transformWidthSamples: number;\n transformHeightSamples: number;\n zeroPaddingApplied: boolean;\n /**\n * Achieved Goodman sampling factor Q = lambda*(z/D)/imagePitch =\n * transform samples / (support samples - 1). Always greater than 2. Null\n * when the support is a single sample on that axis (no finite diameter).\n */\n samplingFactorQX: number | null;\n samplingFactorQY: number | null;\n}\n\ninterface PupilSamplingPlan {\n sampling: LensComplexPupilPsfSampling;\n outputCenterX: number;\n outputCenterY: number;\n}\n\nfunction supportSpan(\n grid: LensComplexPupilGrid,\n axis: \"x\" | \"y\"\n): number {\n let minimum = Number.POSITIVE_INFINITY;\n let maximum = Number.NEGATIVE_INFINITY;\n grid.relativeAmplitude.forEach((amplitude, index) => {\n if (amplitude > 0) {\n const coordinate =\n axis === \"x\"\n ? index % grid.widthSamples\n : Math.floor(index / grid.widthSamples);\n minimum = Math.min(minimum, coordinate);\n maximum = Math.max(maximum, coordinate);\n }\n });\n return maximum - minimum + 1;\n}\n\n/**\n * Sampling guard for the discrete Fraunhofer reference (Ban et al.,\n * arXiv:2511.06936, eqs. 6-9, free: N*dp = lambda*f/dc, Q = lambda*F/dc and\n * Q >= 2. Also see: Goodman, Introduction to Fourier Optics, sampling of\n * DFT/FFT Fraunhofer propagation).\n *\n * A DFT (discrete Fourier transform) of size M over pupil pitch dp gives an\n * image-plane pitch of lambda*z/(M*dp).\n *\n * The intensity PSF is the transform of the pupil autocorrelation. That\n * autocorrelation is twice as wide as the pupil. So Nyquist sampling of the\n * intensity needs Q = lambda*(z/D)/pitch = M*dp/D >= 2.\n *\n * For a pupil spanning S samples, the discrete autocorrelation has 2S-1 lags.\n * So M >= 2S-1 is the exact condition for no circular wrap-around, and it\n * implies Q = M/(S-1) > 2. The declared grid is zero padded to that size.\n *\n * The non-zero support must also fit inside the declared f/N cone. Its\n * diameter D may not exceed z/N for the resolved propagation distance z; that\n * is, the image-side cone D/z may not be wider than 1/N. With the nominal\n * focal-plane reference (z = f) this is the entrance-aperture diameter f/N. An\n * exit pupil declared at its own distance z uses that distance\n * (docs/PSF_FOUNDATION.md).\n */\nfunction planPupilSampling(\n profile: LensComplexPupilProfile,\n propagationDistanceMm: number\n): PupilSamplingPlan {\n const grid = profile.grid;\n const supportX = supportSpan(grid, \"x\");\n const supportY = supportSpan(grid, \"y\");\n const diameterX = (supportX - 1) * grid.pupilSamplePitchMmX;\n const diameterY = (supportY - 1) * grid.pupilSamplePitchMmY;\n const declaredDiameter =\n propagationDistanceMm / profile.context.apertureFNumber;\n // Relative allowance for floating-point rounding only.\n const limit = declaredDiameter * (1 + 1e-9);\n if (diameterX > limit || diameterY > limit) {\n throw new InvalidScientificInputError(\n \"Complex-pupil amplitude support spans \" +\n diameterX.toPrecision(6) +\n \" x \" +\n diameterY.toPrecision(6) +\n \" mm between outermost non-zero samples, wider than the declared f/N cone diameter \" +\n declaredDiameter.toPrecision(6) +\n \" mm (propagationDistanceMm / apertureFNumber).\"\n );\n }\n const transformWidth = Math.max(grid.widthSamples, 2 * supportX - 1);\n const transformHeight = Math.max(grid.heightSamples, 2 * supportY - 1);\n return {\n sampling: {\n criterion: \"discrete-intensity-alias-free-goodman-q-above-2\",\n pupilSupportSamplesX: supportX,\n pupilSupportSamplesY: supportY,\n pupilSupportDiameterMmX: diameterX,\n pupilSupportDiameterMmY: diameterY,\n declaredPupilDiameterMm: declaredDiameter,\n pupilGridWidthSamples: grid.widthSamples,\n pupilGridHeightSamples: grid.heightSamples,\n transformWidthSamples: transformWidth,\n transformHeightSamples: transformHeight,\n zeroPaddingApplied:\n transformWidth !== grid.widthSamples ||\n transformHeight !== grid.heightSamples,\n samplingFactorQX:\n supportX > 1 ? transformWidth / (supportX - 1) : null,\n samplingFactorQY:\n supportY > 1 ? transformHeight / (supportY - 1) : null\n },\n // Symmetric padding keeps zero frequency at the declared centre, shifted\n // by the leading padding.\n outputCenterX:\n grid.centerSampleX +\n Math.floor((transformWidth - grid.widthSamples) / 2),\n outputCenterY:\n grid.centerSampleY +\n Math.floor((transformHeight - grid.heightSamples) / 2)\n };\n}\n\nfunction twiddleTable(size: number): { cos: number[]; sin: number[] } {\n const cos: number[] = [];\n const sin: number[] = [];\n for (let index = 0; index < size; index += 1) {\n const angle = (-2 * Math.PI * index) / size;\n cos.push(Math.cos(angle));\n sin.push(Math.sin(angle));\n }\n return { cos, sin };\n}\n\nfunction positiveModulo(value: number, size: number): number {\n const remainder = value % size;\n return remainder < 0 ? remainder + size : remainder;\n}\n\nfunction calculateDiscreteFraunhoferKernel(\n profile:\n LensComplexPupilProfile,\n propagationDistanceMm: number,\n plan: PupilSamplingPlan\n): LensPsfKernel {\n const grid = profile.grid;\n const width = grid.widthSamples;\n const height = grid.heightSamples;\n const outWidth = plan.sampling.transformWidthSamples;\n const outHeight = plan.sampling.transformHeightSamples;\n const wavelengthMicrometers = profile.context.wavelengthNm / 1000;\n const wavelengthMm = profile.context.wavelengthNm / 1_000_000;\n const pupil: ComplexValue[] =\n grid.relativeAmplitude.map(\n (amplitude, index) =>\n pupilComplexValue(\n amplitude,\n grid.opticalPathDifferenceMicrometers[index]!,\n wavelengthMicrometers\n )\n );\n\n // Separable zero-padded DFT: pupil rows to image kx first, then columns.\n // Padding samples are zero, so only declared pupil samples are summed.\n const twiddleX = twiddleTable(outWidth);\n const twiddleY = twiddleTable(outHeight);\n const rowRe = new Float64Array(height * outWidth);\n const rowIm = new Float64Array(height * outWidth);\n for (let y = 0; y < height; y += 1) {\n for (let outX = 0; outX < outWidth; outX += 1) {\n const kx = outX - plan.outputCenterX;\n let re = 0;\n let im = 0;\n for (let x = 0; x < width; x += 1) {\n const source = pupil[y * width + x]!;\n const t = positiveModulo(kx * (x - grid.centerSampleX), outWidth);\n const cos = twiddleX.cos[t]!;\n const sin = twiddleX.sin[t]!;\n re += source.re * cos - source.im * sin;\n im += source.re * sin + source.im * cos;\n }\n rowRe[y * outWidth + outX] = re;\n rowIm[y * outWidth + outX] = im;\n }\n }\n\n const intensity = new Array<number>(outWidth * outHeight).fill(0);\n for (let outY = 0; outY < outHeight; outY += 1) {\n const ky = outY - plan.outputCenterY;\n for (let outX = 0; outX < outWidth; outX += 1) {\n let re = 0;\n let im = 0;\n for (let y = 0; y < height; y += 1) {\n const sourceRe = rowRe[y * outWidth + outX]!;\n const sourceIm = rowIm[y * outWidth + outX]!;\n const t = positiveModulo(ky * (y - grid.centerSampleY), outHeight);\n const cos = twiddleY.cos[t]!;\n const sin = twiddleY.sin[t]!;\n re += sourceRe * cos - sourceIm * sin;\n im += sourceRe * sin + sourceIm * cos;\n }\n intensity[outY * outWidth + outX] = re * re + im * im;\n }\n }\n\n const sum =\n intensity.reduce(\n (acc, value) =>\n acc + value,\n 0\n );\n if (\n !Number.isFinite(sum) ||\n sum <= 0\n ) {\n throw new InvalidScientificInputError(\n \"Complex-pupil propagation must produce finite positive PSF energy.\"\n );\n }\n const normalized =\n intensity.map(\n (value) =>\n value / sum\n );\n\n const samplePitchMmX =\n wavelengthMm * propagationDistanceMm /\n (outWidth * grid.pupilSamplePitchMmX);\n const samplePitchMmY =\n wavelengthMm * propagationDistanceMm /\n (outHeight * grid.pupilSamplePitchMmY);\n\n if (\n !Number.isFinite(\n samplePitchMmX\n ) ||\n !Number.isFinite(\n samplePitchMmY\n ) ||\n samplePitchMmX <= 0 ||\n samplePitchMmY <= 0\n ) {\n throw new InvalidScientificInputError(\n \"Complex-pupil PSF sample pitch must remain finite and positive.\"\n );\n }\n\n return {\n widthSamples: outWidth,\n heightSamples: outHeight,\n samplePitchMicrometersX:\n samplePitchMmX *\n 1000,\n samplePitchMicrometersY:\n samplePitchMmY *\n 1000,\n centerSampleX: plan.outputCenterX,\n centerSampleY: plan.outputCenterY,\n normalizedIntensity:\n normalized\n };\n}\n\n/**\n * Evaluates a declared complex pupil with explicit amplitude, phase and sampling support. Returns the\n * normalized PSF shape, and the pupil throughput as a separate quantity.\n *\n * The complex pupil is evaluated by summing the declared amplitude and phase over a bounded, regular\n * pupil grid. The PSF shape is normalized separately from the pupil throughput. A single blur radius\n * cannot stand in for coherent phase, pupil energy, or the wavelength and field range where the\n * profile applies. Numeric profiles need provenance showing the data is owned or reusable.\n * @param input - CalculateLensComplexPupilPsfInput. See that type for coordinates, units and profile binding.\n * @returns CalculationResult<LensComplexPupilPsf>. The result states its shape and scientific status; a successful call does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the root export and exact type graph.\n */\nexport function calculateLensComplexPupilPsf(\n input:\n CalculateLensComplexPupilPsfInput\n): CalculationResult<LensComplexPupilPsf> {\n requireInputKeys(input, \"calculateLensComplexPupilPsf\", [\"profile\", \"propagationDistanceMm\"]);\n const profile =\n parseLensComplexPupilProfile(\n input.profile\n );\n const propagationDistanceMm = input.propagationDistanceMm === undefined ? profile.context.focalLengthMm : input.propagationDistanceMm;\n requirePositiveFinite(propagationDistanceMm, \"propagationDistanceMm\");\n const plan = planPupilSampling(profile, propagationDistanceMm);\n const kernel =\n calculateDiscreteFraunhoferKernel(\n profile,\n propagationDistanceMm,\n plan\n );\n\n return approximationResult(\n {\n propagationDistanceMm,\n propagationDistanceSource: input.propagationDistanceMm === undefined ? \"nominal-focal-plane-reference\" : \"explicit\",\n profileId:\n profile.profileId,\n profileVersion:\n profile.profileVersion,\n scientificStatus:\n profile.scientificStatus,\n context: {\n ...profile.context,\n focus: {\n ...profile.context.focus\n },\n fieldPointMm: {\n ...profile.context\n .fieldPointMm\n }\n },\n kernel,\n sampling: plan.sampling,\n relativePupilThroughputFactor:\n profile\n .relativePupilThroughputFactor,\n throughputOwnership:\n \"separate-relative-pupil-throughput-factor\",\n diffractionAndAberrationJointlyEvaluated:\n true,\n pupilClippingShapeIncluded:\n profile\n .responseIncludes\n .pupilClippingShape,\n pupilClippingThroughputAppliedToKernel:\n false,\n scalarFraunhoferReference:\n true,\n full2dOrientationPreserved:\n true,\n geometricDistortionModified:\n false,\n lateralChromaticPositionShiftApplied:\n false,\n sensorOpticalStackIncluded:\n false,\n sensorSamplingIncluded:\n false,\n reconstructionIncluded:\n false,\n strayLightIncluded:\n false,\n scalarSharpnessScoreProduced:\n false,\n componentEvidence: {\n pupilProfile:\n profile.evidence\n },\n uncertainty:\n profile.uncertainty\n },\n \"lens-complex-pupil-fraunhofer-psf\",\n \"2.0.0\",\n [\n \"The reference evaluator performs deterministic scalar Fraunhofer propagation of one explicit complex pupil amplitude plus optical-path-difference grid.\",\n \"The pupil is zero padded so the DFT spans at least 2S-1 samples for a non-zero support of S samples per axis: the discrete intensity PSF then has no wrap-around aliasing and Goodman's sampling factor Q = lambda*N/pitch exceeds 2. Pupil support wider than the declared f/N aperture is rejected.\",\n \"Physical sample pitch uses the explicit propagation distance when supplied; omission preserves the nominal focal-plane reference. Finite focus metadata does not resolve the pupil-to-image geometry automatically.\",\n \"Diffraction and aberration phase are evaluated together in the same pupil propagation; callers must not stack an independent diffraction blur over this result.\",\n \"The output PSF is unit-energy normalized. The explicit relativePupilThroughputFactor is not multiplied into the kernel and remains owned by the separate optical-throughput path.\",\n \"Pupil amplitude shape can represent mechanical clipping/cat-eye geometry without silently encoding unknown transmission loss.\",\n \"The pupil and image-plane axes preserve full 2D orientation; no radial or sagittal/tangential averaging is imposed.\",\n \"This scalar Fraunhofer grid is a bounded reference approximation, not a full vector electromagnetic, polarization, stray-light or sensor-system model.\",\n \"Sensor OLPF, microlens, CFA, sampling and reconstruction are downstream and excluded.\"\n ]\n );\n}\n"]}
1
+ {"version":3,"file":"complex-pupil-psf.js","sourceRoot":"","sources":["../../src/optics/complex-pupil-psf.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * PSF (point-spread function) from a declared complex pupil: amplitude and phase sampled on a grid.\n *\n * The profile parser validates untrusted input and returns the normalized typed contract. Unknown\n * enum values, missing required fields and incompatible scientific data are rejected.\n *\n * The complex pupil is evaluated by summing the declared amplitude and phase over a bounded, regular\n * pupil grid. The PSF shape is normalized separately from the pupil throughput. A single blur radius\n * cannot stand in for coherent phase, pupil energy, or the wavelength and field range where the\n * profile applies. Numeric profiles need provenance showing the data is owned or reusable.\n * @see docs/PSF_FOUNDATION.md for the equations, units, coordinate conventions, known blockers and\n * support limits.\n */\n\nimport {\n approximationResult,\n type CalculationResult\n} from \"../core/calculation-result.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport {\n parseEvidenceList,\n type EvidenceProvenance\n} from \"../core/evidence-provenance.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport {\n parseFocusPlane,\n type FocusPlane\n} from \"./focus-state.js\";\nimport type {\n LensPsfKernel,\n LensPsfScientificStatus,\n LensPsfUncertainty\n} from \"./lens-psf-profile.js\";\nimport { requireInputKeys, rejectUnknownVariantFields, UNCERTAINTY_VARIANT_FIELDS, requireConfigRecord as requireRecord, requireTrimmedConfigString as requireNonEmptyString, requireConfigFinite as requireFinite, parseConfigScientificStatus as parseStatus, requireConfigNonNegativeSafeInteger as requireNonNegativeSafeInteger, requireConfigPositiveSafeInteger as requirePositiveSafeInteger, parseConfigLimitations as parseLimitations, requireConfigFiniteAboveZero as requirePositiveFinite, requireConfigUnitInterval as requireUnitInterval } from \"../core/record-validation.js\";\n\nexport const LENS_COMPLEX_PUPIL_PROFILE_SCHEMA_VERSION =\n \"0.1.0\" as const;\n\nexport interface LensComplexPupilGrid {\n widthSamples: number;\n heightSamples: number;\n pupilSamplePitchMmX: number;\n pupilSamplePitchMmY: number;\n centerSampleX: number;\n centerSampleY: number;\n relativeAmplitude:\n readonly number[];\n opticalPathDifferenceMicrometers:\n readonly number[];\n}\n\nexport interface LensComplexPupilProfile {\n schemaVersion:\n typeof LENS_COMPLEX_PUPIL_PROFILE_SCHEMA_VERSION;\n profileId: string;\n profileVersion: string;\n scientificStatus:\n LensPsfScientificStatus;\n opticalDomain:\n \"lens-primary-optical-path-only\";\n representation:\n \"complex-pupil-amplitude-plus-opd\";\n pupilCoordinateSystem:\n \"pupil-plane-metric-aligned-to-image-plane\";\n imageFieldAxes:\n \"+X right, +Y up\";\n amplitudeMeaning:\n \"relative-complex-pupil-amplitude-shape\";\n wavefrontMeaning:\n \"optical-path-difference-micrometers\";\n throughputOwnership:\n \"separate-relative-pupil-throughput-factor\";\n kernelEnergyNormalization:\n \"unit-energy-shape\";\n propagationModel:\n \"scalar-fraunhofer-discrete-reference\";\n context: {\n focalLengthMm: number;\n focus: FocusPlane;\n apertureFNumber: number;\n fieldPointMm: {\n x: number;\n y: number;\n };\n wavelengthNm: number;\n signedDefocusImagePlaneMicrometers:\n number;\n };\n responseIncludes: {\n diffraction: true;\n aberration: boolean;\n defocus: boolean;\n pupilClippingShape:\n boolean;\n };\n relativePupilThroughputFactor:\n number;\n grid: LensComplexPupilGrid;\n sensorOpticalStackIncluded:\n false;\n sensorSamplingIncluded:\n false;\n reconstructionIncluded:\n false;\n strayLightIncluded: false;\n evidence:\n readonly EvidenceProvenance[];\n uncertainty:\n LensPsfUncertainty;\n limitations: readonly string[];\n}\n\nexport interface CalculateLensComplexPupilPsfInput {\n profile:\n LensComplexPupilProfile;\n /** Physical propagation distance from pupil to image, in mm. If omitted, the\n * nominal focal-plane reference is used. At finite focus the caller must\n * resolve the supported principal-plane geometry; profile metadata does not. */\n propagationDistanceMm?: number;\n}\n\nexport interface LensComplexPupilPsf {\n propagationDistanceMm: number;\n propagationDistanceSource: \"explicit\" | \"nominal-focal-plane-reference\";\n profileId: string;\n profileVersion: string;\n scientificStatus:\n LensPsfScientificStatus;\n context:\n LensComplexPupilProfile[\"context\"];\n kernel: LensPsfKernel;\n /** Nyquist sampling diagnostics and the applied zero padding. */\n sampling: LensComplexPupilPsfSampling;\n relativePupilThroughputFactor:\n number;\n throughputOwnership:\n \"separate-relative-pupil-throughput-factor\";\n diffractionAndAberrationJointlyEvaluated:\n true;\n pupilClippingShapeIncluded:\n boolean;\n pupilClippingThroughputAppliedToKernel:\n false;\n scalarFraunhoferReference:\n true;\n full2dOrientationPreserved:\n true;\n geometricDistortionModified:\n false;\n lateralChromaticPositionShiftApplied:\n false;\n sensorOpticalStackIncluded:\n false;\n sensorSamplingIncluded: false;\n reconstructionIncluded: false;\n strayLightIncluded: false;\n scalarSharpnessScoreProduced:\n false;\n componentEvidence: {\n pupilProfile:\n readonly EvidenceProvenance[];\n };\n uncertainty:\n LensPsfUncertainty;\n}\n\nfunction parseUncertainty(\n value: unknown,\n path: string\n): LensPsfUncertainty {\n const record =\n requireRecord(value, path, null);\n rejectUnknownVariantFields(record, \"kind\", UNCERTAINTY_VARIANT_FIELDS, path);\n if (record.kind === \"relative\") {\n const fraction =\n requireFinite(\n record.fraction,\n path + \".fraction\"\n );\n if (fraction < 0) {\n throw new InvalidConfigurationError(\n path +\n \".fraction must be nonnegative.\"\n );\n }\n return {\n kind: \"relative\",\n fraction,\n basis:\n requireNonEmptyString(\n record.basis,\n path + \".basis\"\n )\n };\n }\n if (\n record.kind ===\n \"not-quantified\"\n ) {\n return {\n kind: \"not-quantified\",\n limitation:\n requireNonEmptyString(\n record.limitation,\n path +\n \".limitation\"\n )\n };\n }\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n}\n\nfunction parseGrid(\n value: unknown\n): LensComplexPupilGrid {\n const record =\n requireRecord(\n value,\n \"lensComplexPupil.grid\", [\"widthSamples\", \"heightSamples\", \"centerSampleX\", \"centerSampleY\", \"relativeAmplitude\", \"opticalPathDifferenceMicrometers\", \"pupilSamplePitchMmX\", \"pupilSamplePitchMmY\"]\n );\n const widthSamples =\n requirePositiveSafeInteger(\n record.widthSamples,\n \"lensComplexPupil.grid.widthSamples\"\n );\n const heightSamples =\n requirePositiveSafeInteger(\n record.heightSamples,\n \"lensComplexPupil.grid.heightSamples\"\n );\n const total =\n widthSamples *\n heightSamples;\n if (\n !Number.isSafeInteger(total) ||\n total > 4096\n ) {\n throw new InvalidConfigurationError(\n \"lensComplexPupil grid must contain at most 4096 samples.\"\n );\n }\n const centerSampleX =\n requireNonNegativeSafeInteger(\n record.centerSampleX,\n \"lensComplexPupil.grid.centerSampleX\"\n );\n const centerSampleY =\n requireNonNegativeSafeInteger(\n record.centerSampleY,\n \"lensComplexPupil.grid.centerSampleY\"\n );\n if (\n centerSampleX >=\n widthSamples ||\n centerSampleY >=\n heightSamples\n ) {\n throw new InvalidConfigurationError(\n \"lensComplexPupil grid center must lie within the pupil array.\"\n );\n }\n if (\n !Array.isArray(\n record.relativeAmplitude\n ) ||\n record.relativeAmplitude\n .length !== total\n ) {\n throw new InvalidConfigurationError(\n \"lensComplexPupil.grid.relativeAmplitude length must equal widthSamples × heightSamples.\"\n );\n }\n if (\n !Array.isArray(\n record\n .opticalPathDifferenceMicrometers\n ) ||\n record\n .opticalPathDifferenceMicrometers\n .length !== total\n ) {\n throw new InvalidConfigurationError(\n \"lensComplexPupil.grid.opticalPathDifferenceMicrometers length must equal widthSamples × heightSamples.\"\n );\n }\n\n const relativeAmplitude =\n record.relativeAmplitude.map(\n (entry, index) =>\n requireUnitInterval(\n entry,\n \"lensComplexPupil.grid.relativeAmplitude[\" +\n index +\n \"]\"\n )\n );\n if (\n !relativeAmplitude.some(\n (value) =>\n value > 0\n )\n ) {\n throw new InvalidConfigurationError(\n \"lensComplexPupil must contain at least one non-zero pupil-amplitude sample.\"\n );\n }\n const opd =\n record\n .opticalPathDifferenceMicrometers\n .map(\n (entry, index) =>\n requireFinite(\n entry,\n \"lensComplexPupil.grid.opticalPathDifferenceMicrometers[\" +\n index +\n \"]\"\n )\n );\n\n return {\n widthSamples,\n heightSamples,\n pupilSamplePitchMmX:\n requirePositiveFinite(\n record\n .pupilSamplePitchMmX,\n \"lensComplexPupil.grid.pupilSamplePitchMmX\"\n ),\n pupilSamplePitchMmY:\n requirePositiveFinite(\n record\n .pupilSamplePitchMmY,\n \"lensComplexPupil.grid.pupilSamplePitchMmY\"\n ),\n centerSampleX,\n centerSampleY,\n relativeAmplitude,\n opticalPathDifferenceMicrometers:\n opd\n };\n}\n\n/**\n * Validates an untrusted declaration and returns the normalized typed contract. Unknown enum values,\n * missing required fields and incompatible scientific data are rejected here.\n *\n * The complex pupil is evaluated by summing the declared amplitude and phase over a bounded, regular\n * pupil grid. The PSF shape is normalized separately from the pupil throughput. A single blur radius\n * cannot stand in for coherent phase, pupil energy, or the wavelength and field range where the\n * profile applies. Numeric profiles need provenance showing the data is owned or reusable.\n * @param value - unknown. Untrusted input; TypeScript types alone are not validation.\n * @returns LensComplexPupilProfile. The result states its shape and scientific status; a successful call does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the root export and exact type graph.\n */\nexport function parseLensComplexPupilProfile(\n value: unknown\n): LensComplexPupilProfile {\n const record =\n requireRecord(\n value,\n \"lensComplexPupil\", [\"schemaVersion\", \"opticalDomain\", \"representation\", \"pupilCoordinateSystem\", \"imageFieldAxes\", \"amplitudeMeaning\", \"wavefrontMeaning\", \"throughputOwnership\", \"kernelEnergyNormalization\", \"propagationModel\", \"sensorOpticalStackIncluded\", \"sensorSamplingIncluded\", \"reconstructionIncluded\", \"strayLightIncluded\", \"scientificStatus\", \"uncertainty\", \"context\", \"responseIncludes\", \"profileId\", \"profileVersion\", \"relativePupilThroughputFactor\", \"grid\", \"evidence\", \"limitations\"]\n );\n if (\n record.schemaVersion !==\n LENS_COMPLEX_PUPIL_PROFILE_SCHEMA_VERSION\n ) {\n throw new InvalidConfigurationError(\n 'lensComplexPupil.schemaVersion must be \"' +\n LENS_COMPLEX_PUPIL_PROFILE_SCHEMA_VERSION +\n '\".'\n );\n }\n if (\n record.opticalDomain !==\n \"lens-primary-optical-path-only\" ||\n record.representation !==\n \"complex-pupil-amplitude-plus-opd\" ||\n record.pupilCoordinateSystem !==\n \"pupil-plane-metric-aligned-to-image-plane\" ||\n record.imageFieldAxes !==\n \"+X right, +Y up\" ||\n record.amplitudeMeaning !==\n \"relative-complex-pupil-amplitude-shape\" ||\n record.wavefrontMeaning !==\n \"optical-path-difference-micrometers\" ||\n record.throughputOwnership !==\n \"separate-relative-pupil-throughput-factor\" ||\n record.kernelEnergyNormalization !==\n \"unit-energy-shape\" ||\n record.propagationModel !==\n \"scalar-fraunhofer-discrete-reference\"\n ) {\n throw new InvalidConfigurationError(\n \"lensComplexPupil representation/coordinate/energy semantics are invalid.\"\n );\n }\n if (\n record.sensorOpticalStackIncluded !==\n false ||\n record.sensorSamplingIncluded !==\n false ||\n record.reconstructionIncluded !==\n false ||\n record.strayLightIncluded !==\n false\n ) {\n throw new InvalidConfigurationError(\n \"V1 complex pupil profiles must exclude sensor/reconstruction/stray-light effects.\"\n );\n }\n const status =\n parseStatus(\n record.scientificStatus,\n \"lensComplexPupil.scientificStatus\"\n );\n const uncertainty =\n parseUncertainty(\n record.uncertainty,\n \"lensComplexPupil.uncertainty\"\n );\n if (\n status === \"calibrated\" &&\n uncertainty.kind ===\n \"not-quantified\"\n ) {\n throw new InvalidConfigurationError(\n \"Calibrated complex-pupil profiles must declare quantified relative uncertainty.\"\n );\n }\n const context =\n requireRecord(\n record.context,\n \"lensComplexPupil.context\", [\"fieldPointMm\", \"focalLengthMm\", \"focus\", \"apertureFNumber\", \"wavelengthNm\", \"signedDefocusImagePlaneMicrometers\"]\n );\n const field =\n requireRecord(\n context.fieldPointMm,\n \"lensComplexPupil.context.fieldPointMm\", [\"x\", \"y\"]\n );\n const response =\n requireRecord(\n record.responseIncludes,\n \"lensComplexPupil.responseIncludes\", [\"diffraction\", \"aberration\", \"defocus\", \"pupilClippingShape\"]\n );\n if (\n response.diffraction !==\n true ||\n typeof response.aberration !==\n \"boolean\" ||\n typeof response.defocus !==\n \"boolean\" ||\n typeof response.pupilClippingShape !==\n \"boolean\"\n ) {\n throw new InvalidConfigurationError(\n \"lensComplexPupil.responseIncludes is invalid; diffraction must be included in this pupil propagation path.\"\n );\n }\n\n return {\n schemaVersion:\n LENS_COMPLEX_PUPIL_PROFILE_SCHEMA_VERSION,\n profileId:\n requireNonEmptyString(\n record.profileId,\n \"lensComplexPupil.profileId\"\n ),\n profileVersion:\n requireNonEmptyString(\n record.profileVersion,\n \"lensComplexPupil.profileVersion\"\n ),\n scientificStatus:\n status,\n opticalDomain:\n \"lens-primary-optical-path-only\",\n representation:\n \"complex-pupil-amplitude-plus-opd\",\n pupilCoordinateSystem:\n \"pupil-plane-metric-aligned-to-image-plane\",\n imageFieldAxes:\n \"+X right, +Y up\",\n amplitudeMeaning:\n \"relative-complex-pupil-amplitude-shape\",\n wavefrontMeaning:\n \"optical-path-difference-micrometers\",\n throughputOwnership:\n \"separate-relative-pupil-throughput-factor\",\n kernelEnergyNormalization:\n \"unit-energy-shape\",\n propagationModel:\n \"scalar-fraunhofer-discrete-reference\",\n context: {\n focalLengthMm:\n requirePositiveFinite(\n context.focalLengthMm,\n \"lensComplexPupil.context.focalLengthMm\"\n ),\n focus:\n parseFocusPlane(\n context.focus\n ),\n apertureFNumber:\n requirePositiveFinite(\n context.apertureFNumber,\n \"lensComplexPupil.context.apertureFNumber\"\n ),\n fieldPointMm: {\n x:\n requireFinite(\n field.x,\n \"lensComplexPupil.context.fieldPointMm.x\"\n ),\n y:\n requireFinite(\n field.y,\n \"lensComplexPupil.context.fieldPointMm.y\"\n )\n },\n wavelengthNm:\n requirePositiveFinite(\n context.wavelengthNm,\n \"lensComplexPupil.context.wavelengthNm\"\n ),\n signedDefocusImagePlaneMicrometers:\n requireFinite(\n context\n .signedDefocusImagePlaneMicrometers,\n \"lensComplexPupil.context.signedDefocusImagePlaneMicrometers\"\n )\n },\n responseIncludes: {\n diffraction: true,\n aberration:\n response.aberration as boolean,\n defocus:\n response.defocus as boolean,\n pupilClippingShape:\n response\n .pupilClippingShape as boolean\n },\n relativePupilThroughputFactor:\n requireUnitInterval(\n record\n .relativePupilThroughputFactor,\n \"lensComplexPupil.relativePupilThroughputFactor\"\n ),\n grid:\n parseGrid(record.grid),\n sensorOpticalStackIncluded:\n false,\n sensorSamplingIncluded:\n false,\n reconstructionIncluded:\n false,\n strayLightIncluded:\n false,\n evidence:\n parseEvidenceList(\n record.evidence,\n \"lensComplexPupil.evidence\"\n ),\n uncertainty,\n limitations:\n parseLimitations(\n record.limitations,\n \"lensComplexPupil.limitations\"\n )\n };\n}\n\ninterface ComplexValue {\n re: number;\n im: number;\n}\n\nfunction pupilComplexValue(\n amplitude: number,\n opdMicrometers: number,\n wavelengthMicrometers:\n number\n): ComplexValue {\n const phase =\n 2 *\n Math.PI *\n opdMicrometers /\n wavelengthMicrometers;\n return {\n re:\n amplitude *\n Math.cos(phase),\n im:\n amplitude *\n Math.sin(phase)\n };\n}\n\nexport interface LensComplexPupilPsfSampling {\n criterion: \"discrete-intensity-alias-free-goodman-q-above-2\";\n /** Number of pupil samples spanned by non-zero amplitude, per axis. */\n pupilSupportSamplesX: number;\n pupilSupportSamplesY: number;\n /**\n * Sampled pupil diameter D = (support samples - 1) x pupil pitch: the\n * centre-to-centre span of the outermost non-zero samples, in millimetres.\n */\n pupilSupportDiameterMmX: number;\n pupilSupportDiameterMmY: number;\n /**\n * Widest support allowed by the declared f-number at the resolved propagation distance:\n * propagationDistanceMm / apertureFNumber, in millimetres. For the nominal focal-plane reference\n * this is focalLengthMm / apertureFNumber.\n */\n declaredPupilDiameterMm: number;\n /** Declared pupil grid size before zero padding. */\n pupilGridWidthSamples: number;\n pupilGridHeightSamples: number;\n /** DFT size after zero padding; equals the output kernel size. */\n transformWidthSamples: number;\n transformHeightSamples: number;\n zeroPaddingApplied: boolean;\n /**\n * Achieved Goodman sampling factor Q = lambda*(z/D)/imagePitch =\n * transform samples / (support samples - 1). Always greater than 2. Null\n * when the support is a single sample on that axis (no finite diameter).\n */\n samplingFactorQX: number | null;\n samplingFactorQY: number | null;\n}\n\ninterface PupilSamplingPlan {\n sampling: LensComplexPupilPsfSampling;\n outputCenterX: number;\n outputCenterY: number;\n}\n\nfunction supportSpan(\n grid: LensComplexPupilGrid,\n axis: \"x\" | \"y\"\n): number {\n let minimum = Number.POSITIVE_INFINITY;\n let maximum = Number.NEGATIVE_INFINITY;\n grid.relativeAmplitude.forEach((amplitude, index) => {\n if (amplitude > 0) {\n const coordinate =\n axis === \"x\"\n ? index % grid.widthSamples\n : Math.floor(index / grid.widthSamples);\n minimum = Math.min(minimum, coordinate);\n maximum = Math.max(maximum, coordinate);\n }\n });\n return maximum - minimum + 1;\n}\n\n/**\n * Sampling guard for the discrete Fraunhofer reference (Ban et al.,\n * arXiv:2511.06936, eqs. 6-9, free: N*dp = lambda*f/dc, Q = lambda*F/dc and\n * Q >= 2. Also see: Goodman, Introduction to Fourier Optics, sampling of\n * DFT/FFT Fraunhofer propagation).\n *\n * A DFT (discrete Fourier transform) of size M over pupil pitch dp gives an\n * image-plane pitch of lambda*z/(M*dp).\n *\n * The intensity PSF is the transform of the pupil autocorrelation. That\n * autocorrelation is twice as wide as the pupil. So Nyquist sampling of the\n * intensity needs Q = lambda*(z/D)/pitch = M*dp/D >= 2.\n *\n * For a pupil spanning S samples, the discrete autocorrelation has 2S-1 lags.\n * So M >= 2S-1 is the exact condition for no circular wrap-around, and it\n * implies Q = M/(S-1) > 2. The declared grid is zero padded to that size.\n *\n * The non-zero support must also fit inside the declared f/N cone. Its\n * diameter D may not exceed z/N for the resolved propagation distance z; that\n * is, the image-side cone D/z may not be wider than 1/N. With the nominal\n * focal-plane reference (z = f) this is the entrance-aperture diameter f/N. An\n * exit pupil declared at its own distance z uses that distance\n * (docs/PSF_FOUNDATION.md).\n */\nfunction planPupilSampling(\n profile: LensComplexPupilProfile,\n propagationDistanceMm: number\n): PupilSamplingPlan {\n const grid = profile.grid;\n const supportX = supportSpan(grid, \"x\");\n const supportY = supportSpan(grid, \"y\");\n const diameterX = (supportX - 1) * grid.pupilSamplePitchMmX;\n const diameterY = (supportY - 1) * grid.pupilSamplePitchMmY;\n const declaredDiameter =\n propagationDistanceMm / profile.context.apertureFNumber;\n // Relative allowance for floating-point rounding only.\n const limit = declaredDiameter * (1 + 1e-9);\n if (diameterX > limit || diameterY > limit) {\n throw new InvalidScientificInputError(\n \"Complex-pupil amplitude support spans \" +\n diameterX.toPrecision(6) +\n \" x \" +\n diameterY.toPrecision(6) +\n \" mm between outermost non-zero samples, wider than the declared f/N cone diameter \" +\n declaredDiameter.toPrecision(6) +\n \" mm (propagationDistanceMm / apertureFNumber).\"\n );\n }\n const transformWidth = Math.max(grid.widthSamples, 2 * supportX - 1);\n const transformHeight = Math.max(grid.heightSamples, 2 * supportY - 1);\n return {\n sampling: {\n criterion: \"discrete-intensity-alias-free-goodman-q-above-2\",\n pupilSupportSamplesX: supportX,\n pupilSupportSamplesY: supportY,\n pupilSupportDiameterMmX: diameterX,\n pupilSupportDiameterMmY: diameterY,\n declaredPupilDiameterMm: declaredDiameter,\n pupilGridWidthSamples: grid.widthSamples,\n pupilGridHeightSamples: grid.heightSamples,\n transformWidthSamples: transformWidth,\n transformHeightSamples: transformHeight,\n zeroPaddingApplied:\n transformWidth !== grid.widthSamples ||\n transformHeight !== grid.heightSamples,\n samplingFactorQX:\n supportX > 1 ? transformWidth / (supportX - 1) : null,\n samplingFactorQY:\n supportY > 1 ? transformHeight / (supportY - 1) : null\n },\n // Symmetric padding keeps zero frequency at the declared centre, shifted\n // by the leading padding.\n outputCenterX:\n grid.centerSampleX +\n Math.floor((transformWidth - grid.widthSamples) / 2),\n outputCenterY:\n grid.centerSampleY +\n Math.floor((transformHeight - grid.heightSamples) / 2)\n };\n}\n\nfunction twiddleTable(size: number): { cos: number[]; sin: number[] } {\n const cos: number[] = [];\n const sin: number[] = [];\n for (let index = 0; index < size; index += 1) {\n const angle = (-2 * Math.PI * index) / size;\n cos.push(Math.cos(angle));\n sin.push(Math.sin(angle));\n }\n return { cos, sin };\n}\n\nexport function positiveModulo(value: number, size: number): number {\n const remainder = value % size;\n return remainder < 0 ? remainder + size : remainder;\n}\n\nfunction calculateDiscreteFraunhoferKernel(\n profile:\n LensComplexPupilProfile,\n propagationDistanceMm: number,\n plan: PupilSamplingPlan\n): LensPsfKernel {\n const grid = profile.grid;\n const width = grid.widthSamples;\n const height = grid.heightSamples;\n const outWidth = plan.sampling.transformWidthSamples;\n const outHeight = plan.sampling.transformHeightSamples;\n const wavelengthMicrometers = profile.context.wavelengthNm / 1000;\n const wavelengthMm = profile.context.wavelengthNm / 1_000_000;\n const pupil: ComplexValue[] =\n grid.relativeAmplitude.map(\n (amplitude, index) =>\n pupilComplexValue(\n amplitude,\n grid.opticalPathDifferenceMicrometers[index]!,\n wavelengthMicrometers\n )\n );\n\n // Separable zero-padded DFT: pupil rows to image kx first, then columns.\n // Padding samples are zero, so only declared pupil samples are summed.\n const twiddleX = twiddleTable(outWidth);\n const twiddleY = twiddleTable(outHeight);\n const rowRe = new Float64Array(height * outWidth);\n const rowIm = new Float64Array(height * outWidth);\n for (let y = 0; y < height; y += 1) {\n for (let outX = 0; outX < outWidth; outX += 1) {\n const kx = outX - plan.outputCenterX;\n let re = 0;\n let im = 0;\n for (let x = 0; x < width; x += 1) {\n const source = pupil[y * width + x]!;\n const t = positiveModulo(kx * (x - grid.centerSampleX), outWidth);\n const cos = twiddleX.cos[t]!;\n const sin = twiddleX.sin[t]!;\n re += source.re * cos - source.im * sin;\n im += source.re * sin + source.im * cos;\n }\n rowRe[y * outWidth + outX] = re;\n rowIm[y * outWidth + outX] = im;\n }\n }\n\n const intensity = new Array<number>(outWidth * outHeight).fill(0);\n for (let outY = 0; outY < outHeight; outY += 1) {\n const ky = outY - plan.outputCenterY;\n for (let outX = 0; outX < outWidth; outX += 1) {\n let re = 0;\n let im = 0;\n for (let y = 0; y < height; y += 1) {\n const sourceRe = rowRe[y * outWidth + outX]!;\n const sourceIm = rowIm[y * outWidth + outX]!;\n const t = positiveModulo(ky * (y - grid.centerSampleY), outHeight);\n const cos = twiddleY.cos[t]!;\n const sin = twiddleY.sin[t]!;\n re += sourceRe * cos - sourceIm * sin;\n im += sourceRe * sin + sourceIm * cos;\n }\n intensity[outY * outWidth + outX] = re * re + im * im;\n }\n }\n\n const sum =\n intensity.reduce(\n (acc, value) =>\n acc + value,\n 0\n );\n if (\n !Number.isFinite(sum) ||\n sum <= 0\n ) {\n throw new InvalidScientificInputError(\n \"Complex-pupil propagation must produce finite positive PSF energy.\"\n );\n }\n const normalized =\n intensity.map(\n (value) =>\n value / sum\n );\n\n const samplePitchMmX =\n wavelengthMm * propagationDistanceMm /\n (outWidth * grid.pupilSamplePitchMmX);\n const samplePitchMmY =\n wavelengthMm * propagationDistanceMm /\n (outHeight * grid.pupilSamplePitchMmY);\n\n if (\n !Number.isFinite(\n samplePitchMmX\n ) ||\n !Number.isFinite(\n samplePitchMmY\n ) ||\n samplePitchMmX <= 0 ||\n samplePitchMmY <= 0\n ) {\n throw new InvalidScientificInputError(\n \"Complex-pupil PSF sample pitch must remain finite and positive.\"\n );\n }\n\n return {\n widthSamples: outWidth,\n heightSamples: outHeight,\n samplePitchMicrometersX:\n samplePitchMmX *\n 1000,\n samplePitchMicrometersY:\n samplePitchMmY *\n 1000,\n centerSampleX: plan.outputCenterX,\n centerSampleY: plan.outputCenterY,\n normalizedIntensity:\n normalized\n };\n}\n\n/**\n * Evaluates a declared complex pupil with explicit amplitude, phase and sampling support. Returns the\n * normalized PSF shape, and the pupil throughput as a separate quantity.\n *\n * The complex pupil is evaluated by summing the declared amplitude and phase over a bounded, regular\n * pupil grid. The PSF shape is normalized separately from the pupil throughput. A single blur radius\n * cannot stand in for coherent phase, pupil energy, or the wavelength and field range where the\n * profile applies. Numeric profiles need provenance showing the data is owned or reusable.\n * @param input - CalculateLensComplexPupilPsfInput. See that type for coordinates, units and profile binding.\n * @returns CalculationResult<LensComplexPupilPsf>. The result states its shape and scientific status; a successful call does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the root export and exact type graph.\n */\nexport function calculateLensComplexPupilPsf(\n input:\n CalculateLensComplexPupilPsfInput\n): CalculationResult<LensComplexPupilPsf> {\n requireInputKeys(input, \"calculateLensComplexPupilPsf\", [\"profile\", \"propagationDistanceMm\"]);\n const profile =\n parseLensComplexPupilProfile(\n input.profile\n );\n const propagationDistanceMm = input.propagationDistanceMm === undefined ? profile.context.focalLengthMm : input.propagationDistanceMm;\n requirePositiveFinite(propagationDistanceMm, \"propagationDistanceMm\");\n const plan = planPupilSampling(profile, propagationDistanceMm);\n const kernel =\n calculateDiscreteFraunhoferKernel(\n profile,\n propagationDistanceMm,\n plan\n );\n\n return approximationResult(\n {\n propagationDistanceMm,\n propagationDistanceSource: input.propagationDistanceMm === undefined ? \"nominal-focal-plane-reference\" : \"explicit\",\n profileId:\n profile.profileId,\n profileVersion:\n profile.profileVersion,\n scientificStatus:\n profile.scientificStatus,\n context: {\n ...profile.context,\n focus: {\n ...profile.context.focus\n },\n fieldPointMm: {\n ...profile.context\n .fieldPointMm\n }\n },\n kernel,\n sampling: plan.sampling,\n relativePupilThroughputFactor:\n profile\n .relativePupilThroughputFactor,\n throughputOwnership:\n \"separate-relative-pupil-throughput-factor\",\n diffractionAndAberrationJointlyEvaluated:\n true,\n pupilClippingShapeIncluded:\n profile\n .responseIncludes\n .pupilClippingShape,\n pupilClippingThroughputAppliedToKernel:\n false,\n scalarFraunhoferReference:\n true,\n full2dOrientationPreserved:\n true,\n geometricDistortionModified:\n false,\n lateralChromaticPositionShiftApplied:\n false,\n sensorOpticalStackIncluded:\n false,\n sensorSamplingIncluded:\n false,\n reconstructionIncluded:\n false,\n strayLightIncluded:\n false,\n scalarSharpnessScoreProduced:\n false,\n componentEvidence: {\n pupilProfile:\n profile.evidence\n },\n uncertainty:\n profile.uncertainty\n },\n \"lens-complex-pupil-fraunhofer-psf\",\n \"2.0.0\",\n [\n \"The reference evaluator performs deterministic scalar Fraunhofer propagation of one explicit complex pupil amplitude plus optical-path-difference grid.\",\n \"The pupil is zero padded so the DFT spans at least 2S-1 samples for a non-zero support of S samples per axis: the discrete intensity PSF then has no wrap-around aliasing and Goodman's sampling factor Q = lambda*N/pitch exceeds 2. Pupil support wider than the declared f/N aperture is rejected.\",\n \"Physical sample pitch uses the explicit propagation distance when supplied; omission preserves the nominal focal-plane reference. Finite focus metadata does not resolve the pupil-to-image geometry automatically.\",\n \"Diffraction and aberration phase are evaluated together in the same pupil propagation; callers must not stack an independent diffraction blur over this result.\",\n \"The output PSF is unit-energy normalized. The explicit relativePupilThroughputFactor is not multiplied into the kernel and remains owned by the separate optical-throughput path.\",\n \"Pupil amplitude shape can represent mechanical clipping/cat-eye geometry without silently encoding unknown transmission loss.\",\n \"The pupil and image-plane axes preserve full 2D orientation; no radial or sagittal/tangential averaging is imposed.\",\n \"This scalar Fraunhofer grid is a bounded reference approximation, not a full vector electromagnetic, polarization, stray-light or sensor-system model.\",\n \"Sensor OLPF, microlens, CFA, sampling and reconstruction are downstream and excluded.\"\n ]\n );\n}\n"]}