Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added optika.sensors.AbstractImagingSensorMaterial.photons_incident() method to compute the expected number of incident photons given the number of measured electrons. #108

Merged
merged 2 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions optika/sensors/_materials/_materials.py
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,31 @@ def electrons_measured(
The vector perpendicular to the surface of the sensor.
"""

@abc.abstractmethod
def photons_incident(
self,
electrons: u.Quantity | na.AbstractScalar,
wavelength: u.Quantity | na.AbstractScalar,
direction: na.AbstractCartesian3dVectorArray,
normal: na.AbstractCartesian3dVectorArray,
) -> na.AbstractScalar:
"""
Given the number of electrons measured by the sensor,
and a grid of wavelengths, compute the expected number of
photons incident on the sensor.

Parameters
----------
electrons
The number of electrons measured by the sensor.
wavelength
An assumed grid of wavelengths for the incident photons.
direction
An assumed propagation direction for the incident photons.
normal
The vector perpendicular to the surface of the sensor.
"""

@abc.abstractmethod
def charge_diffusion(
self,
Expand Down Expand Up @@ -822,6 +847,15 @@ def electrons_measured(

return result

def photons_incident(
self,
electrons: u.Quantity | na.AbstractScalar,
wavelength: u.Quantity | na.AbstractScalar,
direction: na.AbstractCartesian3dVectorArray,
normal: na.AbstractCartesian3dVectorArray,
) -> na.AbstractScalar:
return electrons * u.photon / u.electron

def charge_diffusion(
self,
rays: optika.rays.RayVectorArray,
Expand Down Expand Up @@ -1121,6 +1155,39 @@ def electrons_measured(

return result

def photons_incident(
self,
electrons: u.Quantity | na.AbstractScalar,
wavelength: u.Quantity | na.AbstractScalar,
direction: na.AbstractCartesian3dVectorArray,
normal: na.AbstractCartesian3dVectorArray,
) -> na.AbstractScalar:
"""
Compute the expected number of incident photons for a given number
of electrons.

Parameters
----------
electrons
The energy collected by the sensor in units of electrons.
wavelength
The assumed wavelength of the incident photons.
direction
The assumed direction of the incident photons.
normal
The vector perpendicular to the surface of the sensor.
"""

qe = self.quantum_efficiency(
rays=optika.rays.RayVectorArray(
wavelength=wavelength,
direction=direction,
),
normal=normal,
)

return electrons / qe

def charge_diffusion(
self,
rays: optika.rays.RayVectorArray,
Expand Down
45 changes: 43 additions & 2 deletions optika/sensors/_materials/_materials_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,14 +245,55 @@ class AbstractTestAbstractImagingSensorMaterial(
)
def test_electrons_measured(
self,
a: optika.sensors.AbstractBackilluminatedCCDMaterial,
a: optika.sensors.AbstractImagingSensorMaterial,
rays: optika.rays.RayVectorArray,
normal: na.AbstractCartesian3dVectorArray,
):
result = a.electrons_measured(rays, normal)
assert isinstance(result, optika.rays.RayVectorArray)
assert np.all(result.intensity >= 0 * u.electron)

@pytest.mark.parametrize(
argnames="electrons",
argvalues=[
100 * u.electron,
],
)
@pytest.mark.parametrize(
argnames="wavelength",
argvalues=[
100 * u.AA,
],
)
@pytest.mark.parametrize(
argnames="direction",
argvalues=[
na.Cartesian3dVectorArray(0, 0, 1),
],
)
@pytest.mark.parametrize(
argnames="normal",
argvalues=[
na.Cartesian3dVectorArray(0, 0, -1),
],
)
def test_photons_incident(
self,
a: optika.sensors.AbstractImagingSensorMaterial,
electrons: u.Quantity | na.AbstractScalar,
wavelength: u.Quantity | na.AbstractScalar,
direction: na.AbstractCartesian3dVectorArray,
normal: na.AbstractCartesian3dVectorArray,
):
result = a.photons_incident(
electrons=electrons,
wavelength=wavelength,
direction=direction,
normal=normal,
)
assert isinstance(na.as_named_array(result), na.AbstractScalar)
assert result.unit.is_equivalent(u.photon)

@pytest.mark.parametrize(
argnames="rays",
argvalues=[
Expand All @@ -272,7 +313,7 @@ def test_electrons_measured(
)
def test_charge_diffusion(
self,
a: optika.sensors.AbstractBackilluminatedCCDMaterial,
a: optika.sensors.AbstractImagingSensorMaterial,
rays: optika.rays.RayVectorArray,
normal: na.AbstractCartesian3dVectorArray,
):
Expand Down
Loading