Coverage for tests/test_deferredCharge.py: 21%
85 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-08 05:29 -0700
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-08 05:29 -0700
1# This file is part of ip_isr.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
21import unittest
22import numpy as np
23import tempfile
24import lsst.utils.tests
26from lsst.ip.isr import DeferredChargeCalib, DeferredChargeTask, SerialTrap
29class SerialTrapTestCase(lsst.utils.tests.TestCase):
30 def setUp(self):
31 self.nx = 64
32 self.ny = 128
33 self.prescan = 8
34 self.trapSize = 10.0
35 self.trapDecay = 3.0
36 self.trapPixel = self.nx + self.prescan - 3
37 self.trapCoeffs = [5.0, 1e-3]
39 def testTrapsLinear(self):
40 trap = SerialTrap(self.trapSize, self.trapDecay,
41 self.trapPixel, 'linear', self.trapCoeffs)
42 trap.initialize(self.ny, self.nx, self.prescan)
44 signals = np.full((self.ny, self.nx + self.prescan), 100.0)
45 signals[:, 0:self.prescan] = 0.0
47 freeCharge = np.full((self.ny, self.nx + self.prescan), 100.0)
48 freeCharge[:, 0:self.prescan] = 0.0
50 # Captured charge is of size trapSize, stored in column
51 # trapPixel, and introduced to all rows.
52 capturedCharge = trap.trap_charge(signals)
53 self.assertEqual(capturedCharge.shape, (self.ny, self.nx + self.prescan))
54 self.assertEqual(np.sum(capturedCharge), self.trapSize * (self.ny))
56 # Released charge is the amount released after one decay.
57 releasedCharge = trap.release_charge()
58 self.assertEqual(releasedCharge.shape, (self.ny, self.nx + self.prescan))
59 self.assertAlmostEqual(np.sum(releasedCharge), 362.839922, 4)
61 def testTrapsLogistic(self):
62 trap = SerialTrap(self.trapSize, self.trapDecay,
63 self.trapPixel, 'logistic', self.trapCoeffs)
64 trap.initialize(self.ny, self.nx, self.prescan)
66 signals = np.full((self.ny, self.nx + self.prescan), 100.0)
67 freeCharge = np.full((self.ny, self.nx + self.prescan), 100.0)
68 signals[:, 0:self.prescan] = 0.0
69 freeCharge[:, 0:self.prescan] = 0.0
71 # Captured charge is of size trapSize, stored in column
72 # trapPixel, and introduced to all rows.
73 capturedCharge = trap.trap_charge(signals)
74 self.assertEqual(capturedCharge.shape, (self.ny, self.nx + self.prescan))
75 self.assertAlmostEqual(np.sum(capturedCharge), 5.23732154 * (self.ny), 4)
77 # Released charge is the amount released after one decay.
78 releasedCharge = trap.release_charge()
79 self.assertEqual(releasedCharge.shape, (self.ny, self.nx + self.prescan))
80 self.assertAlmostEqual(np.sum(releasedCharge), 190.030934, 4)
83class DeferredChargeTestCase(lsst.utils.tests.TestCase):
84 def setUp(self):
85 self.nx = 64
86 self.ny = 128
87 self.prescan = 8
88 self.overscan = 16
89 self.trapSize = 10.0
90 self.trapDecay = 3.0
91 self.trapPixel = self.nx//2 + self.prescan
92 self.trapCoeffs = [5.0, 1e-3]
93 self.calib = DeferredChargeCalib()
95 self.calib.driftScale['amp0'] = 1.8e-4
96 self.calib.driftScale['amp1'] = 2.8e-4
97 self.calib.decayTime['amp0'] = 3.1
98 self.calib.decayTime['amp1'] = 3.2
99 self.calib.globalCti['amp0'] = 1.4e-7
100 self.calib.globalCti['amp1'] = 1.5e-7
102 self.calib.serialTraps['amp0'] = SerialTrap(self.trapSize, self.trapDecay,
103 self.trapPixel, 'linear', self.trapCoeffs)
104 self.calib.serialTraps['amp0'] = SerialTrap(self.trapSize, self.trapDecay,
105 self.trapPixel, 'logistic', self.trapCoeffs)
107 def testFullyPopulated(self):
108 # Do IO tests.
109 outPath = tempfile.mktemp() + '.yaml'
110 self.calib.writeText(outPath)
111 newCalib = DeferredChargeCalib().readText(outPath)
112 self.assertEqual(self.calib, newCalib)
114 outPath = tempfile.mktemp() + '.fits'
115 self.calib.writeFits(outPath)
116 newCalib = DeferredChargeCalib().readFits(outPath)
117 self.assertEqual(self.calib, newCalib)
119 def testTaskMethods(self):
120 task = DeferredChargeTask()
122 image = np.full((self.ny, self.nx + self.prescan + self.overscan), 100.0)
123 image[:, 0:self.prescan] = 0.0
124 image[:, -self.overscan:] = 1.0
126 corrected = task.local_offset_inverse(image, self.calib.driftScale['amp0'],
127 self.calib.decayTime['amp0'],
128 num_previous_pixels=15)
129 # 64*128*100 + 16*64 * ~(1 - driftScale)
130 self.assertAlmostEqual(np.sum(corrected), 821094.5118501, 5)
132 corrected = task.local_trap_inverse(corrected, self.calib.serialTraps['amp0'],
133 self.calib.globalCti['amp0'],
134 num_previous_pixels=6)
135 # As above + ~320 deposited in prescan
136 self.assertAlmostEqual(np.sum(corrected), 821733.2317048, 5)
139class MemoryTester(lsst.utils.tests.MemoryTestCase):
140 pass
143def setup_module(module):
144 lsst.utils.tests.init()
147if __name__ == "__main__": 147 ↛ 148line 147 didn't jump to line 148, because the condition on line 147 was never true
148 import sys
149 setup_module(sys.modules[__name__])
150 unittest.main()