Skip to content

Commit

Permalink
Added optika.sensors.E2VCCDAIAMaterial (#7)
Browse files Browse the repository at this point in the history
Added `optika.sensors.E2VCCDAIAMaterial`
  • Loading branch information
byrdie authored Jan 15, 2024
1 parent 3807622 commit 97343a8
Show file tree
Hide file tree
Showing 10 changed files with 336 additions and 78 deletions.
29 changes: 29 additions & 0 deletions docs/refs.bib
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,32 @@ @techreport{Moody2017
year={2017},
url={https://oro.open.ac.uk/49003/1/Moody%202017%20-%20SXRQE_WhitePaper.pdf},
}
@ARTICLE{Boerner2012,
author = {{Boerner}, Paul and {Edwards}, Christopher and {Lemen}, James and {Rausch}, Adam and {Schrijver}, Carolus and {Shine}, Richard and {Shing}, Lawrence and {Stern}, Robert and {Tarbell}, Theodore and {Title}, Alan and {Wolfson}, C. Jacob and {Soufli}, Regina and {Spiller}, Eberhard and {Gullikson}, Eric and {McKenzie}, David and {Windt}, David and {Golub}, Leon and {Podgorski}, William and {Testa}, Paola and {Weber}, Mark},
title = "{Initial Calibration of the Atmospheric Imaging Assembly (AIA) on the Solar Dynamics Observatory (SDO)}",
journal = {\solphys},
keywords = {Instrumentation, EUV, Soft X-ray, Chromosphere, Corona, Transition region},
year = 2012,
month = jan,
volume = {275},
number = {1-2},
pages = {41-66},
doi = {10.1007/s11207-011-9804-8},
adsurl = {https://ui.adsabs.harvard.edu/abs/2012SoPh..275...41B},
adsnote = {Provided by the SAO/NASA Astrophysics Data System}
}
@ARTICLE{Lemen2012,
author = {{Lemen}, James R. and {Title}, Alan M. and {Akin}, David J. and {Boerner}, Paul F. and {Chou}, Catherine and {Drake}, Jerry F. and {Duncan}, Dexter W. and {Edwards}, Christopher G. and {Friedlaender}, Frank M. and {Heyman}, Gary F. and {Hurlburt}, Neal E. and {Katz}, Noah L. and {Kushner}, Gary D. and {Levay}, Michael and {Lindgren}, Russell W. and {Mathur}, Dnyanesh P. and {McFeaters}, Edward L. and {Mitchell}, Sarah and {Rehse}, Roger A. and {Schrijver}, Carolus J. and {Springer}, Larry A. and {Stern}, Robert A. and {Tarbell}, Theodore D. and {Wuelser}, Jean-Pierre and {Wolfson}, C. Jacob and {Yanari}, Carl and {Bookbinder}, Jay A. and {Cheimets}, Peter N. and {Caldwell}, David and {Deluca}, Edward E. and {Gates}, Richard and {Golub}, Leon and {Park}, Sang and {Podgorski}, William A. and {Bush}, Rock I. and {Scherrer}, Philip H. and {Gummin}, Mark A. and {Smith}, Peter and {Auker}, Gary and {Jerram}, Paul and {Pool}, Peter and {Soufli}, Regina and {Windt}, David L. and {Beardsley}, Sarah and {Clapp}, Matthew and {Lang}, James and {Waltham}, Nicholas},
title = "{The Atmospheric Imaging Assembly (AIA) on the Solar Dynamics Observatory (SDO)}",
journal = {\solphys},
keywords = {Solar corona, Solar instrumentation, Solar imaging, Extreme ultraviolet},
year = 2012,
month = jan,
volume = {275},
number = {1-2},
pages = {17-40},
doi = {10.1007/s11207-011-9776-8},
adsurl = {https://ui.adsabs.harvard.edu/abs/2012SoPh..275...17L},
adsnote = {Provided by the SAO/NASA Astrophysics Data System}
}

1 change: 1 addition & 0 deletions optika/sensors/_materials/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from ._materials import *
from ._e2v_ccd97 import *
from ._e2v_ccd_aia import *
121 changes: 45 additions & 76 deletions optika/sensors/_materials/_e2v_ccd97/_e2v_ccd97.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
import functools
import pathlib
import numpy as np
import scipy.optimize
import astropy.units as u
import named_arrays as na
from .._materials import quantum_efficiency_effective
from .._materials import AbstractBackilluminatedCCDMaterial
from .._materials import AbstractStern1994BackilluminatedCCDMaterial

__all__ = [
"E2VCCD97Material",
]


class E2VCCD97Material(
AbstractBackilluminatedCCDMaterial,
AbstractStern1994BackilluminatedCCDMaterial,
):
"""
A model of the light-sensitive material of an e2v CCD90 sensor based on
A model of the light-sensitive material of an e2v CCD97 sensor based on
measurements by :cite:t:`Moody2017`.
Examples
Expand Down Expand Up @@ -96,6 +93,48 @@ class E2VCCD97Material(
.. jupyter-execute::
material_ccd97.cce_backsurface
Plot the effective quantum efficiency of the fit to this data vs. the fit
to the data in :class:`optika.sensors.E2VCCDAIAMaterial`
.. jupyter-execute::
material_ccd_aia = optika.sensors.E2VCCDAIAMaterial()
qe_fit_aia = material_ccd_aia.quantum_efficiency_effective(
rays=optika.rays.RayVectorArray(
wavelength=wavelength_fit,
direction=na.Cartesian3dVectorArray(0, 0, 1),
),
normal=na.Cartesian3dVectorArray(0, 0, -1),
)
with astropy.visualization.quantity_support():
fig, ax = plt.subplots(constrained_layout=True)
na.plt.scatter(
wavelength_measured,
qe_measured,
label="Moody 2017 measured",
)
na.plt.plot(
wavelength_fit,
qe_fit,
label="Moody 2017 fit",
)
na.plt.scatter(
material_ccd_aia.quantum_efficiency_measured.inputs,
material_ccd_aia.quantum_efficiency_measured.outputs,
label="Boerner 2012 measured",
)
na.plt.plot(
wavelength_fit,
qe_fit_aia,
label="Boerner 2012 fit",
)
ax.set_xscale("log")
ax.set_xlabel(f"wavelength ({wavelength_fit.unit:latex_inline})")
ax.set_ylabel("quantum efficiency")
ax.legend()
"""

@property
Expand All @@ -112,73 +151,3 @@ def quantum_efficiency_measured(self) -> na.FunctionArray:
inputs=na.ScalarArray(wavelength, axes="wavelength"),
outputs=na.ScalarArray(qe, axes="wavelength"),
)

@functools.cached_property
def _quantum_efficiency_fit(self) -> dict[str, float | u.Quantity]:
qe_measured = self.quantum_efficiency_measured

unit_thickness_oxide = u.AA
unit_thickness_implant = u.AA
unit_thickness_substrate = u.um

def eqe_rms_difference(x: tuple[float, float, float, float]):
(
thickness_oxide,
thickness_implant,
thickness_substrate,
cce_backsurface,
) = x
qe_fit = quantum_efficiency_effective(
wavelength=qe_measured.inputs,
direction=na.Cartesian3dVectorArray(0, 0, 1),
thickness_oxide=thickness_oxide << unit_thickness_oxide,
thickness_implant=thickness_implant << unit_thickness_implant,
thickness_substrate=thickness_substrate << unit_thickness_substrate,
cce_backsurface=cce_backsurface,
)

return np.sqrt(np.mean(np.square(qe_measured.outputs - qe_fit))).ndarray

thickness_oxide_guess = 50 * u.AA
thickness_implant_guess = 2317 * u.AA
thickness_substrate_guess = 7 * u.um
cce_backsurface_guess = 0.21

fit = scipy.optimize.minimize(
fun=eqe_rms_difference,
x0=[
thickness_oxide_guess.to_value(unit_thickness_oxide),
thickness_implant_guess.to_value(unit_thickness_implant),
thickness_substrate_guess.to_value(unit_thickness_substrate),
cce_backsurface_guess,
],
method="nelder-mead",
)

thickness_oxide, thickness_implant, thickness_substrate, cce_backsurface = fit.x
thickness_oxide = thickness_oxide << unit_thickness_oxide
thickness_implant = thickness_implant << unit_thickness_implant
thickness_substrate = thickness_substrate << unit_thickness_substrate

return dict(
thickness_oxide=thickness_oxide,
thickness_implant=thickness_implant,
thickness_substrate=thickness_substrate,
cce_backsurface=cce_backsurface,
)

@property
def thickness_oxide(self) -> u.Quantity:
return self._quantum_efficiency_fit["thickness_oxide"]

@property
def thickness_implant(self) -> u.Quantity:
return self._quantum_efficiency_fit["thickness_implant"]

@property
def thickness_substrate(self) -> u.Quantity:
return self._quantum_efficiency_fit["thickness_substrate"]

@property
def cce_backsurface(self) -> float:
return self._quantum_efficiency_fit["cce_backsurface"]
4 changes: 2 additions & 2 deletions optika/sensors/_materials/_e2v_ccd97/_e2v_ccd97_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest
import optika
from .._materials_test import AbstractTestAbstractBackilluminatedCCDMaterial
from .._materials_test import AbstractTestAbstractStern1994BackilluminatedCCDMaterial


@pytest.mark.parametrize(
Expand All @@ -10,6 +10,6 @@
],
)
class TestE2VCCD97Material(
AbstractTestAbstractBackilluminatedCCDMaterial,
AbstractTestAbstractStern1994BackilluminatedCCDMaterial,
):
pass
1 change: 1 addition & 0 deletions optika/sensors/_materials/_e2v_ccd_aia/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from ._e2v_ccd_aia import *
123 changes: 123 additions & 0 deletions optika/sensors/_materials/_e2v_ccd_aia/_e2v_ccd_aia.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import pathlib
import numpy as np
import astropy.units as u
import named_arrays as na
from .._materials import AbstractStern1994BackilluminatedCCDMaterial

__all__ = [
"E2VCCDAIAMaterial",
]


class E2VCCDAIAMaterial(
AbstractStern1994BackilluminatedCCDMaterial,
):
"""
A model of the light-sensitive material of the custom e2v CCD sensors
on board the Atmospheric Imaging Assembly :cite:p:`Lemen2012` from
:cite:t:`Boerner2012`
Examples
--------
Plot the measured AIA CCD quantum efficiency vs the fitted
quantum efficiency calculated using the method of :cite:t:`Stern1994`.
.. jupyter-execute::
import matplotlib.pyplot as plt
import astropy.units as u
import astropy.visualization
import named_arrays as na
import optika
# Create a new instance of the e2v CCD97 light-sensitive material
material_ccd_aia = optika.sensors.E2VCCDAIAMaterial()
# Store the wavelengths at which the QE was measured
wavelength_measured = material_ccd_aia.quantum_efficiency_measured.inputs
# Store the QE measurements
qe_measured = material_ccd_aia.quantum_efficiency_measured.outputs
# Define a grid of wavelengths with which to evaluate the fitted QE
wavelength_fit = na.geomspace(10, 10000, axis="wavelength", num=1001) * u.AA
# Evaluate the fitted QE using the given wavelengths
qe_fit = material_ccd_aia.quantum_efficiency_effective(
rays=optika.rays.RayVectorArray(
wavelength=wavelength_fit,
direction=na.Cartesian3dVectorArray(0, 0, 1),
),
normal=na.Cartesian3dVectorArray(0, 0, -1),
)
# Plot the measured QE vs the fitted QE
with astropy.visualization.quantity_support():
fig, ax = plt.subplots(constrained_layout=True)
na.plt.scatter(
wavelength_measured,
qe_measured,
label="measured",
)
na.plt.plot(
wavelength_fit,
qe_fit,
label="fit",
)
ax.set_xscale("log")
ax.set_xlabel(f"wavelength ({wavelength_fit.unit:latex_inline})")
ax.set_ylabel("quantum efficiency")
ax.legend()
The thickness of the oxide layer found by the fit is
.. jupyter-execute::
material_ccd_aia.thickness_oxide
The thickness of the implant layer found by the fit is
.. jupyter-execute::
material_ccd_aia.thickness_implant
The thickness of the substrate found by the fit is
.. jupyter-execute::
material_ccd_aia.thickness_substrate
And the differential charge collection efficiency at the backsurface
found by the fit is
.. jupyter-execute::
material_ccd_aia.cce_backsurface
"""

@property
def quantum_efficiency_measured(self) -> na.FunctionArray:
directory = pathlib.Path(__file__).parent
(
wavelength_1,
qe_1,
wavelength_2,
qe_2,
wavelength_3,
qe_3,
wavelength_4,
qe_4,
) = np.genfromtxt(
fname=directory / "e2v_ccd_aia_qe_boerner2012.csv",
skip_header=2,
delimiter=",",
unpack=True,
)
wavelength = (wavelength_1 + wavelength_2 + wavelength_3 + wavelength_4) / 4
wavelength = wavelength << u.AA
qe = (qe_1 + qe_2 + qe_3 + qe_4) / 4
return na.FunctionArray(
inputs=na.ScalarArray(wavelength, axes="wavelength"),
outputs=na.ScalarArray(qe, axes="wavelength"),
)
15 changes: 15 additions & 0 deletions optika/sensors/_materials/_e2v_ccd_aia/_e2v_ccd_aia_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import pytest
import optika
from .._materials_test import AbstractTestAbstractStern1994BackilluminatedCCDMaterial


@pytest.mark.parametrize(
argnames="a",
argvalues=[
optika.sensors.E2VCCDAIAMaterial(),
],
)
class TestE2VCCD9AIAMaterial(
AbstractTestAbstractStern1994BackilluminatedCCDMaterial,
):
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
ATA1,,ATA2,,ATA3,,ATA4,
X,Y,X,Y,X,Y,X,Y
13.261133439968747,0.9681208053691276,13.195629329127717,0.9620805369127517,13.261133439968747,0.9661073825503357,13.195629329127717,0.9560402684563759
23.552825299134007,0.8976510067114094,23.552825299134007,0.8815436241610739,23.552825299134007,0.8966442953020135,23.552825299134007,0.8916107382550336
44.613096279008374,0.6580536912751678,44.39272739298135,0.6479865771812081,44.613096279008374,0.6681208053691274,44.613096279008374,0.6711409395973154
67.62503873611176,0.5130872483221476,67.29100107235915,0.4818791946308725,67.62503873611176,0.5161073825503355,67.62503873611176,0.5060402684563757
113.74019762127737,0.5352348993288589,113.74019762127737,0.5171140939597315,113.1783715491855,0.539261744966443,113.74019762127737,0.532214765100671
134.59603241553643,0.8624161073825504,135.26417739037652,0.8201342281879195,135.26417739037652,0.8664429530201343,134.92969133847444,0.8483221476510068
170.70964708781221,0.8050335570469799,170.70964708781221,0.7718120805369127,171.55706280142192,0.7859060402684563,171.55706280142192,0.7718120805369127
256.21358339713123,0.7395973154362416,254.94800206188594,0.7083892617449665,254.94800206188594,0.7446308724832215,256.21358339713123,0.7073825503355704
304.6989570903505,0.7003355704697987,304.6989570903505,0.6590604026845637,303.1938795380627,0.7184563758389262,303.1938795380627,0.6766778523489934
585.7899755867955,0.5231543624161072,585.7899755867955,0.47785234899328854,585.7899755867955,0.5251677852348993,585.7899755867955,0.47885906040268456
1213.0283967784094,0.1637583892617448,1213.0283967784094,0.13758389261744963,1213.0283967784094,0.15369127516778514,1213.0283967784094,0.1506711409395971
1608.6131436149833,0.16073825503355677,1616.5984220000837,0.14060402684563744,1616.5984220000837,0.1627516778523488,1616.5984220000837,0.17281879194630856
Loading

0 comments on commit 97343a8

Please sign in to comment.