@photivra/engine 2.18.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 (261) hide show
  1. package/CHANGELOG.md +68 -1
  2. package/CITATION.cff +1 -1
  3. package/README.md +6 -6
  4. package/SECURITY.md +1 -1
  5. package/dist/capture/focus-control.js +2 -75
  6. package/dist/capture/focus-control.js.map +1 -1
  7. package/dist/capture/native-environment-lean.d.ts +1 -0
  8. package/dist/capture/native-environment-lean.js +1 -1
  9. package/dist/capture/native-environment-lean.js.map +1 -1
  10. package/dist/capture/native-environment-optical-stage.d.ts +1 -0
  11. package/dist/capture/native-environment-optical-stage.js +2 -5
  12. package/dist/capture/native-environment-optical-stage.js.map +1 -1
  13. package/dist/capture/native-environment-raw.js +1 -5
  14. package/dist/capture/native-environment-raw.js.map +1 -1
  15. package/dist/capture/release-sequence.js +2 -47
  16. package/dist/capture/release-sequence.js.map +1 -1
  17. package/dist/color/white-balance.d.ts +2 -0
  18. package/dist/color/white-balance.js +3 -56
  19. package/dist/color/white-balance.js.map +1 -1
  20. package/dist/composition/image-formation-plan.d.ts +1 -0
  21. package/dist/composition/image-formation-plan.js +3 -49
  22. package/dist/composition/image-formation-plan.js.map +1 -1
  23. package/dist/core/evidence-provenance.js +1 -16
  24. package/dist/core/evidence-provenance.js.map +1 -1
  25. package/dist/core/record-validation.d.ts +54 -0
  26. package/dist/core/record-validation.js +176 -0
  27. package/dist/core/record-validation.js.map +1 -1
  28. package/dist/core/scientific-assurance.js +1 -18
  29. package/dist/core/scientific-assurance.js.map +1 -1
  30. package/dist/core/shared-helpers.d.ts +33 -0
  31. package/dist/core/shared-helpers.js +34 -0
  32. package/dist/core/shared-helpers.js.map +1 -0
  33. package/dist/core/spectral-composition.js +1 -36
  34. package/dist/core/spectral-composition.js.map +1 -1
  35. package/dist/core/spectral.js +1 -19
  36. package/dist/core/spectral.js.map +1 -1
  37. package/dist/core/version.d.ts +1 -1
  38. package/dist/core/version.js +1 -1
  39. package/dist/core/version.js.map +1 -1
  40. package/dist/equipment/exposure-capabilities.d.ts +1 -0
  41. package/dist/equipment/exposure-capabilities.js +2 -36
  42. package/dist/equipment/exposure-capabilities.js.map +1 -1
  43. package/dist/equipment/iso-capabilities.js +2 -49
  44. package/dist/equipment/iso-capabilities.js.map +1 -1
  45. package/dist/equipment/metering-capabilities.js +1 -26
  46. package/dist/equipment/metering-capabilities.js.map +1 -1
  47. package/dist/equipment/release-capabilities.js +1 -53
  48. package/dist/equipment/release-capabilities.js.map +1 -1
  49. package/dist/exposure/auto-iso-slowest-shutter.js +1 -7
  50. package/dist/exposure/auto-iso-slowest-shutter.js.map +1 -1
  51. package/dist/exposure/exposure-duration-control.js +1 -16
  52. package/dist/exposure/exposure-duration-control.js.map +1 -1
  53. package/dist/exposure/exposure-mode-resolver.js +1 -17
  54. package/dist/exposure/exposure-mode-resolver.js.map +1 -1
  55. package/dist/exposure/filtered-exposure-time.d.ts +93 -0
  56. package/dist/exposure/filtered-exposure-time.js +129 -0
  57. package/dist/exposure/filtered-exposure-time.js.map +1 -0
  58. package/dist/exposure/flash-ttl.d.ts +1 -0
  59. package/dist/exposure/flash-ttl.js +1 -1
  60. package/dist/exposure/flash-ttl.js.map +1 -1
  61. package/dist/exposure/flash.js +1 -49
  62. package/dist/exposure/flash.js.map +1 -1
  63. package/dist/exposure/metering-scene-radiance.js +1 -25
  64. package/dist/exposure/metering-scene-radiance.js.map +1 -1
  65. package/dist/exposure/metering-target.js +1 -30
  66. package/dist/exposure/metering-target.js.map +1 -1
  67. package/dist/exposure/metering-temporal.js +1 -8
  68. package/dist/exposure/metering-temporal.js.map +1 -1
  69. package/dist/exposure/metering.js +1 -72
  70. package/dist/exposure/metering.js.map +1 -1
  71. package/dist/exposure/program-line.js +1 -45
  72. package/dist/exposure/program-line.js.map +1 -1
  73. package/dist/facade/develop-joined-parts.d.ts +29 -0
  74. package/dist/facade/develop-joined-parts.js +33 -0
  75. package/dist/facade/develop-joined-parts.js.map +1 -0
  76. package/dist/facade/generic-lens-capture.d.ts +4 -2
  77. package/dist/facade/generic-lens-capture.js +4 -2
  78. package/dist/facade/generic-lens-capture.js.map +1 -1
  79. package/dist/facade/simulate-capture.d.ts +37 -5
  80. package/dist/facade/simulate-capture.js +153 -96
  81. package/dist/facade/simulate-capture.js.map +1 -1
  82. package/dist/gpu/chart-composite-gpu.js +1 -3
  83. package/dist/gpu/chart-composite-gpu.js.map +1 -1
  84. package/dist/gpu/chart-radiance-gpu.js +1 -5
  85. package/dist/gpu/chart-radiance-gpu.js.map +1 -1
  86. package/dist/gpu/display-view-quality-gpu.d.ts +13 -1
  87. package/dist/gpu/display-view-quality-gpu.js +4 -8
  88. package/dist/gpu/display-view-quality-gpu.js.map +1 -1
  89. package/dist/gpu/display-view-speed-gpu.js +3 -25
  90. package/dist/gpu/display-view-speed-gpu.js.map +1 -1
  91. package/dist/gpu/sensor-stage-gpu.js +1 -5
  92. package/dist/gpu/sensor-stage-gpu.js.map +1 -1
  93. package/dist/gpu/webgpu-runtime.d.ts +2 -0
  94. package/dist/gpu/webgpu-runtime.js +3 -0
  95. package/dist/gpu/webgpu-runtime.js.map +1 -1
  96. package/dist/index.d.ts +4 -1
  97. package/dist/index.js +3 -0
  98. package/dist/index.js.map +1 -1
  99. package/dist/motion/camera-rotation.js +1 -6
  100. package/dist/motion/camera-rotation.js.map +1 -1
  101. package/dist/motion/capture-rotation-inverse-mapping.d.ts +12 -0
  102. package/dist/motion/capture-rotation-inverse-mapping.js +2 -2
  103. package/dist/motion/capture-rotation-inverse-mapping.js.map +1 -1
  104. package/dist/motion/capture-rotation-temporal-quadrature.d.ts +1 -0
  105. package/dist/motion/capture-rotation-temporal-quadrature.js +1 -1
  106. package/dist/motion/capture-rotation-temporal-quadrature.js.map +1 -1
  107. package/dist/motion/capture-rotation-trajectory.js +2 -17
  108. package/dist/motion/capture-rotation-trajectory.js.map +1 -1
  109. package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts +1 -0
  110. package/dist/motion/capture-translation-parallax-temporal-quadrature.js +3 -14
  111. package/dist/motion/capture-translation-parallax-temporal-quadrature.js.map +1 -1
  112. package/dist/motion/extended-object-projection.js +5 -40
  113. package/dist/motion/extended-object-projection.js.map +1 -1
  114. package/dist/optics/atmospheric-haze.js +1 -7
  115. package/dist/optics/atmospheric-haze.js.map +1 -1
  116. package/dist/optics/brown-conrady-distortion.js +1 -7
  117. package/dist/optics/brown-conrady-distortion.js.map +1 -1
  118. package/dist/optics/complex-pupil-psf.d.ts +1 -0
  119. package/dist/optics/complex-pupil-psf.js +2 -84
  120. package/dist/optics/complex-pupil-psf.js.map +1 -1
  121. package/dist/optics/focus-state.js +1 -11
  122. package/dist/optics/focus-state.js.map +1 -1
  123. package/dist/optics/front-of-lens-filter.d.ts +5 -0
  124. package/dist/optics/front-of-lens-filter.js +3 -65
  125. package/dist/optics/front-of-lens-filter.js.map +1 -1
  126. package/dist/optics/generic-nd-filter-presets.d.ts +12 -0
  127. package/dist/optics/generic-nd-filter-presets.js +48 -0
  128. package/dist/optics/generic-nd-filter-presets.js.map +1 -0
  129. package/dist/optics/illumination-vignetting.js +1 -6
  130. package/dist/optics/illumination-vignetting.js.map +1 -1
  131. package/dist/optics/lens-psf-profile.d.ts +4 -1
  132. package/dist/optics/lens-psf-profile.js +12 -111
  133. package/dist/optics/lens-psf-profile.js.map +1 -1
  134. package/dist/optics/longitudinal-chromatic-aberration.js +1 -7
  135. package/dist/optics/longitudinal-chromatic-aberration.js.map +1 -1
  136. package/dist/optics/pupil-vignetting.js +1 -7
  137. package/dist/optics/pupil-vignetting.js.map +1 -1
  138. package/dist/optics/radial-distortion.js +1 -6
  139. package/dist/optics/radial-distortion.js.map +1 -1
  140. package/dist/optics/scene-to-sensor-irradiance.js +4 -96
  141. package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
  142. package/dist/optics/stray-light.d.ts +1 -0
  143. package/dist/optics/stray-light.js +1 -1
  144. package/dist/optics/stray-light.js.map +1 -1
  145. package/dist/optics/zernike-wavefront.js +1 -7
  146. package/dist/optics/zernike-wavefront.js.map +1 -1
  147. package/dist/output/capture-geometry.js +1 -8
  148. package/dist/output/capture-geometry.js.map +1 -1
  149. package/dist/output/developed-lens-corrections.d.ts +62 -0
  150. package/dist/output/developed-lens-corrections.js +135 -0
  151. package/dist/output/developed-lens-corrections.js.map +1 -0
  152. package/dist/output/generic-lens-corrections.d.ts +2 -6
  153. package/dist/output/generic-lens-corrections.js +3 -6
  154. package/dist/output/generic-lens-corrections.js.map +1 -1
  155. package/dist/output/geometric-transforms.js +1 -4
  156. package/dist/output/geometric-transforms.js.map +1 -1
  157. package/dist/output/native-capture-sdr.d.ts +2 -2
  158. package/dist/output/native-capture-sdr.js +3 -2
  159. package/dist/output/native-capture-sdr.js.map +1 -1
  160. package/dist/processing/development-detail.d.ts +29 -0
  161. package/dist/processing/development-detail.js +128 -107
  162. package/dist/processing/development-detail.js.map +1 -1
  163. package/dist/schema/illumination-temporal.js +3 -72
  164. package/dist/schema/illumination-temporal.js.map +1 -1
  165. package/dist/schema/illumination.d.ts +1 -0
  166. package/dist/schema/illumination.js +2 -65
  167. package/dist/schema/illumination.js.map +1 -1
  168. package/dist/schema/scene-radiance-temporal.js +2 -14
  169. package/dist/schema/scene-radiance-temporal.js.map +1 -1
  170. package/dist/schema/scene-radiance.js +2 -60
  171. package/dist/schema/scene-radiance.js.map +1 -1
  172. package/dist/schema/validation.d.ts +2 -0
  173. package/dist/schema/validation.js +2 -17
  174. package/dist/schema/validation.js.map +1 -1
  175. package/dist/sensor/accumulated-charge.js +2 -59
  176. package/dist/sensor/accumulated-charge.js.map +1 -1
  177. package/dist/sensor/architecture.js +1 -16
  178. package/dist/sensor/architecture.js.map +1 -1
  179. package/dist/sensor/camera-saturation-capacity.d.ts +1 -0
  180. package/dist/sensor/camera-saturation-capacity.js +3 -55
  181. package/dist/sensor/camera-saturation-capacity.js.map +1 -1
  182. package/dist/sensor/capture-color-sampling-binding.js +1 -26
  183. package/dist/sensor/capture-color-sampling-binding.js.map +1 -1
  184. package/dist/sensor/capture-mode-timing.js +1 -39
  185. package/dist/sensor/capture-mode-timing.js.map +1 -1
  186. package/dist/sensor/capture-mode.js +1 -23
  187. package/dist/sensor/capture-mode.js.map +1 -1
  188. package/dist/sensor/color-sampling.js +1 -26
  189. package/dist/sensor/color-sampling.js.map +1 -1
  190. package/dist/sensor/constant-rate-temporal-integration.js +2 -46
  191. package/dist/sensor/constant-rate-temporal-integration.js.map +1 -1
  192. package/dist/sensor/dark-current.js +2 -45
  193. package/dist/sensor/dark-current.js.map +1 -1
  194. package/dist/sensor/eqe-electron-rate.js +2 -35
  195. package/dist/sensor/eqe-electron-rate.js.map +1 -1
  196. package/dist/sensor/exposure-window.d.ts +5 -0
  197. package/dist/sensor/exposure-window.js +7 -22
  198. package/dist/sensor/exposure-window.js.map +1 -1
  199. package/dist/sensor/iso-gain.js +1 -7
  200. package/dist/sensor/iso-gain.js.map +1 -1
  201. package/dist/sensor/iso-signal-chain.js +1 -43
  202. package/dist/sensor/iso-signal-chain.js.map +1 -1
  203. package/dist/sensor/optical-stack.js +1 -25
  204. package/dist/sensor/optical-stack.js.map +1 -1
  205. package/dist/sensor/photon-energy.js +1 -26
  206. package/dist/sensor/photon-energy.js.map +1 -1
  207. package/dist/sensor/physical-charge-capacity.js +3 -77
  208. package/dist/sensor/physical-charge-capacity.js.map +1 -1
  209. package/dist/sensor/radiometry-readiness.js +2 -23
  210. package/dist/sensor/radiometry-readiness.js.map +1 -1
  211. package/dist/sensor/raw-readout.d.ts +3 -0
  212. package/dist/sensor/raw-readout.js +4 -66
  213. package/dist/sensor/raw-readout.js.map +1 -1
  214. package/dist/sensor/raw-reconstruction.js +2 -64
  215. package/dist/sensor/raw-reconstruction.js.map +1 -1
  216. package/dist/sensor/readout-exposure-linkage.js +1 -9
  217. package/dist/sensor/readout-exposure-linkage.js.map +1 -1
  218. package/dist/sensor/readout-timing.js +3 -57
  219. package/dist/sensor/readout-timing.js.map +1 -1
  220. package/dist/sensor/response-application-compatibility.d.ts +2 -0
  221. package/dist/sensor/response-application-compatibility.js +3 -29
  222. package/dist/sensor/response-application-compatibility.js.map +1 -1
  223. package/dist/sensor/response-operating-range.d.ts +1 -0
  224. package/dist/sensor/response-operating-range.js +3 -79
  225. package/dist/sensor/response-operating-range.js.map +1 -1
  226. package/dist/sensor/responsivity-photocurrent.js +4 -108
  227. package/dist/sensor/responsivity-photocurrent.js.map +1 -1
  228. package/dist/sensor/sampling-aperture.js +1 -25
  229. package/dist/sensor/sampling-aperture.js.map +1 -1
  230. package/dist/sensor/spatial-sample-reduction.js +2 -19
  231. package/dist/sensor/spatial-sample-reduction.js.map +1 -1
  232. package/dist/sensor/spatial-sampling-quadrature.js +1 -3
  233. package/dist/sensor/spatial-sampling-quadrature.js.map +1 -1
  234. package/dist/sensor/spatio-spectral-reduction.js +1 -18
  235. package/dist/sensor/spatio-spectral-reduction.js.map +1 -1
  236. package/dist/sensor/spectral-coverage.d.ts +10 -1
  237. package/dist/sensor/spectral-coverage.js +1 -1
  238. package/dist/sensor/spectral-coverage.js.map +1 -1
  239. package/dist/sensor/spectral-quadrature.js +2 -35
  240. package/dist/sensor/spectral-quadrature.js.map +1 -1
  241. package/dist/sensor/spectral-response.js +1 -47
  242. package/dist/sensor/spectral-response.js.map +1 -1
  243. package/dist/stabilization/camera-shake.js +1 -6
  244. package/dist/stabilization/camera-shake.js.map +1 -1
  245. package/dist/stabilization/system.js +2 -80
  246. package/dist/stabilization/system.js.map +1 -1
  247. package/docs/AGENT_GUIDE.md +1 -0
  248. package/docs/API_REFERENCE.md +41 -2
  249. package/docs/QUICK_START.md +90 -8
  250. package/docs/USAGE.md +47 -2
  251. package/docs/api/core-version.md +1 -1
  252. package/docs/api/exports.json +53 -3
  253. package/docs/api/exposure-filtered-exposure-time.md +105 -0
  254. package/docs/api/facade-develop-joined-parts.md +32 -0
  255. package/docs/api/facade-simulate-capture.md +36 -5
  256. package/docs/api/optics-generic-nd-filter-presets.md +34 -0
  257. package/docs/api/optics-lens-psf-profile.md +3 -1
  258. package/docs/api/output-developed-lens-corrections.md +12 -0
  259. package/docs/api/output-generic-lens-corrections.md +0 -9
  260. package/llms.txt +1 -0
  261. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"responsivity-photocurrent.js","sourceRoot":"","sources":["../../src/sensor/responsivity-photocurrent.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Responsivity photocurrent: converts light power to detector current using responsivity in amperes\n * per watt (A/W).\n *\n * For each wavelength bin, current = responsivity × radiant power; the bins are summed. The result is\n * the steady (quasi-static) current magnitude at the detector terminals. The electrical bias and load\n * conditions under which the responsivity applies are explicit. This is not EQE, an electron rate, a\n * transimpedance voltage or RAW. Fast-changing current needs a separate time-dependent detector model.\n * @see docs/MOTION_AND_SIGNAL.md for equations, coordinate/unit conventions, blockers and support\n * limits.\n */\n\nimport {\n approximationResult,\n type CalculationResult\n} from \"../core/calculation-result.js\";\nimport { stringifyCanonicalJson } from \"../core/canonical-json.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport {\n parseEvidenceList,\n type EvidenceProvenance\n} from \"../core/evidence-provenance.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport {\n parseSensorColorSamplingProfile,\n type SensorColorSamplingProfile\n} from \"./color-sampling.js\";\nimport type {\n SensorResponseApplicationCompatibilityAssessment\n} from \"./response-application-compatibility.js\";\nimport type {\n SensorResponseOperatingRangeAssessment\n} from \"./response-operating-range.js\";\nimport {\n createSensorSpectralResponseChannelBinding,\n requireCurrentSensorSpectralResponseChannelBinding,\n parseSensorSpectralResponseProfile,\n resolveParsedSensorSpectralResponseAtWavelength,\n type ResolvedSensorSpectralResponse,\n type SensorSpectralResponseProfile,\n type SensorSpectralResponseScientificStatus,\n type SensorSpectralResponseUncertainty\n} from \"./spectral-response.js\";\nimport type {\n SensorSpatioSpectralIrradianceReduction,\n SensorSpatioSpectralWavelengthReduction\n} from \"./spatio-spectral-reduction.js\";\nimport { requireInputObject, requireInputKeys, rejectUnknownFields, rejectUnknownVariantFields, UNCERTAINTY_VARIANT_FIELDS } from \"../core/record-validation.js\";\n\ntype UnknownRecord = Record<string, unknown>;\n\nconst REDUCTION_TOLERANCE = 1e-10;\n\nexport type SensorResponsivityBiasCondition =\n | {\n kind: \"zero-bias-photovoltaic\";\n }\n | {\n kind: \"reverse-biased\";\n magnitudeVolts: number;\n };\n\nexport type SensorResponsivityReadoutLoadCondition =\n | {\n kind: \"virtual-ground-current-readout\";\n }\n | {\n kind: \"finite-input-impedance\";\n inputImpedanceOhms: number;\n };\n\nexport interface SensorResponsivityElectricalConditions {\n bias: SensorResponsivityBiasCondition;\n readoutLoad:\n SensorResponsivityReadoutLoadCondition;\n}\n\nexport type SensorResponsivityElectricalConditionPolicy =\n | {\n kind: \"exact-match-required\";\n }\n | {\n kind: \"assume-compatible\";\n limitation: string;\n evidence: readonly EvidenceProvenance[];\n };\n\nexport interface SensorResponsivityElectricalApplicabilityProfile {\n schemaVersion: \"0.1.0\";\n profileId: string;\n responseApplicationProfileId: string;\n spectralResponseProfileId: string;\n colorSamplingProfileId: string;\n channelId: string;\n outputMeaning:\n \"detector-terminal-photocurrent-magnitude\";\n referenceConditions:\n SensorResponsivityElectricalConditions;\n conditionPolicy:\n SensorResponsivityElectricalConditionPolicy;\n scientificStatus:\n SensorSpectralResponseScientificStatus;\n uncertainty:\n SensorSpectralResponseUncertainty;\n evidence: readonly EvidenceProvenance[];\n}\n\nexport interface CalculateSensorResponsivityPhotocurrentInput {\n reduction:\n SensorSpatioSpectralIrradianceReduction;\n compatibility:\n SensorResponseApplicationCompatibilityAssessment;\n operatingRange:\n SensorResponseOperatingRangeAssessment;\n colorSamplingProfile:\n SensorColorSamplingProfile;\n spectralResponseProfile:\n SensorSpectralResponseProfile;\n electricalApplicabilityProfile:\n SensorResponsivityElectricalApplicabilityProfile;\n operatingElectricalConditions:\n SensorResponsivityElectricalConditions;\n}\n\nexport interface SensorResponsivityWavelengthCurrentContribution {\n spectralSampleIndex: number;\n wavelengthNanometers: number;\n wavelengthMeasureNanometers: number;\n geometricApertureIncidentSpectralFluxWattsPerNanometer:\n number;\n radiantPowerContributionWatts: number;\n spectralResponsivityAmperesPerWatt:\n number;\n responseInterpolationUsed: boolean;\n photocurrentMagnitudeContributionAmperes:\n number;\n}\n\nexport interface SensorResponsivityPhotocurrent {\n colorSamplingProfileId: string;\n responseProfileId: string;\n responseApplicationProfileId: string;\n operatingRangeProfileId: string;\n electricalApplicabilityProfileId:\n string;\n /** The exact source colour site. Results produced by the engine fill this in. */\n site?: {\n x: number;\n y: number;\n };\n channelId: string;\n sourceResponseKind:\n \"effective-spectral-responsivity\";\n responseScope:\n SensorSpatioSpectralIrradianceReduction[\"responseScope\"];\n responseReferencePlane:\n SensorResponseApplicationCompatibilityAssessment[\"requiredSourcePlane\"];\n wavelengthBasis:\n SensorSpatioSpectralIrradianceReduction[\"wavelengthBasis\"];\n wavelengthRangeNanometers:\n SensorSpatioSpectralIrradianceReduction[\"wavelengthRangeNanometers\"];\n electricalReferenceConditions:\n SensorResponsivityElectricalConditions;\n operatingElectricalConditions:\n SensorResponsivityElectricalConditions;\n electricalConditionPolicy:\n SensorResponsivityElectricalConditionPolicy;\n electricalCompatibility:\n | \"exact-match\"\n | \"assumed-compatible\";\n spectralNodeCount: number;\n perWavelength:\n readonly SensorResponsivityWavelengthCurrentContribution[];\n photocurrentMagnitudeAmperes: number;\n currentSignConvention:\n \"magnitude-only-no-circuit-polarity\";\n summationMethod:\n \"kahan-compensated\";\n responseApplicationPerformed: true;\n spectralResponsivityApplied: true;\n quantumEfficiencyApplied: false;\n photonRateCalculated: false;\n electronRateCalculated: false;\n currentCalculated: true;\n chargeCalculated: false;\n temporalResponseModel:\n \"quasi-static-steady-state-only\";\n detectorBandwidthModeled: false;\n transimpedanceGainApplied: false;\n voltageCalculated: false;\n temporalIntegrationApplied: false;\n exposureDurationApplied: false;\n saturationAssessed: false;\n readoutElectronicsLinearityAssessed:\n false;\n shotNoiseApplied: false;\n readNoiseApplied: false;\n adcQuantizationApplied: false;\n rawCodeValueProduced: false;\n responseUncertaintyPropagated: false;\n electricalApplicabilityUncertaintyPropagated:\n false;\n quadratureConvergenceErrorEstimated:\n false;\n componentEvidence: {\n electricalApplicability:\n readonly EvidenceProvenance[];\n electricalConditionAssumption:\n readonly EvidenceProvenance[];\n };\n}\n\ninterface CompensatedSum {\n sum: number;\n correction: number;\n}\n\nfunction addCompensated(\n state: CompensatedSum,\n value: number\n): void {\n const adjusted =\n value - state.correction;\n const next =\n state.sum + adjusted;\n state.correction =\n (next - state.sum) - adjusted;\n state.sum = next;\n}\n\nfunction requireRecord(\n value: unknown,\n path: string,\n allowedKeys: readonly string[] | null\n): UnknownRecord {\n if (\n typeof value !== \"object\" ||\n value === null ||\n Array.isArray(value)\n ) {\n throw new InvalidConfigurationError(\n path + \" must be an object.\"\n );\n }\n if (allowedKeys !== null) rejectUnknownFields(value, allowedKeys, path);\n return value as UnknownRecord;\n}\n\nfunction requireNonEmptyString(\n value: unknown,\n path: string\n): string {\n if (\n typeof value !== \"string\" ||\n value.trim().length === 0\n ) {\n throw new InvalidConfigurationError(\n path + \" must be a non-empty string.\"\n );\n }\n return value;\n}\n\nfunction requireFiniteNonNegative(\n value: unknown,\n path: string\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value) ||\n value < 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must be finite and greater than or equal to zero.\"\n );\n }\n return value;\n}\n\nfunction requirePositiveFiniteConfiguration(\n value: unknown,\n path: string\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value) ||\n value <= 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must be finite and greater than zero.\"\n );\n }\n return value;\n}\n\nfunction requirePositiveFiniteInput(\n value: unknown,\n path: string\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value) ||\n value <= 0\n ) {\n throw new InvalidScientificInputError(\n path +\n \" must be finite and greater than zero.\"\n );\n }\n return value;\n}\n\nfunction requireNonNegativeFiniteInput(\n value: unknown,\n path: string\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value) ||\n value < 0\n ) {\n throw new InvalidScientificInputError(\n path +\n \" must be finite and greater than or equal to zero.\"\n );\n }\n return value;\n}\n\nfunction requireSafeNonNegativeInteger(\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 InvalidScientificInputError(\n path +\n \" must be a non-negative safe integer.\"\n );\n }\n return value;\n}\n\nfunction parseUncertainty(\n value: unknown,\n path: string\n): SensorSpectralResponseUncertainty {\n const record = requireRecord(\n value,\n path, null\n );\n rejectUnknownVariantFields(record, \"kind\", UNCERTAINTY_VARIANT_FIELDS, path);\n\n if (record.kind === \"relative\") {\n const fraction =\n requireFiniteNonNegative(\n record.fraction,\n path + \".fraction\"\n );\n return {\n kind: \"relative\",\n fraction,\n basis:\n requireNonEmptyString(\n record.basis,\n path + \".basis\"\n )\n };\n }\n\n if (\n record.kind === \"not-quantified\"\n ) {\n return {\n kind: \"not-quantified\",\n limitation:\n requireNonEmptyString(\n record.limitation,\n path + \".limitation\"\n )\n };\n }\n\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n}\n\nfunction parseElectricalConditions(\n value: unknown,\n path: string\n): SensorResponsivityElectricalConditions {\n const record = requireRecord(\n value,\n path, [\"bias\", \"readoutLoad\"]\n );\n const bias = requireRecord(\n record.bias,\n path + \".bias\", null\n );\n rejectUnknownVariantFields(bias, \"kind\", { \"zero-bias-photovoltaic\": [\"kind\"], \"reverse-biased\": [\"kind\", \"magnitudeVolts\"] }, path + \".bias\");\n const readoutLoad = requireRecord(\n record.readoutLoad,\n path + \".readoutLoad\", null\n );\n rejectUnknownVariantFields(readoutLoad, \"kind\", { \"virtual-ground-current-readout\": [\"kind\"], \"finite-input-impedance\": [\"kind\", \"inputImpedanceOhms\"] }, path + \".readoutLoad\");\n\n const parsedBias:\n SensorResponsivityBiasCondition =\n bias.kind ===\n \"zero-bias-photovoltaic\"\n ? {\n kind:\n \"zero-bias-photovoltaic\"\n }\n : bias.kind ===\n \"reverse-biased\"\n ? {\n kind:\n \"reverse-biased\",\n magnitudeVolts:\n requirePositiveFiniteConfiguration(\n bias.magnitudeVolts,\n path +\n \".bias.magnitudeVolts\"\n )\n }\n : ((): never => {\n throw new InvalidConfigurationError(\n path +\n \".bias.kind is invalid.\"\n );\n })();\n\n const parsedReadout:\n SensorResponsivityReadoutLoadCondition =\n readoutLoad.kind ===\n \"virtual-ground-current-readout\"\n ? {\n kind:\n \"virtual-ground-current-readout\"\n }\n : readoutLoad.kind ===\n \"finite-input-impedance\"\n ? {\n kind:\n \"finite-input-impedance\",\n inputImpedanceOhms:\n requirePositiveFiniteConfiguration(\n readoutLoad\n .inputImpedanceOhms,\n path +\n \".readoutLoad.inputImpedanceOhms\"\n )\n }\n : ((): never => {\n throw new InvalidConfigurationError(\n path +\n \".readoutLoad.kind is invalid.\"\n );\n })();\n\n return {\n bias: parsedBias,\n readoutLoad: parsedReadout\n };\n}\n\nfunction parseConditionPolicy(\n value: unknown,\n path: string\n): SensorResponsivityElectricalConditionPolicy {\n const record = requireRecord(\n value,\n path, null\n );\n rejectUnknownVariantFields(record, \"kind\", { \"exact-match-required\": [\"kind\"], \"assume-compatible\": [\"kind\", \"limitation\", \"evidence\"] }, path);\n\n if (\n record.kind ===\n \"exact-match-required\"\n ) {\n return {\n kind: \"exact-match-required\"\n };\n }\n\n if (\n record.kind ===\n \"assume-compatible\"\n ) {\n return {\n kind: \"assume-compatible\",\n limitation:\n requireNonEmptyString(\n record.limitation,\n path + \".limitation\"\n ),\n evidence:\n parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n )\n };\n }\n\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n}\n\n/**\n * Validates untrusted input and returns it as a normalized, typed value. Unknown enum values,\n * missing required fields and inconsistent scientific data are rejected.\n *\n * The profile states the electrical bias and load conditions under which an A/W responsivity applies.\n * @param value - Untrusted data. TypeScript types alone are not validation.\n * @returns The result. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function parseSensorResponsivityElectricalApplicabilityProfile(\n value: unknown\n): SensorResponsivityElectricalApplicabilityProfile {\n const record = requireRecord(\n value,\n \"sensorResponsivityElectricalApplicability\", [\"schemaVersion\", \"outputMeaning\", \"scientificStatus\", \"uncertainty\", \"profileId\", \"responseApplicationProfileId\", \"spectralResponseProfileId\", \"colorSamplingProfileId\", \"channelId\", \"referenceConditions\", \"conditionPolicy\", \"evidence\"]\n );\n\n if (\n record.schemaVersion !== \"0.1.0\"\n ) {\n throw new InvalidConfigurationError(\n 'sensorResponsivityElectricalApplicability.schemaVersion must be \"0.1.0\".'\n );\n }\n if (\n record.outputMeaning !==\n \"detector-terminal-photocurrent-magnitude\"\n ) {\n throw new InvalidConfigurationError(\n \"sensorResponsivityElectricalApplicability.outputMeaning is invalid.\"\n );\n }\n if (\n record.scientificStatus !==\n \"calibrated\" &&\n record.scientificStatus !==\n \"approximation\"\n ) {\n throw new InvalidConfigurationError(\n \"sensorResponsivityElectricalApplicability.scientificStatus is invalid.\"\n );\n }\n\n const uncertainty =\n parseUncertainty(\n record.uncertainty,\n \"sensorResponsivityElectricalApplicability.uncertainty\"\n );\n\n if (\n record.scientificStatus ===\n \"calibrated\" &&\n uncertainty.kind ===\n \"not-quantified\"\n ) {\n throw new InvalidConfigurationError(\n \"A calibrated electrical applicability profile must declare quantified relative uncertainty.\"\n );\n }\n\n return {\n schemaVersion: \"0.1.0\",\n profileId:\n requireNonEmptyString(\n record.profileId,\n \"sensorResponsivityElectricalApplicability.profileId\"\n ),\n responseApplicationProfileId:\n requireNonEmptyString(\n record\n .responseApplicationProfileId,\n \"sensorResponsivityElectricalApplicability.responseApplicationProfileId\"\n ),\n spectralResponseProfileId:\n requireNonEmptyString(\n record\n .spectralResponseProfileId,\n \"sensorResponsivityElectricalApplicability.spectralResponseProfileId\"\n ),\n colorSamplingProfileId:\n requireNonEmptyString(\n record.colorSamplingProfileId,\n \"sensorResponsivityElectricalApplicability.colorSamplingProfileId\"\n ),\n channelId:\n requireNonEmptyString(\n record.channelId,\n \"sensorResponsivityElectricalApplicability.channelId\"\n ),\n outputMeaning:\n \"detector-terminal-photocurrent-magnitude\",\n referenceConditions:\n parseElectricalConditions(\n record.referenceConditions,\n \"sensorResponsivityElectricalApplicability.referenceConditions\"\n ),\n conditionPolicy:\n parseConditionPolicy(\n record.conditionPolicy,\n \"sensorResponsivityElectricalApplicability.conditionPolicy\"\n ),\n scientificStatus:\n record.scientificStatus,\n uncertainty,\n evidence:\n parseEvidenceList(\n record.evidence,\n \"sensorResponsivityElectricalApplicability.evidence\"\n )\n };\n}\n\n/**\n * Identity string for parsed plain data that ignores key order, so records with\n * the same content compare equal whatever order their properties were added in.\n */\nfunction canonicalJson(\n value: unknown\n): string {\n if (value === undefined) return \"undefined\";\n return stringifyCanonicalJson(value, {\n undefinedObjectProperties: \"omit\",\n nonFiniteNumberMessage:\n \"A/W photocurrent identity data must contain finite numbers.\",\n unsupportedValueMessage:\n \"A/W photocurrent identity data must be plain JSON data.\"\n });\n}\n\nfunction approximatelyEqual(\n actual: number,\n expected: number\n): boolean {\n const scale = Math.max(\n 1,\n Math.abs(actual),\n Math.abs(expected)\n );\n return (\n Math.abs(actual - expected) <=\n REDUCTION_TOLERANCE * scale\n );\n}\n\nfunction electricalConditionsMatch(\n reference:\n SensorResponsivityElectricalConditions,\n operating:\n SensorResponsivityElectricalConditions\n): boolean {\n return (\n canonicalJson(reference) ===\n canonicalJson(operating)\n );\n}\n\nfunction validateAuthorizationChain(\n reduction:\n SensorSpatioSpectralIrradianceReduction,\n compatibility:\n SensorResponseApplicationCompatibilityAssessment,\n operatingRange:\n SensorResponseOperatingRangeAssessment\n): void {\n requireInputObject(reduction, \"reduction input\");\n if (\n reduction.outputMeaning !==\n \"pre-response-spatio-spectral-radiometric-reduction\" ||\n reduction\n .spectralResponseApplicationPerformed !==\n false ||\n reduction\n .spectralResponsivityApplied !==\n false ||\n reduction.temporalIntegrationApplied !==\n false\n ) {\n throw new InvalidScientificInputError(\n \"reduction must remain pre-response and pre-temporal before A/W photocurrent conversion.\"\n );\n }\n\n if (\n !compatibility\n .structuralCompatibilityEstablished ||\n compatibility.compatibilityStatus ===\n \"blocked\" ||\n compatibility.blockers.length !== 0 ||\n !compatibility.sourcePlaneMatched ||\n compatibility.requiredSignalPath !==\n \"radiant-power-to-current\"\n ) {\n throw new InvalidScientificInputError(\n \"compatibility must establish a non-blocked radiant-power-to-current response path.\"\n );\n }\n\n if (\n compatibility\n .spectralResponseProfileId !==\n reduction.responseProfileId ||\n compatibility.colorSamplingProfileId !==\n reduction.colorSamplingProfileId ||\n compatibility.channelId !==\n reduction.channelId ||\n compatibility.responseScope !==\n reduction.responseScope\n ) {\n throw new InvalidScientificInputError(\n \"compatibility identities must exactly match the reduction.\"\n );\n }\n\n if (\n !operatingRange\n .operatingRangeCompatibilityAssessed ||\n !operatingRange\n .instantaneousResponseRangeCompatible ||\n !operatingRange\n .responseRateConversionAuthorized ||\n operatingRange.status === \"blocked\" ||\n operatingRange.blockers.length !== 0 ||\n operatingRange.requiredSignalPath !==\n \"radiant-power-to-current\" ||\n operatingRange\n .responseApplicationPerformed !==\n false ||\n operatingRange\n .currentConversionPerformed !== false ||\n operatingRange\n .temporalIntegrationAuthorized !== false ||\n !operatingRange\n .spectralNodeRangeCompatibilityAssessed ||\n operatingRange\n .spectralInputModel.kind !==\n \"per-spectral-bin\" ||\n operatingRange\n .spatialLinearityModel.kind !==\n \"linear-superposition-over-geometric-aperture\"\n ) {\n throw new InvalidScientificInputError(\n \"operatingRange must authorize a clean per-bin radiant-power-to-current path.\"\n );\n }\n\n if (\n operatingRange\n .spectralResponseProfileId !==\n reduction.responseProfileId ||\n operatingRange\n .colorSamplingProfileId !==\n reduction.colorSamplingProfileId ||\n operatingRange.channelId !==\n reduction.channelId ||\n operatingRange\n .responseApplicationProfileId !==\n compatibility.applicationProfileId\n ) {\n throw new InvalidScientificInputError(\n \"operatingRange identities must exactly match the reduction and compatibility assessment.\"\n );\n }\n}\n\nfunction validateReductionNodes(\n reduction:\n SensorSpatioSpectralIrradianceReduction\n): readonly SensorSpatioSpectralWavelengthReduction[] {\n if (\n !Array.isArray(\n reduction.perWavelength\n ) ||\n !Number.isSafeInteger(\n reduction.spectralNodeCount\n ) ||\n reduction.spectralNodeCount <= 0 ||\n reduction.perWavelength.length !==\n reduction.spectralNodeCount\n ) {\n throw new InvalidScientificInputError(\n \"reduction.perWavelength must contain exactly spectralNodeCount entries.\"\n );\n }\n\n let priorWavelength =\n Number.NEGATIVE_INFINITY;\n let normalizedWeightSum = 0;\n const totalPower:\n CompensatedSum = {\n sum: 0,\n correction: 0\n };\n\n reduction.perWavelength.forEach(\n (node, arrayIndex) => {\n const sampleIndex =\n requireSafeNonNegativeInteger(\n node.spectralSampleIndex,\n \"reduction.perWavelength[\" +\n arrayIndex +\n \"].spectralSampleIndex\"\n );\n if (sampleIndex !== arrayIndex) {\n throw new InvalidScientificInputError(\n \"reduction spectralSampleIndex values must form the exact contiguous range 0..spectralNodeCount-1.\"\n );\n }\n\n const wavelength =\n requirePositiveFiniteInput(\n node.wavelengthNanometers,\n \"reduction.perWavelength[\" +\n arrayIndex +\n \"].wavelengthNanometers\"\n );\n if (\n wavelength <= priorWavelength\n ) {\n throw new InvalidScientificInputError(\n \"reduction wavelength nodes must be strictly increasing.\"\n );\n }\n priorWavelength = wavelength;\n\n const measure =\n requirePositiveFiniteInput(\n node.wavelengthMeasureNanometers,\n \"reduction.perWavelength[\" +\n arrayIndex +\n \"].wavelengthMeasureNanometers\"\n );\n const normalizedWeight =\n requirePositiveFiniteInput(\n node.normalizedWavelengthWeight,\n \"reduction.perWavelength[\" +\n arrayIndex +\n \"].normalizedWavelengthWeight\"\n );\n const fluxDensity =\n requireNonNegativeFiniteInput(\n node\n .geometricApertureIncidentSpectralFluxWattsPerNanometer,\n \"reduction.perWavelength[\" +\n arrayIndex +\n \"].geometricApertureIncidentSpectralFluxWattsPerNanometer\"\n );\n const power =\n requireNonNegativeFiniteInput(\n node\n .wavelengthIntegratedGeometricApertureIncidentFluxContributionWatts,\n \"reduction.perWavelength[\" +\n arrayIndex +\n \"].wavelengthIntegratedGeometricApertureIncidentFluxContributionWatts\"\n );\n const expected =\n fluxDensity * measure;\n if (\n !Number.isFinite(expected) ||\n !approximatelyEqual(\n power,\n expected\n )\n ) {\n throw new InvalidScientificInputError(\n \"reduction per-wavelength radiant-power contribution must equal spectral flux density × d-lambda.\"\n );\n }\n\n normalizedWeightSum +=\n normalizedWeight;\n addCompensated(\n totalPower,\n power\n );\n }\n );\n\n if (\n !Number.isFinite(\n normalizedWeightSum\n ) ||\n !approximatelyEqual(\n normalizedWeightSum,\n 1\n )\n ) {\n throw new InvalidScientificInputError(\n \"reduction normalized wavelength weights must sum to 1.\"\n );\n }\n\n const reductionPower =\n requireNonNegativeFiniteInput(\n reduction\n .wavelengthIntegratedGeometricApertureIncidentFluxWatts,\n \"reduction.wavelengthIntegratedGeometricApertureIncidentFluxWatts\"\n );\n if (\n !approximatelyEqual(\n totalPower.sum,\n reductionPower\n )\n ) {\n throw new InvalidScientificInputError(\n \"reduction total geometric-aperture radiant power must match the per-wavelength sum.\"\n );\n }\n\n return reduction.perWavelength;\n}\n\nfunction validateOperatingRangeNodeBinding(\n reduction:\n SensorSpatioSpectralIrradianceReduction,\n nodes:\n readonly SensorSpatioSpectralWavelengthReduction[],\n operatingRange:\n SensorResponseOperatingRangeAssessment\n): void {\n const evaluated =\n operatingRange\n .evaluatedSpectralNodeInputs;\n\n if (\n evaluated === undefined ||\n evaluated.length !== nodes.length\n ) {\n throw new InvalidScientificInputError(\n \"operatingRange must carry one evaluated spectral-node input per reduction wavelength node.\"\n );\n }\n\n if (\n operatingRange\n .evaluatedWavelengthRangeNanometers\n .minimum !==\n reduction.wavelengthRangeNanometers\n .minimum ||\n operatingRange\n .evaluatedWavelengthRangeNanometers\n .maximum !==\n reduction.wavelengthRangeNanometers\n .maximum\n ) {\n throw new InvalidScientificInputError(\n \"operatingRange wavelength range must exactly match the reduction.\"\n );\n }\n\n evaluated.forEach(\n (entry, index) => {\n const node = nodes[index]!;\n if (\n entry.spectralSampleIndex !==\n node.spectralSampleIndex ||\n entry.wavelengthNanometers !==\n node.wavelengthNanometers ||\n entry.wavelengthMeasureNanometers !==\n node.wavelengthMeasureNanometers\n ) {\n throw new InvalidScientificInputError(\n \"operatingRange spectral-node identities must exactly match the reduction.\"\n );\n }\n\n const expected =\n operatingRange.inputRange.kind ===\n \"wavelength-integrated-geometric-aperture-radiant-power\"\n ? node\n .wavelengthIntegratedGeometricApertureIncidentFluxContributionWatts\n : node\n .wavelengthIntegratedSpatialAverageContributionWattsPerSquareMeter;\n\n if (\n entry.kind !==\n operatingRange.inputRange.kind ||\n entry.unit !==\n operatingRange.inputRange.unit ||\n !approximatelyEqual(\n entry.value,\n expected\n )\n ) {\n throw new InvalidScientificInputError(\n \"operatingRange spectral-node values must match the reduction values in the calibrated input domain.\"\n );\n }\n }\n );\n}\n\nfunction validateResponseBinding(\n resolved:\n ResolvedSensorSpectralResponse,\n reduction:\n SensorSpatioSpectralIrradianceReduction\n): void {\n if (\n resolved.profileId !==\n reduction.responseProfileId ||\n resolved.colorSamplingProfileId !==\n reduction.colorSamplingProfileId ||\n resolved.channelId !==\n reduction.channelId ||\n resolved.sourceResponseKind !==\n reduction.sourceResponseKind ||\n resolved.responseScope !==\n reduction.responseScope ||\n resolved.scientificStatus !==\n reduction.responseScientificStatus ||\n canonicalJson(\n resolved.uncertainty\n ) !==\n canonicalJson(\n reduction.responseUncertainty\n ) ||\n canonicalJson(\n resolved.componentEvidence\n ) !==\n canonicalJson({\n profile:\n reduction.componentEvidence\n .spectral.profile,\n channel:\n reduction.componentEvidence\n .spectral.channel,\n curves:\n reduction.componentEvidence\n .spectral.curves\n })\n ) {\n throw new InvalidScientificInputError(\n \"Resolved A/W response calibration metadata/evidence must exactly match the reduction.\"\n );\n }\n}\n\nfunction validateExactResponseDataBinding(\n responseProfile:\n SensorSpectralResponseProfile,\n reduction:\n SensorSpatioSpectralIrradianceReduction\n): void {\n const response =\n responseProfile.channels.find(\n (entry) =>\n entry.channelId ===\n reduction.channelId\n );\n if (reduction.responseChannelBinding !== undefined) {\n requireCurrentSensorSpectralResponseChannelBinding(\n reduction.responseChannelBinding\n );\n }\n if (\n response === undefined ||\n reduction.responseChannelBinding ===\n undefined ||\n canonicalJson(\n createSensorSpectralResponseChannelBinding(\n response\n )\n ) !==\n canonicalJson(\n reduction.responseChannelBinding\n )\n ) {\n throw new InvalidScientificInputError(\n \"Supplied spectral response channel data must exactly match the response-channel binding carried by the reduction.\"\n );\n }\n}\n\nfunction validateElectricalBinding(\n profile:\n SensorResponsivityElectricalApplicabilityProfile,\n input:\n CalculateSensorResponsivityPhotocurrentInput,\n operatingElectricalConditions:\n SensorResponsivityElectricalConditions\n): {\n compatibility:\n \"exact-match\" |\n \"assumed-compatible\";\n assumptionEvidence:\n readonly EvidenceProvenance[];\n} {\n if (\n profile.responseApplicationProfileId !==\n input.compatibility\n .applicationProfileId ||\n profile.spectralResponseProfileId !==\n input.reduction\n .responseProfileId ||\n profile.colorSamplingProfileId !==\n input.reduction\n .colorSamplingProfileId ||\n profile.channelId !==\n input.reduction.channelId\n ) {\n throw new InvalidScientificInputError(\n \"Electrical applicability profile identities must exactly match the response pipeline.\"\n );\n }\n\n if (\n profile.conditionPolicy.kind ===\n \"exact-match-required\"\n ) {\n if (\n !electricalConditionsMatch(\n profile.referenceConditions,\n operatingElectricalConditions\n )\n ) {\n throw new InvalidScientificInputError(\n \"Operating electrical conditions must exactly match the A/W calibration reference conditions.\"\n );\n }\n return {\n compatibility: \"exact-match\",\n assumptionEvidence: []\n };\n }\n\n return {\n compatibility:\n \"assumed-compatible\",\n assumptionEvidence:\n profile.conditionPolicy.evidence\n };\n}\n\n/**\n * Sums responsivity (A/W) × radiant power over wavelength bins to get the steady current magnitude,\n * under explicit electrical conditions.\n *\n * This is not EQE, an electron rate, a transimpedance voltage or RAW. Fast-changing current needs a\n * separate time-dependent detector model.\n * @param input - The input; see `CalculateSensorResponsivityPhotocurrentInput` for its fields, units and coordinates.\n * @returns The result. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function calculateSensorResponsivityPhotocurrent(\n input:\n CalculateSensorResponsivityPhotocurrentInput\n): CalculationResult<SensorResponsivityPhotocurrent> {\n requireInputKeys(input, \"calculateSensorResponsivityPhotocurrent\", [\"reduction\", \"compatibility\", \"operatingRange\", \"colorSamplingProfile\", \"spectralResponseProfile\", \"electricalApplicabilityProfile\", \"operatingElectricalConditions\"]);\n validateAuthorizationChain(\n input.reduction,\n input.compatibility,\n input.operatingRange\n );\n\n if (\n input.reduction\n .sourceResponseKind !==\n \"effective-spectral-responsivity\"\n ) {\n throw new InvalidScientificInputError(\n \"A/W photocurrent conversion requires effective spectral responsivity, not EQE.\"\n );\n }\n\n const colorProfile =\n parseSensorColorSamplingProfile(\n input.colorSamplingProfile\n );\n const responseProfile =\n parseSensorSpectralResponseProfile(\n input.spectralResponseProfile\n );\n const electricalProfile =\n parseSensorResponsivityElectricalApplicabilityProfile(\n input.electricalApplicabilityProfile\n );\n\n if (\n colorProfile.profileId !==\n input.reduction\n .colorSamplingProfileId ||\n responseProfile.profileId !==\n input.reduction\n .responseProfileId ||\n responseProfile\n .colorSamplingProfileId !==\n colorProfile.profileId\n ) {\n throw new InvalidScientificInputError(\n \"Supplied color/spectral response profiles must exactly match the reduction identities.\"\n );\n }\n\n validateExactResponseDataBinding(\n responseProfile,\n input.reduction\n );\n\n const operatingElectricalConditions =\n parseElectricalConditions(\n input.operatingElectricalConditions,\n \"operatingElectricalConditions\"\n );\n const electrical =\n validateElectricalBinding(\n electricalProfile,\n input,\n operatingElectricalConditions\n );\n const nodes =\n validateReductionNodes(\n input.reduction\n );\n validateOperatingRangeNodeBinding(\n input.reduction,\n nodes,\n input.operatingRange\n );\n\n const currentSum:\n CompensatedSum = {\n sum: 0,\n correction: 0\n };\n const perWavelength:\n SensorResponsivityWavelengthCurrentContribution[] =\n [];\n let responseBindingValidated =\n false;\n\n for (const node of nodes) {\n const resolved =\n resolveParsedSensorSpectralResponseAtWavelength({\n colorSamplingProfile:\n colorProfile,\n spectralResponseProfile:\n responseProfile,\n channelId:\n input.reduction.channelId,\n wavelengthNanometers:\n node.wavelengthNanometers,\n wavelengthBasis:\n input.reduction\n .wavelengthBasis\n });\n\n if (!responseBindingValidated) {\n validateResponseBinding(\n resolved.value,\n input.reduction\n );\n responseBindingValidated =\n true;\n }\n\n const responsivity =\n resolved.value.response as Extract<\n typeof resolved.value.response,\n {\n kind:\n \"effective-spectral-responsivity\";\n }\n >;\n\n const radiantPowerContributionWatts =\n node\n .geometricApertureIncidentSpectralFluxWattsPerNanometer *\n node.wavelengthMeasureNanometers;\n const photocurrentMagnitudeContributionAmperes =\n radiantPowerContributionWatts *\n responsivity.amperesPerWatt;\n\n if (\n !Number.isFinite(\n radiantPowerContributionWatts\n ) ||\n !Number.isFinite(\n photocurrentMagnitudeContributionAmperes\n ) ||\n photocurrentMagnitudeContributionAmperes <\n 0\n ) {\n throw new InvalidScientificInputError(\n \"A/W wavelength-node photocurrent calculation must remain finite and nonnegative.\"\n );\n }\n\n addCompensated(\n currentSum,\n photocurrentMagnitudeContributionAmperes\n );\n\n perWavelength.push({\n spectralSampleIndex:\n node.spectralSampleIndex,\n wavelengthNanometers:\n node.wavelengthNanometers,\n wavelengthMeasureNanometers:\n node.wavelengthMeasureNanometers,\n geometricApertureIncidentSpectralFluxWattsPerNanometer:\n node\n .geometricApertureIncidentSpectralFluxWattsPerNanometer,\n radiantPowerContributionWatts,\n spectralResponsivityAmperesPerWatt:\n responsivity.amperesPerWatt,\n responseInterpolationUsed:\n resolved.value\n .interpolationUsed,\n photocurrentMagnitudeContributionAmperes\n });\n }\n\n if (\n !Number.isFinite(\n currentSum.sum\n ) ||\n currentSum.sum < 0\n ) {\n throw new InvalidScientificInputError(\n \"Total A/W photocurrent magnitude must remain finite and nonnegative.\"\n );\n }\n\n return approximationResult(\n {\n colorSamplingProfileId:\n input.reduction\n .colorSamplingProfileId,\n responseProfileId:\n input.reduction\n .responseProfileId,\n responseApplicationProfileId:\n input.compatibility\n .applicationProfileId,\n operatingRangeProfileId:\n input.operatingRange\n .operatingRangeProfileId,\n electricalApplicabilityProfileId:\n electricalProfile.profileId,\n site: {\n ...input.reduction.site\n },\n channelId:\n input.reduction.channelId,\n sourceResponseKind:\n \"effective-spectral-responsivity\",\n responseScope:\n input.reduction.responseScope,\n responseReferencePlane:\n input.compatibility\n .requiredSourcePlane,\n wavelengthBasis:\n input.reduction\n .wavelengthBasis,\n wavelengthRangeNanometers: {\n ...input.reduction\n .wavelengthRangeNanometers\n },\n electricalReferenceConditions:\n electricalProfile\n .referenceConditions,\n operatingElectricalConditions,\n electricalConditionPolicy:\n electricalProfile\n .conditionPolicy,\n electricalCompatibility:\n electrical.compatibility,\n spectralNodeCount:\n nodes.length,\n perWavelength,\n photocurrentMagnitudeAmperes:\n currentSum.sum,\n currentSignConvention:\n \"magnitude-only-no-circuit-polarity\",\n summationMethod:\n \"kahan-compensated\",\n responseApplicationPerformed:\n true,\n spectralResponsivityApplied:\n true,\n quantumEfficiencyApplied:\n false,\n photonRateCalculated: false,\n electronRateCalculated: false,\n currentCalculated: true,\n chargeCalculated: false,\n temporalResponseModel:\n \"quasi-static-steady-state-only\",\n detectorBandwidthModeled: false,\n transimpedanceGainApplied:\n false,\n voltageCalculated: false,\n temporalIntegrationApplied:\n false,\n exposureDurationApplied: false,\n saturationAssessed: false,\n readoutElectronicsLinearityAssessed:\n false,\n shotNoiseApplied: false,\n readNoiseApplied: false,\n adcQuantizationApplied:\n false,\n rawCodeValueProduced: false,\n responseUncertaintyPropagated:\n false,\n electricalApplicabilityUncertaintyPropagated:\n false,\n quadratureConvergenceErrorEstimated:\n false,\n componentEvidence: {\n electricalApplicability:\n electricalProfile.evidence,\n electricalConditionAssumption:\n electrical\n .assumptionEvidence\n }\n },\n \"sensor-spectral-responsivity-photocurrent\",\n \"1.0.0\",\n [\n \"Spectral responsivity in A/W is applied independently at every wavelength quadrature node as detector-terminal photocurrent magnitude per incident radiant power.\",\n \"Current sign/polarity is deliberately not modeled; the result is a nonnegative photocurrent magnitude and does not imply a circuit current direction.\",\n \"The A/W calibration is bound to explicit detector electrical conditions. Exact-match mode requires identical bias and readout-load semantics; approximation mode requires evidence and a stated limitation.\",\n \"Virtual-ground current readout and finite input impedance are modeled as calibration-condition identities only; this function does not simulate amplifier circuits or prove impedance adequacy.\",\n \"NIST photodiode guidance shows detector/electronics/loading can affect linear operation, so transimpedance/current-readout conditions are not treated as scientifically inert.\",\n \"Structural compatibility, geometric-aperture linear superposition and per-spectral-bin operating-range applicability must already authorize the radiant-power→current path.\",\n \"Response metadata/evidence and operating-range spectral-node values are rebound to the exact reduction so matching IDs alone or stale authorization cannot enable conversion.\",\n \"The calculation does not use photon energy, QE, photon rate or electron rate. A/W remains a distinct current-domain response representation.\",\n \"No transimpedance gain or voltage conversion is performed; current-to-voltage converter gain/offset/linearity remain downstream electronics contracts.\",\n \"The A/W response is used only as a quasi-static steady-state power→current mapping. Detector impulse response, bandwidth, modulation-frequency response and transient settling are not modeled.\",\n \"Outputs are instantaneous current only. Exposure-time integration to charge, saturation, noise, ADC/RAW conversion and reconstruction remain downstream.\",\n \"Response/electrical uncertainties and quadrature convergence error are not propagated into a combined current uncertainty by this version.\"\n ]\n );\n}\n"]}
1
+ {"version":3,"file":"responsivity-photocurrent.js","sourceRoot":"","sources":["../../src/sensor/responsivity-photocurrent.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Responsivity photocurrent: converts light power to detector current using responsivity in amperes\n * per watt (A/W).\n *\n * For each wavelength bin, current = responsivity × radiant power; the bins are summed. The result is\n * the steady (quasi-static) current magnitude at the detector terminals. The electrical bias and load\n * conditions under which the responsivity applies are explicit. This is not EQE, an electron rate, a\n * transimpedance voltage or RAW. Fast-changing current needs a separate time-dependent detector model.\n * @see docs/MOTION_AND_SIGNAL.md for equations, coordinate/unit conventions, blockers and support\n * limits.\n */\n\nimport {\n approximationResult,\n type CalculationResult\n} from \"../core/calculation-result.js\";\nimport { stringifyCanonicalJson } from \"../core/canonical-json.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport {\n parseEvidenceList,\n type EvidenceProvenance\n} from \"../core/evidence-provenance.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport {\n parseSensorColorSamplingProfile,\n type SensorColorSamplingProfile\n} from \"./color-sampling.js\";\nimport type {\n SensorResponseApplicationCompatibilityAssessment\n} from \"./response-application-compatibility.js\";\nimport type {\n SensorResponseOperatingRangeAssessment\n} from \"./response-operating-range.js\";\nimport {\n createSensorSpectralResponseChannelBinding,\n requireCurrentSensorSpectralResponseChannelBinding,\n parseSensorSpectralResponseProfile,\n resolveParsedSensorSpectralResponseAtWavelength,\n type ResolvedSensorSpectralResponse,\n type SensorSpectralResponseProfile,\n type SensorSpectralResponseScientificStatus,\n type SensorSpectralResponseUncertainty\n} from \"./spectral-response.js\";\nimport type {\n SensorSpatioSpectralIrradianceReduction,\n SensorSpatioSpectralWavelengthReduction\n} from \"./spatio-spectral-reduction.js\";\nimport { requireInputObject, requireInputKeys, rejectUnknownVariantFields, requireConfigRecord as requireRecord, requireConfigString as requireNonEmptyString, requireConfigPositiveFinite as requirePositiveFiniteConfiguration, requireInputNonNegativeFinite as requireNonNegativeFiniteInput, requireInputPositiveFinite as requirePositiveFiniteInput, requireInputNonNegativeSafeInteger as requireSafeNonNegativeInteger } from \"../core/record-validation.js\";\nimport { addCompensated } from \"../core/shared-helpers.js\";\nimport { parseReferenceConditionPolicy as parseConditionPolicy } from \"./response-application-compatibility.js\";\nimport { parseUncertainty } from \"./response-operating-range.js\";\n\nconst REDUCTION_TOLERANCE = 1e-10;\n\nexport type SensorResponsivityBiasCondition =\n | {\n kind: \"zero-bias-photovoltaic\";\n }\n | {\n kind: \"reverse-biased\";\n magnitudeVolts: number;\n };\n\nexport type SensorResponsivityReadoutLoadCondition =\n | {\n kind: \"virtual-ground-current-readout\";\n }\n | {\n kind: \"finite-input-impedance\";\n inputImpedanceOhms: number;\n };\n\nexport interface SensorResponsivityElectricalConditions {\n bias: SensorResponsivityBiasCondition;\n readoutLoad:\n SensorResponsivityReadoutLoadCondition;\n}\n\nexport type SensorResponsivityElectricalConditionPolicy =\n | {\n kind: \"exact-match-required\";\n }\n | {\n kind: \"assume-compatible\";\n limitation: string;\n evidence: readonly EvidenceProvenance[];\n };\n\nexport interface SensorResponsivityElectricalApplicabilityProfile {\n schemaVersion: \"0.1.0\";\n profileId: string;\n responseApplicationProfileId: string;\n spectralResponseProfileId: string;\n colorSamplingProfileId: string;\n channelId: string;\n outputMeaning:\n \"detector-terminal-photocurrent-magnitude\";\n referenceConditions:\n SensorResponsivityElectricalConditions;\n conditionPolicy:\n SensorResponsivityElectricalConditionPolicy;\n scientificStatus:\n SensorSpectralResponseScientificStatus;\n uncertainty:\n SensorSpectralResponseUncertainty;\n evidence: readonly EvidenceProvenance[];\n}\n\nexport interface CalculateSensorResponsivityPhotocurrentInput {\n reduction:\n SensorSpatioSpectralIrradianceReduction;\n compatibility:\n SensorResponseApplicationCompatibilityAssessment;\n operatingRange:\n SensorResponseOperatingRangeAssessment;\n colorSamplingProfile:\n SensorColorSamplingProfile;\n spectralResponseProfile:\n SensorSpectralResponseProfile;\n electricalApplicabilityProfile:\n SensorResponsivityElectricalApplicabilityProfile;\n operatingElectricalConditions:\n SensorResponsivityElectricalConditions;\n}\n\nexport interface SensorResponsivityWavelengthCurrentContribution {\n spectralSampleIndex: number;\n wavelengthNanometers: number;\n wavelengthMeasureNanometers: number;\n geometricApertureIncidentSpectralFluxWattsPerNanometer:\n number;\n radiantPowerContributionWatts: number;\n spectralResponsivityAmperesPerWatt:\n number;\n responseInterpolationUsed: boolean;\n photocurrentMagnitudeContributionAmperes:\n number;\n}\n\nexport interface SensorResponsivityPhotocurrent {\n colorSamplingProfileId: string;\n responseProfileId: string;\n responseApplicationProfileId: string;\n operatingRangeProfileId: string;\n electricalApplicabilityProfileId:\n string;\n /** The exact source colour site. Results produced by the engine fill this in. */\n site?: {\n x: number;\n y: number;\n };\n channelId: string;\n sourceResponseKind:\n \"effective-spectral-responsivity\";\n responseScope:\n SensorSpatioSpectralIrradianceReduction[\"responseScope\"];\n responseReferencePlane:\n SensorResponseApplicationCompatibilityAssessment[\"requiredSourcePlane\"];\n wavelengthBasis:\n SensorSpatioSpectralIrradianceReduction[\"wavelengthBasis\"];\n wavelengthRangeNanometers:\n SensorSpatioSpectralIrradianceReduction[\"wavelengthRangeNanometers\"];\n electricalReferenceConditions:\n SensorResponsivityElectricalConditions;\n operatingElectricalConditions:\n SensorResponsivityElectricalConditions;\n electricalConditionPolicy:\n SensorResponsivityElectricalConditionPolicy;\n electricalCompatibility:\n | \"exact-match\"\n | \"assumed-compatible\";\n spectralNodeCount: number;\n perWavelength:\n readonly SensorResponsivityWavelengthCurrentContribution[];\n photocurrentMagnitudeAmperes: number;\n currentSignConvention:\n \"magnitude-only-no-circuit-polarity\";\n summationMethod:\n \"kahan-compensated\";\n responseApplicationPerformed: true;\n spectralResponsivityApplied: true;\n quantumEfficiencyApplied: false;\n photonRateCalculated: false;\n electronRateCalculated: false;\n currentCalculated: true;\n chargeCalculated: false;\n temporalResponseModel:\n \"quasi-static-steady-state-only\";\n detectorBandwidthModeled: false;\n transimpedanceGainApplied: false;\n voltageCalculated: false;\n temporalIntegrationApplied: false;\n exposureDurationApplied: false;\n saturationAssessed: false;\n readoutElectronicsLinearityAssessed:\n false;\n shotNoiseApplied: false;\n readNoiseApplied: false;\n adcQuantizationApplied: false;\n rawCodeValueProduced: false;\n responseUncertaintyPropagated: false;\n electricalApplicabilityUncertaintyPropagated:\n false;\n quadratureConvergenceErrorEstimated:\n false;\n componentEvidence: {\n electricalApplicability:\n readonly EvidenceProvenance[];\n electricalConditionAssumption:\n readonly EvidenceProvenance[];\n };\n}\n\ninterface CompensatedSum {\n sum: number;\n correction: number;\n}\n\nfunction parseElectricalConditions(\n value: unknown,\n path: string\n): SensorResponsivityElectricalConditions {\n const record = requireRecord(\n value,\n path, [\"bias\", \"readoutLoad\"]\n );\n const bias = requireRecord(\n record.bias,\n path + \".bias\", null\n );\n rejectUnknownVariantFields(bias, \"kind\", { \"zero-bias-photovoltaic\": [\"kind\"], \"reverse-biased\": [\"kind\", \"magnitudeVolts\"] }, path + \".bias\");\n const readoutLoad = requireRecord(\n record.readoutLoad,\n path + \".readoutLoad\", null\n );\n rejectUnknownVariantFields(readoutLoad, \"kind\", { \"virtual-ground-current-readout\": [\"kind\"], \"finite-input-impedance\": [\"kind\", \"inputImpedanceOhms\"] }, path + \".readoutLoad\");\n\n const parsedBias:\n SensorResponsivityBiasCondition =\n bias.kind ===\n \"zero-bias-photovoltaic\"\n ? {\n kind:\n \"zero-bias-photovoltaic\"\n }\n : bias.kind ===\n \"reverse-biased\"\n ? {\n kind:\n \"reverse-biased\",\n magnitudeVolts:\n requirePositiveFiniteConfiguration(\n bias.magnitudeVolts,\n path +\n \".bias.magnitudeVolts\"\n )\n }\n : ((): never => {\n throw new InvalidConfigurationError(\n path +\n \".bias.kind is invalid.\"\n );\n })();\n\n const parsedReadout:\n SensorResponsivityReadoutLoadCondition =\n readoutLoad.kind ===\n \"virtual-ground-current-readout\"\n ? {\n kind:\n \"virtual-ground-current-readout\"\n }\n : readoutLoad.kind ===\n \"finite-input-impedance\"\n ? {\n kind:\n \"finite-input-impedance\",\n inputImpedanceOhms:\n requirePositiveFiniteConfiguration(\n readoutLoad\n .inputImpedanceOhms,\n path +\n \".readoutLoad.inputImpedanceOhms\"\n )\n }\n : ((): never => {\n throw new InvalidConfigurationError(\n path +\n \".readoutLoad.kind is invalid.\"\n );\n })();\n\n return {\n bias: parsedBias,\n readoutLoad: parsedReadout\n };\n}\n\n/**\n * Validates untrusted input and returns it as a normalized, typed value. Unknown enum values,\n * missing required fields and inconsistent scientific data are rejected.\n *\n * The profile states the electrical bias and load conditions under which an A/W responsivity applies.\n * @param value - Untrusted data. TypeScript types alone are not validation.\n * @returns The result. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function parseSensorResponsivityElectricalApplicabilityProfile(\n value: unknown\n): SensorResponsivityElectricalApplicabilityProfile {\n const record = requireRecord(\n value,\n \"sensorResponsivityElectricalApplicability\", [\"schemaVersion\", \"outputMeaning\", \"scientificStatus\", \"uncertainty\", \"profileId\", \"responseApplicationProfileId\", \"spectralResponseProfileId\", \"colorSamplingProfileId\", \"channelId\", \"referenceConditions\", \"conditionPolicy\", \"evidence\"]\n );\n\n if (\n record.schemaVersion !== \"0.1.0\"\n ) {\n throw new InvalidConfigurationError(\n 'sensorResponsivityElectricalApplicability.schemaVersion must be \"0.1.0\".'\n );\n }\n if (\n record.outputMeaning !==\n \"detector-terminal-photocurrent-magnitude\"\n ) {\n throw new InvalidConfigurationError(\n \"sensorResponsivityElectricalApplicability.outputMeaning is invalid.\"\n );\n }\n if (\n record.scientificStatus !==\n \"calibrated\" &&\n record.scientificStatus !==\n \"approximation\"\n ) {\n throw new InvalidConfigurationError(\n \"sensorResponsivityElectricalApplicability.scientificStatus is invalid.\"\n );\n }\n\n const uncertainty =\n parseUncertainty(\n record.uncertainty,\n \"sensorResponsivityElectricalApplicability.uncertainty\"\n );\n\n if (\n record.scientificStatus ===\n \"calibrated\" &&\n uncertainty.kind ===\n \"not-quantified\"\n ) {\n throw new InvalidConfigurationError(\n \"A calibrated electrical applicability profile must declare quantified relative uncertainty.\"\n );\n }\n\n return {\n schemaVersion: \"0.1.0\",\n profileId:\n requireNonEmptyString(\n record.profileId,\n \"sensorResponsivityElectricalApplicability.profileId\"\n ),\n responseApplicationProfileId:\n requireNonEmptyString(\n record\n .responseApplicationProfileId,\n \"sensorResponsivityElectricalApplicability.responseApplicationProfileId\"\n ),\n spectralResponseProfileId:\n requireNonEmptyString(\n record\n .spectralResponseProfileId,\n \"sensorResponsivityElectricalApplicability.spectralResponseProfileId\"\n ),\n colorSamplingProfileId:\n requireNonEmptyString(\n record.colorSamplingProfileId,\n \"sensorResponsivityElectricalApplicability.colorSamplingProfileId\"\n ),\n channelId:\n requireNonEmptyString(\n record.channelId,\n \"sensorResponsivityElectricalApplicability.channelId\"\n ),\n outputMeaning:\n \"detector-terminal-photocurrent-magnitude\",\n referenceConditions:\n parseElectricalConditions(\n record.referenceConditions,\n \"sensorResponsivityElectricalApplicability.referenceConditions\"\n ),\n conditionPolicy:\n parseConditionPolicy(\n record.conditionPolicy,\n \"sensorResponsivityElectricalApplicability.conditionPolicy\"\n ),\n scientificStatus:\n record.scientificStatus,\n uncertainty,\n evidence:\n parseEvidenceList(\n record.evidence,\n \"sensorResponsivityElectricalApplicability.evidence\"\n )\n };\n}\n\n/**\n * Identity string for parsed plain data that ignores key order, so records with\n * the same content compare equal whatever order their properties were added in.\n */\nfunction canonicalJson(\n value: unknown\n): string {\n if (value === undefined) return \"undefined\";\n return stringifyCanonicalJson(value, {\n undefinedObjectProperties: \"omit\",\n nonFiniteNumberMessage:\n \"A/W photocurrent identity data must contain finite numbers.\",\n unsupportedValueMessage:\n \"A/W photocurrent identity data must be plain JSON data.\"\n });\n}\n\nfunction approximatelyEqual(\n actual: number,\n expected: number\n): boolean {\n const scale = Math.max(\n 1,\n Math.abs(actual),\n Math.abs(expected)\n );\n return (\n Math.abs(actual - expected) <=\n REDUCTION_TOLERANCE * scale\n );\n}\n\nfunction electricalConditionsMatch(\n reference:\n SensorResponsivityElectricalConditions,\n operating:\n SensorResponsivityElectricalConditions\n): boolean {\n return (\n canonicalJson(reference) ===\n canonicalJson(operating)\n );\n}\n\nfunction validateAuthorizationChain(\n reduction:\n SensorSpatioSpectralIrradianceReduction,\n compatibility:\n SensorResponseApplicationCompatibilityAssessment,\n operatingRange:\n SensorResponseOperatingRangeAssessment\n): void {\n requireInputObject(reduction, \"reduction input\");\n if (\n reduction.outputMeaning !==\n \"pre-response-spatio-spectral-radiometric-reduction\" ||\n reduction\n .spectralResponseApplicationPerformed !==\n false ||\n reduction\n .spectralResponsivityApplied !==\n false ||\n reduction.temporalIntegrationApplied !==\n false\n ) {\n throw new InvalidScientificInputError(\n \"reduction must remain pre-response and pre-temporal before A/W photocurrent conversion.\"\n );\n }\n\n if (\n !compatibility\n .structuralCompatibilityEstablished ||\n compatibility.compatibilityStatus ===\n \"blocked\" ||\n compatibility.blockers.length !== 0 ||\n !compatibility.sourcePlaneMatched ||\n compatibility.requiredSignalPath !==\n \"radiant-power-to-current\"\n ) {\n throw new InvalidScientificInputError(\n \"compatibility must establish a non-blocked radiant-power-to-current response path.\"\n );\n }\n\n if (\n compatibility\n .spectralResponseProfileId !==\n reduction.responseProfileId ||\n compatibility.colorSamplingProfileId !==\n reduction.colorSamplingProfileId ||\n compatibility.channelId !==\n reduction.channelId ||\n compatibility.responseScope !==\n reduction.responseScope\n ) {\n throw new InvalidScientificInputError(\n \"compatibility identities must exactly match the reduction.\"\n );\n }\n\n if (\n !operatingRange\n .operatingRangeCompatibilityAssessed ||\n !operatingRange\n .instantaneousResponseRangeCompatible ||\n !operatingRange\n .responseRateConversionAuthorized ||\n operatingRange.status === \"blocked\" ||\n operatingRange.blockers.length !== 0 ||\n operatingRange.requiredSignalPath !==\n \"radiant-power-to-current\" ||\n operatingRange\n .responseApplicationPerformed !==\n false ||\n operatingRange\n .currentConversionPerformed !== false ||\n operatingRange\n .temporalIntegrationAuthorized !== false ||\n !operatingRange\n .spectralNodeRangeCompatibilityAssessed ||\n operatingRange\n .spectralInputModel.kind !==\n \"per-spectral-bin\" ||\n operatingRange\n .spatialLinearityModel.kind !==\n \"linear-superposition-over-geometric-aperture\"\n ) {\n throw new InvalidScientificInputError(\n \"operatingRange must authorize a clean per-bin radiant-power-to-current path.\"\n );\n }\n\n if (\n operatingRange\n .spectralResponseProfileId !==\n reduction.responseProfileId ||\n operatingRange\n .colorSamplingProfileId !==\n reduction.colorSamplingProfileId ||\n operatingRange.channelId !==\n reduction.channelId ||\n operatingRange\n .responseApplicationProfileId !==\n compatibility.applicationProfileId\n ) {\n throw new InvalidScientificInputError(\n \"operatingRange identities must exactly match the reduction and compatibility assessment.\"\n );\n }\n}\n\nfunction validateReductionNodes(\n reduction:\n SensorSpatioSpectralIrradianceReduction\n): readonly SensorSpatioSpectralWavelengthReduction[] {\n if (\n !Array.isArray(\n reduction.perWavelength\n ) ||\n !Number.isSafeInteger(\n reduction.spectralNodeCount\n ) ||\n reduction.spectralNodeCount <= 0 ||\n reduction.perWavelength.length !==\n reduction.spectralNodeCount\n ) {\n throw new InvalidScientificInputError(\n \"reduction.perWavelength must contain exactly spectralNodeCount entries.\"\n );\n }\n\n let priorWavelength =\n Number.NEGATIVE_INFINITY;\n let normalizedWeightSum = 0;\n const totalPower:\n CompensatedSum = {\n sum: 0,\n correction: 0\n };\n\n reduction.perWavelength.forEach(\n (node, arrayIndex) => {\n const sampleIndex =\n requireSafeNonNegativeInteger(\n node.spectralSampleIndex,\n \"reduction.perWavelength[\" +\n arrayIndex +\n \"].spectralSampleIndex\"\n );\n if (sampleIndex !== arrayIndex) {\n throw new InvalidScientificInputError(\n \"reduction spectralSampleIndex values must form the exact contiguous range 0..spectralNodeCount-1.\"\n );\n }\n\n const wavelength =\n requirePositiveFiniteInput(\n node.wavelengthNanometers,\n \"reduction.perWavelength[\" +\n arrayIndex +\n \"].wavelengthNanometers\"\n );\n if (\n wavelength <= priorWavelength\n ) {\n throw new InvalidScientificInputError(\n \"reduction wavelength nodes must be strictly increasing.\"\n );\n }\n priorWavelength = wavelength;\n\n const measure =\n requirePositiveFiniteInput(\n node.wavelengthMeasureNanometers,\n \"reduction.perWavelength[\" +\n arrayIndex +\n \"].wavelengthMeasureNanometers\"\n );\n const normalizedWeight =\n requirePositiveFiniteInput(\n node.normalizedWavelengthWeight,\n \"reduction.perWavelength[\" +\n arrayIndex +\n \"].normalizedWavelengthWeight\"\n );\n const fluxDensity =\n requireNonNegativeFiniteInput(\n node\n .geometricApertureIncidentSpectralFluxWattsPerNanometer,\n \"reduction.perWavelength[\" +\n arrayIndex +\n \"].geometricApertureIncidentSpectralFluxWattsPerNanometer\"\n );\n const power =\n requireNonNegativeFiniteInput(\n node\n .wavelengthIntegratedGeometricApertureIncidentFluxContributionWatts,\n \"reduction.perWavelength[\" +\n arrayIndex +\n \"].wavelengthIntegratedGeometricApertureIncidentFluxContributionWatts\"\n );\n const expected =\n fluxDensity * measure;\n if (\n !Number.isFinite(expected) ||\n !approximatelyEqual(\n power,\n expected\n )\n ) {\n throw new InvalidScientificInputError(\n \"reduction per-wavelength radiant-power contribution must equal spectral flux density × d-lambda.\"\n );\n }\n\n normalizedWeightSum +=\n normalizedWeight;\n addCompensated(\n totalPower,\n power\n );\n }\n );\n\n if (\n !Number.isFinite(\n normalizedWeightSum\n ) ||\n !approximatelyEqual(\n normalizedWeightSum,\n 1\n )\n ) {\n throw new InvalidScientificInputError(\n \"reduction normalized wavelength weights must sum to 1.\"\n );\n }\n\n const reductionPower =\n requireNonNegativeFiniteInput(\n reduction\n .wavelengthIntegratedGeometricApertureIncidentFluxWatts,\n \"reduction.wavelengthIntegratedGeometricApertureIncidentFluxWatts\"\n );\n if (\n !approximatelyEqual(\n totalPower.sum,\n reductionPower\n )\n ) {\n throw new InvalidScientificInputError(\n \"reduction total geometric-aperture radiant power must match the per-wavelength sum.\"\n );\n }\n\n return reduction.perWavelength;\n}\n\nfunction validateOperatingRangeNodeBinding(\n reduction:\n SensorSpatioSpectralIrradianceReduction,\n nodes:\n readonly SensorSpatioSpectralWavelengthReduction[],\n operatingRange:\n SensorResponseOperatingRangeAssessment\n): void {\n const evaluated =\n operatingRange\n .evaluatedSpectralNodeInputs;\n\n if (\n evaluated === undefined ||\n evaluated.length !== nodes.length\n ) {\n throw new InvalidScientificInputError(\n \"operatingRange must carry one evaluated spectral-node input per reduction wavelength node.\"\n );\n }\n\n if (\n operatingRange\n .evaluatedWavelengthRangeNanometers\n .minimum !==\n reduction.wavelengthRangeNanometers\n .minimum ||\n operatingRange\n .evaluatedWavelengthRangeNanometers\n .maximum !==\n reduction.wavelengthRangeNanometers\n .maximum\n ) {\n throw new InvalidScientificInputError(\n \"operatingRange wavelength range must exactly match the reduction.\"\n );\n }\n\n evaluated.forEach(\n (entry, index) => {\n const node = nodes[index]!;\n if (\n entry.spectralSampleIndex !==\n node.spectralSampleIndex ||\n entry.wavelengthNanometers !==\n node.wavelengthNanometers ||\n entry.wavelengthMeasureNanometers !==\n node.wavelengthMeasureNanometers\n ) {\n throw new InvalidScientificInputError(\n \"operatingRange spectral-node identities must exactly match the reduction.\"\n );\n }\n\n const expected =\n operatingRange.inputRange.kind ===\n \"wavelength-integrated-geometric-aperture-radiant-power\"\n ? node\n .wavelengthIntegratedGeometricApertureIncidentFluxContributionWatts\n : node\n .wavelengthIntegratedSpatialAverageContributionWattsPerSquareMeter;\n\n if (\n entry.kind !==\n operatingRange.inputRange.kind ||\n entry.unit !==\n operatingRange.inputRange.unit ||\n !approximatelyEqual(\n entry.value,\n expected\n )\n ) {\n throw new InvalidScientificInputError(\n \"operatingRange spectral-node values must match the reduction values in the calibrated input domain.\"\n );\n }\n }\n );\n}\n\nfunction validateResponseBinding(\n resolved:\n ResolvedSensorSpectralResponse,\n reduction:\n SensorSpatioSpectralIrradianceReduction\n): void {\n if (\n resolved.profileId !==\n reduction.responseProfileId ||\n resolved.colorSamplingProfileId !==\n reduction.colorSamplingProfileId ||\n resolved.channelId !==\n reduction.channelId ||\n resolved.sourceResponseKind !==\n reduction.sourceResponseKind ||\n resolved.responseScope !==\n reduction.responseScope ||\n resolved.scientificStatus !==\n reduction.responseScientificStatus ||\n canonicalJson(\n resolved.uncertainty\n ) !==\n canonicalJson(\n reduction.responseUncertainty\n ) ||\n canonicalJson(\n resolved.componentEvidence\n ) !==\n canonicalJson({\n profile:\n reduction.componentEvidence\n .spectral.profile,\n channel:\n reduction.componentEvidence\n .spectral.channel,\n curves:\n reduction.componentEvidence\n .spectral.curves\n })\n ) {\n throw new InvalidScientificInputError(\n \"Resolved A/W response calibration metadata/evidence must exactly match the reduction.\"\n );\n }\n}\n\nfunction validateExactResponseDataBinding(\n responseProfile:\n SensorSpectralResponseProfile,\n reduction:\n SensorSpatioSpectralIrradianceReduction\n): void {\n const response =\n responseProfile.channels.find(\n (entry) =>\n entry.channelId ===\n reduction.channelId\n );\n if (reduction.responseChannelBinding !== undefined) {\n requireCurrentSensorSpectralResponseChannelBinding(\n reduction.responseChannelBinding\n );\n }\n if (\n response === undefined ||\n reduction.responseChannelBinding ===\n undefined ||\n canonicalJson(\n createSensorSpectralResponseChannelBinding(\n response\n )\n ) !==\n canonicalJson(\n reduction.responseChannelBinding\n )\n ) {\n throw new InvalidScientificInputError(\n \"Supplied spectral response channel data must exactly match the response-channel binding carried by the reduction.\"\n );\n }\n}\n\nfunction validateElectricalBinding(\n profile:\n SensorResponsivityElectricalApplicabilityProfile,\n input:\n CalculateSensorResponsivityPhotocurrentInput,\n operatingElectricalConditions:\n SensorResponsivityElectricalConditions\n): {\n compatibility:\n \"exact-match\" |\n \"assumed-compatible\";\n assumptionEvidence:\n readonly EvidenceProvenance[];\n} {\n if (\n profile.responseApplicationProfileId !==\n input.compatibility\n .applicationProfileId ||\n profile.spectralResponseProfileId !==\n input.reduction\n .responseProfileId ||\n profile.colorSamplingProfileId !==\n input.reduction\n .colorSamplingProfileId ||\n profile.channelId !==\n input.reduction.channelId\n ) {\n throw new InvalidScientificInputError(\n \"Electrical applicability profile identities must exactly match the response pipeline.\"\n );\n }\n\n if (\n profile.conditionPolicy.kind ===\n \"exact-match-required\"\n ) {\n if (\n !electricalConditionsMatch(\n profile.referenceConditions,\n operatingElectricalConditions\n )\n ) {\n throw new InvalidScientificInputError(\n \"Operating electrical conditions must exactly match the A/W calibration reference conditions.\"\n );\n }\n return {\n compatibility: \"exact-match\",\n assumptionEvidence: []\n };\n }\n\n return {\n compatibility:\n \"assumed-compatible\",\n assumptionEvidence:\n profile.conditionPolicy.evidence\n };\n}\n\n/**\n * Sums responsivity (A/W) × radiant power over wavelength bins to get the steady current magnitude,\n * under explicit electrical conditions.\n *\n * This is not EQE, an electron rate, a transimpedance voltage or RAW. Fast-changing current needs a\n * separate time-dependent detector model.\n * @param input - The input; see `CalculateSensorResponsivityPhotocurrentInput` for its fields, units and coordinates.\n * @returns The result. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function calculateSensorResponsivityPhotocurrent(\n input:\n CalculateSensorResponsivityPhotocurrentInput\n): CalculationResult<SensorResponsivityPhotocurrent> {\n requireInputKeys(input, \"calculateSensorResponsivityPhotocurrent\", [\"reduction\", \"compatibility\", \"operatingRange\", \"colorSamplingProfile\", \"spectralResponseProfile\", \"electricalApplicabilityProfile\", \"operatingElectricalConditions\"]);\n validateAuthorizationChain(\n input.reduction,\n input.compatibility,\n input.operatingRange\n );\n\n if (\n input.reduction\n .sourceResponseKind !==\n \"effective-spectral-responsivity\"\n ) {\n throw new InvalidScientificInputError(\n \"A/W photocurrent conversion requires effective spectral responsivity, not EQE.\"\n );\n }\n\n const colorProfile =\n parseSensorColorSamplingProfile(\n input.colorSamplingProfile\n );\n const responseProfile =\n parseSensorSpectralResponseProfile(\n input.spectralResponseProfile\n );\n const electricalProfile =\n parseSensorResponsivityElectricalApplicabilityProfile(\n input.electricalApplicabilityProfile\n );\n\n if (\n colorProfile.profileId !==\n input.reduction\n .colorSamplingProfileId ||\n responseProfile.profileId !==\n input.reduction\n .responseProfileId ||\n responseProfile\n .colorSamplingProfileId !==\n colorProfile.profileId\n ) {\n throw new InvalidScientificInputError(\n \"Supplied color/spectral response profiles must exactly match the reduction identities.\"\n );\n }\n\n validateExactResponseDataBinding(\n responseProfile,\n input.reduction\n );\n\n const operatingElectricalConditions =\n parseElectricalConditions(\n input.operatingElectricalConditions,\n \"operatingElectricalConditions\"\n );\n const electrical =\n validateElectricalBinding(\n electricalProfile,\n input,\n operatingElectricalConditions\n );\n const nodes =\n validateReductionNodes(\n input.reduction\n );\n validateOperatingRangeNodeBinding(\n input.reduction,\n nodes,\n input.operatingRange\n );\n\n const currentSum:\n CompensatedSum = {\n sum: 0,\n correction: 0\n };\n const perWavelength:\n SensorResponsivityWavelengthCurrentContribution[] =\n [];\n let responseBindingValidated =\n false;\n\n for (const node of nodes) {\n const resolved =\n resolveParsedSensorSpectralResponseAtWavelength({\n colorSamplingProfile:\n colorProfile,\n spectralResponseProfile:\n responseProfile,\n channelId:\n input.reduction.channelId,\n wavelengthNanometers:\n node.wavelengthNanometers,\n wavelengthBasis:\n input.reduction\n .wavelengthBasis\n });\n\n if (!responseBindingValidated) {\n validateResponseBinding(\n resolved.value,\n input.reduction\n );\n responseBindingValidated =\n true;\n }\n\n const responsivity =\n resolved.value.response as Extract<\n typeof resolved.value.response,\n {\n kind:\n \"effective-spectral-responsivity\";\n }\n >;\n\n const radiantPowerContributionWatts =\n node\n .geometricApertureIncidentSpectralFluxWattsPerNanometer *\n node.wavelengthMeasureNanometers;\n const photocurrentMagnitudeContributionAmperes =\n radiantPowerContributionWatts *\n responsivity.amperesPerWatt;\n\n if (\n !Number.isFinite(\n radiantPowerContributionWatts\n ) ||\n !Number.isFinite(\n photocurrentMagnitudeContributionAmperes\n ) ||\n photocurrentMagnitudeContributionAmperes <\n 0\n ) {\n throw new InvalidScientificInputError(\n \"A/W wavelength-node photocurrent calculation must remain finite and nonnegative.\"\n );\n }\n\n addCompensated(\n currentSum,\n photocurrentMagnitudeContributionAmperes\n );\n\n perWavelength.push({\n spectralSampleIndex:\n node.spectralSampleIndex,\n wavelengthNanometers:\n node.wavelengthNanometers,\n wavelengthMeasureNanometers:\n node.wavelengthMeasureNanometers,\n geometricApertureIncidentSpectralFluxWattsPerNanometer:\n node\n .geometricApertureIncidentSpectralFluxWattsPerNanometer,\n radiantPowerContributionWatts,\n spectralResponsivityAmperesPerWatt:\n responsivity.amperesPerWatt,\n responseInterpolationUsed:\n resolved.value\n .interpolationUsed,\n photocurrentMagnitudeContributionAmperes\n });\n }\n\n if (\n !Number.isFinite(\n currentSum.sum\n ) ||\n currentSum.sum < 0\n ) {\n throw new InvalidScientificInputError(\n \"Total A/W photocurrent magnitude must remain finite and nonnegative.\"\n );\n }\n\n return approximationResult(\n {\n colorSamplingProfileId:\n input.reduction\n .colorSamplingProfileId,\n responseProfileId:\n input.reduction\n .responseProfileId,\n responseApplicationProfileId:\n input.compatibility\n .applicationProfileId,\n operatingRangeProfileId:\n input.operatingRange\n .operatingRangeProfileId,\n electricalApplicabilityProfileId:\n electricalProfile.profileId,\n site: {\n ...input.reduction.site\n },\n channelId:\n input.reduction.channelId,\n sourceResponseKind:\n \"effective-spectral-responsivity\",\n responseScope:\n input.reduction.responseScope,\n responseReferencePlane:\n input.compatibility\n .requiredSourcePlane,\n wavelengthBasis:\n input.reduction\n .wavelengthBasis,\n wavelengthRangeNanometers: {\n ...input.reduction\n .wavelengthRangeNanometers\n },\n electricalReferenceConditions:\n electricalProfile\n .referenceConditions,\n operatingElectricalConditions,\n electricalConditionPolicy:\n electricalProfile\n .conditionPolicy,\n electricalCompatibility:\n electrical.compatibility,\n spectralNodeCount:\n nodes.length,\n perWavelength,\n photocurrentMagnitudeAmperes:\n currentSum.sum,\n currentSignConvention:\n \"magnitude-only-no-circuit-polarity\",\n summationMethod:\n \"kahan-compensated\",\n responseApplicationPerformed:\n true,\n spectralResponsivityApplied:\n true,\n quantumEfficiencyApplied:\n false,\n photonRateCalculated: false,\n electronRateCalculated: false,\n currentCalculated: true,\n chargeCalculated: false,\n temporalResponseModel:\n \"quasi-static-steady-state-only\",\n detectorBandwidthModeled: false,\n transimpedanceGainApplied:\n false,\n voltageCalculated: false,\n temporalIntegrationApplied:\n false,\n exposureDurationApplied: false,\n saturationAssessed: false,\n readoutElectronicsLinearityAssessed:\n false,\n shotNoiseApplied: false,\n readNoiseApplied: false,\n adcQuantizationApplied:\n false,\n rawCodeValueProduced: false,\n responseUncertaintyPropagated:\n false,\n electricalApplicabilityUncertaintyPropagated:\n false,\n quadratureConvergenceErrorEstimated:\n false,\n componentEvidence: {\n electricalApplicability:\n electricalProfile.evidence,\n electricalConditionAssumption:\n electrical\n .assumptionEvidence\n }\n },\n \"sensor-spectral-responsivity-photocurrent\",\n \"1.0.0\",\n [\n \"Spectral responsivity in A/W is applied independently at every wavelength quadrature node as detector-terminal photocurrent magnitude per incident radiant power.\",\n \"Current sign/polarity is deliberately not modeled; the result is a nonnegative photocurrent magnitude and does not imply a circuit current direction.\",\n \"The A/W calibration is bound to explicit detector electrical conditions. Exact-match mode requires identical bias and readout-load semantics; approximation mode requires evidence and a stated limitation.\",\n \"Virtual-ground current readout and finite input impedance are modeled as calibration-condition identities only; this function does not simulate amplifier circuits or prove impedance adequacy.\",\n \"NIST photodiode guidance shows detector/electronics/loading can affect linear operation, so transimpedance/current-readout conditions are not treated as scientifically inert.\",\n \"Structural compatibility, geometric-aperture linear superposition and per-spectral-bin operating-range applicability must already authorize the radiant-power→current path.\",\n \"Response metadata/evidence and operating-range spectral-node values are rebound to the exact reduction so matching IDs alone or stale authorization cannot enable conversion.\",\n \"The calculation does not use photon energy, QE, photon rate or electron rate. A/W remains a distinct current-domain response representation.\",\n \"No transimpedance gain or voltage conversion is performed; current-to-voltage converter gain/offset/linearity remain downstream electronics contracts.\",\n \"The A/W response is used only as a quasi-static steady-state power→current mapping. Detector impulse response, bandwidth, modulation-frequency response and transient settling are not modeled.\",\n \"Outputs are instantaneous current only. Exposure-time integration to charge, saturation, noise, ADC/RAW conversion and reconstruction remain downstream.\",\n \"Response/electrical uncertainties and quadrature convergence error are not propagated into a combined current uncertainty by this version.\"\n ]\n );\n}\n"]}
@@ -15,24 +15,7 @@ import { parseEvidenceList } from "../core/evidence-provenance.js";
15
15
  import { InvalidScientificInputError } from "../core/validation.js";
16
16
  import { resolveNativeEffectiveRasterColorSamplingBinding } from "./capture-color-sampling-binding.js";
17
17
  import { resolveColorSamplingSite } from "./color-sampling.js";
18
- import { requireInputObject, requireInputKeys, rejectUnknownFields } from "../core/record-validation.js";
19
- function requireRecord(value, path, allowedKeys) {
20
- if (typeof value !== "object" ||
21
- value === null ||
22
- Array.isArray(value)) {
23
- throw new InvalidConfigurationError(path + " must be an object.");
24
- }
25
- if (allowedKeys !== null)
26
- rejectUnknownFields(value, allowedKeys, path);
27
- return value;
28
- }
29
- function requireNonEmptyString(value, path) {
30
- if (typeof value !== "string" ||
31
- value.trim().length === 0) {
32
- throw new InvalidConfigurationError(path + " must be a non-empty string.");
33
- }
34
- return value;
35
- }
18
+ import { requireInputObject, requireInputKeys, requireConfigRecord as requireRecord, requireConfigString as requireNonEmptyString, requireConfigFiniteNumber as requireFinite } from "../core/record-validation.js";
36
19
  function requirePositiveFinite(value, path) {
37
20
  if (typeof value !== "number" ||
38
21
  !Number.isFinite(value) ||
@@ -42,13 +25,6 @@ function requirePositiveFinite(value, path) {
42
25
  }
43
26
  return value;
44
27
  }
45
- function requireFinite(value, path) {
46
- if (typeof value !== "number" ||
47
- !Number.isFinite(value)) {
48
- throw new InvalidConfigurationError(path + " must be a finite number.");
49
- }
50
- return value;
51
- }
52
28
  function parseSiteCenterLattice(value, path) {
53
29
  const record = requireRecord(value, path, ["kind", "coordinateSystem", "firstSiteCenterFromImagingAreaTopLeftMicrometers", "pitchXMicrometers", "pitchYMicrometers", "evidence"]);
54
30
  if (record.kind !==
@@ -1 +1 @@
1
- {"version":3,"file":"sampling-aperture.js","sourceRoot":"","sources":["../../src/sensor/sampling-aperture.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Sampling aperture: where the colour-sampling sites sit physically on the sensor, and the\n * light-sensitive area of each site as a simple geometric shape.\n *\n * Site pitch and origin are declared facts, never derived from NativeImageRaster. The sensitive\n * region, when known, is a plain geometric rectangle. It does not include microlens effects, charge\n * diffusion, electrical crosstalk, QE (quantum efficiency), throughput, spectral response or an\n * effective light-collection area.\n * @see docs/MOTION_AND_SIGNAL.md for equations, coordinate/unit conventions, blockers and support\n * limits.\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport {\n parseEvidenceList,\n type EvidenceProvenance\n} from \"../core/evidence-provenance.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport {\n resolveNativeEffectiveRasterColorSamplingBinding,\n type NativeEffectiveRasterColorSamplingBindingProfile\n} from \"./capture-color-sampling-binding.js\";\nimport {\n resolveColorSamplingSite,\n type NativeColorSamplingSiteIndex,\n type SensorColorSamplingProfile\n} from \"./color-sampling.js\";\nimport type {\n NativeImageRaster,\n SensorImagingArea\n} from \"./sensor-geometry.js\";\nimport { requireInputObject, requireInputKeys, rejectUnknownFields } from \"../core/record-validation.js\";\n\ntype UnknownRecord = Record<string, unknown>;\n\nexport interface SensorSiteCenterLatticeRegistration {\n kind: \"regular-rectangular-site-center-lattice\";\n coordinateSystem: \"native-sensor-physical\";\n /** Horizontal centre-to-centre site spacing (pitch) in micrometres. */\n pitchXMicrometers: number;\n /** Vertical centre-to-centre site spacing (pitch) in micrometres. */\n pitchYMicrometers: number;\n /**\n * Centre of the first site, measured from the imaging area's physical\n * top-left corner. +X right, +Y down. Units: micrometres.\n */\n firstSiteCenterFromImagingAreaTopLeftMicrometers: {\n x: number;\n y: number;\n };\n evidence: readonly EvidenceProvenance[];\n}\n\nexport type SensorGeometricSensitiveAperture =\n | {\n /**\n * The light-sensitive area is known to matter, but its shape is not\n * known well enough to use.\n */\n kind: \"unresolved\";\n evidence: readonly EvidenceProvenance[];\n }\n | {\n /**\n * A simple approximation of the sensitive area as a rectangle.\n *\n * The rectangle must stay inside one grid cell, so neighbouring\n * sensitive areas never overlap in schema 0.1.0.\n */\n kind: \"uniform-axis-aligned-rectangle\";\n widthMicrometers: number;\n heightMicrometers: number;\n centerOffsetFromSiteCenterMicrometers: {\n x: number;\n y: number;\n };\n evidence: readonly EvidenceProvenance[];\n };\n\nexport interface SensorSamplingApertureProfile {\n schemaVersion: \"0.1.0\";\n profileId: string;\n colorSamplingProfileId: string;\n colorSamplingBindingId: string;\n evidence: readonly EvidenceProvenance[];\n siteCenterLattice: SensorSiteCenterLatticeRegistration;\n geometricSensitiveAperture: SensorGeometricSensitiveAperture;\n}\n\nexport interface ResolveSensorSamplingApertureInput {\n imagingArea: SensorImagingArea;\n nativeRaster: NativeImageRaster;\n colorSamplingProfile: SensorColorSamplingProfile;\n colorSamplingBindingProfile: NativeEffectiveRasterColorSamplingBindingProfile;\n samplingApertureProfile: SensorSamplingApertureProfile;\n site: NativeColorSamplingSiteIndex;\n}\n\nexport interface NativeSensorPhysicalPointMm {\n x: number;\n y: number;\n}\n\nexport interface NativeSensorPhysicalBoundsMm {\n left: number;\n right: number;\n top: number;\n bottom: number;\n}\n\nexport interface ResolvedSensorSamplingAperture {\n profileId: string;\n colorSamplingProfileId: string;\n colorSamplingBindingId: string;\n coordinateSystem: \"native-sensor-physical\";\n site: NativeColorSamplingSiteIndex;\n channelId: string;\n siteGrid: {\n widthSites: number;\n heightSites: number;\n };\n lattice: {\n pitchXMicrometers: number;\n pitchYMicrometers: number;\n firstSiteCenterFromImagingAreaTopLeftMicrometers: {\n x: number;\n y: number;\n };\n siteCenterFromImagingAreaTopLeftMicrometers: {\n x: number;\n y: number;\n };\n siteCenterFromOpticalAxisMm: NativeSensorPhysicalPointMm;\n nominalCellAreaSquareMicrometers: number;\n };\n geometricSensitiveAperture: {\n kind: \"uniform-axis-aligned-rectangle\";\n widthMicrometers: number;\n heightMicrometers: number;\n centerOffsetFromSiteCenterMicrometers: {\n x: number;\n y: number;\n };\n centerFromOpticalAxisMm: NativeSensorPhysicalPointMm;\n boundsFromOpticalAxisMm: NativeSensorPhysicalBoundsMm;\n areaSquareMicrometers: number;\n geometricSensitiveAreaFractionOfLatticeCell: number;\n spatialWeighting:\n \"uniform-unit-area-average\";\n neighboringGeometricApertureOverlap:\n \"none-by-model\";\n };\n /**\n * Fixed statements of what this result does not establish.\n */\n sitePitchDerivedFromNativeImageRaster: false;\n apertureDerivedFromSitePitch: false;\n antiAliasingResponseIncluded: false;\n microlensSpatialRedistributionIncluded: false;\n chargeDiffusionIncluded: false;\n electricalCrosstalkIncluded: false;\n spectralResponseIncluded: false;\n quantumEfficiencyIncluded: false;\n opticalThroughputIncluded: false;\n radiometricCollectionAreaEstablished: false;\n physicalPhotodiodeGeometryEstablished: false;\n provenance: {\n profile: readonly EvidenceProvenance[];\n lattice: readonly EvidenceProvenance[];\n aperture: readonly EvidenceProvenance[];\n };\n}\n\nfunction requireRecord(\n value: unknown,\n path: string,\n allowedKeys: readonly string[] | null\n): UnknownRecord {\n if (\n typeof value !== \"object\" ||\n value === null ||\n Array.isArray(value)\n ) {\n throw new InvalidConfigurationError(\n path + \" must be an object.\"\n );\n }\n if (allowedKeys !== null) rejectUnknownFields(value, allowedKeys, path);\n return value as UnknownRecord;\n}\n\nfunction requireNonEmptyString(\n value: unknown,\n path: string\n): string {\n if (\n typeof value !== \"string\" ||\n value.trim().length === 0\n ) {\n throw new InvalidConfigurationError(\n path + \" must be a non-empty string.\"\n );\n }\n return value;\n}\n\nfunction requirePositiveFinite(\n value: unknown,\n path: string\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value) ||\n value <= 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must be a finite number greater than zero.\"\n );\n }\n return value;\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 a finite number.\"\n );\n }\n return value;\n}\n\nfunction parseSiteCenterLattice(\n value: unknown,\n path: string\n): SensorSiteCenterLatticeRegistration {\n const record = requireRecord(value, path, [\"kind\", \"coordinateSystem\", \"firstSiteCenterFromImagingAreaTopLeftMicrometers\", \"pitchXMicrometers\", \"pitchYMicrometers\", \"evidence\"]);\n\n if (\n record.kind !==\n \"regular-rectangular-site-center-lattice\"\n ) {\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n }\n if (\n record.coordinateSystem !==\n \"native-sensor-physical\"\n ) {\n throw new InvalidConfigurationError(\n path +\n '.coordinateSystem must be \"native-sensor-physical\".'\n );\n }\n\n const firstCenter = requireRecord(\n record.firstSiteCenterFromImagingAreaTopLeftMicrometers,\n path +\n \".firstSiteCenterFromImagingAreaTopLeftMicrometers\", [\"x\", \"y\"]\n );\n\n const firstX = requireFinite(\n firstCenter.x,\n path +\n \".firstSiteCenterFromImagingAreaTopLeftMicrometers.x\"\n );\n const firstY = requireFinite(\n firstCenter.y,\n path +\n \".firstSiteCenterFromImagingAreaTopLeftMicrometers.y\"\n );\n\n if (firstX < 0 || firstY < 0) {\n throw new InvalidConfigurationError(\n path +\n \".firstSiteCenterFromImagingAreaTopLeftMicrometers must not be negative.\"\n );\n }\n\n return {\n kind:\n \"regular-rectangular-site-center-lattice\",\n coordinateSystem:\n \"native-sensor-physical\",\n pitchXMicrometers:\n requirePositiveFinite(\n record.pitchXMicrometers,\n path + \".pitchXMicrometers\"\n ),\n pitchYMicrometers:\n requirePositiveFinite(\n record.pitchYMicrometers,\n path + \".pitchYMicrometers\"\n ),\n firstSiteCenterFromImagingAreaTopLeftMicrometers:\n {\n x: firstX,\n y: firstY\n },\n evidence: parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n )\n };\n}\n\nfunction parseGeometricSensitiveAperture(\n value: unknown,\n path: string,\n lattice: SensorSiteCenterLatticeRegistration\n): SensorGeometricSensitiveAperture {\n const record = requireRecord(value, path, [\"kind\", \"widthMicrometers\", \"heightMicrometers\", \"centerOffsetFromSiteCenterMicrometers\", \"evidence\"]);\n\n if (record.kind === \"unresolved\") {\n if (\n record.widthMicrometers !== undefined ||\n record.heightMicrometers !== undefined ||\n record.centerOffsetFromSiteCenterMicrometers !==\n undefined\n ) {\n throw new InvalidConfigurationError(\n path +\n \" unresolved aperture must omit rectangle fields.\"\n );\n }\n return {\n kind: \"unresolved\",\n evidence: parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n )\n };\n }\n\n if (\n record.kind !==\n \"uniform-axis-aligned-rectangle\"\n ) {\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n }\n\n const widthMicrometers =\n requirePositiveFinite(\n record.widthMicrometers,\n path + \".widthMicrometers\"\n );\n const heightMicrometers =\n requirePositiveFinite(\n record.heightMicrometers,\n path + \".heightMicrometers\"\n );\n const offset = requireRecord(\n record.centerOffsetFromSiteCenterMicrometers,\n path +\n \".centerOffsetFromSiteCenterMicrometers\", [\"x\", \"y\"]\n );\n const offsetX = requireFinite(\n offset.x,\n path +\n \".centerOffsetFromSiteCenterMicrometers.x\"\n );\n const offsetY = requireFinite(\n offset.y,\n path +\n \".centerOffsetFromSiteCenterMicrometers.y\"\n );\n\n const halfCellX =\n lattice.pitchXMicrometers / 2;\n const halfCellY =\n lattice.pitchYMicrometers / 2;\n\n if (\n Math.abs(offsetX) +\n widthMicrometers / 2 >\n halfCellX ||\n Math.abs(offsetY) +\n heightMicrometers / 2 >\n halfCellY\n ) {\n throw new InvalidConfigurationError(\n path +\n \" rectangle must remain within one regular site lattice cell.\"\n );\n }\n\n return {\n kind:\n \"uniform-axis-aligned-rectangle\",\n widthMicrometers,\n heightMicrometers,\n centerOffsetFromSiteCenterMicrometers:\n {\n x: offsetX,\n y: offsetY\n },\n evidence: parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n )\n };\n}\n\n/**\n * Parses where the colour-sampling sites sit physically, plus a simple geometric\n * model of each site's light-sensitive area.\n *\n * Site pitch and origin are declared facts, never derived from NativeImageRaster.\n * The rectangle, when given, is a geometric sensitive region only. It does not\n * include microlens effects, charge diffusion, electrical crosstalk, QE,\n * throughput, spectral response or an effective light-collection area.\n */\nexport function parseSensorSamplingApertureProfile(\n value: unknown\n): SensorSamplingApertureProfile {\n const profile = requireRecord(\n value,\n \"sensorSamplingAperture\", [\"schemaVersion\", \"siteCenterLattice\", \"profileId\", \"colorSamplingProfileId\", \"colorSamplingBindingId\", \"evidence\", \"geometricSensitiveAperture\"]\n );\n\n if (profile.schemaVersion !== \"0.1.0\") {\n throw new InvalidConfigurationError(\n 'sensorSamplingAperture.schemaVersion must be \"0.1.0\".'\n );\n }\n\n const siteCenterLattice =\n parseSiteCenterLattice(\n profile.siteCenterLattice,\n \"sensorSamplingAperture.siteCenterLattice\"\n );\n\n return {\n schemaVersion: \"0.1.0\",\n profileId: requireNonEmptyString(\n profile.profileId,\n \"sensorSamplingAperture.profileId\"\n ),\n colorSamplingProfileId:\n requireNonEmptyString(\n profile.colorSamplingProfileId,\n \"sensorSamplingAperture.colorSamplingProfileId\"\n ),\n colorSamplingBindingId:\n requireNonEmptyString(\n profile.colorSamplingBindingId,\n \"sensorSamplingAperture.colorSamplingBindingId\"\n ),\n evidence: parseEvidenceList(\n profile.evidence,\n \"sensorSamplingAperture.evidence\"\n ),\n siteCenterLattice,\n geometricSensitiveAperture:\n parseGeometricSensitiveAperture(\n profile.geometricSensitiveAperture,\n \"sensorSamplingAperture.geometricSensitiveAperture\",\n siteCenterLattice\n )\n };\n}\n\nfunction requireSiteIndex(\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 InvalidScientificInputError(\n path +\n \" must be a non-negative safe integer color-sampling-site index.\"\n );\n }\n return value;\n}\n\n/**\n * Relative rounding allowance for the lattice and aperture fit tests against the imaging area.\n *\n * The imaging extent (`widthMm · 1000`) and the far aperture edge (first centre + (n − 1)·pitch +\n * offset + width/2) reach the same real number through different chains of at most about eight\n * IEEE-754 double operations, each with a relative rounding error of at most ε/2 of a magnitude no\n * larger than the extent. A geometry that fits exactly can therefore miss by a few units in the last\n * place: a 34-site row of 9.287925696594426 µm sites gives 315.78947368421046 µm of imaging width but\n * a far aperture edge at 315.7894736842105 µm. The fit tests allow 8 ε of the extent (about 1.8e-15\n * relative; 5e-11 µm on a 30 mm sensor), far below any physical aperture difference, and still reject\n * every genuinely oversized lattice or aperture.\n */\nexport const APERTURE_FIT_RELATIVE_TOLERANCE = 8 * Number.EPSILON;\n\n/** The fit-test allowance in micrometres for an imaging extent in micrometres. */\nexport function apertureFitAllowanceMicrometers(extentMicrometers: number): number {\n return APERTURE_FIT_RELATIVE_TOLERANCE * extentMicrometers;\n}\n\nfunction requirePositiveImagingArea(\n imagingArea: SensorImagingArea\n): void {\n requireInputObject(imagingArea, \"imagingArea input\");\n if (\n !Number.isFinite(imagingArea.widthMm) ||\n imagingArea.widthMm <= 0 ||\n !Number.isFinite(imagingArea.heightMm) ||\n imagingArea.heightMm <= 0\n ) {\n throw new InvalidScientificInputError(\n \"imagingArea width/height must be finite and greater than zero.\"\n );\n }\n}\n\n/**\n * Resolves one site's geometric sampling aperture in native sensor physical space.\n *\n * The result is a normalized footprint that averages evenly over its area, for\n * image sampling, plus its physical area and fill fraction. That geometric area\n * is deliberately not treated as light-collection efficiency or as the true\n * photodiode shape.\n */\nexport function resolveSensorSamplingAperture(\n input: ResolveSensorSamplingApertureInput\n): ResolvedSensorSamplingAperture {\n requireInputKeys(input, \"resolveSensorSamplingAperture\", [\"imagingArea\", \"nativeRaster\", \"colorSamplingProfile\", \"colorSamplingBindingProfile\", \"samplingApertureProfile\", \"site\"]);\n requirePositiveImagingArea(\n input.imagingArea\n );\n\n const profile =\n parseSensorSamplingApertureProfile(\n input.samplingApertureProfile\n );\n const binding =\n resolveNativeEffectiveRasterColorSamplingBinding(\n {\n nativeRaster: input.nativeRaster,\n colorSamplingProfile:\n input.colorSamplingProfile,\n bindingProfile:\n input.colorSamplingBindingProfile\n }\n );\n\n if (\n profile.colorSamplingProfileId !==\n binding.colorSamplingProfileId\n ) {\n throw new InvalidScientificInputError(\n \"Sampling-aperture colorSamplingProfileId must match the resolved color-sampling profile.\"\n );\n }\n if (\n profile.colorSamplingBindingId !==\n binding.bindingId\n ) {\n throw new InvalidScientificInputError(\n \"Sampling-aperture colorSamplingBindingId must match the resolved color-sampling binding.\"\n );\n }\n\n if (\n profile.geometricSensitiveAperture.kind ===\n \"unresolved\"\n ) {\n throw new InvalidScientificInputError(\n \"Geometric sensitive aperture is unresolved; a spatial sampling aperture cannot be produced.\"\n );\n }\n\n const siteX = requireSiteIndex(\n input.site.x,\n \"site.x\"\n );\n const siteY = requireSiteIndex(\n input.site.y,\n \"site.y\"\n );\n\n if (\n siteX >=\n binding.colorSamplingSiteGrid.widthSites ||\n siteY >=\n binding.colorSamplingSiteGrid.heightSites\n ) {\n throw new InvalidScientificInputError(\n \"site must lie within the bound color-sampling site grid.\"\n );\n }\n\n const lattice =\n profile.siteCenterLattice;\n const gridWidth =\n binding.colorSamplingSiteGrid.widthSites;\n const gridHeight =\n binding.colorSamplingSiteGrid.heightSites;\n const imagingWidthMicrometers =\n input.imagingArea.widthMm * 1000;\n const imagingHeightMicrometers =\n input.imagingArea.heightMm * 1000;\n\n const lastCenterX =\n lattice\n .firstSiteCenterFromImagingAreaTopLeftMicrometers\n .x +\n (gridWidth - 1) *\n lattice.pitchXMicrometers;\n const lastCenterY =\n lattice\n .firstSiteCenterFromImagingAreaTopLeftMicrometers\n .y +\n (gridHeight - 1) *\n lattice.pitchYMicrometers;\n\n const allowanceX = apertureFitAllowanceMicrometers(\n imagingWidthMicrometers\n );\n const allowanceY = apertureFitAllowanceMicrometers(\n imagingHeightMicrometers\n );\n\n if (\n lastCenterX > imagingWidthMicrometers + allowanceX ||\n lastCenterY > imagingHeightMicrometers + allowanceY\n ) {\n throw new InvalidScientificInputError(\n \"Declared site-center lattice extends beyond the supplied physical imaging area.\"\n );\n }\n\n const aperture =\n profile.geometricSensitiveAperture;\n const apertureOffsetX =\n aperture.centerOffsetFromSiteCenterMicrometers.x;\n const apertureOffsetY =\n aperture.centerOffsetFromSiteCenterMicrometers.y;\n const apertureHalfWidth =\n aperture.widthMicrometers / 2;\n const apertureHalfHeight =\n aperture.heightMicrometers / 2;\n\n const firstApertureLeft =\n lattice.firstSiteCenterFromImagingAreaTopLeftMicrometers.x +\n apertureOffsetX -\n apertureHalfWidth;\n const firstApertureTop =\n lattice.firstSiteCenterFromImagingAreaTopLeftMicrometers.y +\n apertureOffsetY -\n apertureHalfHeight;\n const lastApertureRight =\n lastCenterX +\n apertureOffsetX +\n apertureHalfWidth;\n const lastApertureBottom =\n lastCenterY +\n apertureOffsetY +\n apertureHalfHeight;\n\n if (\n firstApertureLeft < -allowanceX ||\n firstApertureTop < -allowanceY ||\n lastApertureRight >\n imagingWidthMicrometers + allowanceX ||\n lastApertureBottom >\n imagingHeightMicrometers + allowanceY\n ) {\n throw new InvalidScientificInputError(\n \"Declared geometric sensitive aperture does not fit within the supplied physical imaging area across the complete site grid.\"\n );\n }\n\n const siteCenterFromTopLeftX =\n lattice\n .firstSiteCenterFromImagingAreaTopLeftMicrometers\n .x +\n siteX * lattice.pitchXMicrometers;\n const siteCenterFromTopLeftY =\n lattice\n .firstSiteCenterFromImagingAreaTopLeftMicrometers\n .y +\n siteY * lattice.pitchYMicrometers;\n\n const apertureCenterFromTopLeftX =\n siteCenterFromTopLeftX +\n aperture\n .centerOffsetFromSiteCenterMicrometers\n .x;\n const apertureCenterFromTopLeftY =\n siteCenterFromTopLeftY +\n aperture\n .centerOffsetFromSiteCenterMicrometers\n .y;\n const apertureLeftTopX =\n apertureCenterFromTopLeftX -\n aperture.widthMicrometers / 2;\n const apertureRightBottomX =\n apertureCenterFromTopLeftX +\n aperture.widthMicrometers / 2;\n const apertureLeftTopY =\n apertureCenterFromTopLeftY -\n aperture.heightMicrometers / 2;\n const apertureRightBottomY =\n apertureCenterFromTopLeftY +\n aperture.heightMicrometers / 2;\n\n if (\n apertureLeftTopX < -allowanceX ||\n apertureLeftTopY < -allowanceY ||\n apertureRightBottomX >\n imagingWidthMicrometers + allowanceX ||\n apertureRightBottomY >\n imagingHeightMicrometers + allowanceY\n ) {\n throw new InvalidScientificInputError(\n \"Resolved geometric sensitive aperture extends beyond the supplied physical imaging area.\"\n );\n }\n\n const siteCenterFromOpticalAxisMm = {\n x:\n -input.imagingArea.widthMm / 2 +\n siteCenterFromTopLeftX / 1000,\n y:\n -input.imagingArea.heightMm / 2 +\n siteCenterFromTopLeftY / 1000\n };\n const apertureCenterFromOpticalAxisMm = {\n x:\n -input.imagingArea.widthMm / 2 +\n apertureCenterFromTopLeftX / 1000,\n y:\n -input.imagingArea.heightMm / 2 +\n apertureCenterFromTopLeftY / 1000\n };\n const boundsFromOpticalAxisMm = {\n left:\n -input.imagingArea.widthMm / 2 +\n apertureLeftTopX / 1000,\n right:\n -input.imagingArea.widthMm / 2 +\n apertureRightBottomX / 1000,\n top:\n -input.imagingArea.heightMm / 2 +\n apertureLeftTopY / 1000,\n bottom:\n -input.imagingArea.heightMm / 2 +\n apertureRightBottomY / 1000\n };\n\n const areaSquareMicrometers =\n aperture.widthMicrometers *\n aperture.heightMicrometers;\n const nominalCellAreaSquareMicrometers =\n lattice.pitchXMicrometers *\n lattice.pitchYMicrometers;\n const geometricSensitiveAreaFractionOfLatticeCell =\n areaSquareMicrometers /\n nominalCellAreaSquareMicrometers;\n\n if (\n !Number.isFinite(areaSquareMicrometers) ||\n !Number.isFinite(\n nominalCellAreaSquareMicrometers\n ) ||\n !Number.isFinite(\n geometricSensitiveAreaFractionOfLatticeCell\n )\n ) {\n throw new InvalidScientificInputError(\n \"Derived sampling-aperture geometry must remain finite.\"\n );\n }\n\n const channel =\n resolveColorSamplingSite({\n profile: input.colorSamplingProfile,\n site: {\n x: siteX,\n y: siteY\n }\n });\n\n return {\n profileId: profile.profileId,\n colorSamplingProfileId:\n profile.colorSamplingProfileId,\n colorSamplingBindingId:\n profile.colorSamplingBindingId,\n coordinateSystem:\n \"native-sensor-physical\",\n site: {\n x: siteX,\n y: siteY\n },\n channelId: channel.mapping.channelId,\n siteGrid: {\n widthSites: gridWidth,\n heightSites: gridHeight\n },\n lattice: {\n pitchXMicrometers:\n lattice.pitchXMicrometers,\n pitchYMicrometers:\n lattice.pitchYMicrometers,\n firstSiteCenterFromImagingAreaTopLeftMicrometers:\n {\n ...lattice\n .firstSiteCenterFromImagingAreaTopLeftMicrometers\n },\n siteCenterFromImagingAreaTopLeftMicrometers:\n {\n x: siteCenterFromTopLeftX,\n y: siteCenterFromTopLeftY\n },\n siteCenterFromOpticalAxisMm,\n nominalCellAreaSquareMicrometers\n },\n geometricSensitiveAperture: {\n kind:\n \"uniform-axis-aligned-rectangle\",\n widthMicrometers:\n aperture.widthMicrometers,\n heightMicrometers:\n aperture.heightMicrometers,\n centerOffsetFromSiteCenterMicrometers:\n {\n ...aperture\n .centerOffsetFromSiteCenterMicrometers\n },\n centerFromOpticalAxisMm:\n apertureCenterFromOpticalAxisMm,\n boundsFromOpticalAxisMm,\n areaSquareMicrometers,\n geometricSensitiveAreaFractionOfLatticeCell,\n spatialWeighting:\n \"uniform-unit-area-average\",\n neighboringGeometricApertureOverlap:\n \"none-by-model\"\n },\n sitePitchDerivedFromNativeImageRaster:\n false,\n apertureDerivedFromSitePitch: false,\n antiAliasingResponseIncluded: false,\n microlensSpatialRedistributionIncluded:\n false,\n chargeDiffusionIncluded: false,\n electricalCrosstalkIncluded: false,\n spectralResponseIncluded: false,\n quantumEfficiencyIncluded: false,\n opticalThroughputIncluded: false,\n radiometricCollectionAreaEstablished:\n false,\n physicalPhotodiodeGeometryEstablished:\n false,\n provenance: {\n profile: profile.evidence,\n lattice: lattice.evidence,\n aperture: aperture.evidence\n }\n };\n}\n"]}
1
+ {"version":3,"file":"sampling-aperture.js","sourceRoot":"","sources":["../../src/sensor/sampling-aperture.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Sampling aperture: where the colour-sampling sites sit physically on the sensor, and the\n * light-sensitive area of each site as a simple geometric shape.\n *\n * Site pitch and origin are declared facts, never derived from NativeImageRaster. The sensitive\n * region, when known, is a plain geometric rectangle. It does not include microlens effects, charge\n * diffusion, electrical crosstalk, QE (quantum efficiency), throughput, spectral response or an\n * effective light-collection area.\n * @see docs/MOTION_AND_SIGNAL.md for equations, coordinate/unit conventions, blockers and support\n * limits.\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport {\n parseEvidenceList,\n type EvidenceProvenance\n} from \"../core/evidence-provenance.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport {\n resolveNativeEffectiveRasterColorSamplingBinding,\n type NativeEffectiveRasterColorSamplingBindingProfile\n} from \"./capture-color-sampling-binding.js\";\nimport {\n resolveColorSamplingSite,\n type NativeColorSamplingSiteIndex,\n type SensorColorSamplingProfile\n} from \"./color-sampling.js\";\nimport type {\n NativeImageRaster,\n SensorImagingArea\n} from \"./sensor-geometry.js\";\nimport { requireInputObject, requireInputKeys, requireConfigRecord as requireRecord, requireConfigString as requireNonEmptyString, requireConfigFiniteNumber as requireFinite } from \"../core/record-validation.js\";\n\n\nexport interface SensorSiteCenterLatticeRegistration {\n kind: \"regular-rectangular-site-center-lattice\";\n coordinateSystem: \"native-sensor-physical\";\n /** Horizontal centre-to-centre site spacing (pitch) in micrometres. */\n pitchXMicrometers: number;\n /** Vertical centre-to-centre site spacing (pitch) in micrometres. */\n pitchYMicrometers: number;\n /**\n * Centre of the first site, measured from the imaging area's physical\n * top-left corner. +X right, +Y down. Units: micrometres.\n */\n firstSiteCenterFromImagingAreaTopLeftMicrometers: {\n x: number;\n y: number;\n };\n evidence: readonly EvidenceProvenance[];\n}\n\nexport type SensorGeometricSensitiveAperture =\n | {\n /**\n * The light-sensitive area is known to matter, but its shape is not\n * known well enough to use.\n */\n kind: \"unresolved\";\n evidence: readonly EvidenceProvenance[];\n }\n | {\n /**\n * A simple approximation of the sensitive area as a rectangle.\n *\n * The rectangle must stay inside one grid cell, so neighbouring\n * sensitive areas never overlap in schema 0.1.0.\n */\n kind: \"uniform-axis-aligned-rectangle\";\n widthMicrometers: number;\n heightMicrometers: number;\n centerOffsetFromSiteCenterMicrometers: {\n x: number;\n y: number;\n };\n evidence: readonly EvidenceProvenance[];\n };\n\nexport interface SensorSamplingApertureProfile {\n schemaVersion: \"0.1.0\";\n profileId: string;\n colorSamplingProfileId: string;\n colorSamplingBindingId: string;\n evidence: readonly EvidenceProvenance[];\n siteCenterLattice: SensorSiteCenterLatticeRegistration;\n geometricSensitiveAperture: SensorGeometricSensitiveAperture;\n}\n\nexport interface ResolveSensorSamplingApertureInput {\n imagingArea: SensorImagingArea;\n nativeRaster: NativeImageRaster;\n colorSamplingProfile: SensorColorSamplingProfile;\n colorSamplingBindingProfile: NativeEffectiveRasterColorSamplingBindingProfile;\n samplingApertureProfile: SensorSamplingApertureProfile;\n site: NativeColorSamplingSiteIndex;\n}\n\nexport interface NativeSensorPhysicalPointMm {\n x: number;\n y: number;\n}\n\nexport interface NativeSensorPhysicalBoundsMm {\n left: number;\n right: number;\n top: number;\n bottom: number;\n}\n\nexport interface ResolvedSensorSamplingAperture {\n profileId: string;\n colorSamplingProfileId: string;\n colorSamplingBindingId: string;\n coordinateSystem: \"native-sensor-physical\";\n site: NativeColorSamplingSiteIndex;\n channelId: string;\n siteGrid: {\n widthSites: number;\n heightSites: number;\n };\n lattice: {\n pitchXMicrometers: number;\n pitchYMicrometers: number;\n firstSiteCenterFromImagingAreaTopLeftMicrometers: {\n x: number;\n y: number;\n };\n siteCenterFromImagingAreaTopLeftMicrometers: {\n x: number;\n y: number;\n };\n siteCenterFromOpticalAxisMm: NativeSensorPhysicalPointMm;\n nominalCellAreaSquareMicrometers: number;\n };\n geometricSensitiveAperture: {\n kind: \"uniform-axis-aligned-rectangle\";\n widthMicrometers: number;\n heightMicrometers: number;\n centerOffsetFromSiteCenterMicrometers: {\n x: number;\n y: number;\n };\n centerFromOpticalAxisMm: NativeSensorPhysicalPointMm;\n boundsFromOpticalAxisMm: NativeSensorPhysicalBoundsMm;\n areaSquareMicrometers: number;\n geometricSensitiveAreaFractionOfLatticeCell: number;\n spatialWeighting:\n \"uniform-unit-area-average\";\n neighboringGeometricApertureOverlap:\n \"none-by-model\";\n };\n /**\n * Fixed statements of what this result does not establish.\n */\n sitePitchDerivedFromNativeImageRaster: false;\n apertureDerivedFromSitePitch: false;\n antiAliasingResponseIncluded: false;\n microlensSpatialRedistributionIncluded: false;\n chargeDiffusionIncluded: false;\n electricalCrosstalkIncluded: false;\n spectralResponseIncluded: false;\n quantumEfficiencyIncluded: false;\n opticalThroughputIncluded: false;\n radiometricCollectionAreaEstablished: false;\n physicalPhotodiodeGeometryEstablished: false;\n provenance: {\n profile: readonly EvidenceProvenance[];\n lattice: readonly EvidenceProvenance[];\n aperture: readonly EvidenceProvenance[];\n };\n}\n\nfunction requirePositiveFinite(\n value: unknown,\n path: string\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value) ||\n value <= 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must be a finite number greater than zero.\"\n );\n }\n return value;\n}\n\nfunction parseSiteCenterLattice(\n value: unknown,\n path: string\n): SensorSiteCenterLatticeRegistration {\n const record = requireRecord(value, path, [\"kind\", \"coordinateSystem\", \"firstSiteCenterFromImagingAreaTopLeftMicrometers\", \"pitchXMicrometers\", \"pitchYMicrometers\", \"evidence\"]);\n\n if (\n record.kind !==\n \"regular-rectangular-site-center-lattice\"\n ) {\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n }\n if (\n record.coordinateSystem !==\n \"native-sensor-physical\"\n ) {\n throw new InvalidConfigurationError(\n path +\n '.coordinateSystem must be \"native-sensor-physical\".'\n );\n }\n\n const firstCenter = requireRecord(\n record.firstSiteCenterFromImagingAreaTopLeftMicrometers,\n path +\n \".firstSiteCenterFromImagingAreaTopLeftMicrometers\", [\"x\", \"y\"]\n );\n\n const firstX = requireFinite(\n firstCenter.x,\n path +\n \".firstSiteCenterFromImagingAreaTopLeftMicrometers.x\"\n );\n const firstY = requireFinite(\n firstCenter.y,\n path +\n \".firstSiteCenterFromImagingAreaTopLeftMicrometers.y\"\n );\n\n if (firstX < 0 || firstY < 0) {\n throw new InvalidConfigurationError(\n path +\n \".firstSiteCenterFromImagingAreaTopLeftMicrometers must not be negative.\"\n );\n }\n\n return {\n kind:\n \"regular-rectangular-site-center-lattice\",\n coordinateSystem:\n \"native-sensor-physical\",\n pitchXMicrometers:\n requirePositiveFinite(\n record.pitchXMicrometers,\n path + \".pitchXMicrometers\"\n ),\n pitchYMicrometers:\n requirePositiveFinite(\n record.pitchYMicrometers,\n path + \".pitchYMicrometers\"\n ),\n firstSiteCenterFromImagingAreaTopLeftMicrometers:\n {\n x: firstX,\n y: firstY\n },\n evidence: parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n )\n };\n}\n\nfunction parseGeometricSensitiveAperture(\n value: unknown,\n path: string,\n lattice: SensorSiteCenterLatticeRegistration\n): SensorGeometricSensitiveAperture {\n const record = requireRecord(value, path, [\"kind\", \"widthMicrometers\", \"heightMicrometers\", \"centerOffsetFromSiteCenterMicrometers\", \"evidence\"]);\n\n if (record.kind === \"unresolved\") {\n if (\n record.widthMicrometers !== undefined ||\n record.heightMicrometers !== undefined ||\n record.centerOffsetFromSiteCenterMicrometers !==\n undefined\n ) {\n throw new InvalidConfigurationError(\n path +\n \" unresolved aperture must omit rectangle fields.\"\n );\n }\n return {\n kind: \"unresolved\",\n evidence: parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n )\n };\n }\n\n if (\n record.kind !==\n \"uniform-axis-aligned-rectangle\"\n ) {\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n }\n\n const widthMicrometers =\n requirePositiveFinite(\n record.widthMicrometers,\n path + \".widthMicrometers\"\n );\n const heightMicrometers =\n requirePositiveFinite(\n record.heightMicrometers,\n path + \".heightMicrometers\"\n );\n const offset = requireRecord(\n record.centerOffsetFromSiteCenterMicrometers,\n path +\n \".centerOffsetFromSiteCenterMicrometers\", [\"x\", \"y\"]\n );\n const offsetX = requireFinite(\n offset.x,\n path +\n \".centerOffsetFromSiteCenterMicrometers.x\"\n );\n const offsetY = requireFinite(\n offset.y,\n path +\n \".centerOffsetFromSiteCenterMicrometers.y\"\n );\n\n const halfCellX =\n lattice.pitchXMicrometers / 2;\n const halfCellY =\n lattice.pitchYMicrometers / 2;\n\n if (\n Math.abs(offsetX) +\n widthMicrometers / 2 >\n halfCellX ||\n Math.abs(offsetY) +\n heightMicrometers / 2 >\n halfCellY\n ) {\n throw new InvalidConfigurationError(\n path +\n \" rectangle must remain within one regular site lattice cell.\"\n );\n }\n\n return {\n kind:\n \"uniform-axis-aligned-rectangle\",\n widthMicrometers,\n heightMicrometers,\n centerOffsetFromSiteCenterMicrometers:\n {\n x: offsetX,\n y: offsetY\n },\n evidence: parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n )\n };\n}\n\n/**\n * Parses where the colour-sampling sites sit physically, plus a simple geometric\n * model of each site's light-sensitive area.\n *\n * Site pitch and origin are declared facts, never derived from NativeImageRaster.\n * The rectangle, when given, is a geometric sensitive region only. It does not\n * include microlens effects, charge diffusion, electrical crosstalk, QE,\n * throughput, spectral response or an effective light-collection area.\n */\nexport function parseSensorSamplingApertureProfile(\n value: unknown\n): SensorSamplingApertureProfile {\n const profile = requireRecord(\n value,\n \"sensorSamplingAperture\", [\"schemaVersion\", \"siteCenterLattice\", \"profileId\", \"colorSamplingProfileId\", \"colorSamplingBindingId\", \"evidence\", \"geometricSensitiveAperture\"]\n );\n\n if (profile.schemaVersion !== \"0.1.0\") {\n throw new InvalidConfigurationError(\n 'sensorSamplingAperture.schemaVersion must be \"0.1.0\".'\n );\n }\n\n const siteCenterLattice =\n parseSiteCenterLattice(\n profile.siteCenterLattice,\n \"sensorSamplingAperture.siteCenterLattice\"\n );\n\n return {\n schemaVersion: \"0.1.0\",\n profileId: requireNonEmptyString(\n profile.profileId,\n \"sensorSamplingAperture.profileId\"\n ),\n colorSamplingProfileId:\n requireNonEmptyString(\n profile.colorSamplingProfileId,\n \"sensorSamplingAperture.colorSamplingProfileId\"\n ),\n colorSamplingBindingId:\n requireNonEmptyString(\n profile.colorSamplingBindingId,\n \"sensorSamplingAperture.colorSamplingBindingId\"\n ),\n evidence: parseEvidenceList(\n profile.evidence,\n \"sensorSamplingAperture.evidence\"\n ),\n siteCenterLattice,\n geometricSensitiveAperture:\n parseGeometricSensitiveAperture(\n profile.geometricSensitiveAperture,\n \"sensorSamplingAperture.geometricSensitiveAperture\",\n siteCenterLattice\n )\n };\n}\n\nfunction requireSiteIndex(\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 InvalidScientificInputError(\n path +\n \" must be a non-negative safe integer color-sampling-site index.\"\n );\n }\n return value;\n}\n\n/**\n * Relative rounding allowance for the lattice and aperture fit tests against the imaging area.\n *\n * The imaging extent (`widthMm · 1000`) and the far aperture edge (first centre + (n − 1)·pitch +\n * offset + width/2) reach the same real number through different chains of at most about eight\n * IEEE-754 double operations, each with a relative rounding error of at most ε/2 of a magnitude no\n * larger than the extent. A geometry that fits exactly can therefore miss by a few units in the last\n * place: a 34-site row of 9.287925696594426 µm sites gives 315.78947368421046 µm of imaging width but\n * a far aperture edge at 315.7894736842105 µm. The fit tests allow 8 ε of the extent (about 1.8e-15\n * relative; 5e-11 µm on a 30 mm sensor), far below any physical aperture difference, and still reject\n * every genuinely oversized lattice or aperture.\n */\nexport const APERTURE_FIT_RELATIVE_TOLERANCE = 8 * Number.EPSILON;\n\n/** The fit-test allowance in micrometres for an imaging extent in micrometres. */\nexport function apertureFitAllowanceMicrometers(extentMicrometers: number): number {\n return APERTURE_FIT_RELATIVE_TOLERANCE * extentMicrometers;\n}\n\nfunction requirePositiveImagingArea(\n imagingArea: SensorImagingArea\n): void {\n requireInputObject(imagingArea, \"imagingArea input\");\n if (\n !Number.isFinite(imagingArea.widthMm) ||\n imagingArea.widthMm <= 0 ||\n !Number.isFinite(imagingArea.heightMm) ||\n imagingArea.heightMm <= 0\n ) {\n throw new InvalidScientificInputError(\n \"imagingArea width/height must be finite and greater than zero.\"\n );\n }\n}\n\n/**\n * Resolves one site's geometric sampling aperture in native sensor physical space.\n *\n * The result is a normalized footprint that averages evenly over its area, for\n * image sampling, plus its physical area and fill fraction. That geometric area\n * is deliberately not treated as light-collection efficiency or as the true\n * photodiode shape.\n */\nexport function resolveSensorSamplingAperture(\n input: ResolveSensorSamplingApertureInput\n): ResolvedSensorSamplingAperture {\n requireInputKeys(input, \"resolveSensorSamplingAperture\", [\"imagingArea\", \"nativeRaster\", \"colorSamplingProfile\", \"colorSamplingBindingProfile\", \"samplingApertureProfile\", \"site\"]);\n requirePositiveImagingArea(\n input.imagingArea\n );\n\n const profile =\n parseSensorSamplingApertureProfile(\n input.samplingApertureProfile\n );\n const binding =\n resolveNativeEffectiveRasterColorSamplingBinding(\n {\n nativeRaster: input.nativeRaster,\n colorSamplingProfile:\n input.colorSamplingProfile,\n bindingProfile:\n input.colorSamplingBindingProfile\n }\n );\n\n if (\n profile.colorSamplingProfileId !==\n binding.colorSamplingProfileId\n ) {\n throw new InvalidScientificInputError(\n \"Sampling-aperture colorSamplingProfileId must match the resolved color-sampling profile.\"\n );\n }\n if (\n profile.colorSamplingBindingId !==\n binding.bindingId\n ) {\n throw new InvalidScientificInputError(\n \"Sampling-aperture colorSamplingBindingId must match the resolved color-sampling binding.\"\n );\n }\n\n if (\n profile.geometricSensitiveAperture.kind ===\n \"unresolved\"\n ) {\n throw new InvalidScientificInputError(\n \"Geometric sensitive aperture is unresolved; a spatial sampling aperture cannot be produced.\"\n );\n }\n\n const siteX = requireSiteIndex(\n input.site.x,\n \"site.x\"\n );\n const siteY = requireSiteIndex(\n input.site.y,\n \"site.y\"\n );\n\n if (\n siteX >=\n binding.colorSamplingSiteGrid.widthSites ||\n siteY >=\n binding.colorSamplingSiteGrid.heightSites\n ) {\n throw new InvalidScientificInputError(\n \"site must lie within the bound color-sampling site grid.\"\n );\n }\n\n const lattice =\n profile.siteCenterLattice;\n const gridWidth =\n binding.colorSamplingSiteGrid.widthSites;\n const gridHeight =\n binding.colorSamplingSiteGrid.heightSites;\n const imagingWidthMicrometers =\n input.imagingArea.widthMm * 1000;\n const imagingHeightMicrometers =\n input.imagingArea.heightMm * 1000;\n\n const lastCenterX =\n lattice\n .firstSiteCenterFromImagingAreaTopLeftMicrometers\n .x +\n (gridWidth - 1) *\n lattice.pitchXMicrometers;\n const lastCenterY =\n lattice\n .firstSiteCenterFromImagingAreaTopLeftMicrometers\n .y +\n (gridHeight - 1) *\n lattice.pitchYMicrometers;\n\n const allowanceX = apertureFitAllowanceMicrometers(\n imagingWidthMicrometers\n );\n const allowanceY = apertureFitAllowanceMicrometers(\n imagingHeightMicrometers\n );\n\n if (\n lastCenterX > imagingWidthMicrometers + allowanceX ||\n lastCenterY > imagingHeightMicrometers + allowanceY\n ) {\n throw new InvalidScientificInputError(\n \"Declared site-center lattice extends beyond the supplied physical imaging area.\"\n );\n }\n\n const aperture =\n profile.geometricSensitiveAperture;\n const apertureOffsetX =\n aperture.centerOffsetFromSiteCenterMicrometers.x;\n const apertureOffsetY =\n aperture.centerOffsetFromSiteCenterMicrometers.y;\n const apertureHalfWidth =\n aperture.widthMicrometers / 2;\n const apertureHalfHeight =\n aperture.heightMicrometers / 2;\n\n const firstApertureLeft =\n lattice.firstSiteCenterFromImagingAreaTopLeftMicrometers.x +\n apertureOffsetX -\n apertureHalfWidth;\n const firstApertureTop =\n lattice.firstSiteCenterFromImagingAreaTopLeftMicrometers.y +\n apertureOffsetY -\n apertureHalfHeight;\n const lastApertureRight =\n lastCenterX +\n apertureOffsetX +\n apertureHalfWidth;\n const lastApertureBottom =\n lastCenterY +\n apertureOffsetY +\n apertureHalfHeight;\n\n if (\n firstApertureLeft < -allowanceX ||\n firstApertureTop < -allowanceY ||\n lastApertureRight >\n imagingWidthMicrometers + allowanceX ||\n lastApertureBottom >\n imagingHeightMicrometers + allowanceY\n ) {\n throw new InvalidScientificInputError(\n \"Declared geometric sensitive aperture does not fit within the supplied physical imaging area across the complete site grid.\"\n );\n }\n\n const siteCenterFromTopLeftX =\n lattice\n .firstSiteCenterFromImagingAreaTopLeftMicrometers\n .x +\n siteX * lattice.pitchXMicrometers;\n const siteCenterFromTopLeftY =\n lattice\n .firstSiteCenterFromImagingAreaTopLeftMicrometers\n .y +\n siteY * lattice.pitchYMicrometers;\n\n const apertureCenterFromTopLeftX =\n siteCenterFromTopLeftX +\n aperture\n .centerOffsetFromSiteCenterMicrometers\n .x;\n const apertureCenterFromTopLeftY =\n siteCenterFromTopLeftY +\n aperture\n .centerOffsetFromSiteCenterMicrometers\n .y;\n const apertureLeftTopX =\n apertureCenterFromTopLeftX -\n aperture.widthMicrometers / 2;\n const apertureRightBottomX =\n apertureCenterFromTopLeftX +\n aperture.widthMicrometers / 2;\n const apertureLeftTopY =\n apertureCenterFromTopLeftY -\n aperture.heightMicrometers / 2;\n const apertureRightBottomY =\n apertureCenterFromTopLeftY +\n aperture.heightMicrometers / 2;\n\n if (\n apertureLeftTopX < -allowanceX ||\n apertureLeftTopY < -allowanceY ||\n apertureRightBottomX >\n imagingWidthMicrometers + allowanceX ||\n apertureRightBottomY >\n imagingHeightMicrometers + allowanceY\n ) {\n throw new InvalidScientificInputError(\n \"Resolved geometric sensitive aperture extends beyond the supplied physical imaging area.\"\n );\n }\n\n const siteCenterFromOpticalAxisMm = {\n x:\n -input.imagingArea.widthMm / 2 +\n siteCenterFromTopLeftX / 1000,\n y:\n -input.imagingArea.heightMm / 2 +\n siteCenterFromTopLeftY / 1000\n };\n const apertureCenterFromOpticalAxisMm = {\n x:\n -input.imagingArea.widthMm / 2 +\n apertureCenterFromTopLeftX / 1000,\n y:\n -input.imagingArea.heightMm / 2 +\n apertureCenterFromTopLeftY / 1000\n };\n const boundsFromOpticalAxisMm = {\n left:\n -input.imagingArea.widthMm / 2 +\n apertureLeftTopX / 1000,\n right:\n -input.imagingArea.widthMm / 2 +\n apertureRightBottomX / 1000,\n top:\n -input.imagingArea.heightMm / 2 +\n apertureLeftTopY / 1000,\n bottom:\n -input.imagingArea.heightMm / 2 +\n apertureRightBottomY / 1000\n };\n\n const areaSquareMicrometers =\n aperture.widthMicrometers *\n aperture.heightMicrometers;\n const nominalCellAreaSquareMicrometers =\n lattice.pitchXMicrometers *\n lattice.pitchYMicrometers;\n const geometricSensitiveAreaFractionOfLatticeCell =\n areaSquareMicrometers /\n nominalCellAreaSquareMicrometers;\n\n if (\n !Number.isFinite(areaSquareMicrometers) ||\n !Number.isFinite(\n nominalCellAreaSquareMicrometers\n ) ||\n !Number.isFinite(\n geometricSensitiveAreaFractionOfLatticeCell\n )\n ) {\n throw new InvalidScientificInputError(\n \"Derived sampling-aperture geometry must remain finite.\"\n );\n }\n\n const channel =\n resolveColorSamplingSite({\n profile: input.colorSamplingProfile,\n site: {\n x: siteX,\n y: siteY\n }\n });\n\n return {\n profileId: profile.profileId,\n colorSamplingProfileId:\n profile.colorSamplingProfileId,\n colorSamplingBindingId:\n profile.colorSamplingBindingId,\n coordinateSystem:\n \"native-sensor-physical\",\n site: {\n x: siteX,\n y: siteY\n },\n channelId: channel.mapping.channelId,\n siteGrid: {\n widthSites: gridWidth,\n heightSites: gridHeight\n },\n lattice: {\n pitchXMicrometers:\n lattice.pitchXMicrometers,\n pitchYMicrometers:\n lattice.pitchYMicrometers,\n firstSiteCenterFromImagingAreaTopLeftMicrometers:\n {\n ...lattice\n .firstSiteCenterFromImagingAreaTopLeftMicrometers\n },\n siteCenterFromImagingAreaTopLeftMicrometers:\n {\n x: siteCenterFromTopLeftX,\n y: siteCenterFromTopLeftY\n },\n siteCenterFromOpticalAxisMm,\n nominalCellAreaSquareMicrometers\n },\n geometricSensitiveAperture: {\n kind:\n \"uniform-axis-aligned-rectangle\",\n widthMicrometers:\n aperture.widthMicrometers,\n heightMicrometers:\n aperture.heightMicrometers,\n centerOffsetFromSiteCenterMicrometers:\n {\n ...aperture\n .centerOffsetFromSiteCenterMicrometers\n },\n centerFromOpticalAxisMm:\n apertureCenterFromOpticalAxisMm,\n boundsFromOpticalAxisMm,\n areaSquareMicrometers,\n geometricSensitiveAreaFractionOfLatticeCell,\n spatialWeighting:\n \"uniform-unit-area-average\",\n neighboringGeometricApertureOverlap:\n \"none-by-model\"\n },\n sitePitchDerivedFromNativeImageRaster:\n false,\n apertureDerivedFromSitePitch: false,\n antiAliasingResponseIncluded: false,\n microlensSpatialRedistributionIncluded:\n false,\n chargeDiffusionIncluded: false,\n electricalCrosstalkIncluded: false,\n spectralResponseIncluded: false,\n quantumEfficiencyIncluded: false,\n opticalThroughputIncluded: false,\n radiometricCollectionAreaEstablished:\n false,\n physicalPhotodiodeGeometryEstablished:\n false,\n provenance: {\n profile: profile.evidence,\n lattice: lattice.evidence,\n aperture: aperture.evidence\n }\n };\n}\n"]}
@@ -12,20 +12,12 @@
12
12
  */
13
13
  import { approximationResult } from "../core/calculation-result.js";
14
14
  import { InvalidScientificInputError } from "../core/validation.js";
15
- import { requireInputKeys } from "../core/record-validation.js";
15
+ import { requireInputKeys, requireInputNonNegativeSafeInteger as requireSafeNonNegativeInteger } from "../core/record-validation.js";
16
16
  import { InvalidConfigurationError } from "../core/configuration-error.js";
17
+ import { requirePositive as requirePositiveFinite } from "../exposure/flash-ttl.js";
17
18
  const SQUARE_MICROMETERS_TO_SQUARE_METERS = 1e-12;
18
19
  const WEIGHT_TOLERANCE = 1e-10;
19
20
  const AREA_TOLERANCE = 1e-10;
20
- function requireSafeNonNegativeInteger(value, path) {
21
- if (typeof value !== "number" ||
22
- !Number.isSafeInteger(value) ||
23
- value < 0) {
24
- throw new InvalidScientificInputError(path +
25
- " must be a non-negative safe integer.");
26
- }
27
- return value;
28
- }
29
21
  function requireNonNegativeFinite(value, path) {
30
22
  if (typeof value !== "number" ||
31
23
  !Number.isFinite(value) ||
@@ -35,15 +27,6 @@ function requireNonNegativeFinite(value, path) {
35
27
  }
36
28
  return value;
37
29
  }
38
- function requirePositiveFinite(value, path) {
39
- if (typeof value !== "number" ||
40
- !Number.isFinite(value) ||
41
- value <= 0) {
42
- throw new InvalidScientificInputError(path +
43
- " must be a finite number greater than zero.");
44
- }
45
- return value;
46
- }
47
30
  function parseValueDomain(value) {
48
31
  if (typeof value !== "object" ||
49
32
  value === null ||