Coverage for tests/test_deferredCharge.py: 17%
104 statements
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-11 18:34 +0000
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-11 18:34 +0000
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,
27 IsrTaskConfig)
30class SerialTrapTestCase(lsst.utils.tests.TestCase):
31 def setUp(self):
32 self.nx = 64
33 self.ny = 128
34 self.prescan = 8
35 self.trapSize = 10.0
36 self.trapDecay = 3.0
37 self.trapPixel = self.nx + self.prescan - 3
38 self.trapCoeffs = [5.0, 1e-3]
40 def testTrapsLinear(self):
41 trap = SerialTrap(self.trapSize, self.trapDecay,
42 self.trapPixel, 'linear', self.trapCoeffs)
43 trap.initialize(self.ny, self.nx, self.prescan)
45 signals = np.full((self.ny, self.nx + self.prescan), 100.0)
46 signals[:, 0:self.prescan] = 0.0
48 freeCharge = np.full((self.ny, self.nx + self.prescan), 100.0)
49 freeCharge[:, 0:self.prescan] = 0.0
51 # Captured charge is of size trapSize, stored in column
52 # trapPixel, and introduced to all rows.
53 capturedCharge = trap.trap_charge(signals)
54 self.assertEqual(capturedCharge.shape, (self.ny, self.nx + self.prescan))
55 self.assertEqual(np.sum(capturedCharge), self.trapSize * (self.ny))
57 # Released charge is the amount released after one decay.
58 releasedCharge = trap.release_charge()
59 self.assertEqual(releasedCharge.shape, (self.ny, self.nx + self.prescan))
60 self.assertAlmostEqual(np.sum(releasedCharge), 362.839922, 4)
62 def testTrapsLogistic(self):
63 trap = SerialTrap(self.trapSize, self.trapDecay,
64 self.trapPixel, 'logistic', self.trapCoeffs)
65 trap.initialize(self.ny, self.nx, self.prescan)
67 signals = np.full((self.ny, self.nx + self.prescan), 100.0)
68 freeCharge = np.full((self.ny, self.nx + self.prescan), 100.0)
69 signals[:, 0:self.prescan] = 0.0
70 freeCharge[:, 0:self.prescan] = 0.0
72 # Captured charge is of size trapSize, stored in column
73 # trapPixel, and introduced to all rows.
74 capturedCharge = trap.trap_charge(signals)
75 self.assertEqual(capturedCharge.shape, (self.ny, self.nx + self.prescan))
76 self.assertAlmostEqual(np.sum(capturedCharge), 5.23732154 * (self.ny), 4)
78 # Released charge is the amount released after one decay.
79 releasedCharge = trap.release_charge()
80 self.assertEqual(releasedCharge.shape, (self.ny, self.nx + self.prescan))
81 self.assertAlmostEqual(np.sum(releasedCharge), 190.030934, 4)
84class DeferredChargeTestCase(lsst.utils.tests.TestCase):
85 def setUp(self):
86 self.nx = 64
87 self.ny = 128
88 self.prescan = 8
89 self.overscan = 16
90 self.trapSize = 10.0
91 self.trapDecay = 3.0
92 self.trapPixel = self.nx//2 + self.prescan
93 self.trapCoeffs = [5.0, 1e-3]
94 self.calib = DeferredChargeCalib()
96 self.calib.driftScale['amp0'] = 1.8e-4
97 self.calib.driftScale['amp1'] = 2.8e-4
98 self.calib.decayTime['amp0'] = 3.1
99 self.calib.decayTime['amp1'] = 3.2
100 self.calib.globalCti['amp0'] = 1.4e-7
101 self.calib.globalCti['amp1'] = 1.5e-7
103 self.calib.serialTraps['amp0'] = SerialTrap(self.trapSize, self.trapDecay,
104 self.trapPixel, 'linear', self.trapCoeffs)
105 self.calib.serialTraps['amp0'] = SerialTrap(self.trapSize, self.trapDecay,
106 self.trapPixel, 'logistic', self.trapCoeffs)
108 def testFullyPopulated(self):
109 # Do IO tests.
110 outPath = tempfile.mktemp() + '.yaml'
111 self.calib.writeText(outPath)
112 newCalib = DeferredChargeCalib().readText(outPath)
113 self.assertEqual(self.calib, newCalib)
115 outPath = tempfile.mktemp() + '.fits'
116 self.calib.writeFits(outPath)
117 newCalib = DeferredChargeCalib().readFits(outPath)
118 self.assertEqual(self.calib, newCalib)
120 def testTaskMethods(self):
121 task = DeferredChargeTask()
123 image = np.full((self.ny, self.nx + self.prescan + self.overscan), 100.0)
124 image[:, 0:self.prescan] = 0.0
125 image[:, -self.overscan:] = 1.0
127 corrected = task.local_offset_inverse(image, self.calib.driftScale['amp0'],
128 self.calib.decayTime['amp0'],
129 num_previous_pixels=15)
130 # 64*128*100 + 16*64 * ~(1 - driftScale)
131 self.assertAlmostEqual(np.sum(corrected), 821094.5118501, 5)
133 corrected = task.local_trap_inverse(corrected, self.calib.serialTraps['amp0'],
134 self.calib.globalCti['amp0'],
135 num_previous_pixels=6)
136 # As above + ~320 deposited in prescan
137 self.assertAlmostEqual(np.sum(corrected), 821733.2317048, 5)
139 def testConfigLogic(self):
140 config = IsrTaskConfig()
141 config.doFlat = False
142 config.doCalculateStatistics = True
143 config.isrStats.doCtiStatistics = True
145 # Confirm that image and overscan are treated the same.
146 config.doApplyGains = True
147 config.isrStats.doApplyGainsForCtiStatistics = False
148 with self.assertRaises(ValueError):
149 config.validate()
151 config.doApplyGains = False
152 config.isrStats.doApplyGainsForCtiStatistics = True
153 with self.assertRaises(ValueError):
154 config.validate()
156 # these should not raise
157 config.doApplyGains = True
158 config.isrStats.doApplyGainsForCtiStatistics = True
159 config.validate()
161 config.doApplyGains = False
162 config.isrStats.doApplyGainsForCtiStatistics = False
163 config.validate()
166class MemoryTester(lsst.utils.tests.MemoryTestCase):
167 pass
170def setup_module(module):
171 lsst.utils.tests.init()
174if __name__ == "__main__": 174 ↛ 175line 174 didn't jump to line 175, because the condition on line 174 was never true
175 import sys
176 setup_module(sys.modules[__name__])
177 unittest.main()