def test__add_cti_serial_fast(): arr = np.array(([ [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], ])) arr = ac.Array2D.manual(array=arr, pixel_scales=1.0).native ccd = ac.CCDPhase(full_well_depth=1e3, well_notch_depth=0.0, well_fill_power=1.0) trap_list = [ ac.TrapInstantCapture(density=10.0, release_timescale=-1.0 / np.log(0.5)) ] clocker = ac.Clocker2D() image_via_clocker = clocker.add_cti(data=arr, serial_trap_list=trap_list, serial_ccd=ccd) clocker = ac.Clocker2D(serial_fast_pixels=(1, 3)) image_via_clocker_fast = clocker.add_cti(data=arr, serial_trap_list=trap_list, serial_ccd=ccd) assert image_via_clocker == pytest.approx(image_via_clocker_fast, 1.0e-6)
def test__array_with_offset_through_arctic(): arr = ac.Array2D.manual( array=[[1.0, 2.0], [3.0, 4.0]], pixel_scales=1.0, header=ac.Header(header_sci_obj=None, header_hdu_obj=None, readout_offsets=(3, 5)), ).native roe = ac.ROE( dwell_times=[1.0], empty_traps_between_columns=True, empty_traps_for_first_transfers=False, force_release_away_from_readout=True, use_integer_express_matrix=False, ) ccd_phase = ac.CCDPhase(full_well_depth=1e3, well_notch_depth=0.0, well_fill_power=1.0) ccd = ac.CCD(phases=[ccd_phase], fraction_of_traps_per_phase=[1.0]) traps = [ac.TrapInstantCapture(10.0, -1.0 / np.log(0.5))] image_via_arctic = cti.add_cti( image=arr, parallel_traps=traps, parallel_ccd=ccd, parallel_roe=roe, parallel_express=3, parallel_offset=3, ) clocker = ac.Clocker2D(parallel_express=3, parallel_roe=roe) image_via_clocker = clocker.add_cti(data=arr, parallel_trap_list=traps, parallel_ccd=ccd_phase) assert image_via_arctic == pytest.approx(image_via_clocker, 1.0e-4) image_via_arctic = cti.add_cti( image=arr, serial_traps=traps, serial_ccd=ccd, serial_roe=roe, serial_express=2, serial_offset=5, ) clocker = ac.Clocker2D(serial_express=2, serial_roe=roe) image_via_clocker = clocker.add_cti(data=arr, serial_trap_list=traps, serial_ccd=ccd_phase) assert image_via_arctic == pytest.approx(image_via_clocker, 1.0e-4)
def test__add_cti_with_poisson_trap_densities(): arr = np.array(([ [1.0, 1.0, 1.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], ])) arr = ac.Array2D.manual(array=arr, pixel_scales=1.0).native roe = ac.ROE( dwell_times=[1.0], empty_traps_between_columns=True, empty_traps_for_first_transfers=False, force_release_away_from_readout=True, use_integer_express_matrix=False, ) ccd = ac.CCDPhase(full_well_depth=1e3, well_notch_depth=0.0, well_fill_power=1.0) trap_list = [ ac.TrapInstantCapture(density=10.0, release_timescale=-1.0 / np.log(0.5)) ] clocker = ac.Clocker2D( parallel_poisson_traps=True, poisson_seed=1, parallel_express=3, parallel_roe=roe, serial_express=3, serial_roe=roe, ) image_via_clocker = clocker.add_cti( data=arr, parallel_trap_list=trap_list, parallel_ccd=ccd, serial_trap_list=trap_list, serial_ccd=ccd, ) assert image_via_clocker[0, 0] == pytest.approx(0.980298, 1.0e-4) assert image_via_clocker[0, 1] == pytest.approx(0.9901042, 1.0e-4) assert image_via_clocker[0, 2] == pytest.approx(0.9901981, 1.0e-4) assert (image_via_clocker[:, 3] > 0.0).all()
def test__add_cti_serial_fast__raises_exception_if_nonzero_outside_tuple(): ccd = ac.CCDPhase(full_well_depth=1e3, well_notch_depth=0.0, well_fill_power=1.0) trap_list = [ ac.TrapInstantCapture(density=10.0, release_timescale=-1.0 / np.log(0.5)) ] clocker = ac.Clocker2D(serial_fast_pixels=(1, 3)) arr = np.array(([ [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0], [0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], ])) arr = ac.Array2D.manual(array=arr, pixel_scales=1.0).native with pytest.raises(exc.ClockerException): clocker.add_cti(data=arr, serial_trap_list=trap_list, serial_ccd=ccd) arr = np.array(([ [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0], ])) arr = ac.Array2D.manual(array=arr, pixel_scales=1.0).native with pytest.raises(exc.ClockerException): clocker.add_cti(data=arr, serial_trap_list=trap_list, serial_ccd=ccd) arr = np.array(([ [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 1.0, 1.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], ])) arr = ac.Array2D.manual(array=arr, pixel_scales=1.0).native with pytest.raises(exc.ClockerException): clocker.add_cti(data=arr, serial_trap_list=trap_list, serial_ccd=ccd)
Create the layout of the charge injection pattern for every charge injection normalization. """ layout_list = [ ac.ci.Layout2DCI( shape_2d=shape_native, region_list=regions_list, normalization=normalization, parallel_overscan=parallel_overscan, serial_prescan=serial_prescan, serial_overscan=serial_overscan, ) for normalization in normalization_list ] """ The `Clocker` models the CCD read-out, including CTI. """ clocker = ac.Clocker2D(serial_express=2) """ __CTI Model__ The CTI model used by arCTIc to add CTI to the input image in the serial direction, which contains: - 3 trap species in the parallel direction. - A simple CCD volume beta parametrization. """ serial_trap_0 = ac.TrapInstantCapture(density=0.0442, release_timescale=0.8) serial_trap_1 = ac.TrapInstantCapture(density=0.1326, release_timescale=4.0) serial_trap_2 = ac.TrapInstantCapture(density=3.9782, release_timescale=20.0) serial_ccd = ac.CCDPhase(well_fill_power=0.8, well_notch_depth=0.0, full_well_depth=84700.0)
] """ Lets plot the first `ImagingCI`. """ imaging_ci_plotter = aplt.ImagingCIPlotter(imaging=imaging_ci_list[0]) imaging_ci_plotter.subplot_imaging_ci() """ __Clocking__ The `Clocker` models the CCD read-out, including CTI. For parallel clocking, we use 'charge injection mode' which transfers the charge of every pixel over the full CCD. """ clocker = ac.Clocker2D(parallel_express=2, parallel_charge_injection_mode=True) """ __Model__ We now compose our CTI model, which represents the trap species and CCD volume filling behaviour used to fit the charge injection data. In this example we fit a CTI model with: - Two parallel `TrapInstantCapture`'s which capture electrons during clocking instantly in the parallel direction [4 parameters]. - A simple `CCD` volume filling parametrization with fixed notch depth and capacity [1 parameter]. The number of free parameters and therefore the dimensionality of non-linear parameter space is N=5. """ parallel_traps = [af.Model(ac.TrapInstantCapture), af.Model(ac.TrapInstantCapture)]
""" masked_line_list = [ ac.ci.ImagingCI(imaging_ci=line, mask=mask) for line, mask in zip(line_list, mask_list) ] """ Here is what our image looks like with the mask applied. """ imaging_ci_plotter = aplt.ImagingCIPlotter(imaging=line_list[0]) imaging_ci_plotter.figures_2d(image=True) """ The `Clocker` models the line read-out, including CTI. """ clocker = ac.Clocker2D(parallel_express=2) """ __CTI Model__ The CTI model used by arCTIc to add CTI to the input line, which contains: - 2 `Trap` species. - A simple CCD volume beta parametrization. """ trap_0 = ac.TrapInstantCapture(density=0.0442, release_timescale=0.8) trap_1 = ac.TrapInstantCapture(density=0.1326, release_timescale=4.0) trap_2 = ac.TrapInstantCapture(density=3.9782, release_timescale=20.0) trap_list = [trap_0, trap_1, trap_2] ccd = ac.CCDPhase(well_fill_power=0.8, well_notch_depth=0.0, full_well_depth=84700.0)
def test__raises_exception_if_no_traps_or_ccd_passed(): arr = ac.Array2D.manual( array=[[1.0, 2.0], [3.0, 4.0]], pixel_scales=1.0, header=ac.Header(header_sci_obj=None, header_hdu_obj=None, readout_offsets=(3, 5)), ).native ccd_phase = ac.CCDPhase(full_well_depth=1e3, well_notch_depth=0.0, well_fill_power=1.0) traps = [ac.TrapInstantCapture(10.0, -1.0 / np.log(0.5))] clocker = ac.Clocker2D(parallel_express=3) with pytest.raises(exc.ClockerException): clocker.add_cti(data=arr) with pytest.raises(exc.ClockerException): clocker.add_cti(data=arr, parallel_trap_list=traps) with pytest.raises(exc.ClockerException): clocker.add_cti(data=arr, serial_trap_list=traps) with pytest.raises(exc.ClockerException): clocker.add_cti(data=arr, parallel_trap_list=traps, serial_trap_list=traps) with pytest.raises(exc.ClockerException): clocker.add_cti(data=arr, parallel_ccd=ccd_phase) with pytest.raises(exc.ClockerException): clocker.add_cti(data=arr, serial_ccd=ccd_phase) with pytest.raises(exc.ClockerException): clocker.add_cti(data=arr, parallel_ccd=ccd_phase, serial_ccd=ccd_phase) with pytest.raises(exc.ClockerException): clocker.remove_cti(data=arr) with pytest.raises(exc.ClockerException): clocker.remove_cti(data=arr, parallel_trap_list=traps) with pytest.raises(exc.ClockerException): clocker.remove_cti(data=arr, serial_trap_list=traps) with pytest.raises(exc.ClockerException): clocker.remove_cti(data=arr, parallel_trap_list=traps, serial_trap_list=traps) with pytest.raises(exc.ClockerException): clocker.remove_cti(data=arr, parallel_ccd=ccd_phase) with pytest.raises(exc.ClockerException): clocker.remove_cti(data=arr, serial_ccd=ccd_phase) with pytest.raises(exc.ClockerException): clocker.remove_cti(data=arr, parallel_ccd=ccd_phase, serial_ccd=ccd_phase)
""" __Paths__ The path the results of all chained searches are output: """ path_prefix = path.join("imaging_ci", "chaining", "parallel_x2_serial_x2") """ __Parallel Clocking (Searches 1 & 2)__ The `Clocker` models the CCD read-out, including CTI. We use different clockers for different searches: Searches 1 & 2) Parallel only clocking (including 'charge injection mode'). Searches 3 & 4) Serial only clocking. Searches 5,6 & 7) Parallel and serial joint clocking. """ parallel_clocker = ac.Clocker2D(parallel_express=2, parallel_charge_injection_mode=True) serial_clocker = ac.Clocker2D(serial_express=2) parallel_serial_clocker = ac.Clocker2D(parallel_express=2, parallel_charge_injection_mode=True, serial_express=2) """ __Model + Search + Analysis + Model-Fit (Search 1)__ In Search 1 we fit a CTI model with: - One parallel `TrapInstantCapture`'s species [2 parameters]. - A simple `CCD` volume filling parametrization with fixed notch depth and capacity [1 parameter]. The number of free parameters and therefore the dimensionality of non-linear parameter space is N=3. """
- The properties of the `Trap`'s on the CCD that are responsible for CTI by capturing and releasing electrons during read-out. - The volume-filling behaviour of electrons in CCD pixels, as this effects whether `Trap`'s are able to captrue them or not! **PyAutoCTI** again has in-built tools for automatically loading the CTI model appropriate for correcting ACS data, using the date of observation loaded in the `ACSFrame` object to choose a model based on the date of observation. """ # trap_list = ac.acs.trap_list.from_header(header=header) # ccd = ac.acs.CCD() trap_list = [ac.TrapInstantCapture(density=0.1, release_timescale=1.0)] ccd = ac.CCD(full_well_depth=1000, well_fill_power=0.8, well_notch_depth=100.0) """ We next create a `Clocker`, which determines how we 'clock' the image to mimic the effects of CTI and in turn use this clocked image to perform the CTI correction. For simplicity, we'll use all default values except using 5 iterations, which means when correcting the image we clock it to reproduce CTI and use this image to correct the image, and repeat that process 5 times. """ clocker = ac.Clocker2D(iterations=5, serial_express=20) """ We can now pass the image and CTI model to the `Clocker` to remove CTI. """ frame_corrected = clocker.remove_cti(data=frame, serial_trap_list=trap_list, serial_ccd=ccd) aplt.Frame2D(frame=frame_corrected, plotter=plotter)