Loading csst_ifs_sim/CTI/CTI.py +2 −317 Original line number Diff line number Diff line Loading @@ -14,14 +14,6 @@ parameters in parallel and serial direction. """ import numpy as np # try: # import cdm03bidir # #import cdm03bidirTest as cdm03bidir #for testing purposes only # except ImportError: # print('import CTI module') # #print ('No CDM03bidir module available, please compile it: f2py -c -m cdm03bidir cdm03bidir.f90') #CDM03bidir class CDM03bidir(): Loading Loading @@ -59,7 +51,7 @@ class CDM03bidir(): self.params.update(self.values) #read in trap information trapdata = np.loadtxt(self.values['parallelTrapfile']) trapdata = np.loadtxt(self.values['dir_path']+self.values['paralleltrapfile']) if trapdata.ndim > 1: self.nt_p = trapdata[:, 0] self.sigma_p = trapdata[:, 1] Loading @@ -70,7 +62,7 @@ class CDM03bidir(): self.sigma_p = [trapdata[1],] self.taur_p = [trapdata[2],] trapdata = np.loadtxt(self.values['serialTrapfile']) trapdata = np.loadtxt(self.values['dir_path']+self.values['serialtrapfile']) if trapdata.ndim > 1: self.nt_s = trapdata[:, 0] self.sigma_s = trapdata[:, 1] Loading Loading @@ -99,98 +91,6 @@ class CDM03bidir(): self.logger = False def radiateFullCCD(self): """ This routine allows the whole CCD to be run through a radiation damage mode. The routine takes into account the fact that the amplifiers are in the corners of the CCD. The routine assumes that the CCD is using four amplifiers. There is an excess of .copy() calls, which should probably be cleaned up. However, given that I had problem with the Fortran code, I have kept the calls. If memory becomes an issue then this should be cleaned. :return: radiation damaged image :rtype: ndarray """ ydim, xdim = self.data.shape out = np.zeros((xdim, ydim)) #transpose the data, because Python has different convention than Fortran data = self.data.transpose().copy() for quad in self.values['quads']: if self.logger: self.log.info('Adding CTI to Q%i' % quad) if quad == 0: d = data[0:self.values['xsize'], 0:self.values['ysize']].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[0:self.values['xsize'], 0:self.values['ysize']] = tmp elif quad == 1: d = data[self.values['xsize']:, :self.values['ysize']].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[self.values['xsize']:, :self.values['ysize']] = tmp elif quad == 2: d = data[:self.values['xsize'], self.values['ysize']:].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[:self.values['xsize'], self.values['ysize']:] = tmp elif quad == 3: d = data[self.values['xsize']:, self.values['ysize']:].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[self.values['xsize']:, self.values['ysize']:] = tmp else: print( 'ERROR -- too many quadrants!!' ) self.log.error('Too many quadrants! This method allows only four quadrants.') return out.transpose() def radiateFullCCD2(self): """ This routine allows the whole CCD to be run through a radiation damage mode. The routine takes into account the fact that the amplifiers are in the corners of the CCD. The routine assumes that the CCD is using four amplifiers. There is an excess of .copy() calls, which should probably be cleaned up. However, given that I had problem with the Fortran code, I have kept the calls. If memory becomes an issue then this should be cleaned. :return: radiation damaged image :rtype: ndarray """ ydim, xdim = self.data.shape out = np.empty((ydim, xdim)) #transpose the data, because Python has different convention than Fortran data = self.data.copy() for quad in self.values['quads']: if self.logger: self.log.info('Adding CTI to Q%i' % quad) if quad == 0: d = data[:self.values['ysize'], :self.values['xsize']].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[:self.values['ysize'], :self.values['xsize']] = tmp elif quad == 1: d = data[:self.values['ysize'], self.values['xsize']:].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[:self.values['ysize'], self.values['xsize']:] = tmp elif quad == 2: d = data[self.values['ysize']:, :self.values['xsize']].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[self.values['ysize']:, :self.values['xsize']] = tmp elif quad == 3: d = data[self.values['ysize']:, self.values['xsize']:].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[self.values['ysize']:, self.values['xsize']:] = tmp else: print( 'ERROR -- too many quadrants!!') self.log.error('Too many quadrants! This method allows only four quadrants.') return out def applyRadiationDamage(self, data, iquadrant=0): """ Apply radian damage based on FORTRAN CDM03 model. The method assumes that Loading Loading @@ -255,7 +155,6 @@ class CDM03bidir(): ################################################################################# ###modify import sys #sys.path.append('../so') from ifs_so import cdm03bidir # from ifs_so.cdm03.cpython-38-x86_64-linux-gnu import cdm03bidir Loading @@ -275,220 +174,6 @@ class CDM03bidir(): class CDM03(): """ Class to run CDM03 CTI model, class Fortran routine to perform the actual CDM03 calculations. :param data: input data to be radiated :type data: ndarray :param input: input parameters :type input: dictionary :param log: instance to Python logging :type log: logging instance """ def __init__(self, input, data, log=None): """ Class constructor. :param data: input data to be radiated :type data: ndarray :param input: input parameters :type input: dictionary :param log: instance to Python logging :type log: logging instance """ try: import cdm03 except ImportError: print( 'No CDM03 module available, please compile it: f2py -c -m cdm03 cdm03.f90') self.data = data self.values = dict(quads=(0,1,2,3), xsize=2048, ysize=2066, dob=0.0, rdose=8.0e9) self.values.update(input) self.log = log self._setupLogger() def _setupLogger(self): """ Set up the logger. """ self.logger = True if self.log is None: self.logger = False def radiateFullCCD(self): """ This routine allows the whole CCD to be run through a radiation damage mode. The routine takes into account the fact that the amplifiers are in the corners of the CCD. The routine assumes that the CCD is using four amplifiers. There is an excess of .copy() calls, which should probably be cleaned up. However, given that I had problem with the Fortran code, I have kept the calls. If memory becomes an issue then this should be cleaned. :return: radiation damaged image :rtype: ndarray """ ydim, xdim = self.data.shape out = np.zeros((xdim, ydim)) #transpose the data, because Python has different convention than Fortran data = self.data.transpose().copy() for quad in self.values['quads']: if self.logger: self.log.info('Adding CTI to Q%i' % quad) if quad == 0: d = data[0:self.values['xsize'], 0:self.values['ysize']].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[0:self.values['xsize'], 0:self.values['ysize']] = tmp elif quad == 1: d = data[self.values['xsize']:, :self.values['ysize']].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[self.values['xsize']:, :self.values['ysize']] = tmp elif quad == 2: d = data[:self.values['xsize'], self.values['ysize']:].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[:self.values['xsize'], self.values['ysize']:] = tmp elif quad == 3: d = data[self.values['xsize']:, self.values['ysize']:].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[self.values['xsize']:, self.values['ysize']:] = tmp else: print ('ERROR -- too many quadrants!!') self.log.error('Too many quadrants! This method allows only four quadrants.') return out.transpose() def radiateFullCCD2(self): """ This routine allows the whole CCD to be run through a radiation damage mode. The routine takes into account the fact that the amplifiers are in the corners of the CCD. The routine assumes that the CCD is using four amplifiers. There is an excess of .copy() calls, which should probably be cleaned up. However, given that I had problem with the Fortran code, I have kept the calls. If memory becomes an issue then this should be cleaned. :return: radiation damaged image :rtype: ndarray """ ydim, xdim = self.data.shape out = np.empty((ydim, xdim)) #transpose the data, because Python has different convention than Fortran data = self.data.copy() for quad in self.values['quads']: if self.logger: self.log.info('Adding CTI to Q%i' % quad) if quad == 0: d = data[:self.values['ysize'], :self.values['xsize']].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[:self.values['ysize'], :self.values['xsize']] = tmp elif quad == 1: d = data[:self.values['ysize'], self.values['xsize']:].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[:self.values['ysize'], self.values['xsize']:] = tmp elif quad == 2: d = data[self.values['ysize']:, :self.values['xsize']].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[self.values['ysize']:, :self.values['xsize']] = tmp elif quad == 3: d = data[self.values['ysize']:, self.values['xsize']:].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[self.values['ysize']:, self.values['xsize']:] = tmp else: print ('ERROR -- too many quadrants!!') self.log.error('Too many quadrants! This method allows only four quadrants.') return out def applyRadiationDamage(self, data, iquadrant=0): """ Apply radian damage based on FORTRAN CDM03 model. The method assumes that input data covers only a single quadrant defined by the iquadrant integer. :param data: imaging data to which the CDM03 model will be applied to. :type data: ndarray :param iquandrant: number of the quadrant to process :type iquandrant: int cdm03 - Function signature:: sout = cdm03(sinp,iflip,jflip,dob,rdose,in_nt,in_sigma,in_tr,[xdim,ydim,zdim]) Required arguments: sinp : input rank-2 array('d') with bounds (xdim,ydim) iflip : input int jflip : input int dob : input float rdose : input float in_nt : input rank-1 array('d') with bounds (zdim) in_sigma : input rank-1 array('d') with bounds (zdim) in_tr : input rank-1 array('d') with bounds (zdim) Optional arguments: xdim := shape(sinp,0) input int ydim := shape(sinp,1) input int zdim := len(in_nt) input int Return objects: sout : rank-2 array('d') with bounds (xdim,ydim) .. Note:: Because Python/NumPy arrays are different row/column based, one needs to be extra careful here. NumPy.asfortranarray will be called to get an array laid out in Fortran order in memory. Before returning the array will be laid out in memory in C-style (row-major order). :return: image that has been run through the CDM03 model :rtype: ndarray """ #read in trap information trapdata = np.loadtxt(self.values['trapfile']) nt = trapdata[:, 0] sigma = trapdata[:, 1] taur = trapdata[:, 2] iflip = iquadrant / 2 jflip = iquadrant % 2 if self.logger: self.log.info('nt=' + str(nt)) self.log.info('sigma= ' + str(sigma)) self.log.info('taur= ' + str(taur)) self.log.info('dob=%f' % self.values['dob']) self.log.info('rdose=%e' % self.values['rdose']) self.log.info('xsize=%i' % data.shape[1]) self.log.info('ysize=%i' % data.shape[0]) self.log.info('quadrant=%i' % iquadrant) self.log.info('iflip=%i' % iflip) self.log.info('jflip=%i' % jflip) # #call Fortran routine # CTIed = cdm03.cdm03(np.asfortranarray(data), # iflip, jflip, # self.values['dob'], self.values['rdose'], # nt, sigma, taur) ###modify import sys sys.path.append('../CTI') import cdm03 ################################################################################# CTIed = cdm03.cdm03(np.asfortranarray(data), jflip, iflip, self.values['dob'], self.values['rdose'], nt,sigma,taur ) return np.asanyarray(CTIed) ################################################################################################################# Loading csst_ifs_sim/CTI/__pycache__/CTI.cpython-38.pyc −7.59 KiB (5.3 KiB) File changed.No diff preview for this file type. View original file View changed file csst_ifs_sim/__pycache__/csst_ifs_sim.cpython-38.pyc (86.1 KiB) File changed.No diff preview for this file type. View original file View changed file csst_ifs_sim/csst_ifs_sim.py +17 −55 Original line number Diff line number Diff line Loading @@ -5,10 +5,6 @@ Created on Thu Apr 11 15:18:57 2024 @author: yan """ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # import sys import os from scipy.interpolate import interp1d import astropy.coordinates as coord Loading @@ -18,17 +14,11 @@ import sys # from csst_ifs_sim.support import cosmicrays # from csst_ifs_sim.support import logger as lg # from csst_ifs_sim.CTI import CTI sys.path.append('./csst_ifs_sim') from CTI import CTI from support import logger as lg from support import cosmicrays from support import IFSinstrumentModel # from optparse import OptionParser import configparser as ConfigParser import cmath from scipy import ndimage Loading Loading @@ -62,50 +52,31 @@ The approximate sequence of events in the simulator is as follows: #. Read in a configuration file, which defines for example, detector characteristics (bias, dark and readout noise, gain, plate scale and pixel scale, oversampling factor, exposure time etc.). pixel scale,exposure time etc.). #. Read in another file containing charge trap definitions (for CTI modelling). #. Read in a file defining the cosmic rays (trail lengths and cumulative distributions). #. Read in CCD offset information, displace the image, and modify the output file name to contain the CCD and quadrant information #. Load the wavefront aberration data used to calculate PSF with defined wavelength and field of view. #. Loop over the number of exposures to co-add and for each object in the object catalog: * determine the number of electrons an object should have by scaling the object's magnitude with the given zeropoint and exposure time. * determine whether the object lands on to the detector or not and if it is a star or an extended source (i.e. a galaxy). * if object is extended determine the size (using a size-magnitude relation) and scale counts, convolve with the PSF, and finally overlay onto the detector according to its position. * if object is a star, scale counts according to the derived scaling (first step), and finally overlay onto the detector according to its position. #. Apply calibration unit flux to mimic flat field exposures [optional]. #. Apply a multiplicative flat-field map to emulate pixel-to-pixel non-uniformity [optional]. #. Add a charge injection line (horizontal and/or vertical) [optional]. non-uniformity. #. Add cosmic ray tracks onto the CCD with random positions but known distribution [optional]. #. Apply detector charge bleeding in column direction [optional]. distribution. #. Apply detector charge bleeding in column direction. #. Add constant dark current and background light from Zodiacal light [optional]. #. Include spatially uniform scattered light to the pixel grid [optional]. #. Add photon (Poisson) noise [optional] #. Add cosmetic defects from an input file [optional]. #. Add pre- and overscan regions in the serial direction [optional]. light. #. Include spatially uniform scattered light to the pixel grid. #. Add photon (Poisson) noise #. Add cosmetic defects from an input file. #. Add pre- and overscan regions in the serial direction. #. Apply the CDM03 radiation damage model [optional]. #. Apply CCD273 non-linearity model to the pixel data [optional]. #. Add readout noise selected from a Gaussian distribution [optional]. #. Apply CCD273 non-linearity model to the pixel data. #. Add readout noise selected from a Gaussian distribution. #. Convert from electrons to ADUs using a given gain factor. #. Add a given bias level and discretise the counts (the output is going to be in 16bit unsigned integers). #. Finally the simulated image is converted to a FITS file, a WCS is assigned and the output is saved to the current working directory. #. Add a given bias level and discretise the counts #. Finally the simulated image is converted to a FITS file. Warning:: The code is still work in progress and new features are being added. The code has been tested, but nevertheless bugs may be lurking in corners, so Loading @@ -120,16 +91,7 @@ Note:: This class is Python 3 compatible. 2024.3.20 --- update the fits header as defined order 0 data format """ # from astropy.table import Table ############################################################################### # filterPivotWave = {'nuv': 2875.5, 'u': 3629.6, 'g': 4808.4, # 'r': 6178.2, 'i': 7609.0, 'z': 9012.9, 'y': 9627.9} # filterIndex = {'nuv': 0, 'u': 1, 'g': 2, 'r': 3, 'i': 4, 'z': 5, 'y': 6} #### functions definition ##### def transRaDec2D(ra, dec): """ Loading Loading @@ -5596,7 +5558,7 @@ class IFSsimulator(): self.applyPoissonNoise() print('Applying Possion noise finished.......') ################################## ################################# if self.nonlinearity: self.applyNonlinearity() Loading csst_ifs_sim/ifs_so/__pycache__/__init__.cpython-38.pyc 0 → 100644 +145 B File added.No diff preview for this file type. View file Loading
csst_ifs_sim/CTI/CTI.py +2 −317 Original line number Diff line number Diff line Loading @@ -14,14 +14,6 @@ parameters in parallel and serial direction. """ import numpy as np # try: # import cdm03bidir # #import cdm03bidirTest as cdm03bidir #for testing purposes only # except ImportError: # print('import CTI module') # #print ('No CDM03bidir module available, please compile it: f2py -c -m cdm03bidir cdm03bidir.f90') #CDM03bidir class CDM03bidir(): Loading Loading @@ -59,7 +51,7 @@ class CDM03bidir(): self.params.update(self.values) #read in trap information trapdata = np.loadtxt(self.values['parallelTrapfile']) trapdata = np.loadtxt(self.values['dir_path']+self.values['paralleltrapfile']) if trapdata.ndim > 1: self.nt_p = trapdata[:, 0] self.sigma_p = trapdata[:, 1] Loading @@ -70,7 +62,7 @@ class CDM03bidir(): self.sigma_p = [trapdata[1],] self.taur_p = [trapdata[2],] trapdata = np.loadtxt(self.values['serialTrapfile']) trapdata = np.loadtxt(self.values['dir_path']+self.values['serialtrapfile']) if trapdata.ndim > 1: self.nt_s = trapdata[:, 0] self.sigma_s = trapdata[:, 1] Loading Loading @@ -99,98 +91,6 @@ class CDM03bidir(): self.logger = False def radiateFullCCD(self): """ This routine allows the whole CCD to be run through a radiation damage mode. The routine takes into account the fact that the amplifiers are in the corners of the CCD. The routine assumes that the CCD is using four amplifiers. There is an excess of .copy() calls, which should probably be cleaned up. However, given that I had problem with the Fortran code, I have kept the calls. If memory becomes an issue then this should be cleaned. :return: radiation damaged image :rtype: ndarray """ ydim, xdim = self.data.shape out = np.zeros((xdim, ydim)) #transpose the data, because Python has different convention than Fortran data = self.data.transpose().copy() for quad in self.values['quads']: if self.logger: self.log.info('Adding CTI to Q%i' % quad) if quad == 0: d = data[0:self.values['xsize'], 0:self.values['ysize']].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[0:self.values['xsize'], 0:self.values['ysize']] = tmp elif quad == 1: d = data[self.values['xsize']:, :self.values['ysize']].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[self.values['xsize']:, :self.values['ysize']] = tmp elif quad == 2: d = data[:self.values['xsize'], self.values['ysize']:].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[:self.values['xsize'], self.values['ysize']:] = tmp elif quad == 3: d = data[self.values['xsize']:, self.values['ysize']:].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[self.values['xsize']:, self.values['ysize']:] = tmp else: print( 'ERROR -- too many quadrants!!' ) self.log.error('Too many quadrants! This method allows only four quadrants.') return out.transpose() def radiateFullCCD2(self): """ This routine allows the whole CCD to be run through a radiation damage mode. The routine takes into account the fact that the amplifiers are in the corners of the CCD. The routine assumes that the CCD is using four amplifiers. There is an excess of .copy() calls, which should probably be cleaned up. However, given that I had problem with the Fortran code, I have kept the calls. If memory becomes an issue then this should be cleaned. :return: radiation damaged image :rtype: ndarray """ ydim, xdim = self.data.shape out = np.empty((ydim, xdim)) #transpose the data, because Python has different convention than Fortran data = self.data.copy() for quad in self.values['quads']: if self.logger: self.log.info('Adding CTI to Q%i' % quad) if quad == 0: d = data[:self.values['ysize'], :self.values['xsize']].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[:self.values['ysize'], :self.values['xsize']] = tmp elif quad == 1: d = data[:self.values['ysize'], self.values['xsize']:].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[:self.values['ysize'], self.values['xsize']:] = tmp elif quad == 2: d = data[self.values['ysize']:, :self.values['xsize']].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[self.values['ysize']:, :self.values['xsize']] = tmp elif quad == 3: d = data[self.values['ysize']:, self.values['xsize']:].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[self.values['ysize']:, self.values['xsize']:] = tmp else: print( 'ERROR -- too many quadrants!!') self.log.error('Too many quadrants! This method allows only four quadrants.') return out def applyRadiationDamage(self, data, iquadrant=0): """ Apply radian damage based on FORTRAN CDM03 model. The method assumes that Loading Loading @@ -255,7 +155,6 @@ class CDM03bidir(): ################################################################################# ###modify import sys #sys.path.append('../so') from ifs_so import cdm03bidir # from ifs_so.cdm03.cpython-38-x86_64-linux-gnu import cdm03bidir Loading @@ -275,220 +174,6 @@ class CDM03bidir(): class CDM03(): """ Class to run CDM03 CTI model, class Fortran routine to perform the actual CDM03 calculations. :param data: input data to be radiated :type data: ndarray :param input: input parameters :type input: dictionary :param log: instance to Python logging :type log: logging instance """ def __init__(self, input, data, log=None): """ Class constructor. :param data: input data to be radiated :type data: ndarray :param input: input parameters :type input: dictionary :param log: instance to Python logging :type log: logging instance """ try: import cdm03 except ImportError: print( 'No CDM03 module available, please compile it: f2py -c -m cdm03 cdm03.f90') self.data = data self.values = dict(quads=(0,1,2,3), xsize=2048, ysize=2066, dob=0.0, rdose=8.0e9) self.values.update(input) self.log = log self._setupLogger() def _setupLogger(self): """ Set up the logger. """ self.logger = True if self.log is None: self.logger = False def radiateFullCCD(self): """ This routine allows the whole CCD to be run through a radiation damage mode. The routine takes into account the fact that the amplifiers are in the corners of the CCD. The routine assumes that the CCD is using four amplifiers. There is an excess of .copy() calls, which should probably be cleaned up. However, given that I had problem with the Fortran code, I have kept the calls. If memory becomes an issue then this should be cleaned. :return: radiation damaged image :rtype: ndarray """ ydim, xdim = self.data.shape out = np.zeros((xdim, ydim)) #transpose the data, because Python has different convention than Fortran data = self.data.transpose().copy() for quad in self.values['quads']: if self.logger: self.log.info('Adding CTI to Q%i' % quad) if quad == 0: d = data[0:self.values['xsize'], 0:self.values['ysize']].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[0:self.values['xsize'], 0:self.values['ysize']] = tmp elif quad == 1: d = data[self.values['xsize']:, :self.values['ysize']].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[self.values['xsize']:, :self.values['ysize']] = tmp elif quad == 2: d = data[:self.values['xsize'], self.values['ysize']:].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[:self.values['xsize'], self.values['ysize']:] = tmp elif quad == 3: d = data[self.values['xsize']:, self.values['ysize']:].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[self.values['xsize']:, self.values['ysize']:] = tmp else: print ('ERROR -- too many quadrants!!') self.log.error('Too many quadrants! This method allows only four quadrants.') return out.transpose() def radiateFullCCD2(self): """ This routine allows the whole CCD to be run through a radiation damage mode. The routine takes into account the fact that the amplifiers are in the corners of the CCD. The routine assumes that the CCD is using four amplifiers. There is an excess of .copy() calls, which should probably be cleaned up. However, given that I had problem with the Fortran code, I have kept the calls. If memory becomes an issue then this should be cleaned. :return: radiation damaged image :rtype: ndarray """ ydim, xdim = self.data.shape out = np.empty((ydim, xdim)) #transpose the data, because Python has different convention than Fortran data = self.data.copy() for quad in self.values['quads']: if self.logger: self.log.info('Adding CTI to Q%i' % quad) if quad == 0: d = data[:self.values['ysize'], :self.values['xsize']].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[:self.values['ysize'], :self.values['xsize']] = tmp elif quad == 1: d = data[:self.values['ysize'], self.values['xsize']:].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[:self.values['ysize'], self.values['xsize']:] = tmp elif quad == 2: d = data[self.values['ysize']:, :self.values['xsize']].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[self.values['ysize']:, :self.values['xsize']] = tmp elif quad == 3: d = data[self.values['ysize']:, self.values['xsize']:].copy() tmp = self.applyRadiationDamage(d, iquadrant=quad).copy() out[self.values['ysize']:, self.values['xsize']:] = tmp else: print ('ERROR -- too many quadrants!!') self.log.error('Too many quadrants! This method allows only four quadrants.') return out def applyRadiationDamage(self, data, iquadrant=0): """ Apply radian damage based on FORTRAN CDM03 model. The method assumes that input data covers only a single quadrant defined by the iquadrant integer. :param data: imaging data to which the CDM03 model will be applied to. :type data: ndarray :param iquandrant: number of the quadrant to process :type iquandrant: int cdm03 - Function signature:: sout = cdm03(sinp,iflip,jflip,dob,rdose,in_nt,in_sigma,in_tr,[xdim,ydim,zdim]) Required arguments: sinp : input rank-2 array('d') with bounds (xdim,ydim) iflip : input int jflip : input int dob : input float rdose : input float in_nt : input rank-1 array('d') with bounds (zdim) in_sigma : input rank-1 array('d') with bounds (zdim) in_tr : input rank-1 array('d') with bounds (zdim) Optional arguments: xdim := shape(sinp,0) input int ydim := shape(sinp,1) input int zdim := len(in_nt) input int Return objects: sout : rank-2 array('d') with bounds (xdim,ydim) .. Note:: Because Python/NumPy arrays are different row/column based, one needs to be extra careful here. NumPy.asfortranarray will be called to get an array laid out in Fortran order in memory. Before returning the array will be laid out in memory in C-style (row-major order). :return: image that has been run through the CDM03 model :rtype: ndarray """ #read in trap information trapdata = np.loadtxt(self.values['trapfile']) nt = trapdata[:, 0] sigma = trapdata[:, 1] taur = trapdata[:, 2] iflip = iquadrant / 2 jflip = iquadrant % 2 if self.logger: self.log.info('nt=' + str(nt)) self.log.info('sigma= ' + str(sigma)) self.log.info('taur= ' + str(taur)) self.log.info('dob=%f' % self.values['dob']) self.log.info('rdose=%e' % self.values['rdose']) self.log.info('xsize=%i' % data.shape[1]) self.log.info('ysize=%i' % data.shape[0]) self.log.info('quadrant=%i' % iquadrant) self.log.info('iflip=%i' % iflip) self.log.info('jflip=%i' % jflip) # #call Fortran routine # CTIed = cdm03.cdm03(np.asfortranarray(data), # iflip, jflip, # self.values['dob'], self.values['rdose'], # nt, sigma, taur) ###modify import sys sys.path.append('../CTI') import cdm03 ################################################################################# CTIed = cdm03.cdm03(np.asfortranarray(data), jflip, iflip, self.values['dob'], self.values['rdose'], nt,sigma,taur ) return np.asanyarray(CTIed) ################################################################################################################# Loading
csst_ifs_sim/CTI/__pycache__/CTI.cpython-38.pyc −7.59 KiB (5.3 KiB) File changed.No diff preview for this file type. View original file View changed file
csst_ifs_sim/__pycache__/csst_ifs_sim.cpython-38.pyc (86.1 KiB) File changed.No diff preview for this file type. View original file View changed file
csst_ifs_sim/csst_ifs_sim.py +17 −55 Original line number Diff line number Diff line Loading @@ -5,10 +5,6 @@ Created on Thu Apr 11 15:18:57 2024 @author: yan """ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # import sys import os from scipy.interpolate import interp1d import astropy.coordinates as coord Loading @@ -18,17 +14,11 @@ import sys # from csst_ifs_sim.support import cosmicrays # from csst_ifs_sim.support import logger as lg # from csst_ifs_sim.CTI import CTI sys.path.append('./csst_ifs_sim') from CTI import CTI from support import logger as lg from support import cosmicrays from support import IFSinstrumentModel # from optparse import OptionParser import configparser as ConfigParser import cmath from scipy import ndimage Loading Loading @@ -62,50 +52,31 @@ The approximate sequence of events in the simulator is as follows: #. Read in a configuration file, which defines for example, detector characteristics (bias, dark and readout noise, gain, plate scale and pixel scale, oversampling factor, exposure time etc.). pixel scale,exposure time etc.). #. Read in another file containing charge trap definitions (for CTI modelling). #. Read in a file defining the cosmic rays (trail lengths and cumulative distributions). #. Read in CCD offset information, displace the image, and modify the output file name to contain the CCD and quadrant information #. Load the wavefront aberration data used to calculate PSF with defined wavelength and field of view. #. Loop over the number of exposures to co-add and for each object in the object catalog: * determine the number of electrons an object should have by scaling the object's magnitude with the given zeropoint and exposure time. * determine whether the object lands on to the detector or not and if it is a star or an extended source (i.e. a galaxy). * if object is extended determine the size (using a size-magnitude relation) and scale counts, convolve with the PSF, and finally overlay onto the detector according to its position. * if object is a star, scale counts according to the derived scaling (first step), and finally overlay onto the detector according to its position. #. Apply calibration unit flux to mimic flat field exposures [optional]. #. Apply a multiplicative flat-field map to emulate pixel-to-pixel non-uniformity [optional]. #. Add a charge injection line (horizontal and/or vertical) [optional]. non-uniformity. #. Add cosmic ray tracks onto the CCD with random positions but known distribution [optional]. #. Apply detector charge bleeding in column direction [optional]. distribution. #. Apply detector charge bleeding in column direction. #. Add constant dark current and background light from Zodiacal light [optional]. #. Include spatially uniform scattered light to the pixel grid [optional]. #. Add photon (Poisson) noise [optional] #. Add cosmetic defects from an input file [optional]. #. Add pre- and overscan regions in the serial direction [optional]. light. #. Include spatially uniform scattered light to the pixel grid. #. Add photon (Poisson) noise #. Add cosmetic defects from an input file. #. Add pre- and overscan regions in the serial direction. #. Apply the CDM03 radiation damage model [optional]. #. Apply CCD273 non-linearity model to the pixel data [optional]. #. Add readout noise selected from a Gaussian distribution [optional]. #. Apply CCD273 non-linearity model to the pixel data. #. Add readout noise selected from a Gaussian distribution. #. Convert from electrons to ADUs using a given gain factor. #. Add a given bias level and discretise the counts (the output is going to be in 16bit unsigned integers). #. Finally the simulated image is converted to a FITS file, a WCS is assigned and the output is saved to the current working directory. #. Add a given bias level and discretise the counts #. Finally the simulated image is converted to a FITS file. Warning:: The code is still work in progress and new features are being added. The code has been tested, but nevertheless bugs may be lurking in corners, so Loading @@ -120,16 +91,7 @@ Note:: This class is Python 3 compatible. 2024.3.20 --- update the fits header as defined order 0 data format """ # from astropy.table import Table ############################################################################### # filterPivotWave = {'nuv': 2875.5, 'u': 3629.6, 'g': 4808.4, # 'r': 6178.2, 'i': 7609.0, 'z': 9012.9, 'y': 9627.9} # filterIndex = {'nuv': 0, 'u': 1, 'g': 2, 'r': 3, 'i': 4, 'z': 5, 'y': 6} #### functions definition ##### def transRaDec2D(ra, dec): """ Loading Loading @@ -5596,7 +5558,7 @@ class IFSsimulator(): self.applyPoissonNoise() print('Applying Possion noise finished.......') ################################## ################################# if self.nonlinearity: self.applyNonlinearity() Loading
csst_ifs_sim/ifs_so/__pycache__/__init__.cpython-38.pyc 0 → 100644 +145 B File added.No diff preview for this file type. View file