@photivra/engine 2.17.0 → 2.19.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 (288) hide show
  1. package/CHANGELOG.md +116 -1
  2. package/CITATION.cff +1 -1
  3. package/README.md +6 -6
  4. package/SECURITY.md +1 -1
  5. package/dist/camera/sensor-equivalence.d.ts +156 -0
  6. package/dist/camera/sensor-equivalence.js +208 -0
  7. package/dist/camera/sensor-equivalence.js.map +1 -0
  8. package/dist/capture/focus-control.js +2 -75
  9. package/dist/capture/focus-control.js.map +1 -1
  10. package/dist/capture/native-environment-lean.d.ts +1 -0
  11. package/dist/capture/native-environment-lean.js +1 -1
  12. package/dist/capture/native-environment-lean.js.map +1 -1
  13. package/dist/capture/native-environment-optical-stage.d.ts +1 -0
  14. package/dist/capture/native-environment-optical-stage.js +2 -5
  15. package/dist/capture/native-environment-optical-stage.js.map +1 -1
  16. package/dist/capture/native-environment-raw.js +1 -5
  17. package/dist/capture/native-environment-raw.js.map +1 -1
  18. package/dist/capture/native-environment-tabulated.d.ts +5 -0
  19. package/dist/capture/native-environment-tabulated.js +1 -1
  20. package/dist/capture/native-environment-tabulated.js.map +1 -1
  21. package/dist/capture/release-sequence.js +2 -47
  22. package/dist/capture/release-sequence.js.map +1 -1
  23. package/dist/color/white-balance.d.ts +2 -0
  24. package/dist/color/white-balance.js +3 -56
  25. package/dist/color/white-balance.js.map +1 -1
  26. package/dist/composition/image-formation-plan.d.ts +1 -0
  27. package/dist/composition/image-formation-plan.js +3 -49
  28. package/dist/composition/image-formation-plan.js.map +1 -1
  29. package/dist/core/evidence-provenance.js +1 -16
  30. package/dist/core/evidence-provenance.js.map +1 -1
  31. package/dist/core/record-validation.d.ts +54 -0
  32. package/dist/core/record-validation.js +176 -0
  33. package/dist/core/record-validation.js.map +1 -1
  34. package/dist/core/scientific-assurance.js +1 -18
  35. package/dist/core/scientific-assurance.js.map +1 -1
  36. package/dist/core/shared-helpers.d.ts +33 -0
  37. package/dist/core/shared-helpers.js +34 -0
  38. package/dist/core/shared-helpers.js.map +1 -0
  39. package/dist/core/spectral-composition.js +1 -36
  40. package/dist/core/spectral-composition.js.map +1 -1
  41. package/dist/core/spectral.js +1 -19
  42. package/dist/core/spectral.js.map +1 -1
  43. package/dist/core/version.d.ts +1 -1
  44. package/dist/core/version.js +1 -1
  45. package/dist/core/version.js.map +1 -1
  46. package/dist/equipment/exposure-capabilities.d.ts +1 -0
  47. package/dist/equipment/exposure-capabilities.js +2 -36
  48. package/dist/equipment/exposure-capabilities.js.map +1 -1
  49. package/dist/equipment/ideal-lens.d.ts +25 -0
  50. package/dist/equipment/ideal-lens.js +21 -0
  51. package/dist/equipment/ideal-lens.js.map +1 -0
  52. package/dist/equipment/iso-capabilities.js +2 -49
  53. package/dist/equipment/iso-capabilities.js.map +1 -1
  54. package/dist/equipment/metering-capabilities.js +1 -26
  55. package/dist/equipment/metering-capabilities.js.map +1 -1
  56. package/dist/equipment/release-capabilities.js +1 -53
  57. package/dist/equipment/release-capabilities.js.map +1 -1
  58. package/dist/exposure/auto-iso-slowest-shutter.js +1 -7
  59. package/dist/exposure/auto-iso-slowest-shutter.js.map +1 -1
  60. package/dist/exposure/exposure-duration-control.js +1 -16
  61. package/dist/exposure/exposure-duration-control.js.map +1 -1
  62. package/dist/exposure/exposure-mode-resolver.js +1 -17
  63. package/dist/exposure/exposure-mode-resolver.js.map +1 -1
  64. package/dist/exposure/filtered-exposure-time.d.ts +93 -0
  65. package/dist/exposure/filtered-exposure-time.js +129 -0
  66. package/dist/exposure/filtered-exposure-time.js.map +1 -0
  67. package/dist/exposure/flash-ttl.d.ts +1 -0
  68. package/dist/exposure/flash-ttl.js +1 -1
  69. package/dist/exposure/flash-ttl.js.map +1 -1
  70. package/dist/exposure/flash.js +1 -49
  71. package/dist/exposure/flash.js.map +1 -1
  72. package/dist/exposure/metering-scene-radiance.js +1 -25
  73. package/dist/exposure/metering-scene-radiance.js.map +1 -1
  74. package/dist/exposure/metering-target.js +1 -30
  75. package/dist/exposure/metering-target.js.map +1 -1
  76. package/dist/exposure/metering-temporal.js +1 -8
  77. package/dist/exposure/metering-temporal.js.map +1 -1
  78. package/dist/exposure/metering.js +1 -72
  79. package/dist/exposure/metering.js.map +1 -1
  80. package/dist/exposure/program-line.js +1 -45
  81. package/dist/exposure/program-line.js.map +1 -1
  82. package/dist/facade/catalogue-lens-signal.d.ts +94 -0
  83. package/dist/facade/catalogue-lens-signal.js +362 -0
  84. package/dist/facade/catalogue-lens-signal.js.map +1 -0
  85. package/dist/facade/defocus-image-space-provider.js +5 -2
  86. package/dist/facade/defocus-image-space-provider.js.map +1 -1
  87. package/dist/facade/develop-joined-parts.d.ts +29 -0
  88. package/dist/facade/develop-joined-parts.js +33 -0
  89. package/dist/facade/develop-joined-parts.js.map +1 -0
  90. package/dist/facade/display-view-lens-signal.d.ts +32 -1
  91. package/dist/facade/display-view-lens-signal.js +85 -10
  92. package/dist/facade/display-view-lens-signal.js.map +1 -1
  93. package/dist/facade/expected-signal-setup.d.ts +8 -0
  94. package/dist/facade/expected-signal-setup.js +7 -0
  95. package/dist/facade/expected-signal-setup.js.map +1 -1
  96. package/dist/facade/expected-signal.d.ts +5 -0
  97. package/dist/facade/expected-signal.js +5 -1
  98. package/dist/facade/expected-signal.js.map +1 -1
  99. package/dist/facade/generic-lens-capture.d.ts +5 -2
  100. package/dist/facade/generic-lens-capture.js +5 -2
  101. package/dist/facade/generic-lens-capture.js.map +1 -1
  102. package/dist/facade/simulate-capture.d.ts +67 -8
  103. package/dist/facade/simulate-capture.js +262 -126
  104. package/dist/facade/simulate-capture.js.map +1 -1
  105. package/dist/facade/simulate-display-view.js +1 -1
  106. package/dist/facade/simulate-display-view.js.map +1 -1
  107. package/dist/gpu/chart-composite-gpu.js +1 -3
  108. package/dist/gpu/chart-composite-gpu.js.map +1 -1
  109. package/dist/gpu/chart-radiance-gpu.js +1 -5
  110. package/dist/gpu/chart-radiance-gpu.js.map +1 -1
  111. package/dist/gpu/display-view-quality-gpu.d.ts +13 -1
  112. package/dist/gpu/display-view-quality-gpu.js +4 -8
  113. package/dist/gpu/display-view-quality-gpu.js.map +1 -1
  114. package/dist/gpu/display-view-speed-gpu.js +3 -25
  115. package/dist/gpu/display-view-speed-gpu.js.map +1 -1
  116. package/dist/gpu/sensor-stage-gpu.js +1 -5
  117. package/dist/gpu/sensor-stage-gpu.js.map +1 -1
  118. package/dist/gpu/webgpu-runtime.d.ts +2 -0
  119. package/dist/gpu/webgpu-runtime.js +3 -0
  120. package/dist/gpu/webgpu-runtime.js.map +1 -1
  121. package/dist/index.d.ts +6 -1
  122. package/dist/index.js +5 -0
  123. package/dist/index.js.map +1 -1
  124. package/dist/motion/camera-rotation.js +1 -6
  125. package/dist/motion/camera-rotation.js.map +1 -1
  126. package/dist/motion/capture-rotation-inverse-mapping.d.ts +12 -0
  127. package/dist/motion/capture-rotation-inverse-mapping.js +2 -2
  128. package/dist/motion/capture-rotation-inverse-mapping.js.map +1 -1
  129. package/dist/motion/capture-rotation-temporal-quadrature.d.ts +1 -0
  130. package/dist/motion/capture-rotation-temporal-quadrature.js +1 -1
  131. package/dist/motion/capture-rotation-temporal-quadrature.js.map +1 -1
  132. package/dist/motion/capture-rotation-trajectory.js +2 -17
  133. package/dist/motion/capture-rotation-trajectory.js.map +1 -1
  134. package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts +1 -0
  135. package/dist/motion/capture-translation-parallax-temporal-quadrature.js +3 -14
  136. package/dist/motion/capture-translation-parallax-temporal-quadrature.js.map +1 -1
  137. package/dist/motion/extended-object-projection.js +5 -40
  138. package/dist/motion/extended-object-projection.js.map +1 -1
  139. package/dist/optics/atmospheric-haze.js +1 -7
  140. package/dist/optics/atmospheric-haze.js.map +1 -1
  141. package/dist/optics/brown-conrady-distortion.js +1 -7
  142. package/dist/optics/brown-conrady-distortion.js.map +1 -1
  143. package/dist/optics/complex-pupil-psf.d.ts +1 -0
  144. package/dist/optics/complex-pupil-psf.js +2 -84
  145. package/dist/optics/complex-pupil-psf.js.map +1 -1
  146. package/dist/optics/focus-state.js +1 -11
  147. package/dist/optics/focus-state.js.map +1 -1
  148. package/dist/optics/front-of-lens-filter.d.ts +5 -0
  149. package/dist/optics/front-of-lens-filter.js +3 -65
  150. package/dist/optics/front-of-lens-filter.js.map +1 -1
  151. package/dist/optics/generic-nd-filter-presets.d.ts +12 -0
  152. package/dist/optics/generic-nd-filter-presets.js +48 -0
  153. package/dist/optics/generic-nd-filter-presets.js.map +1 -0
  154. package/dist/optics/illumination-vignetting.js +1 -6
  155. package/dist/optics/illumination-vignetting.js.map +1 -1
  156. package/dist/optics/lens-psf-profile.d.ts +4 -1
  157. package/dist/optics/lens-psf-profile.js +12 -111
  158. package/dist/optics/lens-psf-profile.js.map +1 -1
  159. package/dist/optics/longitudinal-chromatic-aberration.js +1 -7
  160. package/dist/optics/longitudinal-chromatic-aberration.js.map +1 -1
  161. package/dist/optics/pupil-vignetting.js +1 -7
  162. package/dist/optics/pupil-vignetting.js.map +1 -1
  163. package/dist/optics/radial-distortion.js +1 -6
  164. package/dist/optics/radial-distortion.js.map +1 -1
  165. package/dist/optics/scene-to-sensor-irradiance.js +4 -96
  166. package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
  167. package/dist/optics/stray-light.d.ts +1 -0
  168. package/dist/optics/stray-light.js +1 -1
  169. package/dist/optics/stray-light.js.map +1 -1
  170. package/dist/optics/zernike-wavefront.js +1 -7
  171. package/dist/optics/zernike-wavefront.js.map +1 -1
  172. package/dist/output/capture-geometry.js +1 -8
  173. package/dist/output/capture-geometry.js.map +1 -1
  174. package/dist/output/developed-lens-corrections.d.ts +62 -0
  175. package/dist/output/developed-lens-corrections.js +135 -0
  176. package/dist/output/developed-lens-corrections.js.map +1 -0
  177. package/dist/output/generic-lens-corrections.d.ts +2 -6
  178. package/dist/output/generic-lens-corrections.js +3 -6
  179. package/dist/output/generic-lens-corrections.js.map +1 -1
  180. package/dist/output/geometric-transforms.js +1 -4
  181. package/dist/output/geometric-transforms.js.map +1 -1
  182. package/dist/output/native-capture-sdr.d.ts +2 -2
  183. package/dist/output/native-capture-sdr.js +3 -2
  184. package/dist/output/native-capture-sdr.js.map +1 -1
  185. package/dist/processing/development-detail.d.ts +29 -0
  186. package/dist/processing/development-detail.js +128 -107
  187. package/dist/processing/development-detail.js.map +1 -1
  188. package/dist/schema/illumination-temporal.js +3 -72
  189. package/dist/schema/illumination-temporal.js.map +1 -1
  190. package/dist/schema/illumination.d.ts +1 -0
  191. package/dist/schema/illumination.js +2 -65
  192. package/dist/schema/illumination.js.map +1 -1
  193. package/dist/schema/scene-radiance-temporal.js +2 -14
  194. package/dist/schema/scene-radiance-temporal.js.map +1 -1
  195. package/dist/schema/scene-radiance.js +2 -60
  196. package/dist/schema/scene-radiance.js.map +1 -1
  197. package/dist/schema/validation.d.ts +2 -0
  198. package/dist/schema/validation.js +2 -17
  199. package/dist/schema/validation.js.map +1 -1
  200. package/dist/sensor/accumulated-charge.js +2 -59
  201. package/dist/sensor/accumulated-charge.js.map +1 -1
  202. package/dist/sensor/architecture.js +1 -16
  203. package/dist/sensor/architecture.js.map +1 -1
  204. package/dist/sensor/camera-saturation-capacity.d.ts +1 -0
  205. package/dist/sensor/camera-saturation-capacity.js +3 -55
  206. package/dist/sensor/camera-saturation-capacity.js.map +1 -1
  207. package/dist/sensor/capture-color-sampling-binding.js +1 -26
  208. package/dist/sensor/capture-color-sampling-binding.js.map +1 -1
  209. package/dist/sensor/capture-mode-timing.js +1 -39
  210. package/dist/sensor/capture-mode-timing.js.map +1 -1
  211. package/dist/sensor/capture-mode.js +1 -23
  212. package/dist/sensor/capture-mode.js.map +1 -1
  213. package/dist/sensor/color-sampling.js +1 -26
  214. package/dist/sensor/color-sampling.js.map +1 -1
  215. package/dist/sensor/constant-rate-temporal-integration.js +2 -46
  216. package/dist/sensor/constant-rate-temporal-integration.js.map +1 -1
  217. package/dist/sensor/dark-current.js +2 -45
  218. package/dist/sensor/dark-current.js.map +1 -1
  219. package/dist/sensor/eqe-electron-rate.js +2 -35
  220. package/dist/sensor/eqe-electron-rate.js.map +1 -1
  221. package/dist/sensor/exposure-window.d.ts +5 -0
  222. package/dist/sensor/exposure-window.js +7 -22
  223. package/dist/sensor/exposure-window.js.map +1 -1
  224. package/dist/sensor/iso-gain.js +1 -7
  225. package/dist/sensor/iso-gain.js.map +1 -1
  226. package/dist/sensor/iso-signal-chain.js +1 -43
  227. package/dist/sensor/iso-signal-chain.js.map +1 -1
  228. package/dist/sensor/optical-stack.js +1 -25
  229. package/dist/sensor/optical-stack.js.map +1 -1
  230. package/dist/sensor/photon-energy.js +1 -26
  231. package/dist/sensor/photon-energy.js.map +1 -1
  232. package/dist/sensor/physical-charge-capacity.js +3 -77
  233. package/dist/sensor/physical-charge-capacity.js.map +1 -1
  234. package/dist/sensor/radiometry-readiness.js +2 -23
  235. package/dist/sensor/radiometry-readiness.js.map +1 -1
  236. package/dist/sensor/raw-readout.d.ts +3 -0
  237. package/dist/sensor/raw-readout.js +4 -66
  238. package/dist/sensor/raw-readout.js.map +1 -1
  239. package/dist/sensor/raw-reconstruction.js +2 -64
  240. package/dist/sensor/raw-reconstruction.js.map +1 -1
  241. package/dist/sensor/readout-exposure-linkage.js +1 -9
  242. package/dist/sensor/readout-exposure-linkage.js.map +1 -1
  243. package/dist/sensor/readout-timing.js +3 -57
  244. package/dist/sensor/readout-timing.js.map +1 -1
  245. package/dist/sensor/response-application-compatibility.d.ts +2 -0
  246. package/dist/sensor/response-application-compatibility.js +3 -29
  247. package/dist/sensor/response-application-compatibility.js.map +1 -1
  248. package/dist/sensor/response-operating-range.d.ts +1 -0
  249. package/dist/sensor/response-operating-range.js +3 -79
  250. package/dist/sensor/response-operating-range.js.map +1 -1
  251. package/dist/sensor/responsivity-photocurrent.js +4 -108
  252. package/dist/sensor/responsivity-photocurrent.js.map +1 -1
  253. package/dist/sensor/sampling-aperture.js +1 -25
  254. package/dist/sensor/sampling-aperture.js.map +1 -1
  255. package/dist/sensor/spatial-sample-reduction.js +2 -19
  256. package/dist/sensor/spatial-sample-reduction.js.map +1 -1
  257. package/dist/sensor/spatial-sampling-quadrature.js +1 -3
  258. package/dist/sensor/spatial-sampling-quadrature.js.map +1 -1
  259. package/dist/sensor/spatio-spectral-reduction.js +1 -18
  260. package/dist/sensor/spatio-spectral-reduction.js.map +1 -1
  261. package/dist/sensor/spectral-coverage.d.ts +10 -1
  262. package/dist/sensor/spectral-coverage.js +1 -1
  263. package/dist/sensor/spectral-coverage.js.map +1 -1
  264. package/dist/sensor/spectral-quadrature.js +2 -35
  265. package/dist/sensor/spectral-quadrature.js.map +1 -1
  266. package/dist/sensor/spectral-response.js +1 -47
  267. package/dist/sensor/spectral-response.js.map +1 -1
  268. package/dist/stabilization/camera-shake.js +1 -6
  269. package/dist/stabilization/camera-shake.js.map +1 -1
  270. package/dist/stabilization/system.js +2 -80
  271. package/dist/stabilization/system.js.map +1 -1
  272. package/docs/AGENT_GUIDE.md +4 -0
  273. package/docs/API_REFERENCE.md +69 -2
  274. package/docs/QUICK_START.md +136 -6
  275. package/docs/USAGE.md +89 -3
  276. package/docs/api/camera-sensor-equivalence.md +209 -0
  277. package/docs/api/core-version.md +1 -1
  278. package/docs/api/equipment-ideal-lens.md +26 -0
  279. package/docs/api/exports.json +118 -3
  280. package/docs/api/exposure-filtered-exposure-time.md +105 -0
  281. package/docs/api/facade-develop-joined-parts.md +32 -0
  282. package/docs/api/facade-simulate-capture.md +62 -8
  283. package/docs/api/optics-generic-nd-filter-presets.md +34 -0
  284. package/docs/api/optics-lens-psf-profile.md +3 -1
  285. package/docs/api/output-developed-lens-corrections.md +12 -0
  286. package/docs/api/output-generic-lens-corrections.md +0 -9
  287. package/llms.txt +3 -0
  288. package/package.json +1 -1
@@ -21,7 +21,7 @@ import { freezeOwnedData } from "../core/owned-data.js";
21
21
  import { parseEvidenceList } from "../core/evidence-provenance.js";
22
22
  import { InvalidScientificInputError } from "../core/validation.js";
23
23
  import { parseFocusPlane } from "./focus-state.js";
24
- import { requireInputKeys, rejectUnknownFields, rejectUnknownVariantFields, UNCERTAINTY_VARIANT_FIELDS } from "../core/record-validation.js";
24
+ import { requireInputKeys, rejectUnknownVariantFields, UNCERTAINTY_VARIANT_FIELDS, requireConfigRecord as requireRecord, requireTrimmedConfigString as requireNonEmptyString, requireConfigFinite as requireFinite, parseConfigScientificStatus as parseStatus, requireConfigNonNegativeSafeInteger as requireNonNegativeSafeInteger, requireConfigPositiveSafeInteger as requirePositiveSafeInteger, requireInputFinite as requireScientificFinite, parseConfigLimitations as parseLimitations, requireConfigFiniteAboveZero as requirePositiveFinite, requireConfigFiniteAtLeastZero as requireNonNegativeFinite, requireInputFiniteAboveZero as requireScientificPositiveFinite, requireConfigUnitInterval as requireUnitInterval } from "../core/record-validation.js";
25
25
  export const LENS_SAMPLED_PSF_PROFILE_SCHEMA_VERSION = "0.1.0";
26
26
  export const LENS_MTF_DIAGNOSTIC_PROFILE_SCHEMA_VERSION = "0.1.0";
27
27
  const LENS_SAMPLED_PSF_INTERPOLATIONS = [
@@ -38,82 +38,7 @@ const AXIS_KEYS = [
38
38
  "wavelengthNm",
39
39
  "signedDefocusImagePlaneMicrometers"
40
40
  ];
41
- function requireRecord(value, path, allowedKeys) {
42
- if (typeof value !== "object" ||
43
- value === null ||
44
- Array.isArray(value)) {
45
- throw new InvalidConfigurationError(path + " must be an object.");
46
- }
47
- if (allowedKeys !== null)
48
- rejectUnknownFields(value, allowedKeys, path);
49
- return value;
50
- }
51
- function requireNonEmptyString(value, path) {
52
- if (typeof value !== "string" ||
53
- value.trim().length === 0) {
54
- throw new InvalidConfigurationError(path +
55
- " must be a non-empty string.");
56
- }
57
- return value.trim();
58
- }
59
- function requireFinite(value, path) {
60
- if (typeof value !== "number" ||
61
- !Number.isFinite(value)) {
62
- throw new InvalidConfigurationError(path + " must be finite.");
63
- }
64
- return value;
65
- }
66
- function requirePositiveFinite(value, path) {
67
- const parsed = requireFinite(value, path);
68
- if (parsed <= 0) {
69
- throw new InvalidConfigurationError(path +
70
- " must be greater than zero.");
71
- }
72
- return parsed;
73
- }
74
- function requireNonNegativeFinite(value, path) {
75
- const parsed = requireFinite(value, path);
76
- if (parsed < 0) {
77
- throw new InvalidConfigurationError(path +
78
- " must be greater than or equal to zero.");
79
- }
80
- return parsed;
81
- }
82
- function requireUnitInterval(value, path) {
83
- const parsed = requireFinite(value, path);
84
- if (parsed < 0 ||
85
- parsed > 1) {
86
- throw new InvalidConfigurationError(path +
87
- " must lie from zero through one.");
88
- }
89
- return parsed;
90
- }
91
- function requirePositiveSafeInteger(value, path) {
92
- if (typeof value !== "number" ||
93
- !Number.isSafeInteger(value) ||
94
- value <= 0) {
95
- throw new InvalidConfigurationError(path +
96
- " must be a positive safe integer.");
97
- }
98
- return value;
99
- }
100
- function requireNonNegativeSafeInteger(value, path) {
101
- if (typeof value !== "number" ||
102
- !Number.isSafeInteger(value) ||
103
- value < 0) {
104
- throw new InvalidConfigurationError(path +
105
- " must be a non-negative safe integer.");
106
- }
107
- return value;
108
- }
109
- function parseStatus(value, path) {
110
- if (value !== "calibrated" &&
111
- value !== "approximation") {
112
- throw new InvalidConfigurationError(path + " is invalid.");
113
- }
114
- return value;
115
- }
116
- function parseUncertainty(value, path) {
41
+ export function parseUncertainty(value, path) {
117
42
  const record = requireRecord(value, path, null);
118
43
  rejectUnknownVariantFields(record, "kind", UNCERTAINTY_VARIANT_FIELDS, path);
119
44
  if (record.kind === "relative") {
@@ -133,21 +58,6 @@ function parseUncertainty(value, path) {
133
58
  }
134
59
  throw new InvalidConfigurationError(path + ".kind is invalid.");
135
60
  }
136
- function parseLimitations(value, path) {
137
- if (!Array.isArray(value)) {
138
- throw new InvalidConfigurationError(path + " must be an array.");
139
- }
140
- const parsed = value.map((entry, index) => requireNonEmptyString(entry, path +
141
- "[" +
142
- index +
143
- "]"));
144
- if (new Set(parsed).size !==
145
- parsed.length) {
146
- throw new InvalidConfigurationError(path +
147
- " must not contain duplicates.");
148
- }
149
- return parsed;
150
- }
151
61
  function parseAxis(value, path, options = {}) {
152
62
  if (!Array.isArray(value) ||
153
63
  value.length === 0) {
@@ -518,21 +428,6 @@ function focusDiopters(focus) {
518
428
  : 1 /
519
429
  parsed.distanceM;
520
430
  }
521
- function requireScientificFinite(value, path) {
522
- if (typeof value !== "number" ||
523
- !Number.isFinite(value)) {
524
- throw new InvalidScientificInputError(path + " must be finite.");
525
- }
526
- return value;
527
- }
528
- function requireScientificPositiveFinite(value, path) {
529
- const parsed = requireScientificFinite(value, path);
530
- if (parsed <= 0) {
531
- throw new InvalidScientificInputError(path +
532
- " must be greater than zero.");
533
- }
534
- return parsed;
535
- }
536
431
  function bracketAxis(values, target, path) {
537
432
  const minimum = values[0];
538
433
  const maximum = values[values.length - 1];
@@ -784,20 +679,26 @@ function interpolateKernelCentroidAligned(weighted) {
784
679
  });
785
680
  return normalizedKernel(first, values);
786
681
  }
787
- /** Rotates a kernel by angleRadians (counter-clockwise, +Y up) about its centre sample. */
682
+ /**
683
+ * Rotates a kernel by angleRadians (counter-clockwise from image +X towards image +Y) about its centre sample.
684
+ * The row index increases with image +Y, the convention the environment PSF quadrature applies (`sensorPsfSourcePoint`:
685
+ * tap (kx, ky) lands at image offset (+(kx − cx)·pₓ, +(ky − cy)·p_y), +Y up), so a kernel declared along +X and rotated to
686
+ * field azimuth atan2(y, x) points the same way in the rendered image as a 2-D grid node declared at (x, y). Before 2.19.0
687
+ * this read rows as image −Y, which mirrored asymmetric kernels in y (#566).
688
+ */
788
689
  function rotateKernel(kernel, angleRadians) {
789
690
  const cos = Math.cos(angleRadians);
790
691
  const sin = Math.sin(angleRadians);
791
692
  const values = [];
792
693
  for (let row = 0; row < kernel.heightSamples; row += 1) {
793
- // Array rows increase downward; image +Y is up.
794
- const y = kernel.centerSampleY - row;
694
+ // Row index increases with image +Y (sensorPsfSourcePoint).
695
+ const y = row - kernel.centerSampleY;
795
696
  for (let column = 0; column < kernel.widthSamples; column += 1) {
796
697
  const x = column - kernel.centerSampleX;
797
698
  // Inverse rotation: destination (x, y) samples source R(-angle) (x, y).
798
699
  const sourceX = cos * x + sin * y;
799
700
  const sourceY = -sin * x + cos * y;
800
- values.push(bilinearSample(kernel, kernel.centerSampleX + sourceX, kernel.centerSampleY - sourceY));
701
+ values.push(bilinearSample(kernel, kernel.centerSampleX + sourceX, kernel.centerSampleY + sourceY));
801
702
  }
802
703
  }
803
704
  return normalizedKernel(kernel, values);
@@ -1 +1 @@
1
- {"version":3,"file":"lens-psf-profile.js","sourceRoot":"","sources":["../../src/optics/lens-psf-profile.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Sampled lens PSF (point-spread function) profiles, and MTF-only diagnostic profiles.\n *\n * The parsers validate untrusted input and return the normalized typed contract. Unknown enum\n * values, missing required fields and incompatible scientific data are rejected.\n *\n * The resolver finds the sampled PSF for a declared optical state and query point. It never\n * extrapolates and never invents missing dimensions.\n *\n * A sampled lens PSF is tied to an exact generic optical state and to declared ranges of field\n * position, wavelength and signed defocus. Interpolation stays inside those declared ranges. It keeps\n * the normalized shape separate from the throughput. MTF (modulation transfer function) data alone\n * has no phase or spatial information, so it cannot justify rendering one unique PSF.\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 { freezeOwnedData } from \"../core/owned-data.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 { requireInputKeys, rejectUnknownFields, rejectUnknownVariantFields, UNCERTAINTY_VARIANT_FIELDS } from \"../core/record-validation.js\";\n\ntype UnknownRecord = Record<string, unknown>;\n\nexport const LENS_SAMPLED_PSF_PROFILE_SCHEMA_VERSION =\n \"0.1.0\" as const;\nexport const LENS_MTF_DIAGNOSTIC_PROFILE_SCHEMA_VERSION =\n \"0.1.0\" as const;\n\nexport type LensPsfScientificStatus =\n | \"calibrated\"\n | \"approximation\";\n\nexport type LensPsfUncertainty =\n | {\n kind: \"relative\";\n fraction: number;\n basis: string;\n }\n | {\n kind: \"not-quantified\";\n limitation: string;\n };\n\n/**\n * Kernel interpolation between regular-grid nodes.\n * - `bounded-regular-grid-multilinear`: the legacy weighted sum of kernel values. Blending kernels\n * whose peaks sit at different positions gives several peaks.\n * - `bounded-regular-grid-centroid-aligned`: each node kernel is first shifted so its intensity\n * centroid sits at the weighted (interpolated) centroid. Then the same multilinear weights are\n * applied. Shifted or asymmetric PSFs therefore blend into one peak at the interpolated position.\n * - `rotationally-symmetric-radial-field-centroid-aligned`: for a rotationally symmetric lens. Nodes\n * are declared only along the +X field axis (fieldYmm = [0], fieldXmm >= 0). A query at field\n * (x, y) is interpolated, with centroid alignment, at radius hypot(x, y). The kernel is then\n * rotated by atan2(y, x) about its centre. The sample pitch must be square.\n * Shifts and rotations use bilinear resampling. This smooths the kernel slightly (by at most about\n * one sample). Samples outside the kernel are zero, and the result is renormalised to unit energy.\n */\nexport type LensSampledPsfInterpolation =\n | \"bounded-regular-grid-multilinear\"\n | \"bounded-regular-grid-centroid-aligned\"\n | \"rotationally-symmetric-radial-field-centroid-aligned\";\n\nconst LENS_SAMPLED_PSF_INTERPOLATIONS: readonly LensSampledPsfInterpolation[] = [\n \"bounded-regular-grid-multilinear\",\n \"bounded-regular-grid-centroid-aligned\",\n \"rotationally-symmetric-radial-field-centroid-aligned\"\n];\n\nexport interface LensPsfKernel {\n widthSamples: number;\n heightSamples: number;\n samplePitchMicrometersX: number;\n samplePitchMicrometersY: number;\n centerSampleX: number;\n centerSampleY: number;\n normalizedIntensity:\n readonly number[];\n}\n\nexport interface LensPsfGridAxes {\n focalLengthMm:\n readonly number[];\n focusDiopters:\n readonly number[];\n apertureFNumber:\n readonly number[];\n fieldXmm:\n readonly number[];\n fieldYmm:\n readonly number[];\n wavelengthNm:\n readonly number[];\n signedDefocusImagePlaneMicrometers:\n readonly number[];\n}\n\nexport interface LensSampledPsfGridCoordinate {\n focalLengthMm: number;\n focusDiopters: number;\n apertureFNumber: number;\n fieldXmm: number;\n fieldYmm: number;\n wavelengthNm: number;\n signedDefocusImagePlaneMicrometers:\n number;\n}\n\nexport interface LensSampledPsfGridNode {\n nodeId: string;\n coordinate:\n LensSampledPsfGridCoordinate;\n kernel: LensPsfKernel;\n bestFocusImagePlaneOffsetMicrometers:\n number;\n relativePupilThroughputFactor:\n number;\n evidence:\n readonly EvidenceProvenance[];\n uncertainty:\n LensPsfUncertainty;\n}\n\nexport interface LensSampledPsfProfile {\n schemaVersion:\n typeof LENS_SAMPLED_PSF_PROFILE_SCHEMA_VERSION;\n profileId: string;\n profileVersion: string;\n scientificStatus:\n LensPsfScientificStatus;\n opticalDomain:\n \"lens-primary-optical-path-only\";\n coordinateSystem:\n \"image-plane-metric\";\n fieldAxes:\n \"+X right, +Y up\";\n kernelEnergyNormalization:\n \"unit-energy-shape\";\n interpolation:\n LensSampledPsfInterpolation;\n throughputOwnership:\n \"separate-relative-pupil-throughput-factor\";\n responseIncludes: {\n diffraction: boolean;\n aberration: boolean;\n defocus: boolean;\n pupilClippingShape:\n boolean;\n };\n sensorOpticalStackIncluded:\n false;\n sensorSamplingIncluded:\n false;\n reconstructionIncluded:\n false;\n strayLightIncluded: false;\n axes: LensPsfGridAxes;\n nodes:\n readonly LensSampledPsfGridNode[];\n evidence:\n readonly EvidenceProvenance[];\n limitations: readonly string[];\n}\n\nexport interface ResolveLensSampledPsfInput {\n profile:\n LensSampledPsfProfile;\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\nexport interface ResolvedLensSampledPsf {\n profileId: string;\n profileVersion: string;\n scientificStatus:\n LensPsfScientificStatus;\n resolutionStatus:\n | \"exact-grid-sample\"\n | \"interpolated\";\n coordinate:\n LensSampledPsfGridCoordinate;\n focus: FocusPlane;\n kernel: LensPsfKernel;\n bestFocusImagePlaneOffsetMicrometers:\n number;\n relativePupilThroughputFactor:\n number;\n sourceNodes:\n readonly {\n nodeId: string;\n weight: number;\n evidence:\n readonly EvidenceProvenance[];\n uncertainty:\n LensPsfUncertainty;\n }[];\n responseIncludes:\n LensSampledPsfProfile[\"responseIncludes\"];\n throughputOwnership:\n \"separate-relative-pupil-throughput-factor\";\n longitudinalChromaticFocusMayVaryWithWavelength:\n true;\n fieldCurvatureMayVaryWithFieldPosition:\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}\n\nexport interface LensMtfDiagnosticSample {\n spatialFrequencyCyclesPerMm:\n number;\n sagittalMagnitude: number;\n tangentialMagnitude: number;\n}\n\nexport interface LensMtfDiagnosticProfile {\n schemaVersion:\n typeof LENS_MTF_DIAGNOSTIC_PROFILE_SCHEMA_VERSION;\n profileId: string;\n profileVersion: string;\n opticalDomain:\n \"lens-primary-optical-path-only\";\n phaseInformationAvailable:\n false;\n magnitudeMeaning:\n \"mtf-magnitude-only\";\n fieldPointMm: {\n x: number;\n y: number;\n };\n focalLengthMm: number;\n focus: FocusPlane;\n apertureFNumber: number;\n wavelengthNm: number | null;\n samples:\n readonly LensMtfDiagnosticSample[];\n evidence:\n readonly EvidenceProvenance[];\n limitations: readonly string[];\n}\n\nexport interface MtfOnlyPsfRenderabilityAssessment {\n profileId: string;\n psfReconstructionAuthorized:\n false;\n reason:\n \"mtf-magnitude-lacks-phase-and-does-not-uniquely-determine-psf\";\n diagnosticUseAuthorized: true;\n}\n\ninterface AxisBracket {\n lower: number;\n upper: number;\n /** Positions of lower and upper in the axis values. */\n lowerIndex: number;\n upperIndex: number;\n fraction: number;\n exact: boolean;\n}\n\ninterface WeightedNode {\n node:\n LensSampledPsfGridNode;\n weight: number;\n}\n\nconst AXIS_KEYS = [\n \"focalLengthMm\",\n \"focusDiopters\",\n \"apertureFNumber\",\n \"fieldXmm\",\n \"fieldYmm\",\n \"wavelengthNm\",\n \"signedDefocusImagePlaneMicrometers\"\n] as const;\n\ntype AxisKey =\n typeof AXIS_KEYS[number];\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 requireNonNegativeFinite(\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 or equal to 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 return {\n kind: \"relative\",\n fraction:\n requireNonNegativeFinite(\n record.fraction,\n path + \".fraction\"\n ),\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 parseAxis(\n value: unknown,\n path: string,\n options: {\n positive?: boolean;\n nonNegative?: boolean;\n } = {}\n): readonly number[] {\n if (\n !Array.isArray(value) ||\n value.length === 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must be a non-empty array.\"\n );\n }\n const parsed =\n value.map(\n (entry, index) => {\n const itemPath =\n path +\n \"[\" +\n index +\n \"]\";\n if (options.positive) {\n return requirePositiveFinite(\n entry,\n itemPath\n );\n }\n if (\n options.nonNegative\n ) {\n return requireNonNegativeFinite(\n entry,\n itemPath\n );\n }\n return requireFinite(\n entry,\n itemPath\n );\n }\n );\n for (\n let index = 1;\n index < parsed.length;\n index += 1\n ) {\n if (\n parsed[index]! <=\n parsed[index - 1]!\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must be strictly increasing with unique values.\"\n );\n }\n }\n return parsed;\n}\n\nfunction parseKernel(\n value: unknown,\n path: string\n): LensPsfKernel {\n const record =\n requireRecord(value, path, [\"widthSamples\", \"heightSamples\", \"centerSampleX\", \"centerSampleY\", \"normalizedIntensity\", \"samplePitchMicrometersX\", \"samplePitchMicrometersY\"]);\n const widthSamples =\n requirePositiveSafeInteger(\n record.widthSamples,\n path + \".widthSamples\"\n );\n const heightSamples =\n requirePositiveSafeInteger(\n record.heightSamples,\n path + \".heightSamples\"\n );\n const total =\n widthSamples *\n heightSamples;\n if (!Number.isSafeInteger(total)) {\n throw new InvalidConfigurationError(\n path +\n \" sample count must remain a safe integer.\"\n );\n }\n const centerSampleX =\n requireNonNegativeSafeInteger(\n record.centerSampleX,\n path + \".centerSampleX\"\n );\n const centerSampleY =\n requireNonNegativeSafeInteger(\n record.centerSampleY,\n path + \".centerSampleY\"\n );\n if (\n centerSampleX >=\n widthSamples ||\n centerSampleY >=\n heightSamples\n ) {\n throw new InvalidConfigurationError(\n path +\n \" center sample must lie within the kernel grid.\"\n );\n }\n if (\n !Array.isArray(\n record.normalizedIntensity\n ) ||\n record\n .normalizedIntensity\n .length !== total\n ) {\n throw new InvalidConfigurationError(\n path +\n \".normalizedIntensity length must equal widthSamples × heightSamples.\"\n );\n }\n const normalizedIntensity =\n record\n .normalizedIntensity\n .map(\n (entry, index) =>\n requireNonNegativeFinite(\n entry,\n path +\n \".normalizedIntensity[\" +\n index +\n \"]\"\n )\n );\n const sum =\n normalizedIntensity.reduce(\n (acc, entry) =>\n acc + entry,\n 0\n );\n if (\n !Number.isFinite(sum) ||\n Math.abs(sum - 1) >\n 1e-10\n ) {\n throw new InvalidConfigurationError(\n path +\n \".normalizedIntensity must sum to one.\"\n );\n }\n\n return {\n widthSamples,\n heightSamples,\n samplePitchMicrometersX:\n requirePositiveFinite(\n record\n .samplePitchMicrometersX,\n path +\n \".samplePitchMicrometersX\"\n ),\n samplePitchMicrometersY:\n requirePositiveFinite(\n record\n .samplePitchMicrometersY,\n path +\n \".samplePitchMicrometersY\"\n ),\n centerSampleX,\n centerSampleY,\n normalizedIntensity\n };\n}\n\nfunction parseAxes(\n value: unknown\n): LensPsfGridAxes {\n const record =\n requireRecord(\n value,\n \"lensPsfProfile.axes\", [\"focalLengthMm\", \"focusDiopters\", \"apertureFNumber\", \"fieldXmm\", \"fieldYmm\", \"wavelengthNm\", \"signedDefocusImagePlaneMicrometers\"]\n );\n return {\n focalLengthMm:\n parseAxis(\n record.focalLengthMm,\n \"lensPsfProfile.axes.focalLengthMm\",\n {\n positive: true\n }\n ),\n focusDiopters:\n parseAxis(\n record.focusDiopters,\n \"lensPsfProfile.axes.focusDiopters\",\n {\n nonNegative: true\n }\n ),\n apertureFNumber:\n parseAxis(\n record.apertureFNumber,\n \"lensPsfProfile.axes.apertureFNumber\",\n {\n positive: true\n }\n ),\n fieldXmm:\n parseAxis(\n record.fieldXmm,\n \"lensPsfProfile.axes.fieldXmm\"\n ),\n fieldYmm:\n parseAxis(\n record.fieldYmm,\n \"lensPsfProfile.axes.fieldYmm\"\n ),\n wavelengthNm:\n parseAxis(\n record.wavelengthNm,\n \"lensPsfProfile.axes.wavelengthNm\",\n {\n positive: true\n }\n ),\n signedDefocusImagePlaneMicrometers:\n parseAxis(\n record\n .signedDefocusImagePlaneMicrometers,\n \"lensPsfProfile.axes.signedDefocusImagePlaneMicrometers\"\n )\n };\n}\n\nfunction parseCoordinate(\n value: unknown,\n path: string\n): LensSampledPsfGridCoordinate {\n const record =\n requireRecord(value, path, [\"focalLengthMm\", \"focusDiopters\", \"apertureFNumber\", \"fieldXmm\", \"fieldYmm\", \"wavelengthNm\", \"signedDefocusImagePlaneMicrometers\"]);\n return {\n focalLengthMm:\n requirePositiveFinite(\n record.focalLengthMm,\n path + \".focalLengthMm\"\n ),\n focusDiopters:\n requireNonNegativeFinite(\n record.focusDiopters,\n path + \".focusDiopters\"\n ),\n apertureFNumber:\n requirePositiveFinite(\n record.apertureFNumber,\n path +\n \".apertureFNumber\"\n ),\n fieldXmm:\n requireFinite(\n record.fieldXmm,\n path + \".fieldXmm\"\n ),\n fieldYmm:\n requireFinite(\n record.fieldYmm,\n path + \".fieldYmm\"\n ),\n wavelengthNm:\n requirePositiveFinite(\n record.wavelengthNm,\n path + \".wavelengthNm\"\n ),\n signedDefocusImagePlaneMicrometers:\n requireFinite(\n record\n .signedDefocusImagePlaneMicrometers,\n path +\n \".signedDefocusImagePlaneMicrometers\"\n )\n };\n}\n\nfunction coordinateKey(\n coordinate:\n LensSampledPsfGridCoordinate\n): string {\n return AXIS_KEYS.map(\n (key) =>\n coordinate[key]\n .toString()\n ).join(\"|\");\n}\n\nfunction axisContains(\n values:\n readonly number[],\n target: number\n): boolean {\n return values.some(\n (value) =>\n value === target\n );\n}\n\nfunction validateNodeCoordinate(\n axes: LensPsfGridAxes,\n coordinate:\n LensSampledPsfGridCoordinate,\n path: string\n): void {\n for (\n const key of AXIS_KEYS\n ) {\n if (\n !axisContains(\n axes[key],\n coordinate[key]\n )\n ) {\n throw new InvalidConfigurationError(\n path +\n \".\" +\n key +\n \" must exactly match one declared grid-axis value.\"\n );\n }\n }\n}\n\nfunction parseNode(\n value: unknown,\n index: number,\n axes: LensPsfGridAxes,\n status:\n LensPsfScientificStatus\n): LensSampledPsfGridNode {\n const path =\n \"lensPsfProfile.nodes[\" +\n index +\n \"]\";\n const record =\n requireRecord(value, path, [\"coordinate\", \"uncertainty\", \"nodeId\", \"kernel\", \"bestFocusImagePlaneOffsetMicrometers\", \"relativePupilThroughputFactor\", \"evidence\"]);\n const coordinate =\n parseCoordinate(\n record.coordinate,\n path + \".coordinate\"\n );\n validateNodeCoordinate(\n axes,\n coordinate,\n path + \".coordinate\"\n );\n const uncertainty =\n parseUncertainty(\n record.uncertainty,\n path + \".uncertainty\"\n );\n if (\n status === \"calibrated\" &&\n uncertainty.kind ===\n \"not-quantified\"\n ) {\n throw new InvalidConfigurationError(\n path +\n \" calibrated PSF data must declare quantified relative uncertainty.\"\n );\n }\n\n return {\n nodeId:\n requireNonEmptyString(\n record.nodeId,\n path + \".nodeId\"\n ),\n coordinate,\n kernel:\n parseKernel(\n record.kernel,\n path + \".kernel\"\n ),\n bestFocusImagePlaneOffsetMicrometers:\n requireFinite(\n record\n .bestFocusImagePlaneOffsetMicrometers,\n path +\n \".bestFocusImagePlaneOffsetMicrometers\"\n ),\n relativePupilThroughputFactor:\n requireUnitInterval(\n record\n .relativePupilThroughputFactor,\n path +\n \".relativePupilThroughputFactor\"\n ),\n evidence:\n parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n ),\n uncertainty\n };\n}\n\nfunction expectedNodeCount(\n axes: LensPsfGridAxes\n): number {\n let count = 1;\n for (\n const key of AXIS_KEYS\n ) {\n count *= axes[key].length;\n if (\n !Number.isSafeInteger(count) ||\n count > 100_000\n ) {\n throw new InvalidConfigurationError(\n \"lensPsfProfile regular grid must contain at most 100000 nodes.\"\n );\n }\n }\n return count;\n}\n\nfunction sameKernelGeometry(\n first: LensPsfKernel,\n second: LensPsfKernel\n): boolean {\n return (\n first.widthSamples ===\n second.widthSamples &&\n first.heightSamples ===\n second.heightSamples &&\n first\n .samplePitchMicrometersX ===\n second\n .samplePitchMicrometersX &&\n first\n .samplePitchMicrometersY ===\n second\n .samplePitchMicrometersY &&\n first.centerSampleX ===\n second.centerSampleX &&\n first.centerSampleY ===\n second.centerSampleY\n );\n}\n\n/** Private profile declarations owned by the engine, registered by markEngineOwnedLensSampledPsfProfile. */\nconst ENGINE_OWNED_PROFILES = new WeakSet<object>();\n/** Deep-frozen parse of a deep-frozen engine-owned declaration. */\nconst PARSED_OWNED_PROFILES = new WeakMap<object, LensSampledPsfProfile>();\n/** Nodes by grid position (see buildGridNodeIndex). */\ninterface GridNodeIndex {\n readonly strides: readonly number[];\n readonly nodes: readonly (LensSampledPsfGridNode | undefined)[];\n}\n/** Grid node index of a cached, deep-frozen parse. */\nconst TRUSTED_NODE_INDEX = new WeakMap<LensSampledPsfProfile, GridNodeIndex>();\n\n/**\n * Internal: registers a private profile declaration owned by the engine, so that repeated\n * resolveLensSampledPsf calls reuse one parse. The declaration is a structured clone that caller code\n * never sees.\n *\n * The first resolve parses it exactly like untrusted input. It then deep-freezes the declaration and\n * caches the frozen parse with its node index. A frozen declaration cannot change, so the cached\n * parse stays exact. Caller objects that were never registered are always parsed again.\n */\nexport function markEngineOwnedLensSampledPsfProfile(value: unknown): void {\n if (typeof value === \"object\" && value !== null) ENGINE_OWNED_PROFILES.add(value);\n}\n\nfunction parseOwnedOrUntrustedProfile(value: unknown): LensSampledPsfProfile {\n if (typeof value !== \"object\" || value === null || !ENGINE_OWNED_PROFILES.has(value)) {\n return parseLensSampledPsfProfile(value);\n }\n const cached = PARSED_OWNED_PROFILES.get(value);\n if (cached !== undefined) return cached;\n const parsed = parseLensSampledPsfProfile(value);\n try {\n freezeOwnedData(value);\n } catch {\n // Not plain data that freezeOwnedData accepts (for example typed-array storage), so do not cache.\n ENGINE_OWNED_PROFILES.delete(value);\n return parsed;\n }\n freezeOwnedData(parsed);\n TRUSTED_NODE_INDEX.set(parsed, buildGridNodeIndex(parsed));\n PARSED_OWNED_PROFILES.set(value, parsed);\n return parsed;\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 * A sampled lens PSF is tied to an exact generic optical state and to declared ranges of field\n * position, wavelength and signed defocus. Interpolation stays inside those declared ranges. It keeps\n * the normalized shape separate from the throughput. MTF (modulation transfer function) data alone\n * has no phase or spatial information, so it cannot justify rendering one unique PSF.\n * @param value - unknown. Untrusted input; TypeScript types alone are not validation.\n * @returns LensSampledPsfProfile. 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 parseLensSampledPsfProfile(\n value: unknown\n): LensSampledPsfProfile {\n const record =\n requireRecord(\n value,\n \"lensPsfProfile\", [\"schemaVersion\", \"opticalDomain\", \"coordinateSystem\", \"fieldAxes\", \"kernelEnergyNormalization\", \"interpolation\", \"throughputOwnership\", \"sensorOpticalStackIncluded\", \"sensorSamplingIncluded\", \"reconstructionIncluded\", \"strayLightIncluded\", \"scientificStatus\", \"responseIncludes\", \"axes\", \"nodes\", \"profileId\", \"profileVersion\", \"evidence\", \"limitations\"]\n );\n if (\n record.schemaVersion !==\n LENS_SAMPLED_PSF_PROFILE_SCHEMA_VERSION\n ) {\n throw new InvalidConfigurationError(\n 'lensPsfProfile.schemaVersion must be \"' +\n LENS_SAMPLED_PSF_PROFILE_SCHEMA_VERSION +\n '\".'\n );\n }\n if (\n record.opticalDomain !==\n \"lens-primary-optical-path-only\"\n ) {\n throw new InvalidConfigurationError(\n 'lensPsfProfile.opticalDomain must be \"lens-primary-optical-path-only\".'\n );\n }\n if (\n record.coordinateSystem !==\n \"image-plane-metric\" ||\n record.fieldAxes !==\n \"+X right, +Y up\"\n ) {\n throw new InvalidConfigurationError(\n \"lensPsfProfile image-plane coordinate semantics are invalid.\"\n );\n }\n if (\n record.kernelEnergyNormalization !==\n \"unit-energy-shape\" ||\n !(LENS_SAMPLED_PSF_INTERPOLATIONS as readonly unknown[]).includes(\n record.interpolation\n ) ||\n record.throughputOwnership !==\n \"separate-relative-pupil-throughput-factor\"\n ) {\n throw new InvalidConfigurationError(\n \"lensPsfProfile normalization/interpolation/throughput ownership is 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 lens PSF profiles must remain lens-primary-optical-path-only and exclude sensor/reconstruction/stray-light effects.\"\n );\n }\n\n const status =\n parseStatus(\n record.scientificStatus,\n \"lensPsfProfile.scientificStatus\"\n );\n const response =\n requireRecord(\n record.responseIncludes,\n \"lensPsfProfile.responseIncludes\", [\"diffraction\", \"aberration\", \"defocus\", \"pupilClippingShape\"]\n );\n for (\n const key of [\n \"diffraction\",\n \"aberration\",\n \"defocus\",\n \"pupilClippingShape\"\n ] as const\n ) {\n if (\n typeof response[key] !==\n \"boolean\"\n ) {\n throw new InvalidConfigurationError(\n \"lensPsfProfile.responseIncludes.\" +\n key +\n \" must be boolean.\"\n );\n }\n }\n const axes =\n parseAxes(record.axes);\n if (\n !Array.isArray(\n record.nodes\n )\n ) {\n throw new InvalidConfigurationError(\n \"lensPsfProfile.nodes must be an array.\"\n );\n }\n if (\n record.nodes.length !==\n expectedNodeCount(axes)\n ) {\n throw new InvalidConfigurationError(\n \"lensPsfProfile.nodes must contain exactly one node for every regular-grid coordinate.\"\n );\n }\n const nodes =\n record.nodes.map(\n (node, index) =>\n parseNode(\n node,\n index,\n axes,\n status\n )\n );\n const ids =\n nodes.map(\n (node) =>\n node.nodeId\n );\n if (\n new Set(ids).size !==\n ids.length\n ) {\n throw new InvalidConfigurationError(\n \"lensPsfProfile.nodes must not contain duplicate nodeId values.\"\n );\n }\n const coordinateKeys =\n nodes.map(\n (node) =>\n coordinateKey(\n node.coordinate\n )\n );\n if (\n new Set(coordinateKeys).size !==\n coordinateKeys.length\n ) {\n throw new InvalidConfigurationError(\n \"lensPsfProfile.nodes must not contain duplicate grid coordinates.\"\n );\n }\n\n const firstKernel =\n nodes[0]?.kernel;\n if (firstKernel === undefined) {\n throw new InvalidConfigurationError(\n \"lensPsfProfile.nodes must not be empty.\"\n );\n }\n for (\n const node of nodes\n ) {\n if (\n !sameKernelGeometry(\n firstKernel,\n node.kernel\n )\n ) {\n throw new InvalidConfigurationError(\n \"Every lensPsfProfile node must use identical PSF kernel grid geometry for multilinear interpolation.\"\n );\n }\n }\n\n if (\n record.interpolation ===\n \"rotationally-symmetric-radial-field-centroid-aligned\"\n ) {\n if (\n axes.fieldYmm.length !== 1 ||\n axes.fieldYmm[0] !== 0 ||\n axes.fieldXmm.some((value) => value < 0)\n ) {\n throw new InvalidConfigurationError(\n \"Rotationally symmetric PSF profiles must declare fieldYmm = [0] and non-negative fieldXmm radii.\"\n );\n }\n if (\n firstKernel.samplePitchMicrometersX !==\n firstKernel.samplePitchMicrometersY\n ) {\n throw new InvalidConfigurationError(\n \"Rotationally symmetric PSF profiles require square kernel sample pitch for rotation.\"\n );\n }\n }\n\n return {\n schemaVersion:\n LENS_SAMPLED_PSF_PROFILE_SCHEMA_VERSION,\n profileId:\n requireNonEmptyString(\n record.profileId,\n \"lensPsfProfile.profileId\"\n ),\n profileVersion:\n requireNonEmptyString(\n record.profileVersion,\n \"lensPsfProfile.profileVersion\"\n ),\n scientificStatus:\n status,\n opticalDomain:\n \"lens-primary-optical-path-only\",\n coordinateSystem:\n \"image-plane-metric\",\n fieldAxes:\n \"+X right, +Y up\",\n kernelEnergyNormalization:\n \"unit-energy-shape\",\n interpolation:\n record.interpolation as LensSampledPsfInterpolation,\n throughputOwnership:\n \"separate-relative-pupil-throughput-factor\",\n responseIncludes: {\n diffraction:\n response.diffraction as boolean,\n aberration:\n response.aberration as boolean,\n defocus:\n response.defocus as boolean,\n pupilClippingShape:\n response\n .pupilClippingShape as boolean\n },\n sensorOpticalStackIncluded:\n false,\n sensorSamplingIncluded:\n false,\n reconstructionIncluded:\n false,\n strayLightIncluded:\n false,\n axes,\n nodes,\n evidence:\n parseEvidenceList(\n record.evidence,\n \"lensPsfProfile.evidence\"\n ),\n limitations:\n parseLimitations(\n record.limitations,\n \"lensPsfProfile.limitations\"\n )\n };\n}\n\nfunction focusDiopters(\n focus: FocusPlane\n): number {\n const parsed =\n parseFocusPlane(focus);\n return parsed.kind ===\n \"infinity\"\n ? 0\n : 1 /\n parsed.distanceM;\n}\n\nfunction requireScientificFinite(\n value: number,\n path: string\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value)\n ) {\n throw new InvalidScientificInputError(\n path + \" must be finite.\"\n );\n }\n return value;\n}\n\nfunction requireScientificPositiveFinite(\n value: number,\n path: string\n): number {\n const parsed =\n requireScientificFinite(\n value,\n path\n );\n if (parsed <= 0) {\n throw new InvalidScientificInputError(\n path +\n \" must be greater than zero.\"\n );\n }\n return parsed;\n}\n\nfunction bracketAxis(\n values:\n readonly number[],\n target: number,\n path: string\n): AxisBracket {\n const minimum =\n values[0]!;\n const maximum =\n values[\n values.length - 1\n ]!;\n const scale =\n Math.max(\n 1,\n Math.abs(target),\n Math.abs(minimum),\n Math.abs(maximum)\n );\n const tolerance =\n Number.EPSILON *\n 64 *\n scale;\n if (\n target <\n minimum - tolerance ||\n target >\n maximum + tolerance\n ) {\n throw new InvalidScientificInputError(\n path +\n \" lies outside the declared PSF profile grid; extrapolation is not permitted.\"\n );\n }\n\n for (\n let index = 0;\n index < values.length;\n index += 1\n ) {\n const value = values[index]!;\n if (\n Math.abs(\n target - value\n ) <= tolerance\n ) {\n return {\n lower: value,\n upper: value,\n lowerIndex: index,\n upperIndex: index,\n fraction: 0,\n exact: true\n };\n }\n }\n\n for (\n let index = 0;\n index <\n values.length - 1;\n index += 1\n ) {\n const lower =\n values[index]!;\n const upper =\n values[index + 1]!;\n if (\n target > lower &&\n target < upper\n ) {\n return {\n lower,\n upper,\n lowerIndex: index,\n upperIndex: index + 1,\n fraction:\n (target - lower) /\n (upper - lower),\n exact: false\n };\n }\n }\n\n throw new InvalidScientificInputError(\n path +\n \" could not be bracketed inside the declared PSF profile grid.\"\n );\n}\n\nfunction queryCoordinate(\n input:\n ResolveLensSampledPsfInput\n): {\n coordinate:\n LensSampledPsfGridCoordinate;\n focus: FocusPlane;\n} {\n const focus =\n parseFocusPlane(\n input.focus\n );\n return {\n coordinate: {\n focalLengthMm:\n requireScientificPositiveFinite(\n input.focalLengthMm,\n \"focalLengthMm\"\n ),\n focusDiopters:\n focusDiopters(focus),\n apertureFNumber:\n requireScientificPositiveFinite(\n input.apertureFNumber,\n \"apertureFNumber\"\n ),\n fieldXmm:\n requireScientificFinite(\n input.fieldPointMm.x,\n \"fieldPointMm.x\"\n ),\n fieldYmm:\n requireScientificFinite(\n input.fieldPointMm.y,\n \"fieldPointMm.y\"\n ),\n wavelengthNm:\n requireScientificPositiveFinite(\n input.wavelengthNm,\n \"wavelengthNm\"\n ),\n signedDefocusImagePlaneMicrometers:\n requireScientificFinite(\n input\n .signedDefocusImagePlaneMicrometers,\n \"signedDefocusImagePlaneMicrometers\"\n )\n },\n focus\n };\n}\n\nfunction bracketCoordinate(\n axes: LensPsfGridAxes,\n coordinate:\n LensSampledPsfGridCoordinate\n): Record<AxisKey, AxisBracket> {\n return {\n focalLengthMm:\n bracketAxis(\n axes.focalLengthMm,\n coordinate.focalLengthMm,\n \"focalLengthMm\"\n ),\n focusDiopters:\n bracketAxis(\n axes.focusDiopters,\n coordinate.focusDiopters,\n \"focus\"\n ),\n apertureFNumber:\n bracketAxis(\n axes.apertureFNumber,\n coordinate.apertureFNumber,\n \"apertureFNumber\"\n ),\n fieldXmm:\n bracketAxis(\n axes.fieldXmm,\n coordinate.fieldXmm,\n \"fieldPointMm.x\"\n ),\n fieldYmm:\n bracketAxis(\n axes.fieldYmm,\n coordinate.fieldYmm,\n \"fieldPointMm.y\"\n ),\n wavelengthNm:\n bracketAxis(\n axes.wavelengthNm,\n coordinate.wavelengthNm,\n \"wavelengthNm\"\n ),\n signedDefocusImagePlaneMicrometers:\n bracketAxis(\n axes\n .signedDefocusImagePlaneMicrometers,\n coordinate\n .signedDefocusImagePlaneMicrometers,\n \"signedDefocusImagePlaneMicrometers\"\n )\n };\n}\n\n/** Flat-index strides of the regular grid over AXIS_KEYS (the last axis varies fastest). */\nfunction gridStrides(axes: LensPsfGridAxes): number[] {\n const strides = new Array<number>(AXIS_KEYS.length);\n let stride = 1;\n for (let a = AXIS_KEYS.length - 1; a >= 0; a -= 1) {\n strides[a] = stride;\n stride *= axes[AXIS_KEYS[a]!].length;\n }\n return strides;\n}\n\n/**\n * Nodes indexed by grid position. Node coordinates match declared axis values exactly (checked by the\n * parser, with `===`, so −0 and 0 are one position) and are unique, so each position holds at most one node.\n */\nfunction buildGridNodeIndex(profile: LensSampledPsfProfile): GridNodeIndex {\n const strides = gridStrides(profile.axes);\n const nodes = new Array<LensSampledPsfGridNode | undefined>(AXIS_KEYS.reduce((n, key) => n * profile.axes[key].length, 1));\n for (const node of profile.nodes) {\n let flat = 0;\n for (let a = 0; a < AXIS_KEYS.length; a += 1) {\n const key = AXIS_KEYS[a]!;\n flat += profile.axes[key].indexOf(node.coordinate[key]) * strides[a]!;\n }\n nodes[flat] = node;\n }\n return { strides, nodes };\n}\n\n/**\n * The multilinear corners of a bracketed query and their weights, in a fixed order: axes in AXIS_KEYS order,\n * lower before upper, zero-weight options skipped. Each weight is the product of its per-axis weights in that order.\n */\nfunction resolveWeightedNodes(\n profile:\n LensSampledPsfProfile,\n brackets:\n Record<\n AxisKey,\n AxisBracket\n >\n): readonly WeightedNode[] {\n const index = TRUSTED_NODE_INDEX.get(profile) ?? buildGridNodeIndex(profile);\n let flats = [0], weights = [1];\n for (let a = 0; a < AXIS_KEYS.length; a += 1) {\n const bracket = brackets[AXIS_KEYS[a]!], stride = index.strides[a]!;\n const nextFlats: number[] = [], nextWeights: number[] = [];\n for (let c = 0; c < flats.length; c += 1) {\n if (bracket.exact) {\n nextFlats.push(flats[c]! + bracket.lowerIndex * stride);\n nextWeights.push(weights[c]! * 1);\n continue;\n }\n const lowerWeight = 1 - bracket.fraction, upperWeight = bracket.fraction;\n if (lowerWeight !== 0) { nextFlats.push(flats[c]! + bracket.lowerIndex * stride); nextWeights.push(weights[c]! * lowerWeight); }\n if (upperWeight !== 0) { nextFlats.push(flats[c]! + bracket.upperIndex * stride); nextWeights.push(weights[c]! * upperWeight); }\n }\n flats = nextFlats;\n weights = nextWeights;\n }\n return flats.map((flat, c) => {\n const node = index.nodes[flat];\n if (node === undefined) {\n throw new InvalidScientificInputError(\n \"PSF profile grid is missing a required interpolation corner.\"\n );\n }\n return { node, weight: weights[c]! };\n });\n}\n\nfunction interpolateKernel(\n weighted:\n readonly WeightedNode[]\n): LensPsfKernel {\n const first =\n weighted[0]?.node.kernel;\n if (first === undefined) {\n throw new InvalidScientificInputError(\n \"PSF interpolation requires at least one source node.\"\n );\n }\n const values =\n new Array<number>(\n first\n .normalizedIntensity\n .length\n ).fill(0);\n\n for (\n const entry of weighted\n ) {\n for (\n let index = 0;\n index < values.length;\n index += 1\n ) {\n values[index]! +=\n entry.weight *\n entry.node.kernel\n .normalizedIntensity[index]!;\n }\n }\n\n const sum =\n values.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 \"Interpolated PSF energy must remain finite and positive.\"\n );\n }\n const normalized =\n values.map(\n (value) =>\n value / sum\n );\n\n return {\n widthSamples:\n first.widthSamples,\n heightSamples:\n first.heightSamples,\n samplePitchMicrometersX:\n first\n .samplePitchMicrometersX,\n samplePitchMicrometersY:\n first\n .samplePitchMicrometersY,\n centerSampleX:\n first.centerSampleX,\n centerSampleY:\n first.centerSampleY,\n normalizedIntensity:\n normalized\n };\n}\n\nfunction kernelCentroid(\n kernel: LensPsfKernel\n): { x: number; y: number } {\n let sum = 0;\n let x = 0;\n let y = 0;\n for (let row = 0; row < kernel.heightSamples; row += 1) {\n for (let column = 0; column < kernel.widthSamples; column += 1) {\n const value = kernel.normalizedIntensity[row * kernel.widthSamples + column]!;\n sum += value;\n x += value * (column - kernel.centerSampleX);\n y += value * (row - kernel.centerSampleY);\n }\n }\n return { x: x / sum, y: y / sum };\n}\n\n/** Bilinear sample at fractional array coordinates; zero outside the kernel. */\nfunction bilinearSample(\n kernel: LensPsfKernel,\n column: number,\n row: number\n): number {\n const x0 = Math.floor(column);\n const y0 = Math.floor(row);\n const fx = column - x0;\n const fy = row - y0;\n const at = (x: number, y: number): number =>\n x < 0 || y < 0 || x >= kernel.widthSamples || y >= kernel.heightSamples\n ? 0\n : kernel.normalizedIntensity[y * kernel.widthSamples + x]!;\n const top = fx === 0 ? at(x0, y0) : (1 - fx) * at(x0, y0) + fx * at(x0 + 1, y0);\n if (fy === 0) {\n return top;\n }\n const bottom = fx === 0 ? at(x0, y0 + 1) : (1 - fx) * at(x0, y0 + 1) + fx * at(x0 + 1, y0 + 1);\n return (1 - fy) * top + fy * bottom;\n}\n\nfunction normalizedKernel(\n template: LensPsfKernel,\n values: readonly number[]\n): LensPsfKernel {\n const sum = values.reduce((acc, value) => acc + value, 0);\n if (!Number.isFinite(sum) || sum <= 0) {\n throw new InvalidScientificInputError(\n \"Interpolated PSF energy must remain finite and positive.\"\n );\n }\n return {\n widthSamples: template.widthSamples,\n heightSamples: template.heightSamples,\n samplePitchMicrometersX: template.samplePitchMicrometersX,\n samplePitchMicrometersY: template.samplePitchMicrometersY,\n centerSampleX: template.centerSampleX,\n centerSampleY: template.centerSampleY,\n normalizedIntensity: values.map((value) => value / sum)\n };\n}\n\n/**\n * Centroid-aligned interpolation. Each node kernel is shifted so its intensity centroid lands on the\n * weighted centroid. Then the multilinear weights are applied. A single exact node is returned\n * unchanged.\n */\nfunction interpolateKernelCentroidAligned(\n weighted: readonly WeightedNode[]\n): LensPsfKernel {\n const first = weighted[0]?.node.kernel;\n if (first === undefined) {\n throw new InvalidScientificInputError(\n \"PSF interpolation requires at least one source node.\"\n );\n }\n if (weighted.length === 1) {\n // An exact grid node is already a validated unit-energy kernel; return it bit-for-bit.\n return { ...first, normalizedIntensity: [...first.normalizedIntensity] };\n }\n const centroids = weighted.map((entry) => kernelCentroid(entry.node.kernel));\n const target = centroids.reduce(\n (acc, centroid, index) => ({\n x: acc.x + weighted[index]!.weight * centroid.x,\n y: acc.y + weighted[index]!.weight * centroid.y\n }),\n { x: 0, y: 0 }\n );\n const values = new Array<number>(first.normalizedIntensity.length).fill(0);\n weighted.forEach((entry, index) => {\n const dx = centroids[index]!.x - target.x;\n const dy = centroids[index]!.y - target.y;\n for (let row = 0; row < first.heightSamples; row += 1) {\n for (let column = 0; column < first.widthSamples; column += 1) {\n values[row * first.widthSamples + column]! +=\n entry.weight * bilinearSample(entry.node.kernel, column + dx, row + dy);\n }\n }\n });\n return normalizedKernel(first, values);\n}\n\n/** Rotates a kernel by angleRadians (counter-clockwise, +Y up) about its centre sample. */\nfunction rotateKernel(\n kernel: LensPsfKernel,\n angleRadians: number\n): LensPsfKernel {\n const cos = Math.cos(angleRadians);\n const sin = Math.sin(angleRadians);\n const values: number[] = [];\n for (let row = 0; row < kernel.heightSamples; row += 1) {\n // Array rows increase downward; image +Y is up.\n const y = kernel.centerSampleY - row;\n for (let column = 0; column < kernel.widthSamples; column += 1) {\n const x = column - kernel.centerSampleX;\n // Inverse rotation: destination (x, y) samples source R(-angle) (x, y).\n const sourceX = cos * x + sin * y;\n const sourceY = -sin * x + cos * y;\n values.push(\n bilinearSample(\n kernel,\n kernel.centerSampleX + sourceX,\n kernel.centerSampleY - sourceY\n )\n );\n }\n }\n return normalizedKernel(kernel, values);\n}\n\nfunction weightedScalar(\n weighted:\n readonly WeightedNode[],\n select:\n (\n node:\n LensSampledPsfGridNode\n ) => number\n): number {\n return weighted.reduce(\n (sum, entry) =>\n sum +\n entry.weight *\n select(entry.node),\n 0\n );\n}\n\n/** The resolved PSF before its result envelope; resolveLensSampledPsf and the lean native executor share it. */\ninterface ResolvedLensSampledPsfCore {\n profile: LensSampledPsfProfile;\n query: ReturnType<typeof queryCoordinate>;\n rotational: boolean;\n exact: boolean;\n weighted: readonly WeightedNode[];\n kernel: LensPsfKernel;\n bestFocus: number;\n throughput: number;\n}\n\nfunction resolveLensSampledPsfCore(\n input:\n ResolveLensSampledPsfInput\n): ResolvedLensSampledPsfCore {\n requireInputKeys(input, \"resolveLensSampledPsf\", [\"profile\", \"focalLengthMm\", \"focus\", \"apertureFNumber\", \"fieldPointMm\", \"wavelengthNm\", \"signedDefocusImagePlaneMicrometers\"]);\n const profile =\n parseOwnedOrUntrustedProfile(\n input.profile\n );\n const query =\n queryCoordinate(input);\n const rotational =\n profile.interpolation ===\n \"rotationally-symmetric-radial-field-centroid-aligned\";\n const fieldRadiusMm = Math.hypot(\n query.coordinate.fieldXmm,\n query.coordinate.fieldYmm\n );\n const fieldAngleRadians = rotational\n ? Math.atan2(query.coordinate.fieldYmm, query.coordinate.fieldXmm)\n : 0;\n const brackets =\n bracketCoordinate(\n profile.axes,\n rotational\n ? { ...query.coordinate, fieldXmm: fieldRadiusMm, fieldYmm: 0 }\n : query.coordinate\n );\n const weighted =\n resolveWeightedNodes(\n profile,\n brackets\n );\n const exact =\n AXIS_KEYS.every(\n (key) =>\n brackets[key].exact\n ) && fieldAngleRadians === 0;\n const kernel =\n profile.interpolation === \"bounded-regular-grid-multilinear\"\n ? interpolateKernel(weighted)\n : fieldAngleRadians === 0\n ? interpolateKernelCentroidAligned(weighted)\n : rotateKernel(\n interpolateKernelCentroidAligned(weighted),\n fieldAngleRadians\n );\n const bestFocus =\n weightedScalar(\n weighted,\n (node) =>\n node\n .bestFocusImagePlaneOffsetMicrometers\n );\n // A multilinear blend is a convex combination, so it cannot exceed its largest node value. But its\n // floating-point weights can sum to a few ulps above 1. A result above 1 that lies within\n // 8·ε·(node count)·max of the largest node is that rounding error. It is clamped to the largest node\n // value (≤ 1, so the result is again a declared value). Results already within [0, 1] are unchanged.\n const blended =\n weightedScalar(\n weighted,\n (node) =>\n node\n .relativePupilThroughputFactor\n );\n const largestThroughput = Math.max(...weighted.map((entry) => entry.node.relativePupilThroughputFactor));\n const throughput =\n blended > 1 && largestThroughput <= 1 &&\n blended - largestThroughput <= 8 * Number.EPSILON * weighted.length * Math.max(1, largestThroughput)\n ? largestThroughput\n : blended;\n if (\n !Number.isFinite(\n bestFocus\n ) ||\n !Number.isFinite(\n throughput\n ) ||\n throughput < 0 ||\n throughput > 1\n ) {\n throw new InvalidScientificInputError(\n \"Interpolated PSF metadata must remain finite and physically bounded.\"\n );\n }\n\n return { profile, query, rotational, exact, weighted, kernel, bestFocus, throughput };\n}\n\n/**\n * Internal (2.0 performance): the kernel resolveLensSampledPsf returns for the same input, computed by\n * the same code without building the result envelope. Throws whenever resolveLensSampledPsf would throw\n * before its envelope. Not exported from the package.\n */\nexport function resolveLensSampledPsfKernel(\n input:\n ResolveLensSampledPsfInput\n): LensPsfKernel {\n return resolveLensSampledPsfCore(input).kernel;\n}\n\n/**\n * Resolves the sampled PSF for a declared optical state and query point. It never extrapolates and\n * never invents missing dimensions.\n *\n * A sampled lens PSF is tied to an exact generic optical state and to declared ranges of field\n * position, wavelength and signed defocus. Interpolation stays inside those declared ranges. It keeps\n * the normalized shape separate from the throughput. MTF (modulation transfer function) data alone\n * has no phase or spatial information, so it cannot justify rendering one unique PSF.\n * @param input - ResolveLensSampledPsfInput. See that type for coordinates, units and profile binding.\n * @returns CalculationResult<ResolvedLensSampledPsf>. 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 resolveLensSampledPsf(\n input:\n ResolveLensSampledPsfInput\n): CalculationResult<ResolvedLensSampledPsf> {\n const { profile, query, rotational, exact, weighted, kernel, bestFocus, throughput } =\n resolveLensSampledPsfCore(input);\n return approximationResult(\n {\n profileId:\n profile.profileId,\n profileVersion:\n profile.profileVersion,\n scientificStatus:\n profile.scientificStatus,\n resolutionStatus:\n exact\n ? \"exact-grid-sample\"\n : \"interpolated\",\n coordinate:\n query.coordinate,\n focus:\n query.focus,\n kernel,\n bestFocusImagePlaneOffsetMicrometers:\n bestFocus,\n relativePupilThroughputFactor:\n throughput,\n sourceNodes:\n weighted.map(\n (entry) => ({\n nodeId:\n entry.node.nodeId,\n weight:\n entry.weight,\n evidence:\n entry.node.evidence,\n uncertainty:\n entry.node\n .uncertainty\n })\n ),\n responseIncludes: {\n ...profile\n .responseIncludes\n },\n throughputOwnership:\n \"separate-relative-pupil-throughput-factor\",\n longitudinalChromaticFocusMayVaryWithWavelength:\n true,\n fieldCurvatureMayVaryWithFieldPosition:\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 },\n profile.interpolation === \"bounded-regular-grid-multilinear\"\n ? \"lens-sampled-psf-bounded-interpolation\"\n : rotational\n ? \"lens-sampled-psf-rotational-centroid-aligned-interpolation\"\n : \"lens-sampled-psf-centroid-aligned-interpolation\",\n \"1.0.0\",\n [\n ...(profile.interpolation === \"bounded-regular-grid-multilinear\"\n ? []\n : [\n \"Node kernels are translated to the weighted intensity centroid before blending (bilinear resampling, outside samples zero, renormalised), so shifted PSFs blend into one peak.\",\n ...(rotational\n ? [\"Rotationally symmetric lens: nodes along +X are interpolated at the field radius and the kernel is rotated by the field azimuth.\"]\n : [])\n ]),\n \"PSF intensity is a unit-energy shape; relative pupil throughput remains a separate factor for the optical-throughput path.\",\n \"Regular-grid interpolation is bounded and never extrapolates beyond declared focal-length, focus, aperture, field, wavelength or signed-defocus axes.\",\n \"Full 2D image-plane kernel orientation is preserved in +X right, +Y up coordinates; no radial or sagittal/tangential averaging is forced.\",\n \"bestFocusImagePlaneOffsetMicrometers may vary with field and wavelength, representing field-curvature and longitudinal-chromatic-focus behavior without changing geometric distortion or lateral chromatic position.\",\n \"Lens PSF remains upstream of sensor optical stack, sampling and reconstruction, and excludes stray-light/ghosting contributions.\",\n \"No scalar lens-quality, sharpness or bokeh-quality score is produced.\"\n ]\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 * A sampled lens PSF is tied to an exact generic optical state and to declared ranges of field\n * position, wavelength and signed defocus. Interpolation stays inside those declared ranges. It keeps\n * the normalized shape separate from the throughput. MTF (modulation transfer function) data alone\n * has no phase or spatial information, so it cannot justify rendering one unique PSF.\n * @param value - unknown. Untrusted input; TypeScript types alone are not validation.\n * @returns LensMtfDiagnosticProfile. 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 parseLensMtfDiagnosticProfile(\n value: unknown\n): LensMtfDiagnosticProfile {\n const record =\n requireRecord(\n value,\n \"lensMtfProfile\", [\"schemaVersion\", \"opticalDomain\", \"phaseInformationAvailable\", \"magnitudeMeaning\", \"samples\", \"fieldPointMm\", \"wavelengthNm\", \"profileId\", \"profileVersion\", \"focalLengthMm\", \"focus\", \"apertureFNumber\", \"evidence\", \"limitations\"]\n );\n if (\n record.schemaVersion !==\n LENS_MTF_DIAGNOSTIC_PROFILE_SCHEMA_VERSION\n ) {\n throw new InvalidConfigurationError(\n 'lensMtfProfile.schemaVersion must be \"' +\n LENS_MTF_DIAGNOSTIC_PROFILE_SCHEMA_VERSION +\n '\".'\n );\n }\n if (\n record.opticalDomain !==\n \"lens-primary-optical-path-only\" ||\n record.phaseInformationAvailable !==\n false ||\n record.magnitudeMeaning !==\n \"mtf-magnitude-only\"\n ) {\n throw new InvalidConfigurationError(\n \"lensMtfProfile optical/phase semantics are invalid.\"\n );\n }\n if (\n !Array.isArray(\n record.samples\n ) ||\n record.samples.length ===\n 0\n ) {\n throw new InvalidConfigurationError(\n \"lensMtfProfile.samples must be a non-empty array.\"\n );\n }\n let priorFrequency =\n -1;\n const samples =\n record.samples.map(\n (entry, index) => {\n const path =\n \"lensMtfProfile.samples[\" +\n index +\n \"]\";\n const sample =\n requireRecord(\n entry,\n path, [\"spatialFrequencyCyclesPerMm\", \"sagittalMagnitude\", \"tangentialMagnitude\"]\n );\n const frequency =\n requireNonNegativeFinite(\n sample\n .spatialFrequencyCyclesPerMm,\n path +\n \".spatialFrequencyCyclesPerMm\"\n );\n if (\n frequency <=\n priorFrequency\n ) {\n throw new InvalidConfigurationError(\n \"lensMtfProfile sample frequencies must be strictly increasing.\"\n );\n }\n priorFrequency =\n frequency;\n return {\n spatialFrequencyCyclesPerMm:\n frequency,\n sagittalMagnitude:\n requireUnitInterval(\n sample\n .sagittalMagnitude,\n path +\n \".sagittalMagnitude\"\n ),\n tangentialMagnitude:\n requireUnitInterval(\n sample\n .tangentialMagnitude,\n path +\n \".tangentialMagnitude\"\n )\n };\n }\n );\n const field =\n requireRecord(\n record.fieldPointMm,\n \"lensMtfProfile.fieldPointMm\", [\"x\", \"y\"]\n );\n const wavelength =\n record.wavelengthNm ===\n null\n ? null\n : requirePositiveFinite(\n record.wavelengthNm,\n \"lensMtfProfile.wavelengthNm\"\n );\n\n return {\n schemaVersion:\n LENS_MTF_DIAGNOSTIC_PROFILE_SCHEMA_VERSION,\n profileId:\n requireNonEmptyString(\n record.profileId,\n \"lensMtfProfile.profileId\"\n ),\n profileVersion:\n requireNonEmptyString(\n record.profileVersion,\n \"lensMtfProfile.profileVersion\"\n ),\n opticalDomain:\n \"lens-primary-optical-path-only\",\n phaseInformationAvailable:\n false,\n magnitudeMeaning:\n \"mtf-magnitude-only\",\n fieldPointMm: {\n x:\n requireFinite(\n field.x,\n \"lensMtfProfile.fieldPointMm.x\"\n ),\n y:\n requireFinite(\n field.y,\n \"lensMtfProfile.fieldPointMm.y\"\n )\n },\n focalLengthMm:\n requirePositiveFinite(\n record.focalLengthMm,\n \"lensMtfProfile.focalLengthMm\"\n ),\n focus:\n parseFocusPlane(\n record.focus\n ),\n apertureFNumber:\n requirePositiveFinite(\n record.apertureFNumber,\n \"lensMtfProfile.apertureFNumber\"\n ),\n wavelengthNm:\n wavelength,\n samples,\n evidence:\n parseEvidenceList(\n record.evidence,\n \"lensMtfProfile.evidence\"\n ),\n limitations:\n parseLimitations(\n record.limitations,\n \"lensMtfProfile.limitations\"\n )\n };\n}\n\n/**\n * Explains why MTF-only evidence cannot determine one unique renderable PSF. Returns blockers instead\n * of making up phase information.\n *\n * A sampled lens PSF is tied to an exact generic optical state and to declared ranges of field\n * position, wavelength and signed defocus. Interpolation stays inside those declared ranges. It keeps\n * the normalized shape separate from the throughput. MTF (modulation transfer function) data alone\n * has no phase or spatial information, so it cannot justify rendering one unique PSF.\n * @param profile - LensMtfDiagnosticProfile. See that type for coordinates, units and profile binding.\n * @returns MtfOnlyPsfRenderabilityAssessment. Read the structured blockers before relying on any authorization.\n *\n * @see docs/API_REFERENCE.md for the root export and exact type graph.\n */\nexport function assessMtfOnlyPsfRenderability(\n profile:\n LensMtfDiagnosticProfile\n): MtfOnlyPsfRenderabilityAssessment {\n const parsed =\n parseLensMtfDiagnosticProfile(\n profile\n );\n return {\n profileId:\n parsed.profileId,\n psfReconstructionAuthorized:\n false,\n reason:\n \"mtf-magnitude-lacks-phase-and-does-not-uniquely-determine-psf\",\n diagnosticUseAuthorized:\n true\n };\n}\n"]}
1
+ {"version":3,"file":"lens-psf-profile.js","sourceRoot":"","sources":["../../src/optics/lens-psf-profile.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Sampled lens PSF (point-spread function) profiles, and MTF-only diagnostic profiles.\n *\n * The parsers validate untrusted input and return the normalized typed contract. Unknown enum\n * values, missing required fields and incompatible scientific data are rejected.\n *\n * The resolver finds the sampled PSF for a declared optical state and query point. It never\n * extrapolates and never invents missing dimensions.\n *\n * A sampled lens PSF is tied to an exact generic optical state and to declared ranges of field\n * position, wavelength and signed defocus. Interpolation stays inside those declared ranges. It keeps\n * the normalized shape separate from the throughput. MTF (modulation transfer function) data alone\n * has no phase or spatial information, so it cannot justify rendering one unique PSF.\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 { freezeOwnedData } from \"../core/owned-data.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 { requireInputKeys, rejectUnknownVariantFields, UNCERTAINTY_VARIANT_FIELDS, requireConfigRecord as requireRecord, requireTrimmedConfigString as requireNonEmptyString, requireConfigFinite as requireFinite, parseConfigScientificStatus as parseStatus, requireConfigNonNegativeSafeInteger as requireNonNegativeSafeInteger, requireConfigPositiveSafeInteger as requirePositiveSafeInteger, requireInputFinite as requireScientificFinite, parseConfigLimitations as parseLimitations, requireConfigFiniteAboveZero as requirePositiveFinite, requireConfigFiniteAtLeastZero as requireNonNegativeFinite, requireInputFiniteAboveZero as requireScientificPositiveFinite, requireConfigUnitInterval as requireUnitInterval } from \"../core/record-validation.js\";\n\nexport const LENS_SAMPLED_PSF_PROFILE_SCHEMA_VERSION =\n \"0.1.0\" as const;\nexport const LENS_MTF_DIAGNOSTIC_PROFILE_SCHEMA_VERSION =\n \"0.1.0\" as const;\n\nexport type LensPsfScientificStatus =\n | \"calibrated\"\n | \"approximation\";\n\nexport type LensPsfUncertainty =\n | {\n kind: \"relative\";\n fraction: number;\n basis: string;\n }\n | {\n kind: \"not-quantified\";\n limitation: string;\n };\n\n/**\n * Kernel interpolation between regular-grid nodes.\n * - `bounded-regular-grid-multilinear`: the legacy weighted sum of kernel values. Blending kernels\n * whose peaks sit at different positions gives several peaks.\n * - `bounded-regular-grid-centroid-aligned`: each node kernel is first shifted so its intensity\n * centroid sits at the weighted (interpolated) centroid. Then the same multilinear weights are\n * applied. Shifted or asymmetric PSFs therefore blend into one peak at the interpolated position.\n * - `rotationally-symmetric-radial-field-centroid-aligned`: for a rotationally symmetric lens. Nodes\n * are declared only along the +X field axis (fieldYmm = [0], fieldXmm >= 0). A query at field\n * (x, y) is interpolated, with centroid alignment, at radius hypot(x, y). The kernel is then\n * rotated by atan2(y, x) about its centre, with the kernel row index increasing with image +Y (the\n * convention the environment PSF quadrature applies), so an asymmetric kernel points the same way\n * as in the 2-D grid modes. The sample pitch must be square.\n * Shifts and rotations use bilinear resampling. This smooths the kernel slightly (by at most about\n * one sample). Samples outside the kernel are zero, and the result is renormalised to unit energy.\n */\nexport type LensSampledPsfInterpolation =\n | \"bounded-regular-grid-multilinear\"\n | \"bounded-regular-grid-centroid-aligned\"\n | \"rotationally-symmetric-radial-field-centroid-aligned\";\n\nconst LENS_SAMPLED_PSF_INTERPOLATIONS: readonly LensSampledPsfInterpolation[] = [\n \"bounded-regular-grid-multilinear\",\n \"bounded-regular-grid-centroid-aligned\",\n \"rotationally-symmetric-radial-field-centroid-aligned\"\n];\n\nexport interface LensPsfKernel {\n widthSamples: number;\n heightSamples: number;\n samplePitchMicrometersX: number;\n samplePitchMicrometersY: number;\n centerSampleX: number;\n centerSampleY: number;\n normalizedIntensity:\n readonly number[];\n}\n\nexport interface LensPsfGridAxes {\n focalLengthMm:\n readonly number[];\n focusDiopters:\n readonly number[];\n apertureFNumber:\n readonly number[];\n fieldXmm:\n readonly number[];\n fieldYmm:\n readonly number[];\n wavelengthNm:\n readonly number[];\n signedDefocusImagePlaneMicrometers:\n readonly number[];\n}\n\nexport interface LensSampledPsfGridCoordinate {\n focalLengthMm: number;\n focusDiopters: number;\n apertureFNumber: number;\n fieldXmm: number;\n fieldYmm: number;\n wavelengthNm: number;\n signedDefocusImagePlaneMicrometers:\n number;\n}\n\nexport interface LensSampledPsfGridNode {\n nodeId: string;\n coordinate:\n LensSampledPsfGridCoordinate;\n kernel: LensPsfKernel;\n bestFocusImagePlaneOffsetMicrometers:\n number;\n relativePupilThroughputFactor:\n number;\n evidence:\n readonly EvidenceProvenance[];\n uncertainty:\n LensPsfUncertainty;\n}\n\nexport interface LensSampledPsfProfile {\n schemaVersion:\n typeof LENS_SAMPLED_PSF_PROFILE_SCHEMA_VERSION;\n profileId: string;\n profileVersion: string;\n scientificStatus:\n LensPsfScientificStatus;\n opticalDomain:\n \"lens-primary-optical-path-only\";\n coordinateSystem:\n \"image-plane-metric\";\n fieldAxes:\n \"+X right, +Y up\";\n kernelEnergyNormalization:\n \"unit-energy-shape\";\n interpolation:\n LensSampledPsfInterpolation;\n throughputOwnership:\n \"separate-relative-pupil-throughput-factor\";\n responseIncludes: {\n diffraction: boolean;\n aberration: boolean;\n defocus: boolean;\n pupilClippingShape:\n boolean;\n };\n sensorOpticalStackIncluded:\n false;\n sensorSamplingIncluded:\n false;\n reconstructionIncluded:\n false;\n strayLightIncluded: false;\n axes: LensPsfGridAxes;\n nodes:\n readonly LensSampledPsfGridNode[];\n evidence:\n readonly EvidenceProvenance[];\n limitations: readonly string[];\n}\n\nexport interface ResolveLensSampledPsfInput {\n profile:\n LensSampledPsfProfile;\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\nexport interface ResolvedLensSampledPsf {\n profileId: string;\n profileVersion: string;\n scientificStatus:\n LensPsfScientificStatus;\n resolutionStatus:\n | \"exact-grid-sample\"\n | \"interpolated\";\n coordinate:\n LensSampledPsfGridCoordinate;\n focus: FocusPlane;\n kernel: LensPsfKernel;\n bestFocusImagePlaneOffsetMicrometers:\n number;\n relativePupilThroughputFactor:\n number;\n sourceNodes:\n readonly {\n nodeId: string;\n weight: number;\n evidence:\n readonly EvidenceProvenance[];\n uncertainty:\n LensPsfUncertainty;\n }[];\n responseIncludes:\n LensSampledPsfProfile[\"responseIncludes\"];\n throughputOwnership:\n \"separate-relative-pupil-throughput-factor\";\n longitudinalChromaticFocusMayVaryWithWavelength:\n true;\n fieldCurvatureMayVaryWithFieldPosition:\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}\n\nexport interface LensMtfDiagnosticSample {\n spatialFrequencyCyclesPerMm:\n number;\n sagittalMagnitude: number;\n tangentialMagnitude: number;\n}\n\nexport interface LensMtfDiagnosticProfile {\n schemaVersion:\n typeof LENS_MTF_DIAGNOSTIC_PROFILE_SCHEMA_VERSION;\n profileId: string;\n profileVersion: string;\n opticalDomain:\n \"lens-primary-optical-path-only\";\n phaseInformationAvailable:\n false;\n magnitudeMeaning:\n \"mtf-magnitude-only\";\n fieldPointMm: {\n x: number;\n y: number;\n };\n focalLengthMm: number;\n focus: FocusPlane;\n apertureFNumber: number;\n wavelengthNm: number | null;\n samples:\n readonly LensMtfDiagnosticSample[];\n evidence:\n readonly EvidenceProvenance[];\n limitations: readonly string[];\n}\n\nexport interface MtfOnlyPsfRenderabilityAssessment {\n profileId: string;\n psfReconstructionAuthorized:\n false;\n reason:\n \"mtf-magnitude-lacks-phase-and-does-not-uniquely-determine-psf\";\n diagnosticUseAuthorized: true;\n}\n\ninterface AxisBracket {\n lower: number;\n upper: number;\n /** Positions of lower and upper in the axis values. */\n lowerIndex: number;\n upperIndex: number;\n fraction: number;\n exact: boolean;\n}\n\ninterface WeightedNode {\n node:\n LensSampledPsfGridNode;\n weight: number;\n}\n\nconst AXIS_KEYS = [\n \"focalLengthMm\",\n \"focusDiopters\",\n \"apertureFNumber\",\n \"fieldXmm\",\n \"fieldYmm\",\n \"wavelengthNm\",\n \"signedDefocusImagePlaneMicrometers\"\n] as const;\n\ntype AxisKey =\n typeof AXIS_KEYS[number];\n\nexport function 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 return {\n kind: \"relative\",\n fraction:\n requireNonNegativeFinite(\n record.fraction,\n path + \".fraction\"\n ),\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 parseAxis(\n value: unknown,\n path: string,\n options: {\n positive?: boolean;\n nonNegative?: boolean;\n } = {}\n): readonly number[] {\n if (\n !Array.isArray(value) ||\n value.length === 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must be a non-empty array.\"\n );\n }\n const parsed =\n value.map(\n (entry, index) => {\n const itemPath =\n path +\n \"[\" +\n index +\n \"]\";\n if (options.positive) {\n return requirePositiveFinite(\n entry,\n itemPath\n );\n }\n if (\n options.nonNegative\n ) {\n return requireNonNegativeFinite(\n entry,\n itemPath\n );\n }\n return requireFinite(\n entry,\n itemPath\n );\n }\n );\n for (\n let index = 1;\n index < parsed.length;\n index += 1\n ) {\n if (\n parsed[index]! <=\n parsed[index - 1]!\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must be strictly increasing with unique values.\"\n );\n }\n }\n return parsed;\n}\n\nfunction parseKernel(\n value: unknown,\n path: string\n): LensPsfKernel {\n const record =\n requireRecord(value, path, [\"widthSamples\", \"heightSamples\", \"centerSampleX\", \"centerSampleY\", \"normalizedIntensity\", \"samplePitchMicrometersX\", \"samplePitchMicrometersY\"]);\n const widthSamples =\n requirePositiveSafeInteger(\n record.widthSamples,\n path + \".widthSamples\"\n );\n const heightSamples =\n requirePositiveSafeInteger(\n record.heightSamples,\n path + \".heightSamples\"\n );\n const total =\n widthSamples *\n heightSamples;\n if (!Number.isSafeInteger(total)) {\n throw new InvalidConfigurationError(\n path +\n \" sample count must remain a safe integer.\"\n );\n }\n const centerSampleX =\n requireNonNegativeSafeInteger(\n record.centerSampleX,\n path + \".centerSampleX\"\n );\n const centerSampleY =\n requireNonNegativeSafeInteger(\n record.centerSampleY,\n path + \".centerSampleY\"\n );\n if (\n centerSampleX >=\n widthSamples ||\n centerSampleY >=\n heightSamples\n ) {\n throw new InvalidConfigurationError(\n path +\n \" center sample must lie within the kernel grid.\"\n );\n }\n if (\n !Array.isArray(\n record.normalizedIntensity\n ) ||\n record\n .normalizedIntensity\n .length !== total\n ) {\n throw new InvalidConfigurationError(\n path +\n \".normalizedIntensity length must equal widthSamples × heightSamples.\"\n );\n }\n const normalizedIntensity =\n record\n .normalizedIntensity\n .map(\n (entry, index) =>\n requireNonNegativeFinite(\n entry,\n path +\n \".normalizedIntensity[\" +\n index +\n \"]\"\n )\n );\n const sum =\n normalizedIntensity.reduce(\n (acc, entry) =>\n acc + entry,\n 0\n );\n if (\n !Number.isFinite(sum) ||\n Math.abs(sum - 1) >\n 1e-10\n ) {\n throw new InvalidConfigurationError(\n path +\n \".normalizedIntensity must sum to one.\"\n );\n }\n\n return {\n widthSamples,\n heightSamples,\n samplePitchMicrometersX:\n requirePositiveFinite(\n record\n .samplePitchMicrometersX,\n path +\n \".samplePitchMicrometersX\"\n ),\n samplePitchMicrometersY:\n requirePositiveFinite(\n record\n .samplePitchMicrometersY,\n path +\n \".samplePitchMicrometersY\"\n ),\n centerSampleX,\n centerSampleY,\n normalizedIntensity\n };\n}\n\nfunction parseAxes(\n value: unknown\n): LensPsfGridAxes {\n const record =\n requireRecord(\n value,\n \"lensPsfProfile.axes\", [\"focalLengthMm\", \"focusDiopters\", \"apertureFNumber\", \"fieldXmm\", \"fieldYmm\", \"wavelengthNm\", \"signedDefocusImagePlaneMicrometers\"]\n );\n return {\n focalLengthMm:\n parseAxis(\n record.focalLengthMm,\n \"lensPsfProfile.axes.focalLengthMm\",\n {\n positive: true\n }\n ),\n focusDiopters:\n parseAxis(\n record.focusDiopters,\n \"lensPsfProfile.axes.focusDiopters\",\n {\n nonNegative: true\n }\n ),\n apertureFNumber:\n parseAxis(\n record.apertureFNumber,\n \"lensPsfProfile.axes.apertureFNumber\",\n {\n positive: true\n }\n ),\n fieldXmm:\n parseAxis(\n record.fieldXmm,\n \"lensPsfProfile.axes.fieldXmm\"\n ),\n fieldYmm:\n parseAxis(\n record.fieldYmm,\n \"lensPsfProfile.axes.fieldYmm\"\n ),\n wavelengthNm:\n parseAxis(\n record.wavelengthNm,\n \"lensPsfProfile.axes.wavelengthNm\",\n {\n positive: true\n }\n ),\n signedDefocusImagePlaneMicrometers:\n parseAxis(\n record\n .signedDefocusImagePlaneMicrometers,\n \"lensPsfProfile.axes.signedDefocusImagePlaneMicrometers\"\n )\n };\n}\n\nfunction parseCoordinate(\n value: unknown,\n path: string\n): LensSampledPsfGridCoordinate {\n const record =\n requireRecord(value, path, [\"focalLengthMm\", \"focusDiopters\", \"apertureFNumber\", \"fieldXmm\", \"fieldYmm\", \"wavelengthNm\", \"signedDefocusImagePlaneMicrometers\"]);\n return {\n focalLengthMm:\n requirePositiveFinite(\n record.focalLengthMm,\n path + \".focalLengthMm\"\n ),\n focusDiopters:\n requireNonNegativeFinite(\n record.focusDiopters,\n path + \".focusDiopters\"\n ),\n apertureFNumber:\n requirePositiveFinite(\n record.apertureFNumber,\n path +\n \".apertureFNumber\"\n ),\n fieldXmm:\n requireFinite(\n record.fieldXmm,\n path + \".fieldXmm\"\n ),\n fieldYmm:\n requireFinite(\n record.fieldYmm,\n path + \".fieldYmm\"\n ),\n wavelengthNm:\n requirePositiveFinite(\n record.wavelengthNm,\n path + \".wavelengthNm\"\n ),\n signedDefocusImagePlaneMicrometers:\n requireFinite(\n record\n .signedDefocusImagePlaneMicrometers,\n path +\n \".signedDefocusImagePlaneMicrometers\"\n )\n };\n}\n\nfunction coordinateKey(\n coordinate:\n LensSampledPsfGridCoordinate\n): string {\n return AXIS_KEYS.map(\n (key) =>\n coordinate[key]\n .toString()\n ).join(\"|\");\n}\n\nfunction axisContains(\n values:\n readonly number[],\n target: number\n): boolean {\n return values.some(\n (value) =>\n value === target\n );\n}\n\nfunction validateNodeCoordinate(\n axes: LensPsfGridAxes,\n coordinate:\n LensSampledPsfGridCoordinate,\n path: string\n): void {\n for (\n const key of AXIS_KEYS\n ) {\n if (\n !axisContains(\n axes[key],\n coordinate[key]\n )\n ) {\n throw new InvalidConfigurationError(\n path +\n \".\" +\n key +\n \" must exactly match one declared grid-axis value.\"\n );\n }\n }\n}\n\nfunction parseNode(\n value: unknown,\n index: number,\n axes: LensPsfGridAxes,\n status:\n LensPsfScientificStatus\n): LensSampledPsfGridNode {\n const path =\n \"lensPsfProfile.nodes[\" +\n index +\n \"]\";\n const record =\n requireRecord(value, path, [\"coordinate\", \"uncertainty\", \"nodeId\", \"kernel\", \"bestFocusImagePlaneOffsetMicrometers\", \"relativePupilThroughputFactor\", \"evidence\"]);\n const coordinate =\n parseCoordinate(\n record.coordinate,\n path + \".coordinate\"\n );\n validateNodeCoordinate(\n axes,\n coordinate,\n path + \".coordinate\"\n );\n const uncertainty =\n parseUncertainty(\n record.uncertainty,\n path + \".uncertainty\"\n );\n if (\n status === \"calibrated\" &&\n uncertainty.kind ===\n \"not-quantified\"\n ) {\n throw new InvalidConfigurationError(\n path +\n \" calibrated PSF data must declare quantified relative uncertainty.\"\n );\n }\n\n return {\n nodeId:\n requireNonEmptyString(\n record.nodeId,\n path + \".nodeId\"\n ),\n coordinate,\n kernel:\n parseKernel(\n record.kernel,\n path + \".kernel\"\n ),\n bestFocusImagePlaneOffsetMicrometers:\n requireFinite(\n record\n .bestFocusImagePlaneOffsetMicrometers,\n path +\n \".bestFocusImagePlaneOffsetMicrometers\"\n ),\n relativePupilThroughputFactor:\n requireUnitInterval(\n record\n .relativePupilThroughputFactor,\n path +\n \".relativePupilThroughputFactor\"\n ),\n evidence:\n parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n ),\n uncertainty\n };\n}\n\nfunction expectedNodeCount(\n axes: LensPsfGridAxes\n): number {\n let count = 1;\n for (\n const key of AXIS_KEYS\n ) {\n count *= axes[key].length;\n if (\n !Number.isSafeInteger(count) ||\n count > 100_000\n ) {\n throw new InvalidConfigurationError(\n \"lensPsfProfile regular grid must contain at most 100000 nodes.\"\n );\n }\n }\n return count;\n}\n\nfunction sameKernelGeometry(\n first: LensPsfKernel,\n second: LensPsfKernel\n): boolean {\n return (\n first.widthSamples ===\n second.widthSamples &&\n first.heightSamples ===\n second.heightSamples &&\n first\n .samplePitchMicrometersX ===\n second\n .samplePitchMicrometersX &&\n first\n .samplePitchMicrometersY ===\n second\n .samplePitchMicrometersY &&\n first.centerSampleX ===\n second.centerSampleX &&\n first.centerSampleY ===\n second.centerSampleY\n );\n}\n\n/** Private profile declarations owned by the engine, registered by markEngineOwnedLensSampledPsfProfile. */\nconst ENGINE_OWNED_PROFILES = new WeakSet<object>();\n/** Deep-frozen parse of a deep-frozen engine-owned declaration. */\nconst PARSED_OWNED_PROFILES = new WeakMap<object, LensSampledPsfProfile>();\n/** Nodes by grid position (see buildGridNodeIndex). */\ninterface GridNodeIndex {\n readonly strides: readonly number[];\n readonly nodes: readonly (LensSampledPsfGridNode | undefined)[];\n}\n/** Grid node index of a cached, deep-frozen parse. */\nconst TRUSTED_NODE_INDEX = new WeakMap<LensSampledPsfProfile, GridNodeIndex>();\n\n/**\n * Internal: registers a private profile declaration owned by the engine, so that repeated\n * resolveLensSampledPsf calls reuse one parse. The declaration is a structured clone that caller code\n * never sees.\n *\n * The first resolve parses it exactly like untrusted input. It then deep-freezes the declaration and\n * caches the frozen parse with its node index. A frozen declaration cannot change, so the cached\n * parse stays exact. Caller objects that were never registered are always parsed again.\n */\nexport function markEngineOwnedLensSampledPsfProfile(value: unknown): void {\n if (typeof value === \"object\" && value !== null) ENGINE_OWNED_PROFILES.add(value);\n}\n\nfunction parseOwnedOrUntrustedProfile(value: unknown): LensSampledPsfProfile {\n if (typeof value !== \"object\" || value === null || !ENGINE_OWNED_PROFILES.has(value)) {\n return parseLensSampledPsfProfile(value);\n }\n const cached = PARSED_OWNED_PROFILES.get(value);\n if (cached !== undefined) return cached;\n const parsed = parseLensSampledPsfProfile(value);\n try {\n freezeOwnedData(value);\n } catch {\n // Not plain data that freezeOwnedData accepts (for example typed-array storage), so do not cache.\n ENGINE_OWNED_PROFILES.delete(value);\n return parsed;\n }\n freezeOwnedData(parsed);\n TRUSTED_NODE_INDEX.set(parsed, buildGridNodeIndex(parsed));\n PARSED_OWNED_PROFILES.set(value, parsed);\n return parsed;\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 * A sampled lens PSF is tied to an exact generic optical state and to declared ranges of field\n * position, wavelength and signed defocus. Interpolation stays inside those declared ranges. It keeps\n * the normalized shape separate from the throughput. MTF (modulation transfer function) data alone\n * has no phase or spatial information, so it cannot justify rendering one unique PSF.\n * @param value - unknown. Untrusted input; TypeScript types alone are not validation.\n * @returns LensSampledPsfProfile. 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 parseLensSampledPsfProfile(\n value: unknown\n): LensSampledPsfProfile {\n const record =\n requireRecord(\n value,\n \"lensPsfProfile\", [\"schemaVersion\", \"opticalDomain\", \"coordinateSystem\", \"fieldAxes\", \"kernelEnergyNormalization\", \"interpolation\", \"throughputOwnership\", \"sensorOpticalStackIncluded\", \"sensorSamplingIncluded\", \"reconstructionIncluded\", \"strayLightIncluded\", \"scientificStatus\", \"responseIncludes\", \"axes\", \"nodes\", \"profileId\", \"profileVersion\", \"evidence\", \"limitations\"]\n );\n if (\n record.schemaVersion !==\n LENS_SAMPLED_PSF_PROFILE_SCHEMA_VERSION\n ) {\n throw new InvalidConfigurationError(\n 'lensPsfProfile.schemaVersion must be \"' +\n LENS_SAMPLED_PSF_PROFILE_SCHEMA_VERSION +\n '\".'\n );\n }\n if (\n record.opticalDomain !==\n \"lens-primary-optical-path-only\"\n ) {\n throw new InvalidConfigurationError(\n 'lensPsfProfile.opticalDomain must be \"lens-primary-optical-path-only\".'\n );\n }\n if (\n record.coordinateSystem !==\n \"image-plane-metric\" ||\n record.fieldAxes !==\n \"+X right, +Y up\"\n ) {\n throw new InvalidConfigurationError(\n \"lensPsfProfile image-plane coordinate semantics are invalid.\"\n );\n }\n if (\n record.kernelEnergyNormalization !==\n \"unit-energy-shape\" ||\n !(LENS_SAMPLED_PSF_INTERPOLATIONS as readonly unknown[]).includes(\n record.interpolation\n ) ||\n record.throughputOwnership !==\n \"separate-relative-pupil-throughput-factor\"\n ) {\n throw new InvalidConfigurationError(\n \"lensPsfProfile normalization/interpolation/throughput ownership is 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 lens PSF profiles must remain lens-primary-optical-path-only and exclude sensor/reconstruction/stray-light effects.\"\n );\n }\n\n const status =\n parseStatus(\n record.scientificStatus,\n \"lensPsfProfile.scientificStatus\"\n );\n const response =\n requireRecord(\n record.responseIncludes,\n \"lensPsfProfile.responseIncludes\", [\"diffraction\", \"aberration\", \"defocus\", \"pupilClippingShape\"]\n );\n for (\n const key of [\n \"diffraction\",\n \"aberration\",\n \"defocus\",\n \"pupilClippingShape\"\n ] as const\n ) {\n if (\n typeof response[key] !==\n \"boolean\"\n ) {\n throw new InvalidConfigurationError(\n \"lensPsfProfile.responseIncludes.\" +\n key +\n \" must be boolean.\"\n );\n }\n }\n const axes =\n parseAxes(record.axes);\n if (\n !Array.isArray(\n record.nodes\n )\n ) {\n throw new InvalidConfigurationError(\n \"lensPsfProfile.nodes must be an array.\"\n );\n }\n if (\n record.nodes.length !==\n expectedNodeCount(axes)\n ) {\n throw new InvalidConfigurationError(\n \"lensPsfProfile.nodes must contain exactly one node for every regular-grid coordinate.\"\n );\n }\n const nodes =\n record.nodes.map(\n (node, index) =>\n parseNode(\n node,\n index,\n axes,\n status\n )\n );\n const ids =\n nodes.map(\n (node) =>\n node.nodeId\n );\n if (\n new Set(ids).size !==\n ids.length\n ) {\n throw new InvalidConfigurationError(\n \"lensPsfProfile.nodes must not contain duplicate nodeId values.\"\n );\n }\n const coordinateKeys =\n nodes.map(\n (node) =>\n coordinateKey(\n node.coordinate\n )\n );\n if (\n new Set(coordinateKeys).size !==\n coordinateKeys.length\n ) {\n throw new InvalidConfigurationError(\n \"lensPsfProfile.nodes must not contain duplicate grid coordinates.\"\n );\n }\n\n const firstKernel =\n nodes[0]?.kernel;\n if (firstKernel === undefined) {\n throw new InvalidConfigurationError(\n \"lensPsfProfile.nodes must not be empty.\"\n );\n }\n for (\n const node of nodes\n ) {\n if (\n !sameKernelGeometry(\n firstKernel,\n node.kernel\n )\n ) {\n throw new InvalidConfigurationError(\n \"Every lensPsfProfile node must use identical PSF kernel grid geometry for multilinear interpolation.\"\n );\n }\n }\n\n if (\n record.interpolation ===\n \"rotationally-symmetric-radial-field-centroid-aligned\"\n ) {\n if (\n axes.fieldYmm.length !== 1 ||\n axes.fieldYmm[0] !== 0 ||\n axes.fieldXmm.some((value) => value < 0)\n ) {\n throw new InvalidConfigurationError(\n \"Rotationally symmetric PSF profiles must declare fieldYmm = [0] and non-negative fieldXmm radii.\"\n );\n }\n if (\n firstKernel.samplePitchMicrometersX !==\n firstKernel.samplePitchMicrometersY\n ) {\n throw new InvalidConfigurationError(\n \"Rotationally symmetric PSF profiles require square kernel sample pitch for rotation.\"\n );\n }\n }\n\n return {\n schemaVersion:\n LENS_SAMPLED_PSF_PROFILE_SCHEMA_VERSION,\n profileId:\n requireNonEmptyString(\n record.profileId,\n \"lensPsfProfile.profileId\"\n ),\n profileVersion:\n requireNonEmptyString(\n record.profileVersion,\n \"lensPsfProfile.profileVersion\"\n ),\n scientificStatus:\n status,\n opticalDomain:\n \"lens-primary-optical-path-only\",\n coordinateSystem:\n \"image-plane-metric\",\n fieldAxes:\n \"+X right, +Y up\",\n kernelEnergyNormalization:\n \"unit-energy-shape\",\n interpolation:\n record.interpolation as LensSampledPsfInterpolation,\n throughputOwnership:\n \"separate-relative-pupil-throughput-factor\",\n responseIncludes: {\n diffraction:\n response.diffraction as boolean,\n aberration:\n response.aberration as boolean,\n defocus:\n response.defocus as boolean,\n pupilClippingShape:\n response\n .pupilClippingShape as boolean\n },\n sensorOpticalStackIncluded:\n false,\n sensorSamplingIncluded:\n false,\n reconstructionIncluded:\n false,\n strayLightIncluded:\n false,\n axes,\n nodes,\n evidence:\n parseEvidenceList(\n record.evidence,\n \"lensPsfProfile.evidence\"\n ),\n limitations:\n parseLimitations(\n record.limitations,\n \"lensPsfProfile.limitations\"\n )\n };\n}\n\nfunction focusDiopters(\n focus: FocusPlane\n): number {\n const parsed =\n parseFocusPlane(focus);\n return parsed.kind ===\n \"infinity\"\n ? 0\n : 1 /\n parsed.distanceM;\n}\n\nfunction bracketAxis(\n values:\n readonly number[],\n target: number,\n path: string\n): AxisBracket {\n const minimum =\n values[0]!;\n const maximum =\n values[\n values.length - 1\n ]!;\n const scale =\n Math.max(\n 1,\n Math.abs(target),\n Math.abs(minimum),\n Math.abs(maximum)\n );\n const tolerance =\n Number.EPSILON *\n 64 *\n scale;\n if (\n target <\n minimum - tolerance ||\n target >\n maximum + tolerance\n ) {\n throw new InvalidScientificInputError(\n path +\n \" lies outside the declared PSF profile grid; extrapolation is not permitted.\"\n );\n }\n\n for (\n let index = 0;\n index < values.length;\n index += 1\n ) {\n const value = values[index]!;\n if (\n Math.abs(\n target - value\n ) <= tolerance\n ) {\n return {\n lower: value,\n upper: value,\n lowerIndex: index,\n upperIndex: index,\n fraction: 0,\n exact: true\n };\n }\n }\n\n for (\n let index = 0;\n index <\n values.length - 1;\n index += 1\n ) {\n const lower =\n values[index]!;\n const upper =\n values[index + 1]!;\n if (\n target > lower &&\n target < upper\n ) {\n return {\n lower,\n upper,\n lowerIndex: index,\n upperIndex: index + 1,\n fraction:\n (target - lower) /\n (upper - lower),\n exact: false\n };\n }\n }\n\n throw new InvalidScientificInputError(\n path +\n \" could not be bracketed inside the declared PSF profile grid.\"\n );\n}\n\nfunction queryCoordinate(\n input:\n ResolveLensSampledPsfInput\n): {\n coordinate:\n LensSampledPsfGridCoordinate;\n focus: FocusPlane;\n} {\n const focus =\n parseFocusPlane(\n input.focus\n );\n return {\n coordinate: {\n focalLengthMm:\n requireScientificPositiveFinite(\n input.focalLengthMm,\n \"focalLengthMm\"\n ),\n focusDiopters:\n focusDiopters(focus),\n apertureFNumber:\n requireScientificPositiveFinite(\n input.apertureFNumber,\n \"apertureFNumber\"\n ),\n fieldXmm:\n requireScientificFinite(\n input.fieldPointMm.x,\n \"fieldPointMm.x\"\n ),\n fieldYmm:\n requireScientificFinite(\n input.fieldPointMm.y,\n \"fieldPointMm.y\"\n ),\n wavelengthNm:\n requireScientificPositiveFinite(\n input.wavelengthNm,\n \"wavelengthNm\"\n ),\n signedDefocusImagePlaneMicrometers:\n requireScientificFinite(\n input\n .signedDefocusImagePlaneMicrometers,\n \"signedDefocusImagePlaneMicrometers\"\n )\n },\n focus\n };\n}\n\nfunction bracketCoordinate(\n axes: LensPsfGridAxes,\n coordinate:\n LensSampledPsfGridCoordinate\n): Record<AxisKey, AxisBracket> {\n return {\n focalLengthMm:\n bracketAxis(\n axes.focalLengthMm,\n coordinate.focalLengthMm,\n \"focalLengthMm\"\n ),\n focusDiopters:\n bracketAxis(\n axes.focusDiopters,\n coordinate.focusDiopters,\n \"focus\"\n ),\n apertureFNumber:\n bracketAxis(\n axes.apertureFNumber,\n coordinate.apertureFNumber,\n \"apertureFNumber\"\n ),\n fieldXmm:\n bracketAxis(\n axes.fieldXmm,\n coordinate.fieldXmm,\n \"fieldPointMm.x\"\n ),\n fieldYmm:\n bracketAxis(\n axes.fieldYmm,\n coordinate.fieldYmm,\n \"fieldPointMm.y\"\n ),\n wavelengthNm:\n bracketAxis(\n axes.wavelengthNm,\n coordinate.wavelengthNm,\n \"wavelengthNm\"\n ),\n signedDefocusImagePlaneMicrometers:\n bracketAxis(\n axes\n .signedDefocusImagePlaneMicrometers,\n coordinate\n .signedDefocusImagePlaneMicrometers,\n \"signedDefocusImagePlaneMicrometers\"\n )\n };\n}\n\n/** Flat-index strides of the regular grid over AXIS_KEYS (the last axis varies fastest). */\nfunction gridStrides(axes: LensPsfGridAxes): number[] {\n const strides = new Array<number>(AXIS_KEYS.length);\n let stride = 1;\n for (let a = AXIS_KEYS.length - 1; a >= 0; a -= 1) {\n strides[a] = stride;\n stride *= axes[AXIS_KEYS[a]!].length;\n }\n return strides;\n}\n\n/**\n * Nodes indexed by grid position. Node coordinates match declared axis values exactly (checked by the\n * parser, with `===`, so −0 and 0 are one position) and are unique, so each position holds at most one node.\n */\nfunction buildGridNodeIndex(profile: LensSampledPsfProfile): GridNodeIndex {\n const strides = gridStrides(profile.axes);\n const nodes = new Array<LensSampledPsfGridNode | undefined>(AXIS_KEYS.reduce((n, key) => n * profile.axes[key].length, 1));\n for (const node of profile.nodes) {\n let flat = 0;\n for (let a = 0; a < AXIS_KEYS.length; a += 1) {\n const key = AXIS_KEYS[a]!;\n flat += profile.axes[key].indexOf(node.coordinate[key]) * strides[a]!;\n }\n nodes[flat] = node;\n }\n return { strides, nodes };\n}\n\n/**\n * The multilinear corners of a bracketed query and their weights, in a fixed order: axes in AXIS_KEYS order,\n * lower before upper, zero-weight options skipped. Each weight is the product of its per-axis weights in that order.\n */\nfunction resolveWeightedNodes(\n profile:\n LensSampledPsfProfile,\n brackets:\n Record<\n AxisKey,\n AxisBracket\n >\n): readonly WeightedNode[] {\n const index = TRUSTED_NODE_INDEX.get(profile) ?? buildGridNodeIndex(profile);\n let flats = [0], weights = [1];\n for (let a = 0; a < AXIS_KEYS.length; a += 1) {\n const bracket = brackets[AXIS_KEYS[a]!], stride = index.strides[a]!;\n const nextFlats: number[] = [], nextWeights: number[] = [];\n for (let c = 0; c < flats.length; c += 1) {\n if (bracket.exact) {\n nextFlats.push(flats[c]! + bracket.lowerIndex * stride);\n nextWeights.push(weights[c]! * 1);\n continue;\n }\n const lowerWeight = 1 - bracket.fraction, upperWeight = bracket.fraction;\n if (lowerWeight !== 0) { nextFlats.push(flats[c]! + bracket.lowerIndex * stride); nextWeights.push(weights[c]! * lowerWeight); }\n if (upperWeight !== 0) { nextFlats.push(flats[c]! + bracket.upperIndex * stride); nextWeights.push(weights[c]! * upperWeight); }\n }\n flats = nextFlats;\n weights = nextWeights;\n }\n return flats.map((flat, c) => {\n const node = index.nodes[flat];\n if (node === undefined) {\n throw new InvalidScientificInputError(\n \"PSF profile grid is missing a required interpolation corner.\"\n );\n }\n return { node, weight: weights[c]! };\n });\n}\n\nfunction interpolateKernel(\n weighted:\n readonly WeightedNode[]\n): LensPsfKernel {\n const first =\n weighted[0]?.node.kernel;\n if (first === undefined) {\n throw new InvalidScientificInputError(\n \"PSF interpolation requires at least one source node.\"\n );\n }\n const values =\n new Array<number>(\n first\n .normalizedIntensity\n .length\n ).fill(0);\n\n for (\n const entry of weighted\n ) {\n for (\n let index = 0;\n index < values.length;\n index += 1\n ) {\n values[index]! +=\n entry.weight *\n entry.node.kernel\n .normalizedIntensity[index]!;\n }\n }\n\n const sum =\n values.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 \"Interpolated PSF energy must remain finite and positive.\"\n );\n }\n const normalized =\n values.map(\n (value) =>\n value / sum\n );\n\n return {\n widthSamples:\n first.widthSamples,\n heightSamples:\n first.heightSamples,\n samplePitchMicrometersX:\n first\n .samplePitchMicrometersX,\n samplePitchMicrometersY:\n first\n .samplePitchMicrometersY,\n centerSampleX:\n first.centerSampleX,\n centerSampleY:\n first.centerSampleY,\n normalizedIntensity:\n normalized\n };\n}\n\nfunction kernelCentroid(\n kernel: LensPsfKernel\n): { x: number; y: number } {\n let sum = 0;\n let x = 0;\n let y = 0;\n for (let row = 0; row < kernel.heightSamples; row += 1) {\n for (let column = 0; column < kernel.widthSamples; column += 1) {\n const value = kernel.normalizedIntensity[row * kernel.widthSamples + column]!;\n sum += value;\n x += value * (column - kernel.centerSampleX);\n y += value * (row - kernel.centerSampleY);\n }\n }\n return { x: x / sum, y: y / sum };\n}\n\n/** Bilinear sample at fractional array coordinates; zero outside the kernel. */\nfunction bilinearSample(\n kernel: LensPsfKernel,\n column: number,\n row: number\n): number {\n const x0 = Math.floor(column);\n const y0 = Math.floor(row);\n const fx = column - x0;\n const fy = row - y0;\n const at = (x: number, y: number): number =>\n x < 0 || y < 0 || x >= kernel.widthSamples || y >= kernel.heightSamples\n ? 0\n : kernel.normalizedIntensity[y * kernel.widthSamples + x]!;\n const top = fx === 0 ? at(x0, y0) : (1 - fx) * at(x0, y0) + fx * at(x0 + 1, y0);\n if (fy === 0) {\n return top;\n }\n const bottom = fx === 0 ? at(x0, y0 + 1) : (1 - fx) * at(x0, y0 + 1) + fx * at(x0 + 1, y0 + 1);\n return (1 - fy) * top + fy * bottom;\n}\n\nfunction normalizedKernel(\n template: LensPsfKernel,\n values: readonly number[]\n): LensPsfKernel {\n const sum = values.reduce((acc, value) => acc + value, 0);\n if (!Number.isFinite(sum) || sum <= 0) {\n throw new InvalidScientificInputError(\n \"Interpolated PSF energy must remain finite and positive.\"\n );\n }\n return {\n widthSamples: template.widthSamples,\n heightSamples: template.heightSamples,\n samplePitchMicrometersX: template.samplePitchMicrometersX,\n samplePitchMicrometersY: template.samplePitchMicrometersY,\n centerSampleX: template.centerSampleX,\n centerSampleY: template.centerSampleY,\n normalizedIntensity: values.map((value) => value / sum)\n };\n}\n\n/**\n * Centroid-aligned interpolation. Each node kernel is shifted so its intensity centroid lands on the\n * weighted centroid. Then the multilinear weights are applied. A single exact node is returned\n * unchanged.\n */\nfunction interpolateKernelCentroidAligned(\n weighted: readonly WeightedNode[]\n): LensPsfKernel {\n const first = weighted[0]?.node.kernel;\n if (first === undefined) {\n throw new InvalidScientificInputError(\n \"PSF interpolation requires at least one source node.\"\n );\n }\n if (weighted.length === 1) {\n // An exact grid node is already a validated unit-energy kernel; return it bit-for-bit.\n return { ...first, normalizedIntensity: [...first.normalizedIntensity] };\n }\n const centroids = weighted.map((entry) => kernelCentroid(entry.node.kernel));\n const target = centroids.reduce(\n (acc, centroid, index) => ({\n x: acc.x + weighted[index]!.weight * centroid.x,\n y: acc.y + weighted[index]!.weight * centroid.y\n }),\n { x: 0, y: 0 }\n );\n const values = new Array<number>(first.normalizedIntensity.length).fill(0);\n weighted.forEach((entry, index) => {\n const dx = centroids[index]!.x - target.x;\n const dy = centroids[index]!.y - target.y;\n for (let row = 0; row < first.heightSamples; row += 1) {\n for (let column = 0; column < first.widthSamples; column += 1) {\n values[row * first.widthSamples + column]! +=\n entry.weight * bilinearSample(entry.node.kernel, column + dx, row + dy);\n }\n }\n });\n return normalizedKernel(first, values);\n}\n\n/**\n * Rotates a kernel by angleRadians (counter-clockwise from image +X towards image +Y) about its centre sample.\n * The row index increases with image +Y, the convention the environment PSF quadrature applies (`sensorPsfSourcePoint`:\n * tap (kx, ky) lands at image offset (+(kx − cx)·pₓ, +(ky − cy)·p_y), +Y up), so a kernel declared along +X and rotated to\n * field azimuth atan2(y, x) points the same way in the rendered image as a 2-D grid node declared at (x, y). Before 2.19.0\n * this read rows as image −Y, which mirrored asymmetric kernels in y (#566).\n */\nfunction rotateKernel(\n kernel: LensPsfKernel,\n angleRadians: number\n): LensPsfKernel {\n const cos = Math.cos(angleRadians);\n const sin = Math.sin(angleRadians);\n const values: number[] = [];\n for (let row = 0; row < kernel.heightSamples; row += 1) {\n // Row index increases with image +Y (sensorPsfSourcePoint).\n const y = row - kernel.centerSampleY;\n for (let column = 0; column < kernel.widthSamples; column += 1) {\n const x = column - kernel.centerSampleX;\n // Inverse rotation: destination (x, y) samples source R(-angle) (x, y).\n const sourceX = cos * x + sin * y;\n const sourceY = -sin * x + cos * y;\n values.push(\n bilinearSample(\n kernel,\n kernel.centerSampleX + sourceX,\n kernel.centerSampleY + sourceY\n )\n );\n }\n }\n return normalizedKernel(kernel, values);\n}\n\nfunction weightedScalar(\n weighted:\n readonly WeightedNode[],\n select:\n (\n node:\n LensSampledPsfGridNode\n ) => number\n): number {\n return weighted.reduce(\n (sum, entry) =>\n sum +\n entry.weight *\n select(entry.node),\n 0\n );\n}\n\n/** The resolved PSF before its result envelope; resolveLensSampledPsf and the lean native executor share it. */\ninterface ResolvedLensSampledPsfCore {\n profile: LensSampledPsfProfile;\n query: ReturnType<typeof queryCoordinate>;\n rotational: boolean;\n exact: boolean;\n weighted: readonly WeightedNode[];\n kernel: LensPsfKernel;\n bestFocus: number;\n throughput: number;\n}\n\nfunction resolveLensSampledPsfCore(\n input:\n ResolveLensSampledPsfInput\n): ResolvedLensSampledPsfCore {\n requireInputKeys(input, \"resolveLensSampledPsf\", [\"profile\", \"focalLengthMm\", \"focus\", \"apertureFNumber\", \"fieldPointMm\", \"wavelengthNm\", \"signedDefocusImagePlaneMicrometers\"]);\n const profile =\n parseOwnedOrUntrustedProfile(\n input.profile\n );\n const query =\n queryCoordinate(input);\n const rotational =\n profile.interpolation ===\n \"rotationally-symmetric-radial-field-centroid-aligned\";\n const fieldRadiusMm = Math.hypot(\n query.coordinate.fieldXmm,\n query.coordinate.fieldYmm\n );\n const fieldAngleRadians = rotational\n ? Math.atan2(query.coordinate.fieldYmm, query.coordinate.fieldXmm)\n : 0;\n const brackets =\n bracketCoordinate(\n profile.axes,\n rotational\n ? { ...query.coordinate, fieldXmm: fieldRadiusMm, fieldYmm: 0 }\n : query.coordinate\n );\n const weighted =\n resolveWeightedNodes(\n profile,\n brackets\n );\n const exact =\n AXIS_KEYS.every(\n (key) =>\n brackets[key].exact\n ) && fieldAngleRadians === 0;\n const kernel =\n profile.interpolation === \"bounded-regular-grid-multilinear\"\n ? interpolateKernel(weighted)\n : fieldAngleRadians === 0\n ? interpolateKernelCentroidAligned(weighted)\n : rotateKernel(\n interpolateKernelCentroidAligned(weighted),\n fieldAngleRadians\n );\n const bestFocus =\n weightedScalar(\n weighted,\n (node) =>\n node\n .bestFocusImagePlaneOffsetMicrometers\n );\n // A multilinear blend is a convex combination, so it cannot exceed its largest node value. But its\n // floating-point weights can sum to a few ulps above 1. A result above 1 that lies within\n // 8·ε·(node count)·max of the largest node is that rounding error. It is clamped to the largest node\n // value (≤ 1, so the result is again a declared value). Results already within [0, 1] are unchanged.\n const blended =\n weightedScalar(\n weighted,\n (node) =>\n node\n .relativePupilThroughputFactor\n );\n const largestThroughput = Math.max(...weighted.map((entry) => entry.node.relativePupilThroughputFactor));\n const throughput =\n blended > 1 && largestThroughput <= 1 &&\n blended - largestThroughput <= 8 * Number.EPSILON * weighted.length * Math.max(1, largestThroughput)\n ? largestThroughput\n : blended;\n if (\n !Number.isFinite(\n bestFocus\n ) ||\n !Number.isFinite(\n throughput\n ) ||\n throughput < 0 ||\n throughput > 1\n ) {\n throw new InvalidScientificInputError(\n \"Interpolated PSF metadata must remain finite and physically bounded.\"\n );\n }\n\n return { profile, query, rotational, exact, weighted, kernel, bestFocus, throughput };\n}\n\n/**\n * Internal (2.0 performance): the kernel resolveLensSampledPsf returns for the same input, computed by\n * the same code without building the result envelope. Throws whenever resolveLensSampledPsf would throw\n * before its envelope. Not exported from the package.\n */\nexport function resolveLensSampledPsfKernel(\n input:\n ResolveLensSampledPsfInput\n): LensPsfKernel {\n return resolveLensSampledPsfCore(input).kernel;\n}\n\n/**\n * Resolves the sampled PSF for a declared optical state and query point. It never extrapolates and\n * never invents missing dimensions.\n *\n * A sampled lens PSF is tied to an exact generic optical state and to declared ranges of field\n * position, wavelength and signed defocus. Interpolation stays inside those declared ranges. It keeps\n * the normalized shape separate from the throughput. MTF (modulation transfer function) data alone\n * has no phase or spatial information, so it cannot justify rendering one unique PSF.\n * @param input - ResolveLensSampledPsfInput. See that type for coordinates, units and profile binding.\n * @returns CalculationResult<ResolvedLensSampledPsf>. 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 resolveLensSampledPsf(\n input:\n ResolveLensSampledPsfInput\n): CalculationResult<ResolvedLensSampledPsf> {\n const { profile, query, rotational, exact, weighted, kernel, bestFocus, throughput } =\n resolveLensSampledPsfCore(input);\n return approximationResult(\n {\n profileId:\n profile.profileId,\n profileVersion:\n profile.profileVersion,\n scientificStatus:\n profile.scientificStatus,\n resolutionStatus:\n exact\n ? \"exact-grid-sample\"\n : \"interpolated\",\n coordinate:\n query.coordinate,\n focus:\n query.focus,\n kernel,\n bestFocusImagePlaneOffsetMicrometers:\n bestFocus,\n relativePupilThroughputFactor:\n throughput,\n sourceNodes:\n weighted.map(\n (entry) => ({\n nodeId:\n entry.node.nodeId,\n weight:\n entry.weight,\n evidence:\n entry.node.evidence,\n uncertainty:\n entry.node\n .uncertainty\n })\n ),\n responseIncludes: {\n ...profile\n .responseIncludes\n },\n throughputOwnership:\n \"separate-relative-pupil-throughput-factor\",\n longitudinalChromaticFocusMayVaryWithWavelength:\n true,\n fieldCurvatureMayVaryWithFieldPosition:\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 },\n profile.interpolation === \"bounded-regular-grid-multilinear\"\n ? \"lens-sampled-psf-bounded-interpolation\"\n : rotational\n ? \"lens-sampled-psf-rotational-centroid-aligned-interpolation\"\n : \"lens-sampled-psf-centroid-aligned-interpolation\",\n \"1.0.0\",\n [\n ...(profile.interpolation === \"bounded-regular-grid-multilinear\"\n ? []\n : [\n \"Node kernels are translated to the weighted intensity centroid before blending (bilinear resampling, outside samples zero, renormalised), so shifted PSFs blend into one peak.\",\n ...(rotational\n ? [\"Rotationally symmetric lens: nodes along +X are interpolated at the field radius and the kernel is rotated by the field azimuth.\"]\n : [])\n ]),\n \"PSF intensity is a unit-energy shape; relative pupil throughput remains a separate factor for the optical-throughput path.\",\n \"Regular-grid interpolation is bounded and never extrapolates beyond declared focal-length, focus, aperture, field, wavelength or signed-defocus axes.\",\n \"Full 2D image-plane kernel orientation is preserved in +X right, +Y up coordinates; no radial or sagittal/tangential averaging is forced.\",\n \"bestFocusImagePlaneOffsetMicrometers may vary with field and wavelength, representing field-curvature and longitudinal-chromatic-focus behavior without changing geometric distortion or lateral chromatic position.\",\n \"Lens PSF remains upstream of sensor optical stack, sampling and reconstruction, and excludes stray-light/ghosting contributions.\",\n \"No scalar lens-quality, sharpness or bokeh-quality score is produced.\"\n ]\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 * A sampled lens PSF is tied to an exact generic optical state and to declared ranges of field\n * position, wavelength and signed defocus. Interpolation stays inside those declared ranges. It keeps\n * the normalized shape separate from the throughput. MTF (modulation transfer function) data alone\n * has no phase or spatial information, so it cannot justify rendering one unique PSF.\n * @param value - unknown. Untrusted input; TypeScript types alone are not validation.\n * @returns LensMtfDiagnosticProfile. 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 parseLensMtfDiagnosticProfile(\n value: unknown\n): LensMtfDiagnosticProfile {\n const record =\n requireRecord(\n value,\n \"lensMtfProfile\", [\"schemaVersion\", \"opticalDomain\", \"phaseInformationAvailable\", \"magnitudeMeaning\", \"samples\", \"fieldPointMm\", \"wavelengthNm\", \"profileId\", \"profileVersion\", \"focalLengthMm\", \"focus\", \"apertureFNumber\", \"evidence\", \"limitations\"]\n );\n if (\n record.schemaVersion !==\n LENS_MTF_DIAGNOSTIC_PROFILE_SCHEMA_VERSION\n ) {\n throw new InvalidConfigurationError(\n 'lensMtfProfile.schemaVersion must be \"' +\n LENS_MTF_DIAGNOSTIC_PROFILE_SCHEMA_VERSION +\n '\".'\n );\n }\n if (\n record.opticalDomain !==\n \"lens-primary-optical-path-only\" ||\n record.phaseInformationAvailable !==\n false ||\n record.magnitudeMeaning !==\n \"mtf-magnitude-only\"\n ) {\n throw new InvalidConfigurationError(\n \"lensMtfProfile optical/phase semantics are invalid.\"\n );\n }\n if (\n !Array.isArray(\n record.samples\n ) ||\n record.samples.length ===\n 0\n ) {\n throw new InvalidConfigurationError(\n \"lensMtfProfile.samples must be a non-empty array.\"\n );\n }\n let priorFrequency =\n -1;\n const samples =\n record.samples.map(\n (entry, index) => {\n const path =\n \"lensMtfProfile.samples[\" +\n index +\n \"]\";\n const sample =\n requireRecord(\n entry,\n path, [\"spatialFrequencyCyclesPerMm\", \"sagittalMagnitude\", \"tangentialMagnitude\"]\n );\n const frequency =\n requireNonNegativeFinite(\n sample\n .spatialFrequencyCyclesPerMm,\n path +\n \".spatialFrequencyCyclesPerMm\"\n );\n if (\n frequency <=\n priorFrequency\n ) {\n throw new InvalidConfigurationError(\n \"lensMtfProfile sample frequencies must be strictly increasing.\"\n );\n }\n priorFrequency =\n frequency;\n return {\n spatialFrequencyCyclesPerMm:\n frequency,\n sagittalMagnitude:\n requireUnitInterval(\n sample\n .sagittalMagnitude,\n path +\n \".sagittalMagnitude\"\n ),\n tangentialMagnitude:\n requireUnitInterval(\n sample\n .tangentialMagnitude,\n path +\n \".tangentialMagnitude\"\n )\n };\n }\n );\n const field =\n requireRecord(\n record.fieldPointMm,\n \"lensMtfProfile.fieldPointMm\", [\"x\", \"y\"]\n );\n const wavelength =\n record.wavelengthNm ===\n null\n ? null\n : requirePositiveFinite(\n record.wavelengthNm,\n \"lensMtfProfile.wavelengthNm\"\n );\n\n return {\n schemaVersion:\n LENS_MTF_DIAGNOSTIC_PROFILE_SCHEMA_VERSION,\n profileId:\n requireNonEmptyString(\n record.profileId,\n \"lensMtfProfile.profileId\"\n ),\n profileVersion:\n requireNonEmptyString(\n record.profileVersion,\n \"lensMtfProfile.profileVersion\"\n ),\n opticalDomain:\n \"lens-primary-optical-path-only\",\n phaseInformationAvailable:\n false,\n magnitudeMeaning:\n \"mtf-magnitude-only\",\n fieldPointMm: {\n x:\n requireFinite(\n field.x,\n \"lensMtfProfile.fieldPointMm.x\"\n ),\n y:\n requireFinite(\n field.y,\n \"lensMtfProfile.fieldPointMm.y\"\n )\n },\n focalLengthMm:\n requirePositiveFinite(\n record.focalLengthMm,\n \"lensMtfProfile.focalLengthMm\"\n ),\n focus:\n parseFocusPlane(\n record.focus\n ),\n apertureFNumber:\n requirePositiveFinite(\n record.apertureFNumber,\n \"lensMtfProfile.apertureFNumber\"\n ),\n wavelengthNm:\n wavelength,\n samples,\n evidence:\n parseEvidenceList(\n record.evidence,\n \"lensMtfProfile.evidence\"\n ),\n limitations:\n parseLimitations(\n record.limitations,\n \"lensMtfProfile.limitations\"\n )\n };\n}\n\n/**\n * Explains why MTF-only evidence cannot determine one unique renderable PSF. Returns blockers instead\n * of making up phase information.\n *\n * A sampled lens PSF is tied to an exact generic optical state and to declared ranges of field\n * position, wavelength and signed defocus. Interpolation stays inside those declared ranges. It keeps\n * the normalized shape separate from the throughput. MTF (modulation transfer function) data alone\n * has no phase or spatial information, so it cannot justify rendering one unique PSF.\n * @param profile - LensMtfDiagnosticProfile. See that type for coordinates, units and profile binding.\n * @returns MtfOnlyPsfRenderabilityAssessment. Read the structured blockers before relying on any authorization.\n *\n * @see docs/API_REFERENCE.md for the root export and exact type graph.\n */\nexport function assessMtfOnlyPsfRenderability(\n profile:\n LensMtfDiagnosticProfile\n): MtfOnlyPsfRenderabilityAssessment {\n const parsed =\n parseLensMtfDiagnosticProfile(\n profile\n );\n return {\n profileId:\n parsed.profileId,\n psfReconstructionAuthorized:\n false,\n reason:\n \"mtf-magnitude-lacks-phase-and-does-not-uniquely-determine-psf\",\n diagnosticUseAuthorized:\n true\n };\n}\n"]}