Commit 36189a3e authored by JX's avatar JX 😵
Browse files

Merge remote-tracking branch 'origin/develop'

parents dd26d370 27646bc4
Pipeline #4509 passed with stage
in 0 seconds
"""
generate image header
"""
import numpy as np
from astropy.io import fits
import astropy.wcs as pywcs
from scipy import math
import random
import os
import sys
def chara2digit(char):
""" Function to judge and convert characters to digitals
Parameters
----------
"""
try:
float(char) # for int, long and float
except ValueError:
pass
return char
else:
data = float(char)
return data
def read_header_parameter(filename='global_header.param'):
""" Function to read the header parameters
Parameters
----------
"""
name = []
value = []
description = []
for line in open(filename):
line = line.strip("\n")
arr = line.split('|')
# csvReader = csv.reader(csvDataFile)
# for arr in csvReader:
name.append(arr[0])
value.append(chara2digit(arr[1]))
description.append(arr[2])
# print(value)
return name, value, description
def rotate_CD_matrix(cd, pa_aper):
"""Rotate CD matrix
Parameters
----------
cd: (2,2) array
CD matrix
pa_aper: float
Position angle, in degrees E from N, of y axis of the detector
Returns
-------
cd_rot: (2,2) array
Rotated CD matrix
Comments
--------
`astropy.wcs.WCS.rotateCD` doesn't work for non-square pixels in that it
doesn't preserve the pixel scale! The bug seems to come from the fact
that `rotateCD` assumes a transposed version of its own CD matrix.
"""
rad = np.deg2rad(-pa_aper)
mat = np.zeros((2,2))
mat[0,:] = np.array([np.cos(rad),-np.sin(rad)])
mat[1,:] = np.array([np.sin(rad),np.cos(rad)])
cd_rot = np.dot(mat, cd)
return cd_rot
def Header_extention(xlen = 9232, ylen = 9216, gain = 1.0, readout = 5.0, dark = 0.02,saturation=90000, row_num = 1, col_num = 1):
""" Creat an image frame for CCST with multiple extensions
Parameters
----------
"""
flag_ltm_x = [0,1,-1,1,-1]
flag_ltm_y = [0,1,1,-1,-1]
flag_ltv_x = [0,0,1,0,1]
flag_ltv_y = [0,0,0,1,1]
detector_size_x = int(xlen)
detector_size_y = int(ylen)
data_x = str(int(detector_size_x))
data_y = str(int(detector_size_y))
data_sec = '[1:'+data_x+',1:'+data_y+']'
name = []
value = []
description = []
for k in range(1,2):
# f = open("extension"+str(k)+"_image.param","w")
j = row_num
i = col_num
ccdnum = str((j-1)*5+i)
name = ['EXTNAME',
'BSCALE',
'BZERO',
'OBSID',
'CCDNAME',
'AMPNAME',
'GAIN',
'RDNOISE',
'DARK',
'SATURATE',
'RSPEED',
'CHIPTEMP',
'CCDCHIP',
'DATASEC',
'CCDSUM',
'NSUM',
'LTM1_1',
'LTM2_2',
'LTV1',
'LTV2',
'ATM1_1',
'ATM2_2',
'ATV1',
'ATV2',
'DTV1',
'DTV2',
'DTM1_1',
'DTM2_2']
value = ['IM'+str(k),
1.0,
0.0,
'CSST.20200101T000000',
'ccd' + ccdnum.rjust(2,'0'),
'ccd' + ccdnum.rjust(2,'0') + ':'+str(k),
gain,
readout,
dark,
saturation,
10.0,
-100.0,
'ccd' + ccdnum.rjust(2,'0'),
data_sec,
'1 1',
'1 1',
flag_ltm_x[k],
flag_ltm_y[k],
flag_ltv_x[k]*(detector_size_x-20*2+1),
flag_ltv_y[k]*(detector_size_y+1),
flag_ltm_x[k],
flag_ltm_y[k],
flag_ltv_x[k]*(detector_size_x-20*2+1),
flag_ltv_y[k]*(detector_size_y+1),
0,
0,
1,
1]
description = ['Extension name',
' ',
' ',
'Observation ID',
'CCD name',
'Amplifier name',
'Gain (e-/ADU)',
'Readout noise (e-/pixel)',
'Dark noise (e-/pixel/s)',
'Saturation (e-)',
'Read speed',
'Chip temperature',
'CCD chip ID',
'Data section',
'CCD pixel summing',
'CCD pixel summing',
'CCD to image transformation',
'CCD to image transformation',
'CCD to image transformation',
'CCD to image transformation',
'CCD to amplifier transformation',
'CCD to amplifier transformation',
'CCD to amplifier transformation',
'CCD to amplifier transformation',
'CCD to detector transformatio',
'CCD to detector transformatio',
'CCD to detector transformatio',
'CCD to detector transformatio']
return name, value, description
##9232 9216 898 534 1309 60 -40 -23.4333
def WCS_def(xlen = 9232, ylen = 9216, gapx = 898.0, gapy1 = 534, gapy2 = 1309, ra = 60, dec = -40, pa = -23.433,psize = 0.074, row_num = 1, col_num = 1):
""" Creat a wcs frame for CCST with multiple extensions
Parameters
----------
"""
flag_x = [0, 1, -1, 1, -1]
flag_y = [0, 1, 1, -1, -1]
flag_ext_x = [0,-1,1,-1,1]
flag_ext_y = [0,-1,-1,1,1]
x_num = 5
y_num = 6
detector_num = x_num*y_num
detector_size_x = xlen
detector_size_y = ylen
gap_x = gapx
gap_y = [gapy1,gapy2]
ra_ref = ra
dec_ref = dec
pa_aper = pa
pixel_size = psize
gap_y1_num = 3
gap_y2_num = 2
x_center = (detector_size_x*x_num+gap_x*(x_num-1))/2
y_center = (detector_size_y*y_num+gap_y[0]*gap_y1_num+gap_y[1]*gap_y2_num)/2
gap_y_map = np.array([[0,0,0,0,0],[gap_y[0],gap_y[1],gap_y[1],gap_y[1],gap_y[1]],[gap_y[1],gap_y[0],gap_y[0],gap_y[0],gap_y[0]],[gap_y[0],gap_y[0],gap_y[0],gap_y[0],gap_y[0]],[gap_y[0],gap_y[0],gap_y[0],gap_y[0],gap_y[1]],[gap_y[1],gap_y[1],gap_y[1],gap_y[1],gap_y[0]]])
frame_array = np.empty((5,6),dtype=np.float64)
# print(x_center,y_center)
j = row_num
i = col_num
ccdnum = str((j-1)*5+i)
x_ref, y_ref = (detector_size_x+gap_x)*i-gap_x-detector_size_x/2, detector_size_y*j + sum(gap_y_map[0:j,i-1]) - detector_size_y/2
# print(i,j,x_ref,y_ref,ra_ref,dec_ref)
name = []
value = []
description = []
for k in range(1,2):
cd = np.array([[ pixel_size, 0], [0, pixel_size]])/3600.*flag_x[k]
cd_rot = rotate_CD_matrix(cd, pa_aper)
# f = open("CCD"+ccdnum.rjust(2,'0')+"_extension"+str(k)+"_wcs.param","w")
name = ['EQUINOX',
'WCSDIM',
'CTYPE1',
'CTYPE2',
'CRVAL1',
'CRVAL2',
'CRPIX1',
'CRPIX2',
'CD1_1',
'CD1_2',
'CD2_1',
'CD2_2']
value = [2000.0,
2.0,
'RA---TAN',
'DEC--TAN',
ra_ref,
dec_ref,
flag_ext_x[k]*((x_ref+flag_ext_x[k]*detector_size_x/2)-x_center),
flag_ext_y[k]*((y_ref+flag_ext_y[k]*detector_size_y/2)-y_center),
cd_rot[0,0],
cd_rot[0,1],
cd_rot[1,0],
cd_rot[1,1]]
description = ['Equinox of WCS',
'WCS Dimensionality',
'Coordinate type',
'Coordinate typ',
'Coordinate reference value',
'Coordinate reference value',
'Coordinate reference pixel',
'Coordinate reference pixel',
'Coordinate matrix',
'Coordinate matrix',
'Coordinate matrix',
'Coordinate matrix']
return name, value, description
def generatePrimaryHeader(xlen = 9232, ylen = 9216,pointNum = '1', ra = 60, dec = -40, psize = 0.074, row_num = 1, col_num = 1):
# array_size1, array_size2, flux, sigma = int(argv[1]), int(argv[2]), 1000.0, 5.0
filerParm_fn = os.path.split(os.path.realpath(__file__))[0] + '/filter.lst'
f = open(filerParm_fn)
s = f.readline()
s = s.strip("\n")
filter = s.split(' ')
k = (row_num-1)*5+col_num
ccdnum = str(k)
g_header_fn = os.path.split(os.path.realpath(__file__))[0] + '/global_header.param'
name, value, description = read_header_parameter(g_header_fn)
h_prim = fits.Header()
date = '200930'
time_obs = '120000'
for i in range(len(name)):
if(name[i]=='FILTER'):
value[i] = filter[k-1]
if(name[i]=='FILENAME'):
value[i] = 'CSST_' + date + '_' +time_obs + '_' + pointNum.rjust(6,'0') + '_' +ccdnum.rjust(2,'0')+'_raw'
if(name[i]=='DETSIZE'):
value[i] = '[1:' + str(int(xlen)) + ',1:'+ str(int(ylen)) + ']'
if(name[i]=='PIXSCAL1'):
value[i] = str(psize)
if(name[i]=='PIXSCAL2'):
value[i] = str(psize)
h_prim[name[i]] = (value[i],description[i])
h_prim.add_comment('==================================================================',after='FILETYPE')
h_prim.add_comment('Target information')
h_prim.add_comment('==================================================================')
h_prim.add_comment('==================================================================',after='EQUINOX')
h_prim.add_comment('Exposure information')
h_prim.add_comment('==================================================================')
h_prim.add_comment('==================================================================',after='MJDEND')
h_prim.add_comment('Telescope information')
h_prim.add_comment('==================================================================')
h_prim.add_comment('==================================================================',after='REFFRAME')
h_prim.add_comment('Detector information')
h_prim.add_comment('==================================================================')
h_prim.add_comment('==================================================================',after='FILTER')
h_prim.add_comment('Other information')
h_prim.add_comment('==================================================================')
return h_prim
def generateExtensionHeader(xlen = 9232, ylen = 9216,ra = 60, dec = -40, pa = -23.433, gain = 1.0, readout = 5.0, dark = 0.02, saturation=90000, psize = 0.074, row_num = 1, col_num = 1):
h_ext = fits.Header()
for i in range(1,2):
# NAXIS1:Number of pixels per row; NAXIS2:Number of rows
h_ext['NAXIS1'] = xlen
h_ext['NAXIS2'] = ylen
name, value, description = Header_extention(xlen = xlen, ylen = ylen, gain = gain, readout = readout, dark = dark, saturation=saturation, row_num = row_num, col_num = col_num)
for j in range(len(name)):
h_ext[name[j]] = (value[j],description[j])
name, value, description = WCS_def(xlen = xlen, ylen = ylen, gapx = 898.0, gapy1 = 534, gapy2 = 1309, ra = ra, dec = dec, pa = pa ,psize = psize, row_num = row_num, col_num = col_num)
for j in range(len(name)):
h_ext[name[j]] = (value[j],description[j])
h_ext.add_comment('==================================================================',after='OBSID')
h_ext.add_comment('Readout information')
h_ext.add_comment('==================================================================')
h_ext.add_comment('==================================================================',after='CHIPTEMP')
h_ext.add_comment('Chip information')
h_ext.add_comment('==================================================================')
h_ext.add_comment('==================================================================',after='DTM2_2')
h_ext.add_comment('WCS information')
h_ext.add_comment('==================================================================')
return h_ext
def main(argv):
xlen = int(argv[1])
ylen = int(argv[2])
pointingNum = argv[3]
ra = float(argv[4])
dec = float(argv[5])
pSize = float(argv[6])
ccd_row_num = int(argv[7])
ccd_col_num = int(argv[8])
pa_aper = float(argv[9])
gain = float(argv[10])
readout = float(argv[11])
dark = float(argv[12])
fw = float(argv[13])
h_prim = generatePrimaryHeader(xlen = xlen, ylen = ylen,ra = ra, dec = dec, psize = pSize, row_num = ccd_row_num, col_num = ccd_col_num, pointNum = pointingNum)
h_ext = generateExtensionHeader(xlen = xlen, ylen = ylen,ra = ra, dec = dec, pa = pa_aper, gain = gain, readout = readout, dark = dark, saturation=fw, psize = pSize, row_num = ccd_row_num, col_num = ccd_col_num)
hdu1 = fits.PrimaryHDU(header=h_prim)
hdu2 = fits.ImageHDU(np.zeros([ylen,xlen]),header = h_ext)
hdul = fits.HDUList([hdu1,hdu2])
hdul.writeto(h_prim['FILENAME']+'.fits',output_verify='ignore')
# if __name__ == "__main__":
# main(sys.argv)
This diff is collapsed.
import numpy as np
try:
import importlib.resources as pkg_resources
except ImportError:
# Try backported to PY<37 'importlib_resources'
import importlib_resources as pkg_resources
class Telescope(object):
def __init__(self, param=None, optEffCurve_path=None):
self.diameter = 2.0 # in unit of meter
if param is not None:
self.diameter = param["diameter"]
self.pupil_area = np.pi * (0.5 * self.diameter)**2
if optEffCurve_path is not None:
self.efficiency = self._get_efficiency(optEffCurve_path)
else:
try:
with pkg_resources.files('ObservationSim.Instrument.data').joinpath('mirror_ccdnote.txt') as optEffCurve_path:
self.efficiency = self._get_efficiency(optEffCurve_path)
except AttributeError:
with pkg_resources.path('ObservationSim.Instrument.data', 'mirror_ccdnote.txt') as optEffCurve_path:
self.efficiency = self._get_efficiency(optEffCurve_path)
def _get_efficiency(self, effCurve_path):
""" Read in the efficiency of optics
for each band
Parameters:
effCurve_path: the path for efficiency file
Returns:
opticsEff: a dictionary of efficiency (a scalar) for each band
"""
f = open(effCurve_path, 'r')
for _ in range(2):
header = f.readline()
iline = 0
opticsEff = {}
for line in f:
line = line.strip()
columns = line.split()
opticsEff[str(columns[0])] = float(columns[2])
f.close()
return opticsEff
\ No newline at end of file
import numpy as np
import os
import math
from pylab import *
from scipy import interpolate
try:
import importlib.resources as pkg_resources
except ImportError:
# Try backported to PY<37 'importlib_resources'
import importlib_resources as pkg_resources
VC_A = 2.99792458e+18 # speed of light: A/s
VC_M = 2.99792458e+8 # speed of light: m/s
H_PLANK = 6.626196e-27 # Plank constant: erg s
ALL_FILTERS = ["NUV","u", "g", "r", "i","z","y","GU", "GV", "GI", "FGS"]
PHOT_FILTERS = ["NUV", "u", "g", 'r', 'i', 'z', 'y', 'FGS']
SPEC_FILTERS = ["GI", "GV", "GU"]
def rotate_conterclockwise(x0, y0, x, y, angle):
"""
Rotate a point counterclockwise by a given angle around a given origin.
The angle should be given in radians.
"""
angle = np.deg2rad(angle)
qx = x0 + np.cos(angle)*(x - x0) - np.sin(angle) * (y - y0)
qy = y0 + np.sin(angle)*(x - x0) + np.cos(angle) * (y - y0)
return qx, qy
def photonEnergy(lambd):
""" The energy of photon at a given wavelength
Parameter:
lambd: the wavelength in unit of Angstrom
Return:
eph: energy of photon in unit of erg
"""
nu = VC_A / lambd
eph = H_PLANK * nu
return eph
def calculateLimitMag(aperture = 2.0, psf_fwhm = 0.1969,pixelSize = 0.074, pmRation = 0.8, throughputFn = 'i_throughput.txt', readout = 5.0, skyFn= 'sky_emiss_hubble_50_50_A.dat', darknoise = 0.02,exTime = 150, exNum = 1, fw = 90000):
'''
description:
param {*} aperture: unit m, default 2 m
param {*} psf_fwhm: psf fwhm, default 0.1969"
param {*} pixelSize: pixel size, default 0.074"
param {*} pmRation: the ratio of souce flux in the limit mag calculation
param {*} throughputFn: throuput file name
param {*} readout: unit, e-/pixel
param {*} skyFn: sky sed file name, average of hst, 'sky_emiss_hubble_50_50_A.dat'
param {*} darknoise: unit, e-/pixel/s
param {*} exTime: exposure time one time, default 150s
param {*} exNum: exposure number, defautl 1
param {*} fw, full well value( or saturation value),default 90000e-/pixel
return {*} limit mag and saturation mag
'''
try:
with pkg_resources.files('ObservationSim.Instrument.data.throughputs').joinpath(throughputFn) as data_file:
throughput_f = np.loadtxt(data_file)
except AttributeError:
with pkg_resources.path('ObservationSim.Instrument.data.throughputs', throughputFn) as data_file:
throughput_f = np.loadtxt(data_file)
thr_i = interpolate.interp1d(throughput_f[:,0]/10, throughput_f[:,1]); # wavelength in anstrom
f_s = 200
f_e = 1100
delt_f = 0.5
data_num = int((f_e-f_s)/delt_f+1)
eff = np.zeros([data_num,2])
eff[:,0] = np.arange(f_s,f_e+delt_f,delt_f)
eff[:,1] = thr_i(eff[:,0])
wave = np.arange(f_s,f_e+delt_f,delt_f)
wavey = np.ones(wave.shape[0])
try:
with pkg_resources.files('ObservationSim.Instrument.data.throughputs').joinpath(skyFn) as data_file:
skydata = np.loadtxt(data_file)
except AttributeError:
with pkg_resources.path('ObservationSim.Instrument.data.throughputs', skyFn) as data_file:
skydata = np.loadtxt(data_file)
skydatai = interpolate.interp1d(skydata[:,0]/10, skydata[:,1]*10)
sky_data = np.zeros([data_num,2])
sky_data[:,0] = np.arange(f_s,f_e+delt_f,delt_f)
sky_data[:,1] = skydatai(sky_data[:,0])
flux_sky = trapz((sky_data[:,1])*eff[:,1],sky_data[:,0])
skyPix = flux_sky*pixelSize*pixelSize*pi*(aperture*aperture/4)
###limit mag
r_pix = psf_fwhm*0.7618080243778568/pixelSize # radius RE80, pixel
cnum = math.pi * r_pix * r_pix
sn = 5
d = skyPix*exTime*exNum*cnum + darknoise*exTime*exNum*cnum+readout*readout*cnum*exNum
a=1
b=-sn*sn
c=-sn*sn*d
flux = (-b+sqrt(b*b-4*a*c))/(2*a)/pmRation
limitMag = -2.5*log10(flux/(54799275581.04437 * trapz(wavey*eff[:,1]/wave,wave, 0.1)*exTime*exNum*pi*(aperture/2)*(aperture/2)))
### saturation mag
from astropy.modeling.models import Gaussian2D
m_size = int(20 * psf_fwhm/pixelSize)
if m_size%2 == 0:
m_size + 1
m_cen = m_size//2
psf_sigma = psf_fwhm/2.355/pixelSize
gaussShape = Gaussian2D(1, m_cen, m_cen, psf_sigma, psf_sigma)
yp, xp = np.mgrid[0:m_size, 0:m_size]
psfMap = gaussShape(xp, yp)
maxRatio = np.amax(psfMap)/np.sum(psfMap)
# print(maxRatio)
flux_sat = fw/maxRatio*exNum
satMag = -2.5*log10(flux_sat/(54799275581.04437 * trapz(wavey*eff[:,1]/wave,wave, 0.1)*exTime*exNum*pi*(aperture/2)*(aperture/2)));
return limitMag , satMag
\ No newline at end of file
from ObservationSim.MockObject.MockObject import MockObject
class CosmicRay(MockObject):
pass
\ No newline at end of file
import galsim
import sep
import numpy as np
from scipy.interpolate import interp1d
from ObservationSim.PSF.PSFModel import PSFModel
class PSFGauss(PSFModel):
def __init__(self, chip, fwhm=0.187, sigSpin=0., psfRa=None):
self.pix_size = chip.pix_scale
self.chip = chip
if psfRa is None:
self.fwhm = fwhm
self.sigGauss = 0.15
else:
self.fwhm = self.fwhmGauss(r=psfRa)
self.sigGauss = psfRa # 80% light radius
self.sigSpin = sigSpin
self.psf = galsim.Gaussian(flux=1.0,fwhm=fwhm)
def perfGauss(self, r, sig):
"""
pseudo-error function, i.e. Cumulative distribution function of Gaussian distribution
Parameter:
r: radius
sig: sigma of the Gaussian distribution
Return:
the value of the pseudo CDF
"""
gaussFun = lambda sigma, r: 1.0/(np.sqrt(2.0*np.pi)*sigma) * np.exp(-r**2/(2.0*sigma**2))
nxx = 1000
rArr = np.linspace(0.0,r,nxx)
gauss = gaussFun(sig,rArr)
erf = 2.0*np.trapz(gauss,rArr)
return erf
def fracGauss(self, sig, r=0.15, pscale=None):
"""
For a given Gaussian PSF with sigma=sig,
derive the flux ratio ar the given radius r
Parameters:
sig: sigma of the Gauss PSF Function in arcsec
r: radius in arcsec
pscale: pixel scale
Return: the flux ratio
"""
if pscale == None:
pscale = self.pix_size
gaussx = galsim.Gaussian(flux=1.0,sigma=sig)
gaussImg = gaussx.drawImage(scale=pscale, method='no_pixel')
gaussImg = gaussImg.array
size = np.size(gaussImg,axis=0)
cxy = 0.5*(size-1)
flux, ferr, flag = sep.sum_circle(gaussImg,[cxy],[cxy],[r/pscale],subpix=0)
return flux
def fwhmGauss(self, r=0.15,fr=0.8,pscale=None):
"""
Given a total flux ratio 'fr' within a fixed radius 'r',
estimate the fwhm of the Gaussian function
return the fwhm in arcsec
"""
if pscale == None:
pscale = self.pix_size
err = 1.0e-3
nxx = 100
sig = np.linspace(0.5*pscale,1.0,nxx)
frA = np.zeros(nxx)
for i in range(nxx): frA[i] = self.fracGauss(sig[i],r=r,pscale=pscale)
index = [i for i in range(nxx-1) if (fr-frA[i])*(fr-frA[i+1])<=0.0][0]
while abs(frA[index]-fr)>1.0e-3:
sig = np.linspace(sig[index],sig[index+1],nxx)
for i in range(nxx): frA[i] = self.fracGauss(sig[i],r=r,pscale=pscale)
index = [i for i in range(nxx-1) if (fr-frA[i])*(fr-frA[i+1])<=0.0][0]
fwhm = 2.35482*sig[index]
return fwhm
def get_PSF(self, pos_img, chip=None, bandpass=None, folding_threshold=5.e-3):
dx = pos_img.x - self.chip.cen_pix_x
dy = pos_img.y - self.chip.cen_pix_y
return self.PSFspin(dx, dy)
def PSFspin(self, x, y):
"""
The PSF profile at a given image position relative to the axis center
Parameters:
theta : spin angles in a given exposure in unit of [arcsecond]
dx, dy: relative position to the axis center in unit of [pixels]
Return:
Spinned PSF: g1, g2 and axis ratio 'a/b'
"""
a2Rad = np.pi/(60.0*60.0*180.0)
ff = self.sigGauss * 0.107 * (1000.0/10.0) # in unit of [pixels]
rc = np.sqrt(x*x + y*y)
cpix = rc*(self.sigSpin*a2Rad)
beta = (np.arctan2(y,x) + np.pi/2)
ell = cpix**2/(2.0*ff**2+cpix**2)
#ell *= 10.0
qr = np.sqrt((1.0+ell)/(1.0-ell))
#psfShape = galsim.Shear(e=ell, beta=beta)
#g1, g2 = psfShape.g1, psfShape.g2
#qr = np.sqrt((1.0+ell)/(1.0-ell))
#return ell, beta, qr
PSFshear = galsim.Shear(e=ell, beta=beta*galsim.radians)
return self.psf.shear(PSFshear), PSFshear
\ No newline at end of file
import galsim
import sep
import numpy as np
from scipy.interpolate import interp1d
import pylab as pl
import os, sys
class PSFModel(object):
def __init__(self, sigSpin=0., psfRa=0.15):
# TODO: what are the nesseary fields in PSFModel class?
pass
def PSFspin(self, psf, sigSpin, sigGauss, dx, dy):
"""
The PSF profile at a given image position relative to the axis center
Parameters:
theta : spin angles in a given exposure in unit of [arcsecond]
dx, dy: relative position to the axis center in unit of [pixels]
Return:
Spinned PSF: g1, g2 and axis ratio 'a/b'
"""
a2Rad = np.pi/(60.0*60.0*180.0)
ff = sigGauss * 0.107 * (1000.0/10.0) # in unit of [pixels]
rc = np.sqrt(dx*dx + dy*dy)
cpix = rc*(sigSpin*a2Rad)
beta = (np.arctan2(dy,dx) + np.pi/2)
ell = cpix**2/(2.0*ff**2+cpix**2)
#ell *= 10.0
qr = np.sqrt((1.0+ell)/(1.0-ell))
#psfShape = galsim.Shear(e=ell, beta=beta)
#g1, g2 = psfShape.g1, psfShape.g2
#qr = np.sqrt((1.0+ell)/(1.0-ell))
#return ell, beta, qr
PSFshear = galsim.Shear(e=ell, beta=beta*galsim.radians)
return psf.shear(PSFshear), PSFshear
\ No newline at end of file
...@@ -4,15 +4,16 @@ import astropy.constants as cons ...@@ -4,15 +4,16 @@ import astropy.constants as cons
from astropy.table import Table from astropy.table import Table
from scipy import interpolate from scipy import interpolate
from ObservationSim.MockObject import CatalogBase, Star, Galaxy, Quasar from observation_sim.mock_objects import CatalogBase, Star, Galaxy, Quasar
class Catalog(CatalogBase): class Catalog(CatalogBase):
"""An user customizable class for reading in catalog(s) of objects and SEDs. """An user customizable class for reading in catalog(s) of objects and SEDs.
NOTE: must inherit the "CatalogBase" abstract class NOTE: must inherit the "CatalogBase" abstract class
... ...
Attributes Attributes
---------- ----------
cat_dir : str cat_dir : str
...@@ -24,7 +25,7 @@ class Catalog(CatalogBase): ...@@ -24,7 +25,7 @@ class Catalog(CatalogBase):
objs : list objs : list
a list of ObservationSim.MockObject (Star, Galaxy, or Quasar) a list of ObservationSim.MockObject (Star, Galaxy, or Quasar)
NOTE: must have "obj" list when implement your own Catalog NOTE: must have "obj" list when implement your own Catalog
Methods Methods
---------- ----------
load_sed(obj, **kwargs): load_sed(obj, **kwargs):
...@@ -32,9 +33,10 @@ class Catalog(CatalogBase): ...@@ -32,9 +33,10 @@ class Catalog(CatalogBase):
load_norm_filt(obj): load_norm_filt(obj):
load the filter throughput for the input catalog's photometric system. load the filter throughput for the input catalog's photometric system.
""" """
def __init__(self, config, chip, **kwargs): def __init__(self, config, chip, **kwargs):
"""Constructor method. """Constructor method.
Parameters Parameters
---------- ----------
config : dict config : dict
...@@ -44,20 +46,22 @@ class Catalog(CatalogBase): ...@@ -44,20 +46,22 @@ class Catalog(CatalogBase):
**kwargs : dict **kwargs : dict
other needed input parameters (in key-value pairs), please modify corresponding other needed input parameters (in key-value pairs), please modify corresponding
initialization call in "ObservationSim.py" as you need. initialization call in "ObservationSim.py" as you need.
Returns Returns
---------- ----------
None None
""" """
super().__init__() super().__init__()
self.cat_dir = os.path.join(config["data_dir"], config["catalog_options"]["input_path"]["cat_dir"]) self.cat_dir = os.path.join(
config["data_dir"], config["catalog_options"]["input_path"]["cat_dir"])
self.chip = chip self.chip = chip
if "star_cat" in config["catalog_options"]["input_path"] and config["catalog_options"]["input_path"]["star_cat"]: if "star_cat" in config["catalog_options"]["input_path"] and config["catalog_options"]["input_path"]["star_cat"]:
star_file = config["catalog_options"]["input_path"]["star_cat"] star_file = config["catalog_options"]["input_path"]["star_cat"]
star_SED_file = config["catalog_options"]["SED_templates_path"]["star_SED"] star_SED_file = config["catalog_options"]["SED_templates_path"]["star_SED"]
self.star_path = os.path.join(self.cat_dir, star_file) self.star_path = os.path.join(self.cat_dir, star_file)
self.star_SED_path = os.path.join(config["data_dir"], star_SED_file) self.star_SED_path = os.path.join(
config["data_dir"], star_SED_file)
# NOTE: must call _load() method here to read in all objects # NOTE: must call _load() method here to read in all objects
self.objs = [] self.objs = []
self._load() self._load()
...@@ -67,7 +71,7 @@ class Catalog(CatalogBase): ...@@ -67,7 +71,7 @@ class Catalog(CatalogBase):
This is a must implemented method which is used to read in all objects, and This is a must implemented method which is used to read in all objects, and
then convert them to ObservationSim.MockObject (Star, Galaxy, or Quasar). then convert them to ObservationSim.MockObject (Star, Galaxy, or Quasar).
Currently, Currently,
the model of ObservationSim.MockObject.Star class requires: the model of ObservationSim.MockObject.Star class requires:
param["star"] : int param["star"] : int
...@@ -83,7 +87,7 @@ class Catalog(CatalogBase): ...@@ -83,7 +87,7 @@ class Catalog(CatalogBase):
NOTE: if that filter is not the corresponding CSST filter, the NOTE: if that filter is not the corresponding CSST filter, the
load_norm_filt(obj) function must be implemented to load the filter load_norm_filt(obj) function must be implemented to load the filter
throughput of that particular photometric system throughput of that particular photometric system
the model of ObservationSim.MockObject.Galaxy class requires: the model of ObservationSim.MockObject.Galaxy class requires:
param["star"] : int param["star"] : int
specify the object type: 0: galaxy, 1: star, 2: quasar specify the object type: 0: galaxy, 1: star, 2: quasar
...@@ -173,7 +177,8 @@ class Catalog(CatalogBase): ...@@ -173,7 +177,8 @@ class Catalog(CatalogBase):
""" """
if obj.type == 'star': if obj.type == 'star':
wave = Table.read(self.star_SED_path, path=f"/SED/wave_{obj.model_tag}") wave = Table.read(self.star_SED_path,
path=f"/SED/wave_{obj.model_tag}")
flux = Table.read(self.star_SED_path, path=f"/SED/{obj.sed_type}") flux = Table.read(self.star_SED_path, path=f"/SED/{obj.sed_type}")
wave, flux = wave['col0'].data, flux['col0'].data wave, flux = wave['col0'].data, flux['col0'].data
else: else:
...@@ -203,4 +208,4 @@ class Catalog(CatalogBase): ...@@ -203,4 +208,4 @@ class Catalog(CatalogBase):
norm_filt["WAVELENGTH"] : wavelengthes in Angstroms norm_filt["WAVELENGTH"] : wavelengthes in Angstroms
norm_filt["SENSITIVITY"] : efficiencies norm_filt["SENSITIVITY"] : efficiencies
""" """
return None return None
\ No newline at end of file
...@@ -11,12 +11,12 @@ from astropy.table import Table ...@@ -11,12 +11,12 @@ from astropy.table import Table
from scipy import interpolate from scipy import interpolate
from datetime import datetime from datetime import datetime
from ObservationSim.MockObject import CatalogBase, Star, Galaxy, Quasar, Stamp from observation_sim.mock_objects import CatalogBase, Star, Galaxy, Quasar, Stamp
from ObservationSim.MockObject._util import tag_sed, getObservedSED, getABMAG, integrate_sed_bandpass, comoving_dist from observation_sim.mock_objects._util import tag_sed, getObservedSED, getABMAG, integrate_sed_bandpass, comoving_dist
from ObservationSim.Astrometry.Astrometry_util import on_orbit_obs_position from observation_sim.astrometry.Astrometry_util import on_orbit_obs_position
import astropy.io.fits as fitsio import astropy.io.fits as fitsio
from ObservationSim.MockObject._util import seds, sed_assign, extAv from observation_sim.mock_objects._util import seds, sed_assign, extAv
# (TEST) # (TEST)
from astropy.cosmology import FlatLambdaCDM from astropy.cosmology import FlatLambdaCDM
...@@ -31,11 +31,12 @@ except ImportError: ...@@ -31,11 +31,12 @@ except ImportError:
NSIDE = 128 NSIDE = 128
class Catalog(CatalogBase): class Catalog(CatalogBase):
def __init__(self, config, chip, pointing, chip_output, filt, **kwargs): def __init__(self, config, chip, pointing, chip_output, filt, **kwargs):
super().__init__() super().__init__()
self.cat_dir = config["catalog_options"]["input_path"]["cat_dir"] self.cat_dir = config["catalog_options"]["input_path"]["cat_dir"]
self.seed_Av = 121212 #config["catalog_options"]["seed_Av"] self.seed_Av = 121212 # config["catalog_options"]["seed_Av"]
# (TEST) # (TEST)
self.cosmo = FlatLambdaCDM(H0=67.66, Om0=0.3111) self.cosmo = FlatLambdaCDM(H0=67.66, Om0=0.3111)
...@@ -44,11 +45,11 @@ class Catalog(CatalogBase): ...@@ -44,11 +45,11 @@ class Catalog(CatalogBase):
self.filt = filt self.filt = filt
self.logger = chip_output.logger self.logger = chip_output.logger
with pkg_resources.path('Catalog.data', 'SLOAN_SDSS.g.fits') as filter_path: with pkg_resources.path('catalog.data', 'SLOAN_SDSS.g.fits') as filter_path:
self.normF_star = Table.read(str(filter_path)) self.normF_star = Table.read(str(filter_path))
with pkg_resources.path('Catalog.data', 'lsst_throuput_g.fits') as filter_path: with pkg_resources.path('catalog.data', 'lsst_throuput_g.fits') as filter_path:
self.normF_galaxy = Table.read(str(filter_path)) self.normF_galaxy = Table.read(str(filter_path))
self.config = config self.config = config
self.chip = chip self.chip = chip
self.pointing = pointing self.pointing = pointing
...@@ -58,24 +59,27 @@ class Catalog(CatalogBase): ...@@ -58,24 +59,27 @@ class Catalog(CatalogBase):
if "stamp_cat" in config["catalog_options"]["input_path"] and config["catalog_options"]["input_path"]["stamp_cat"] and config["catalog_options"]["stamp_yes"]: if "stamp_cat" in config["catalog_options"]["input_path"] and config["catalog_options"]["input_path"]["stamp_cat"] and config["catalog_options"]["stamp_yes"]:
stamp_file = config["catalog_options"]["input_path"]["stamp_cat"] stamp_file = config["catalog_options"]["input_path"]["stamp_cat"]
self.stamp_path = os.path.join(self.cat_dir, stamp_file) self.stamp_path = os.path.join(self.cat_dir, stamp_file)
#self.stamp_SED_path = os.path.join(config["data_dir"], config["SED_templates_path"]["stamp_SED"]) ###shoule be stamp-SED # self.stamp_SED_path = os.path.join(config["data_dir"], config["SED_templates_path"]["stamp_SED"]) ###shoule be stamp-SED
#self._load_SED_lib_stamps() ###shoule be stamp-SED # self._load_SED_lib_stamps() ###shoule be stamp-SED
self.tempSed_gal, self.tempRed_gal = seds("galaxy.list", seddir="/public/home/chengliang/CSSOSDataProductsSims/testCats/Templates/Galaxy/") #only for test self.tempSed_gal, self.tempRed_gal = seds(
"galaxy.list", seddir="/public/home/chengliang/CSSOSDataProductsSims/testCats/Templates/Galaxy/") # only for test
self._add_output_columns_header() self._add_output_columns_header()
self._get_healpix_list() self._get_healpix_list()
self._load() self._load()
def _add_output_columns_header(self): def _add_output_columns_header(self):
self.add_hdr = " model_tag teff logg feh" self.add_hdr = " model_tag teff logg feh"
self.add_hdr += " bulgemass diskmass detA e1 e2 kappa g1 g2 size galType veldisp " self.add_hdr += " bulgemass diskmass detA e1 e2 kappa g1 g2 size galType veldisp "
self.add_fmt = " %10s %8.4f %8.4f %8.4f" self.add_fmt = " %10s %8.4f %8.4f %8.4f"
self.add_fmt += " %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %4d %8.4f " self.add_fmt += " %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %4d %8.4f "
self.chip_output.update_output_header(additional_column_names=self.add_hdr) self.chip_output.update_output_header(
additional_column_names=self.add_hdr)
def _get_healpix_list(self): def _get_healpix_list(self):
self.sky_coverage = self.chip.getSkyCoverageEnlarged(self.chip.img.wcs, margin=0.2) self.sky_coverage = self.chip.getSkyCoverageEnlarged(
self.chip.img.wcs, margin=0.2)
ra_min, ra_max, dec_min, dec_max = self.sky_coverage.xmin, self.sky_coverage.xmax, self.sky_coverage.ymin, self.sky_coverage.ymax ra_min, ra_max, dec_min, dec_max = self.sky_coverage.xmin, self.sky_coverage.xmax, self.sky_coverage.ymin, self.sky_coverage.ymax
ra = np.deg2rad(np.array([ra_min, ra_max, ra_max, ra_min])) ra = np.deg2rad(np.array([ra_min, ra_max, ra_max, ra_min]))
dec = np.deg2rad(np.array([dec_max, dec_max, dec_min, dec_min])) dec = np.deg2rad(np.array([dec_max, dec_max, dec_min, dec_min]))
...@@ -94,7 +98,7 @@ class Catalog(CatalogBase): ...@@ -94,7 +98,7 @@ class Catalog(CatalogBase):
def load_norm_filt(self, obj): def load_norm_filt(self, obj):
if obj.type == "stamp": if obj.type == "stamp":
return self.normF_galaxy ###normalize_filter for stamp return self.normF_galaxy # normalize_filter for stamp
else: else:
return None return None
...@@ -102,35 +106,38 @@ class Catalog(CatalogBase): ...@@ -102,35 +106,38 @@ class Catalog(CatalogBase):
print("debug:: load_stamps") print("debug:: load_stamps")
nstamps = len(stamps['filename']) nstamps = len(stamps['filename'])
self.rng_sedGal = random.Random() self.rng_sedGal = random.Random()
self.rng_sedGal.seed(float(pix_id)) # Use healpix index as the random seed # Use healpix index as the random seed
self.rng_sedGal.seed(float(pix_id))
self.ud = galsim.UniformDeviate(pix_id) self.ud = galsim.UniformDeviate(pix_id)
for istamp in range(nstamps): for istamp in range(nstamps):
print("debug::", istamp) print("debug::", istamp)
fitsfile = os.path.join(self.cat_dir, "stampCats/"+stamps['filename'][istamp].decode('utf-8')) fitsfile = os.path.join(
self.cat_dir, "stampCats/"+stamps['filename'][istamp].decode('utf-8'))
print("debug::", istamp, fitsfile) print("debug::", istamp, fitsfile)
hdu=fitsio.open(fitsfile) hdu = fitsio.open(fitsfile)
param = self.initialize_param() param = self.initialize_param()
param['id'] = hdu[0].header['index'] #istamp param['id'] = hdu[0].header['index'] # istamp
param['star'] = 3 # Stamp type in .cat file param['star'] = 3 # Stamp type in .cat file
param['ra'] = hdu[0].header['ra'] param['ra'] = hdu[0].header['ra']
param['dec']= hdu[0].header['dec'] param['dec'] = hdu[0].header['dec']
param['pixScale']= hdu[0].header['pixScale'] param['pixScale'] = hdu[0].header['pixScale']
#param['srcGalaxyID'] = hdu[0].header['srcGID'] # param['srcGalaxyID'] = hdu[0].header['srcGID']
#param['mu']= hdu[0].header['mu'] # param['mu']= hdu[0].header['mu']
#param['PA']= hdu[0].header['PA'] # param['PA']= hdu[0].header['PA']
#param['bfrac']= hdu[0].header['bfrac'] # param['bfrac']= hdu[0].header['bfrac']
#param['z']= hdu[0].header['z'] # param['z']= hdu[0].header['z']
param['mag_use_normal'] = hdu[0].header['mag_g'] #gals['mag_true_g_lsst'] # gals['mag_true_g_lsst']
param['mag_use_normal'] = hdu[0].header['mag_g']
# Apply astrometric modeling # Apply astrometric modeling
# in C3 case only aberration # in C3 case only aberration
param['ra_orig'] = param['ra'] param['ra_orig'] = param['ra']
param['dec_orig']= param['dec'] param['dec_orig'] = param['dec']
if self.config["obs_setting"]["enable_astrometric_model"]: if self.config["obs_setting"]["enable_astrometric_model"]:
ra_list = [param['ra']] #ra_arr.tolist() ra_list = [param['ra']] # ra_arr.tolist()
dec_list= [param['dec']] #dec_arr.tolist() dec_list = [param['dec']] # dec_arr.tolist()
pmra_list = np.zeros(1).tolist() pmra_list = np.zeros(1).tolist()
pmdec_list = np.zeros(1).tolist() pmdec_list = np.zeros(1).tolist()
rv_list = np.zeros(1).tolist() rv_list = np.zeros(1).tolist()
...@@ -157,19 +164,20 @@ class Catalog(CatalogBase): ...@@ -157,19 +164,20 @@ class Catalog(CatalogBase):
input_time_str=time_str input_time_str=time_str
) )
param['ra'] = ra_arr[0] param['ra'] = ra_arr[0]
param['dec']= dec_arr[0] param['dec'] = dec_arr[0]
# Assign each galaxy a template SED # Assign each galaxy a template SED
param['sed_type'] = sed_assign(phz=param['z'], btt=param['bfrac'], rng=self.rng_sedGal) param['sed_type'] = sed_assign(
phz=param['z'], btt=param['bfrac'], rng=self.rng_sedGal)
param['redden'] = self.tempRed_gal[param['sed_type']] param['redden'] = self.tempRed_gal[param['sed_type']]
param['av'] = 0.0 param['av'] = 0.0
param['redden'] = 0 param['redden'] = 0
param['mu'] = 1 param['mu'] = 1
#param["CSSTmag"]= True # param["CSSTmag"]= True
#param["mag_r"] = 20. # param["mag_r"] = 20.
#param[''] # param['']
###more keywords for stamp### ### more keywords for stamp###
param['image'] = hdu[0].data param['image'] = hdu[0].data
param['image'] = param['image']/(np.sum(param['image'])) param['image'] = param['image']/(np.sum(param['image']))
obj = Stamp(param) obj = Stamp(param)
...@@ -181,12 +189,12 @@ class Catalog(CatalogBase): ...@@ -181,12 +189,12 @@ class Catalog(CatalogBase):
if "stamp_cat" in self.config["catalog_options"]["input_path"] and self.config["catalog_options"]["input_path"]["stamp_cat"] and self.config["catalog_options"]["stamp_yes"]: if "stamp_cat" in self.config["catalog_options"]["input_path"] and self.config["catalog_options"]["input_path"]["stamp_cat"] and self.config["catalog_options"]["stamp_yes"]:
stamps_cat = h5.File(self.stamp_path, 'r')['Stamps'] stamps_cat = h5.File(self.stamp_path, 'r')['Stamps']
print("debug::",stamps_cat.keys()) print("debug::", stamps_cat.keys())
for pix in self.pix_list: for pix in self.pix_list:
try: try:
stamps = stamps_cat[str(pix)] stamps = stamps_cat[str(pix)]
print("debug::",stamps.keys()) print("debug::", stamps.keys())
self._load_stamps(stamps, pix_id=pix) self._load_stamps(stamps, pix_id=pix)
del stamps del stamps
except Exception as e: except Exception as e:
...@@ -194,12 +202,12 @@ class Catalog(CatalogBase): ...@@ -194,12 +202,12 @@ class Catalog(CatalogBase):
print(e) print(e)
if self.logger is not None: if self.logger is not None:
self.logger.info("maximum galaxy size: %.4f"%(self.max_size)) self.logger.info("maximum galaxy size: %.4f" % (self.max_size))
self.logger.info("number of objects in catalog: %d"%(len(self.objs))) self.logger.info("number of objects in catalog: %d" %
(len(self.objs)))
else: else:
print("number of objects in catalog: ", len(self.objs)) print("number of objects in catalog: ", len(self.objs))
def load_sed(self, obj, **kwargs): def load_sed(self, obj, **kwargs):
if obj.type == 'stamp': if obj.type == 'stamp':
sed_data = getObservedSED( sed_data = getObservedSED(
...@@ -217,7 +225,7 @@ class Catalog(CatalogBase): ...@@ -217,7 +225,7 @@ class Catalog(CatalogBase):
# erg/s/cm2/A --> photon/s/m2/A # erg/s/cm2/A --> photon/s/m2/A
all_sed = y * lamb / (cons.h.value * cons.c.value) * 1e-13 all_sed = y * lamb / (cons.h.value * cons.c.value) * 1e-13
sed = Table(np.array([lamb, all_sed]).T, names=('WAVELENGTH', 'FLUX')) sed = Table(np.array([lamb, all_sed]).T, names=('WAVELENGTH', 'FLUX'))
del wave del wave
del flux del flux
return sed return sed
...@@ -8,24 +8,26 @@ from datetime import datetime ...@@ -8,24 +8,26 @@ from datetime import datetime
import traceback import traceback
from ObservationSim.Config import ChipOutput from observation_sim.config import ChipOutput
from ObservationSim.Instrument import Telescope, Filter, FilterParam, FocalPlane, Chip from observation_sim.instruments import Telescope, Filter, FilterParam, FocalPlane, Chip
from ObservationSim.Instrument.Chip import Effects from observation_sim.instruments.chip import effects
from ObservationSim.Instrument.Chip import ChipUtils as chip_utils from observation_sim.instruments.chip import chip_utils as chip_utils
from ObservationSim.Astrometry.Astrometry_util import on_orbit_obs_position from observation_sim.astrometry.Astrometry_util import on_orbit_obs_position
from ObservationSim.sim_steps import SimSteps, SIM_STEP_TYPES from observation_sim.sim_steps import SimSteps, SIM_STEP_TYPES
class Observation(object): class Observation(object):
def __init__(self, config, Catalog, work_dir=None, data_dir=None): def __init__(self, config, Catalog, work_dir=None, data_dir=None):
self.config = config self.config = config
self.tel = Telescope() self.tel = Telescope()
self.filter_param = FilterParam() self.filter_param = FilterParam()
self.Catalog = Catalog self.Catalog = Catalog
def prepare_chip_for_exposure(self, chip, ra_cen, dec_cen, pointing, wcs_fp=None): def prepare_chip_for_exposure(self, chip, ra_cen, dec_cen, pointing, wcs_fp=None):
# Get WCS for the focal plane # Get WCS for the focal plane
if wcs_fp == None: if wcs_fp == None:
wcs_fp = self.focal_plane.getTanWCS(ra_cen, dec_cen, pointing.img_pa, chip.pix_scale) wcs_fp = self.focal_plane.getTanWCS(
ra_cen, dec_cen, pointing.img_pa, chip.pix_scale)
# Create chip Image # Create chip Image
chip.img = galsim.ImageF(chip.npix_x, chip.npix_y) chip.img = galsim.ImageF(chip.npix_x, chip.npix_y)
...@@ -35,29 +37,36 @@ class Observation(object): ...@@ -35,29 +37,36 @@ class Observation(object):
# Get random generators for this chip # Get random generators for this chip
chip.rng_poisson, chip.poisson_noise = chip_utils.get_poisson( chip.rng_poisson, chip.poisson_noise = chip_utils.get_poisson(
seed=int(self.config["random_seeds"]["seed_poisson"]) + pointing.id*30 + chip.chipID, sky_level=0.) seed=int(self.config["random_seeds"]["seed_poisson"]) + pointing.id*30 + chip.chipID, sky_level=0.)
# Get flat, shutter, and PRNU images # Get flat, shutter, and PRNU images
chip.flat_img, _ = chip_utils.get_flat(img=chip.img, seed=int(self.config["random_seeds"]["seed_flat"])) chip.flat_img, _ = chip_utils.get_flat(
img=chip.img, seed=int(self.config["random_seeds"]["seed_flat"]))
if chip.chipID > 30: if chip.chipID > 30:
chip.shutter_img = np.ones_like(chip.img.array) chip.shutter_img = np.ones_like(chip.img.array)
else: else:
chip.shutter_img = Effects.ShutterEffectArr(chip.img, t_shutter=1.3, dist_bearing=735, dt=1E-3) chip.shutter_img = effects.ShutterEffectArr(
chip.prnu_img = Effects.PRNU_Img(xsize=chip.npix_x, ysize=chip.npix_y, sigma=0.01, chip.img, t_shutter=1.3, dist_bearing=735, dt=1E-3)
chip.prnu_img = effects.PRNU_Img(xsize=chip.npix_x, ysize=chip.npix_y, sigma=0.01,
seed=int(self.config["random_seeds"]["seed_prnu"]+chip.chipID)) seed=int(self.config["random_seeds"]["seed_prnu"]+chip.chipID))
return chip return chip
def run_one_chip(self, chip, filt, pointing, chip_output, wcs_fp=None, psf_model=None, cat_dir=None, sed_dir=None): def run_one_chip(self, chip, filt, pointing, chip_output, wcs_fp=None, psf_model=None, cat_dir=None, sed_dir=None):
chip_output.Log_info(':::::::::::::::::::Current Pointing Information::::::::::::::::::') chip_output.Log_info(
':::::::::::::::::::Current Pointing Information::::::::::::::::::')
chip_output.Log_info("RA: %f, DEC; %f" % (pointing.ra, pointing.dec)) chip_output.Log_info("RA: %f, DEC; %f" % (pointing.ra, pointing.dec))
chip_output.Log_info("Time: %s" % datetime.utcfromtimestamp(pointing.timestamp).isoformat()) chip_output.Log_info("Time: %s" % datetime.utcfromtimestamp(
pointing.timestamp).isoformat())
chip_output.Log_info("Exposure time: %f" % pointing.exp_time) chip_output.Log_info("Exposure time: %f" % pointing.exp_time)
chip_output.Log_info("Satellite Position (x, y, z): (%f, %f, %f)" % (pointing.sat_x, pointing.sat_y, pointing.sat_z)) chip_output.Log_info("Satellite Position (x, y, z): (%f, %f, %f)" % (
chip_output.Log_info("Satellite Velocity (x, y, z): (%f, %f, %f)" % (pointing.sat_vx, pointing.sat_vy, pointing.sat_vz)) pointing.sat_x, pointing.sat_y, pointing.sat_z))
chip_output.Log_info("Satellite Velocity (x, y, z): (%f, %f, %f)" % (
pointing.sat_vx, pointing.sat_vy, pointing.sat_vz))
chip_output.Log_info("Position Angle: %f" % pointing.img_pa.deg) chip_output.Log_info("Position Angle: %f" % pointing.img_pa.deg)
chip_output.Log_info('Chip : %d' % chip.chipID) chip_output.Log_info('Chip : %d' % chip.chipID)
chip_output.Log_info(':::::::::::::::::::::::::::END:::::::::::::::::::::::::::::::::::') chip_output.Log_info(
':::::::::::::::::::::::::::END:::::::::::::::::::::::::::::::::::')
# Apply astrometric simulation for pointing # Apply astrometric simulation for pointing
if self.config["obs_setting"]["enable_astrometric_model"]: if self.config["obs_setting"]["enable_astrometric_model"]:
...@@ -91,32 +100,35 @@ class Observation(object): ...@@ -91,32 +100,35 @@ class Observation(object):
chip = self.prepare_chip_for_exposure(chip, ra_cen, dec_cen, pointing) chip = self.prepare_chip_for_exposure(chip, ra_cen, dec_cen, pointing)
# Initialize SimSteps # Initialize SimSteps
sim_steps = SimSteps(overall_config=self.config, chip_output=chip_output, all_filters=self.all_filters) sim_steps = SimSteps(overall_config=self.config,
chip_output=chip_output, all_filters=self.all_filters)
for step in pointing.obs_param["call_sequence"]: for step in pointing.obs_param["call_sequence"]:
if self.config["run_option"]["out_cat_only"]: if self.config["run_option"]["out_cat_only"]:
if step != "scie_obs": if step != "scie_obs":
continue continue
chip_output.Log_info("Starting simulation step: %s, calling function: %s"%(step, SIM_STEP_TYPES[step])) chip_output.Log_info("Starting simulation step: %s, calling function: %s" % (
step, SIM_STEP_TYPES[step]))
obs_param = pointing.obs_param["call_sequence"][step] obs_param = pointing.obs_param["call_sequence"][step]
step_name = SIM_STEP_TYPES[step] step_name = SIM_STEP_TYPES[step]
try: try:
step_func = getattr(sim_steps, step_name) step_func = getattr(sim_steps, step_name)
chip, filt, tel, pointing = step_func( chip, filt, tel, pointing = step_func(
chip=chip, chip=chip,
filt=filt, filt=filt,
tel=self.tel, tel=self.tel,
pointing=pointing, pointing=pointing,
catalog=self.Catalog, catalog=self.Catalog,
obs_param=obs_param) obs_param=obs_param)
chip_output.Log_info("Finished simulation step: %s"%(step)) chip_output.Log_info("Finished simulation step: %s" % (step))
except Exception as e: except Exception as e:
traceback.print_exc() traceback.print_exc()
chip_output.Log_error(e) chip_output.Log_error(e)
chip_output.Log_error("Failed simulation on step: %s"%(step)) chip_output.Log_error("Failed simulation on step: %s" % (step))
break break
chip_output.Log_info("check running:1: pointing-%d chip-%d pid-%d memory-%6.2fGB"%(pointing.id, chip.chipID, os.getpid(), (psutil.Process(os.getpid()).memory_info().rss / 1024 / 1024 / 1024) )) chip_output.Log_info("check running:1: pointing-%d chip-%d pid-%d memory-%6.2fGB" % (pointing.id,
chip.chipID, os.getpid(), (psutil.Process(os.getpid()).memory_info().rss / 1024 / 1024 / 1024)))
del chip.img del chip.img
def runExposure_MPI_PointingList(self, pointing_list, chips=None): def runExposure_MPI_PointingList(self, pointing_list, chips=None):
...@@ -131,9 +143,11 @@ class Observation(object): ...@@ -131,9 +143,11 @@ class Observation(object):
# pointing_ID = pointing.id # pointing_ID = pointing.id
pointing_ID = pointing.obs_id pointing_ID = pointing.obs_id
pointing.make_output_pointing_dir(overall_config=self.config, copy_obs_config=True) pointing.make_output_pointing_dir(
overall_config=self.config, copy_obs_config=True)
self.focal_plane = FocalPlane(chip_list=pointing.obs_param["run_chips"]) self.focal_plane = FocalPlane(
chip_list=pointing.obs_param["run_chips"])
# Make Chip & Filter lists # Make Chip & Filter lists
self.chip_list = [] self.chip_list = []
self.filter_list = [] self.filter_list = []
...@@ -167,7 +181,7 @@ class Observation(object): ...@@ -167,7 +181,7 @@ class Observation(object):
run_chips.append(chip) run_chips.append(chip)
run_filts.append(filt) run_filts.append(filt)
nchips_per_fp = len(chips) nchips_per_fp = len(chips)
for ichip in range(nchips_per_fp): for ichip in range(nchips_per_fp):
i_process = process_counter + ichip i_process = process_counter + ichip
if i_process % num_thread != ind_thread: if i_process % num_thread != ind_thread:
...@@ -176,20 +190,22 @@ class Observation(object): ...@@ -176,20 +190,22 @@ class Observation(object):
chip = run_chips[ichip] chip = run_chips[ichip]
filt = run_filts[ichip] filt = run_filts[ichip]
chip_output = ChipOutput( chip_output = ChipOutput(
config = self.config, config=self.config,
chip = chip, chip=chip,
filt = filt, filt=filt,
pointing = pointing pointing=pointing
) )
chip_output.Log_info("running pointing#%d, chip#%d, at PID#%d..."%(int(pointing_ID), chip.chipID, pid)) chip_output.Log_info("running pointing#%d, chip#%d, at PID#%d..." % (
int(pointing_ID), chip.chipID, pid))
self.run_one_chip( self.run_one_chip(
chip=chip, chip=chip,
filt=filt, filt=filt,
chip_output=chip_output, chip_output=chip_output,
pointing=pointing) pointing=pointing)
chip_output.Log_info("finished running chip#%d..."%(chip.chipID)) chip_output.Log_info(
"finished running chip#%d..." % (chip.chipID))
for handler in chip_output.logger.handlers[:]: for handler in chip_output.logger.handlers[:]:
chip_output.logger.removeHandler(handler) chip_output.logger.removeHandler(handler)
gc.collect() gc.collect()
......
...@@ -2,6 +2,7 @@ import galsim ...@@ -2,6 +2,7 @@ import galsim
import numpy as np import numpy as np
import cmath import cmath
class FieldDistortion(object): class FieldDistortion(object):
def __init__(self, chip, fdModel=None, fdModel_path=None, img_rot=0.): def __init__(self, chip, fdModel=None, fdModel_path=None, img_rot=0.):
...@@ -13,7 +14,8 @@ class FieldDistortion(object): ...@@ -13,7 +14,8 @@ class FieldDistortion(object):
with open(fdModel_path, "rb") as f: with open(fdModel_path, "rb") as f:
self.fdModel = pickle.load(f) self.fdModel = pickle.load(f)
else: else:
raise ValueError("Error: no field distortion model has been specified!") raise ValueError(
"Error: no field distortion model has been specified!")
else: else:
self.fdModel = fdModel self.fdModel = fdModel
self.img_rot = img_rot self.img_rot = img_rot
...@@ -21,19 +23,20 @@ class FieldDistortion(object): ...@@ -21,19 +23,20 @@ class FieldDistortion(object):
self.ixfdModel = self.ifdModel["xImagePos"] self.ixfdModel = self.ifdModel["xImagePos"]
self.iyfdModel = self.ifdModel["yImagePos"] self.iyfdModel = self.ifdModel["yImagePos"]
# first-order derivatives of the global field distortion model # first-order derivatives of the global field distortion model
self.ifx_dx = self.ixfdModel.partial_derivative(1,0) self.ifx_dx = self.ixfdModel.partial_derivative(1, 0)
self.ifx_dy = self.ixfdModel.partial_derivative(0,1) self.ifx_dy = self.ixfdModel.partial_derivative(0, 1)
self.ify_dx = self.iyfdModel.partial_derivative(1,0) self.ify_dx = self.iyfdModel.partial_derivative(1, 0)
self.ify_dy = self.iyfdModel.partial_derivative(0,1) self.ify_dy = self.iyfdModel.partial_derivative(0, 1)
if "residual" in self.fdModel["wave1"]: if "residual" in self.fdModel["wave1"]:
self.irsModel = self.fdModel["wave1"]["residual"]["ccd" + chip.getChipLabel(chipID=chip.chipID)] self.irsModel = self.fdModel["wave1"]["residual"]["ccd" +
chip.getChipLabel(chipID=chip.chipID)]
self.ixrsModel = self.irsModel["xResidual"] self.ixrsModel = self.irsModel["xResidual"]
self.iyrsModel = self.irsModel["yResidual"] self.iyrsModel = self.irsModel["yResidual"]
# first-order derivatives of the residual field distortion model # first-order derivatives of the residual field distortion model
self.irx_dx = self.ixrsModel.partial_derivative(1,0) self.irx_dx = self.ixrsModel.partial_derivative(1, 0)
self.irx_dy = self.ixrsModel.partial_derivative(0,1) self.irx_dy = self.ixrsModel.partial_derivative(0, 1)
self.iry_dx = self.iyrsModel.partial_derivative(1,0) self.iry_dx = self.iyrsModel.partial_derivative(1, 0)
self.iry_dy = self.iyrsModel.partial_derivative(0,1) self.iry_dy = self.iyrsModel.partial_derivative(0, 1)
else: else:
self.irsModel = None self.irsModel = None
...@@ -95,8 +98,8 @@ class FieldDistortion(object): ...@@ -95,8 +98,8 @@ class FieldDistortion(object):
ix_dy = self.ifx_dy(x, y) ix_dy = self.ifx_dy(x, y)
iy_dx = self.ify_dx(x, y) iy_dx = self.ify_dx(x, y)
iy_dy = self.ify_dy(x, y) iy_dy = self.ify_dy(x, y)
g1k_fd = 0.0 + (iy_dy - ix_dx) / (iy_dy + ix_dx) g1k_fd = 0.0 + (iy_dy - ix_dx) / (iy_dy + ix_dx)
g2k_fd = 0.0 - (iy_dx + ix_dy) / (iy_dy + ix_dx) g2k_fd = 0.0 - (iy_dx + ix_dy) / (iy_dy + ix_dx)
# [TODO] [TESTING] Rotate the shear: # [TODO] [TESTING] Rotate the shear:
g_abs = np.sqrt(g1k_fd**2 + g2k_fd**2) g_abs = np.sqrt(g1k_fd**2 + g2k_fd**2)
...@@ -107,4 +110,3 @@ class FieldDistortion(object): ...@@ -107,4 +110,3 @@ class FieldDistortion(object):
fd_shear = galsim.Shear(g1=g1k_fd, g2=g2k_fd) fd_shear = galsim.Shear(g1=g1k_fd, g2=g2k_fd)
return galsim.PositionD(x, y), fd_shear return galsim.PositionD(x, y), fd_shear
import galsim
import sep
import numpy as np
from scipy.interpolate import interp1d
from observation_sim.PSF.PSFModel import PSFModel
class PSFGauss(PSFModel):
def __init__(self, chip, fwhm=0.187, sigSpin=0., psfRa=None):
self.pix_size = chip.pix_scale
self.chip = chip
if psfRa is None:
self.fwhm = fwhm
self.sigGauss = 0.15
else:
self.fwhm = self.fwhmGauss(r=psfRa)
self.sigGauss = psfRa # 80% light radius
self.sigSpin = sigSpin
self.psf = galsim.Gaussian(flux=1.0, fwhm=fwhm)
def perfGauss(self, r, sig):
"""
pseudo-error function, i.e. Cumulative distribution function of Gaussian distribution
Parameter:
r: radius
sig: sigma of the Gaussian distribution
Return:
the value of the pseudo CDF
"""
def gaussFun(sigma, r): return 1.0/(np.sqrt(2.0*np.pi)
* sigma) * np.exp(-r**2/(2.0*sigma**2))
nxx = 1000
rArr = np.linspace(0.0, r, nxx)
gauss = gaussFun(sig, rArr)
erf = 2.0*np.trapz(gauss, rArr)
return erf
def fracGauss(self, sig, r=0.15, pscale=None):
"""
For a given Gaussian PSF with sigma=sig,
derive the flux ratio ar the given radius r
Parameters:
sig: sigma of the Gauss PSF Function in arcsec
r: radius in arcsec
pscale: pixel scale
Return: the flux ratio
"""
if pscale == None:
pscale = self.pix_size
gaussx = galsim.Gaussian(flux=1.0, sigma=sig)
gaussImg = gaussx.drawImage(scale=pscale, method='no_pixel')
gaussImg = gaussImg.array
size = np.size(gaussImg, axis=0)
cxy = 0.5*(size-1)
flux, ferr, flag = sep.sum_circle(
gaussImg, [cxy], [cxy], [r/pscale], subpix=0)
return flux
def fwhmGauss(self, r=0.15, fr=0.8, pscale=None):
"""
Given a total flux ratio 'fr' within a fixed radius 'r',
estimate the fwhm of the Gaussian function
return the fwhm in arcsec
"""
if pscale == None:
pscale = self.pix_size
err = 1.0e-3
nxx = 100
sig = np.linspace(0.5*pscale, 1.0, nxx)
frA = np.zeros(nxx)
for i in range(nxx):
frA[i] = self.fracGauss(sig[i], r=r, pscale=pscale)
index = [i for i in range(nxx-1) if (fr-frA[i])
* (fr-frA[i+1]) <= 0.0][0]
while abs(frA[index]-fr) > 1.0e-3:
sig = np.linspace(sig[index], sig[index+1], nxx)
for i in range(nxx):
frA[i] = self.fracGauss(sig[i], r=r, pscale=pscale)
index = [i for i in range(
nxx-1) if (fr-frA[i])*(fr-frA[i+1]) <= 0.0][0]
fwhm = 2.35482*sig[index]
return fwhm
def get_PSF(self, pos_img, chip=None, bandpass=None, folding_threshold=5.e-3):
dx = pos_img.x - self.chip.cen_pix_x
dy = pos_img.y - self.chip.cen_pix_y
return self.PSFspin(dx, dy)
def PSFspin(self, x, y):
"""
The PSF profile at a given image position relative to the axis center
Parameters:
theta : spin angles in a given exposure in unit of [arcsecond]
dx, dy: relative position to the axis center in unit of [pixels]
Return:
Spinned PSF: g1, g2 and axis ratio 'a/b'
"""
a2Rad = np.pi/(60.0*60.0*180.0)
ff = self.sigGauss * 0.107 * (1000.0/10.0) # in unit of [pixels]
rc = np.sqrt(x*x + y*y)
cpix = rc*(self.sigSpin*a2Rad)
beta = (np.arctan2(y, x) + np.pi/2)
ell = cpix**2/(2.0*ff**2+cpix**2)
# ell *= 10.0
qr = np.sqrt((1.0+ell)/(1.0-ell))
# psfShape = galsim.Shear(e=ell, beta=beta)
# g1, g2 = psfShape.g1, psfShape.g2
# qr = np.sqrt((1.0+ell)/(1.0-ell))
# return ell, beta, qr
PSFshear = galsim.Shear(e=ell, beta=beta*galsim.radians)
return self.psf.shear(PSFshear), PSFshear
...@@ -12,14 +12,14 @@ import scipy.spatial as spatial ...@@ -12,14 +12,14 @@ import scipy.spatial as spatial
import galsim import galsim
import h5py import h5py
from ObservationSim.PSF.PSFModel import PSFModel from observation_sim.PSF.PSFModel import PSFModel
NPSF = 900 #***# 30*30 NPSF = 900 # ***# 30*30
PixSizeInMicrons = 5. #***# in microns PixSizeInMicrons = 5. # ***# in microns
###find neighbors-KDtree### ### find neighbors-KDtree###
def findNeighbors(tx, ty, px, py, dr=0.1, dn=1, OnlyDistance=True): def findNeighbors(tx, ty, px, py, dr=0.1, dn=1, OnlyDistance=True):
""" """
find nearest neighbors by 2D-KDTree find nearest neighbors by 2D-KDTree
...@@ -38,7 +38,7 @@ def findNeighbors(tx, ty, px, py, dr=0.1, dn=1, OnlyDistance=True): ...@@ -38,7 +38,7 @@ def findNeighbors(tx, ty, px, py, dr=0.1, dn=1, OnlyDistance=True):
datay = py datay = py
tree = spatial.KDTree(list(zip(datax.ravel(), datay.ravel()))) tree = spatial.KDTree(list(zip(datax.ravel(), datay.ravel())))
dataq=[] dataq = []
rr = dr rr = dr
if OnlyDistance == True: if OnlyDistance == True:
dataq = tree.query_ball_point([tx, ty], rr) dataq = tree.query_ball_point([tx, ty], rr)
...@@ -51,7 +51,9 @@ def findNeighbors(tx, ty, px, py, dr=0.1, dn=1, OnlyDistance=True): ...@@ -51,7 +51,9 @@ def findNeighbors(tx, ty, px, py, dr=0.1, dn=1, OnlyDistance=True):
dataq = np.array(dataq)[ddSortindx[0:dn]] dataq = np.array(dataq)[ddSortindx[0:dn]]
return dataq return dataq
###find neighbors-hoclist### ### find neighbors-hoclist###
def hocBuild(partx, party, nhocx, nhocy, dhocx, dhocy): def hocBuild(partx, party, nhocx, nhocy, dhocx, dhocy):
if np.max(partx) > nhocx*dhocx: if np.max(partx) > nhocx*dhocx:
print('ERROR') print('ERROR')
...@@ -60,8 +62,8 @@ def hocBuild(partx, party, nhocx, nhocy, dhocx, dhocy): ...@@ -60,8 +62,8 @@ def hocBuild(partx, party, nhocx, nhocy, dhocx, dhocy):
print('ERROR') print('ERROR')
sys.exit() sys.exit()
npart = partx.size npart = partx.size
hoclist= np.zeros(npart, dtype=np.int32)-1 hoclist = np.zeros(npart, dtype=np.int32)-1
hoc = np.zeros([nhocy, nhocx], dtype=np.int32)-1 hoc = np.zeros([nhocy, nhocx], dtype=np.int32)-1
for ipart in range(npart): for ipart in range(npart):
ix = int(partx[ipart]/dhocx) ix = int(partx[ipart]/dhocx)
...@@ -70,18 +72,20 @@ def hocBuild(partx, party, nhocx, nhocy, dhocx, dhocy): ...@@ -70,18 +72,20 @@ def hocBuild(partx, party, nhocx, nhocy, dhocx, dhocy):
hoc[iy, ix] = ipart hoc[iy, ix] = ipart
return hoc, hoclist return hoc, hoclist
def hocFind(px, py, dhocx, dhocy, hoc, hoclist): def hocFind(px, py, dhocx, dhocy, hoc, hoclist):
ix = int(px/dhocx) ix = int(px/dhocx)
iy = int(py/dhocy) iy = int(py/dhocy)
neigh=[] neigh = []
it = hoc[iy, ix] it = hoc[iy, ix]
while it != -1: while it != -1:
neigh.append(it) neigh.append(it)
it = hoclist[it] it = hoclist[it]
return neigh return neigh
def findNeighbors_hoclist(px, py, tx=None,ty=None, dn=4, hoc=None, hoclist=None):
def findNeighbors_hoclist(px, py, tx=None, ty=None, dn=4, hoc=None, hoclist=None):
nhocy = nhocx = 20 nhocy = nhocx = 20
pxMin = np.min(px) pxMin = np.min(px)
...@@ -91,21 +95,21 @@ def findNeighbors_hoclist(px, py, tx=None,ty=None, dn=4, hoc=None, hoclist=None) ...@@ -91,21 +95,21 @@ def findNeighbors_hoclist(px, py, tx=None,ty=None, dn=4, hoc=None, hoclist=None)
dhocx = (pxMax - pxMin)/(nhocx-1) dhocx = (pxMax - pxMin)/(nhocx-1)
dhocy = (pyMax - pyMin)/(nhocy-1) dhocy = (pyMax - pyMin)/(nhocy-1)
partx = px - pxMin +dhocx/2 partx = px - pxMin + dhocx/2
party = py - pyMin +dhocy/2 party = py - pyMin + dhocy/2
if hoc is None: if hoc is None:
hoc, hoclist = hocBuild(partx, party, nhocx, nhocy, dhocx, dhocy) hoc, hoclist = hocBuild(partx, party, nhocx, nhocy, dhocx, dhocy)
return hoc, hoclist return hoc, hoclist
if hoc is not None: if hoc is not None:
tx = tx - pxMin +dhocx/2 tx = tx - pxMin + dhocx/2
ty = ty - pyMin +dhocy/2 ty = ty - pyMin + dhocy/2
itx = int(tx/dhocx) itx = int(tx/dhocx)
ity = int(ty/dhocy) ity = int(ty/dhocy)
ps = [-1, 0, 1] ps = [-1, 0, 1]
neigh=[] neigh = []
for ii in range(3): for ii in range(3):
for jj in range(3): for jj in range(3):
ix = itx + ps[ii] ix = itx + ps[ii]
...@@ -119,23 +123,23 @@ def findNeighbors_hoclist(px, py, tx=None,ty=None, dn=4, hoc=None, hoclist=None) ...@@ -119,23 +123,23 @@ def findNeighbors_hoclist(px, py, tx=None,ty=None, dn=4, hoc=None, hoclist=None)
if iy > nhocy-1: if iy > nhocy-1:
continue continue
#neightt = myUtil.hocFind(ppx, ppy, dhocx, dhocy, hoc, hoclist) # neightt = myUtil.hocFind(ppx, ppy, dhocx, dhocy, hoc, hoclist)
it = hoc[iy, ix] it = hoc[iy, ix]
while it != -1: while it != -1:
neigh.append(it) neigh.append(it)
it = hoclist[it] it = hoclist[it]
#neigh.append(neightt) # neigh.append(neightt)
#ll = [i for k in neigh for i in k] # ll = [i for k in neigh for i in k]
if dn != -1: if dn != -1:
ptx = np.array(partx[neigh]) ptx = np.array(partx[neigh])
pty = np.array(party[neigh]) pty = np.array(party[neigh])
dd = np.hypot(ptx-tx, pty-ty) dd = np.hypot(ptx-tx, pty-ty)
idx = np.argsort(dd) idx = np.argsort(dd)
neigh= np.array(neigh)[idx[0:dn]] neigh = np.array(neigh)[idx[0:dn]]
return neigh return neigh
###PSF-IDW### ### PSF-IDW###
def psfMaker_IDW(px, py, PSFMat, cen_col, cen_row, IDWindex=2, OnlyNeighbors=True, hoc=None, hoclist=None, PSFCentroidWgt=False): def psfMaker_IDW(px, py, PSFMat, cen_col, cen_row, IDWindex=2, OnlyNeighbors=True, hoc=None, hoclist=None, PSFCentroidWgt=False):
""" """
psf interpolation by IDW psf interpolation by IDW
...@@ -161,9 +165,11 @@ def psfMaker_IDW(px, py, PSFMat, cen_col, cen_row, IDWindex=2, OnlyNeighbors=Tru ...@@ -161,9 +165,11 @@ def psfMaker_IDW(px, py, PSFMat, cen_col, cen_row, IDWindex=2, OnlyNeighbors=Tru
if OnlyNeighbors == True: if OnlyNeighbors == True:
if hoc is None: if hoc is None:
neigh = findNeighbors(px, py, cen_col, cen_row, dr=5., dn=4, OnlyDistance=False) neigh = findNeighbors(px, py, cen_col, cen_row,
dr=5., dn=4, OnlyDistance=False)
if hoc is not None: if hoc is not None:
neigh = findNeighbors_hoclist(cen_col, cen_row, tx=px,ty=py, dn=4, hoc=hoc, hoclist=hoclist) neigh = findNeighbors_hoclist(
cen_col, cen_row, tx=px, ty=py, dn=4, hoc=hoc, hoclist=hoclist)
neighFlag = np.zeros(npsf) neighFlag = np.zeros(npsf)
neighFlag[neigh] = 1 neighFlag[neigh] = 1
...@@ -173,7 +179,8 @@ def psfMaker_IDW(px, py, PSFMat, cen_col, cen_row, IDWindex=2, OnlyNeighbors=Tru ...@@ -173,7 +179,8 @@ def psfMaker_IDW(px, py, PSFMat, cen_col, cen_row, IDWindex=2, OnlyNeighbors=Tru
if neighFlag[ipsf] != 1: if neighFlag[ipsf] != 1:
continue continue
dist = np.sqrt((ref_col - cen_col[ipsf])**2 + (ref_row - cen_row[ipsf])**2) dist = np.sqrt((ref_col - cen_col[ipsf])
** 2 + (ref_row - cen_row[ipsf])**2)
if IDWindex == 1: if IDWindex == 1:
psfWeight[ipsf] = dist psfWeight[ipsf] = dist
if IDWindex == 2: if IDWindex == 2:
...@@ -186,7 +193,7 @@ def psfMaker_IDW(px, py, PSFMat, cen_col, cen_row, IDWindex=2, OnlyNeighbors=Tru ...@@ -186,7 +193,7 @@ def psfMaker_IDW(px, py, PSFMat, cen_col, cen_row, IDWindex=2, OnlyNeighbors=Tru
psfWeight[ipsf] = 1./psfWeight[ipsf] psfWeight[ipsf] = 1./psfWeight[ipsf]
psfWeight /= np.sum(psfWeight) psfWeight /= np.sum(psfWeight)
psfMaker = np.zeros([ngy, ngx], dtype=np.float32) psfMaker = np.zeros([ngy, ngx], dtype=np.float32)
for ipsf in range(npsf): for ipsf in range(npsf):
if OnlyNeighbors == True: if OnlyNeighbors == True:
if neighFlag[ipsf] != 1: if neighFlag[ipsf] != 1:
...@@ -201,15 +208,14 @@ def psfMaker_IDW(px, py, PSFMat, cen_col, cen_row, IDWindex=2, OnlyNeighbors=Tru ...@@ -201,15 +208,14 @@ def psfMaker_IDW(px, py, PSFMat, cen_col, cen_row, IDWindex=2, OnlyNeighbors=Tru
return psfMaker return psfMaker
### define PSFInterp###
###define PSFInterp###
class PSFInterp(PSFModel): class PSFInterp(PSFModel):
def __init__(self, chip, npsf=NPSF, PSF_data=None, PSF_data_file=None, PSF_data_prefix="", sigSpin=0, psfRa=0.15, HocBuild=False, LOG_DEBUG=False): def __init__(self, chip, npsf=NPSF, PSF_data=None, PSF_data_file=None, PSF_data_prefix="", sigSpin=0, psfRa=0.15, HocBuild=False, LOG_DEBUG=False):
self.LOG_DEBUG = LOG_DEBUG self.LOG_DEBUG = LOG_DEBUG
if self.LOG_DEBUG: if self.LOG_DEBUG:
print('===================================================') print('===================================================')
print('DEBUG: psf module for csstSim ' \ print('DEBUG: psf module for csstSim '
+time.strftime("(%Y-%m-%d %H:%M:%S)", time.localtime()), flush=True) + time.strftime("(%Y-%m-%d %H:%M:%S)", time.localtime()), flush=True)
print('===================================================') print('===================================================')
self.sigSpin = sigSpin self.sigSpin = sigSpin
...@@ -221,53 +227,62 @@ class PSFInterp(PSFModel): ...@@ -221,53 +227,62 @@ class PSFInterp(PSFModel):
print('Error - PSF_data_file is None') print('Error - PSF_data_file is None')
sys.exit() sys.exit()
self.nwave= self._getPSFwave(self.iccd, PSF_data_file, PSF_data_prefix) self.nwave = self._getPSFwave(
self.iccd, PSF_data_file, PSF_data_prefix)
self.npsf = npsf self.npsf = npsf
self.PSF_data = self._loadPSF(self.iccd, PSF_data_file, PSF_data_prefix) self.PSF_data = self._loadPSF(
self.iccd, PSF_data_file, PSF_data_prefix)
if self.LOG_DEBUG: if self.LOG_DEBUG:
print('nwave-{:} on ccd-{:}::'.format(self.nwave, self.iccd), flush=True) print('nwave-{:} on ccd-{:}::'.format(self.nwave,
self.iccd), flush=True)
print('self.PSF_data ... ok', flush=True) print('self.PSF_data ... ok', flush=True)
print('Preparing self.[psfMat,cen_col,cen_row] for psfMaker ... ', end='', flush=True) print(
'Preparing self.[psfMat,cen_col,cen_row] for psfMaker ... ', end='', flush=True)
ngy, ngx = self.PSF_data[0][0]['psfMat'].shape
self.psfMat = np.zeros([self.nwave, self.npsf, ngy, ngx], dtype=np.float32) ngy, ngx = self.PSF_data[0][0]['psfMat'].shape
self.cen_col= np.zeros([self.nwave, self.npsf], dtype=np.float32) self.psfMat = np.zeros(
self.cen_row= np.zeros([self.nwave, self.npsf], dtype=np.float32) [self.nwave, self.npsf, ngy, ngx], dtype=np.float32)
self.hoc =[] self.cen_col = np.zeros([self.nwave, self.npsf], dtype=np.float32)
self.hoclist=[] self.cen_row = np.zeros([self.nwave, self.npsf], dtype=np.float32)
self.hoc = []
self.hoclist = []
for twave in range(self.nwave): for twave in range(self.nwave):
for tpsf in range(self.npsf): for tpsf in range(self.npsf):
self.psfMat[twave, tpsf, :, :] = self.PSF_data[twave][tpsf]['psfMat'] self.psfMat[twave, tpsf, :,
self.PSF_data[twave][tpsf]['psfMat'] = 0 ###free psfMat :] = self.PSF_data[twave][tpsf]['psfMat']
self.PSF_data[twave][tpsf]['psfMat'] = 0 # free psfMat
self.pixsize = self.PSF_data[twave][tpsf]['pixsize']*1e-3 ##mm self.pixsize = self.PSF_data[twave][tpsf]['pixsize']*1e-3 # mm
self.cen_col[twave, tpsf] = self.PSF_data[twave][tpsf]['image_x'] + self.PSF_data[twave][tpsf]['centroid_x'] self.cen_col[twave, tpsf] = self.PSF_data[twave][tpsf]['image_x'] + \
self.cen_row[twave, tpsf] = self.PSF_data[twave][tpsf]['image_y'] + self.PSF_data[twave][tpsf]['centroid_y'] self.PSF_data[twave][tpsf]['centroid_x']
self.cen_row[twave, tpsf] = self.PSF_data[twave][tpsf]['image_y'] + \
self.PSF_data[twave][tpsf]['centroid_y']
if HocBuild: if HocBuild:
#hoclist on twave for neighborsFinding # hoclist on twave for neighborsFinding
hoc,hoclist = findNeighbors_hoclist(self.cen_col[twave], self.cen_row[twave]) hoc, hoclist = findNeighbors_hoclist(
self.cen_col[twave], self.cen_row[twave])
self.hoc.append(hoc) self.hoc.append(hoc)
self.hoclist.append(hoclist) self.hoclist.append(hoclist)
if self.LOG_DEBUG: if self.LOG_DEBUG:
print('ok', flush=True) print('ok', flush=True)
def _getPSFwave(self, iccd, PSF_data_file, PSF_data_prefix): def _getPSFwave(self, iccd, PSF_data_file, PSF_data_prefix):
# fq = h5py.File(PSF_data_file+'/' +PSF_data_prefix +'psfCube_ccd{:}.h5'.format(iccd), 'r') # fq = h5py.File(PSF_data_file+'/' +PSF_data_prefix +'psfCube_ccd{:}.h5'.format(iccd), 'r')
fq = h5py.File(PSF_data_file+'/' +PSF_data_prefix +'psfCube_{:}.h5'.format(iccd), 'r') fq = h5py.File(PSF_data_file+'/' + PSF_data_prefix +
'psfCube_{:}.h5'.format(iccd), 'r')
nwave = len(fq.keys()) nwave = len(fq.keys())
fq.close() fq.close()
return nwave return nwave
def _loadPSF(self, iccd, PSF_data_file, PSF_data_prefix): def _loadPSF(self, iccd, PSF_data_file, PSF_data_prefix):
psfSet = [] psfSet = []
# fq = h5py.File(PSF_data_file+'/' +PSF_data_prefix +'psfCube_ccd{:}.h5'.format(iccd), 'r') # fq = h5py.File(PSF_data_file+'/' +PSF_data_prefix +'psfCube_ccd{:}.h5'.format(iccd), 'r')
fq = h5py.File(PSF_data_file+'/' +PSF_data_prefix +'psfCube_{:}.h5'.format(iccd), 'r') fq = h5py.File(PSF_data_file+'/' + PSF_data_prefix +
'psfCube_{:}.h5'.format(iccd), 'r')
for ii in range(self.nwave): for ii in range(self.nwave):
iwave = ii+1 iwave = ii+1
psfWave = [] psfWave = []
...@@ -276,30 +291,30 @@ class PSFInterp(PSFModel): ...@@ -276,30 +291,30 @@ class PSFInterp(PSFModel):
for jj in range(self.npsf): for jj in range(self.npsf):
ipsf = jj+1 ipsf = jj+1
psfInfo = {} psfInfo = {}
psfInfo['wavelength']= fq_iwave['wavelength'][()] psfInfo['wavelength'] = fq_iwave['wavelength'][()]
fq_iwave_ipsf = fq_iwave['psf_{:}'.format(ipsf)] fq_iwave_ipsf = fq_iwave['psf_{:}'.format(ipsf)]
psfInfo['pixsize'] = PixSizeInMicrons psfInfo['pixsize'] = PixSizeInMicrons
psfInfo['field_x'] = fq_iwave_ipsf['field_x'][()] psfInfo['field_x'] = fq_iwave_ipsf['field_x'][()]
psfInfo['field_y'] = fq_iwave_ipsf['field_y'][()] psfInfo['field_y'] = fq_iwave_ipsf['field_y'][()]
psfInfo['image_x'] = fq_iwave_ipsf['image_x'][()] psfInfo['image_x'] = fq_iwave_ipsf['image_x'][()]
psfInfo['image_y'] = fq_iwave_ipsf['image_y'][()] psfInfo['image_y'] = fq_iwave_ipsf['image_y'][()]
psfInfo['centroid_x']= fq_iwave_ipsf['cx'][()] psfInfo['centroid_x'] = fq_iwave_ipsf['cx'][()]
psfInfo['centroid_y']= fq_iwave_ipsf['cy'][()] psfInfo['centroid_y'] = fq_iwave_ipsf['cy'][()]
psfInfo['psfMat'] = fq_iwave_ipsf['psfMat'][()] psfInfo['psfMat'] = fq_iwave_ipsf['psfMat'][()]
psfWave.append(psfInfo) psfWave.append(psfInfo)
psfSet.append(psfWave) psfSet.append(psfWave)
fq.close() fq.close()
if self.LOG_DEBUG: if self.LOG_DEBUG:
print('psfSet has been loaded:', flush=True) print('psfSet has been loaded:', flush=True)
print('psfSet[iwave][ipsf][keys]:', psfSet[0][0].keys(), flush=True) print('psfSet[iwave][ipsf][keys]:',
psfSet[0][0].keys(), flush=True)
return psfSet return psfSet
def _findWave(self, bandpass): def _findWave(self, bandpass):
if isinstance(bandpass,int): if isinstance(bandpass, int):
twave = bandpass twave = bandpass
return twave return twave
...@@ -308,7 +323,6 @@ class PSFInterp(PSFModel): ...@@ -308,7 +323,6 @@ class PSFInterp(PSFModel):
if bandpass.blue_limit < bandwave and bandwave < bandpass.red_limit: if bandpass.blue_limit < bandwave and bandwave < bandpass.red_limit:
return twave return twave
return -1 return -1
def get_PSF(self, chip, pos_img, bandpass, galsimGSObject=True, findNeighMode='treeFind', folding_threshold=5.e-3, pointing_pa=0.0): def get_PSF(self, chip, pos_img, bandpass, galsimGSObject=True, findNeighMode='treeFind', folding_threshold=5.e-3, pointing_pa=0.0):
""" """
...@@ -323,7 +337,7 @@ class PSFInterp(PSFModel): ...@@ -323,7 +337,7 @@ class PSFInterp(PSFModel):
Returns: Returns:
PSF: A 'galsim.GSObject'. PSF: A 'galsim.GSObject'.
""" """
pixSize = np.rad2deg(self.pixsize*1e-3/28)*3600 #set psf pixsize pixSize = np.rad2deg(self.pixsize*1e-3/28)*3600 # set psf pixsize
# assert self.iccd == int(chip.getChipLabel(chipID=chip.chipID)), 'ERROR: self.iccd != chip.chipID' # assert self.iccd == int(chip.getChipLabel(chipID=chip.chipID)), 'ERROR: self.iccd != chip.chipID'
twave = self._findWave(bandpass) twave = self._findWave(bandpass)
...@@ -331,16 +345,18 @@ class PSFInterp(PSFModel): ...@@ -331,16 +345,18 @@ class PSFInterp(PSFModel):
print("!!!PSF bandpass does not match.") print("!!!PSF bandpass does not match.")
exit() exit()
PSFMat = self.psfMat[twave] PSFMat = self.psfMat[twave]
cen_col= self.cen_col[twave] cen_col = self.cen_col[twave]
cen_row= self.cen_row[twave] cen_row = self.cen_row[twave]
px = (pos_img.x - chip.cen_pix_x)*0.01 px = (pos_img.x - chip.cen_pix_x)*0.01
py = (pos_img.y - chip.cen_pix_y)*0.01 py = (pos_img.y - chip.cen_pix_y)*0.01
if findNeighMode == 'treeFind': if findNeighMode == 'treeFind':
imPSF = psfMaker_IDW(px, py, PSFMat, cen_col, cen_row, IDWindex=2, OnlyNeighbors=True, PSFCentroidWgt=True) imPSF = psfMaker_IDW(px, py, PSFMat, cen_col, cen_row,
IDWindex=2, OnlyNeighbors=True, PSFCentroidWgt=True)
if findNeighMode == 'hoclistFind': if findNeighMode == 'hoclistFind':
assert(self.hoc != 0), 'hoclist should be built correctly!' assert (self.hoc != 0), 'hoclist should be built correctly!'
imPSF = psfMaker_IDW(px, py, PSFMat, cen_col, cen_row, IDWindex=2, OnlyNeighbors=True, hoc=self.hoc[twave], hoclist=self.hoclist[twave], PSFCentroidWgt=True) imPSF = psfMaker_IDW(px, py, PSFMat, cen_col, cen_row, IDWindex=2, OnlyNeighbors=True,
hoc=self.hoc[twave], hoclist=self.hoclist[twave], PSFCentroidWgt=True)
''' '''
############TEST: START ############TEST: START
...@@ -353,20 +369,21 @@ class PSFInterp(PSFModel): ...@@ -353,20 +369,21 @@ class PSFInterp(PSFModel):
''' '''
if galsimGSObject: if galsimGSObject:
imPSFt = np.zeros([257,257]) imPSFt = np.zeros([257, 257])
imPSFt[0:256, 0:256] = imPSF imPSFt[0:256, 0:256] = imPSF
# imPSFt[120:130, 0:256] = 1. # imPSFt[120:130, 0:256] = 1.
img = galsim.ImageF(imPSFt, scale=pixSize) img = galsim.ImageF(imPSFt, scale=pixSize)
gsp = galsim.GSParams(folding_threshold=folding_threshold) gsp = galsim.GSParams(folding_threshold=folding_threshold)
############TEST: START # TEST: START
# Use sheared PSF to test the PSF orientation # Use sheared PSF to test the PSF orientation
# self.psf = galsim.InterpolatedImage(img, gsparams=gsp).shear(g1=0.8, g2=0.) # self.psf = galsim.InterpolatedImage(img, gsparams=gsp).shear(g1=0.8, g2=0.)
############TEST: END # TEST: END
self.psf = galsim.InterpolatedImage(img, gsparams=gsp) self.psf = galsim.InterpolatedImage(img, gsparams=gsp)
wcs = chip.img.wcs.local(pos_img) wcs = chip.img.wcs.local(pos_img)
scale = galsim.PixelScale(0.074) scale = galsim.PixelScale(0.074)
self.psf = wcs.toWorld(scale.toImage(self.psf), image_pos=(pos_img)) self.psf = wcs.toWorld(scale.toImage(
self.psf), image_pos=(pos_img))
# return self.PSFspin(x=px/0.01, y=py/0.01) # return self.PSFspin(x=px/0.01, y=py/0.01)
return self.psf, galsim.Shear(e=0., beta=(np.pi/2)*galsim.radians) return self.psf, galsim.Shear(e=0., beta=(np.pi/2)*galsim.radians)
......
...@@ -4,6 +4,7 @@ PSF interpolation for CSST-Sim ...@@ -4,6 +4,7 @@ PSF interpolation for CSST-Sim
NOTE: [iccd, iwave, ipsf] are counted from 1 to n, but [tccd, twave, tpsf] are counted from 0 to n-1 NOTE: [iccd, iwave, ipsf] are counted from 1 to n, but [tccd, twave, tpsf] are counted from 0 to n-1
''' '''
import yaml
import sys import sys
import time import time
import copy import copy
...@@ -12,8 +13,9 @@ import scipy.spatial as spatial ...@@ -12,8 +13,9 @@ import scipy.spatial as spatial
import galsim import galsim
import h5py import h5py
from ObservationSim.PSF.PSFModel import PSFModel from observation_sim.instruments import Filter, FilterParam, Chip
from ObservationSim.Instrument.Chip import ChipUtils as chip_utils from observation_sim.PSF.PSFModel import PSFModel
from observation_sim.instruments.chip import chip_utils
import os import os
from astropy.io import fits from astropy.io import fits
...@@ -21,12 +23,12 @@ from astropy.modeling.models import Gaussian2D ...@@ -21,12 +23,12 @@ from astropy.modeling.models import Gaussian2D
from scipy import signal from scipy import signal
LOG_DEBUG = False #***# LOG_DEBUG = False # ***#
NPSF = 900 #***# 30*30 NPSF = 900 # ***# 30*30
PixSizeInMicrons = 5. #***# in microns PIX_SIZE_MICRON = 5. # ***# in microns
###find neighbors-KDtree### ### find neighbors-KDtree###
# def findNeighbors(tx, ty, px, py, dr=0.1, dn=1, OnlyDistance=True): # def findNeighbors(tx, ty, px, py, dr=0.1, dn=1, OnlyDistance=True):
# """ # """
# find nearest neighbors by 2D-KDTree # find nearest neighbors by 2D-KDTree
...@@ -208,36 +210,35 @@ PixSizeInMicrons = 5. #***# in microns ...@@ -208,36 +210,35 @@ PixSizeInMicrons = 5. #***# in microns
# return psfMaker # return psfMaker
### define PSFInterp###
###define PSFInterp###
class PSFInterpSLS(PSFModel): class PSFInterpSLS(PSFModel):
def __init__(self, chip, filt,PSF_data_prefix="", sigSpin=0, psfRa=0.15, pix_size = 0.005): def __init__(self, chip, filt, PSF_data_prefix="", sigSpin=0, psfRa=0.15, pix_size=0.005):
if LOG_DEBUG: if LOG_DEBUG:
print('===================================================') print('===================================================')
print('DEBUG: psf module for csstSim ' \ print('DEBUG: psf module for csstSim '
+time.strftime("(%Y-%m-%d %H:%M:%S)", time.localtime()), flush=True) + time.strftime("(%Y-%m-%d %H:%M:%S)", time.localtime()), flush=True)
print('===================================================') print('===================================================')
self.sigSpin = sigSpin self.sigSpin = sigSpin
self.sigGauss = psfRa self.sigGauss = psfRa
self.grating_ids = chip_utils.getChipSLSGratingID(chip.chipID) self.grating_ids = chip_utils.getChipSLSGratingID(chip.chipID)
_,self.grating_type = chip.getChipFilter(chipID=chip.chipID) _, self.grating_type = chip.getChipFilter(chipID=chip.chipID)
self.data_folder = PSF_data_prefix self.data_folder = PSF_data_prefix
self.getPSFDataFromFile(filt) self.getPSFDataFromFile(filt)
self.pixsize = pix_size # um self.pixsize = pix_size # um
def getPSFDataFromFile(self, filt): def getPSFDataFromFile(self, filt):
gratingInwavelist = {'GU':0,'GV':1,'GI':2} gratingInwavelist = {'GU': 0, 'GV': 1, 'GI': 2}
grating_orders = ['0','1'] grating_orders = ['0', '1']
waveListFn = self.data_folder + '/wavelist.dat' waveListFn = self.data_folder + '/wavelist.dat'
wavelists = np.loadtxt(waveListFn) wavelists = np.loadtxt(waveListFn)
self.waveList = wavelists[:,gratingInwavelist[self.grating_type]] self.waveList = wavelists[:, gratingInwavelist[self.grating_type]]
bandranges = np.zeros([4,2]) bandranges = np.zeros([4, 2])
midBand = (self.waveList[0:3] + self.waveList[1:4])/2.*10000. midBand = (self.waveList[0:3] + self.waveList[1:4])/2.*10000.
bandranges[0,0] = filt.blue_limit bandranges[0, 0] = filt.blue_limit
bandranges[1:4,0] = midBand bandranges[1:4, 0] = midBand
bandranges[0:3, 1] = midBand bandranges[0:3, 1] = midBand
bandranges[3,1] = filt.red_limit bandranges[3, 1] = filt.red_limit
self.bandranges = bandranges self.bandranges = bandranges
...@@ -246,7 +247,7 @@ class PSFInterpSLS(PSFModel): ...@@ -246,7 +247,7 @@ class PSFInterpSLS(PSFModel):
for g_order in grating_orders: for g_order in grating_orders:
g_folder_order = g_folder + 'PSF_Order_' + g_order + '/' g_folder_order = g_folder + 'PSF_Order_' + g_order + '/'
grating_order_data = {} grating_order_data = {}
for bandi in [1,2,3,4]: for bandi in [1, 2, 3, 4]:
subBand_data = {} subBand_data = {}
subBand_data['bandrange'] = bandranges[bandi-1] subBand_data['bandrange'] = bandranges[bandi-1]
final_folder = g_folder_order + str(bandi) + '/' final_folder = g_folder_order + str(bandi) + '/'
...@@ -305,7 +306,7 @@ class PSFInterpSLS(PSFModel): ...@@ -305,7 +306,7 @@ class PSFInterpSLS(PSFModel):
# psfInfo['wavelength']= fq_iwave['wavelength'][()] # psfInfo['wavelength']= fq_iwave['wavelength'][()]
# #
# fq_iwave_ipsf = fq_iwave['psf_{:}'.format(ipsf)] # fq_iwave_ipsf = fq_iwave['psf_{:}'.format(ipsf)]
# psfInfo['pixsize'] = PixSizeInMicrons # psfInfo['pixsize'] = PIX_SIZE_MICRON
# psfInfo['field_x'] = fq_iwave_ipsf['field_x'][()] # psfInfo['field_x'] = fq_iwave_ipsf['field_x'][()]
# psfInfo['field_y'] = fq_iwave_ipsf['field_y'][()] # psfInfo['field_y'] = fq_iwave_ipsf['field_y'][()]
# psfInfo['image_x'] = fq_iwave_ipsf['image_x'][()] # psfInfo['image_x'] = fq_iwave_ipsf['image_x'][()]
...@@ -342,7 +343,7 @@ class PSFInterpSLS(PSFModel): ...@@ -342,7 +343,7 @@ class PSFInterpSLS(PSFModel):
offset = int(np.ceil(sigma * 3)) offset = int(np.ceil(sigma * 3))
g_size = 2 * offset + 1 g_size = 2 * offset + 1
m_cen = int(g_size / 2) m_cen = int(g_size / 2)
print('-----',g_size) print('-----', g_size)
g_PSF_ = Gaussian2D(1, m_cen, m_cen, sigma, sigma) g_PSF_ = Gaussian2D(1, m_cen, m_cen, sigma, sigma)
yp, xp = np.mgrid[0:g_size, 0:g_size] yp, xp = np.mgrid[0:g_size, 0:g_size]
g_PSF = g_PSF_(xp, yp) g_PSF = g_PSF_(xp, yp)
...@@ -351,8 +352,7 @@ class PSFInterpSLS(PSFModel): ...@@ -351,8 +352,7 @@ class PSFInterpSLS(PSFModel):
convImg = convImg/np.sum(convImg) convImg = convImg/np.sum(convImg)
return convImg return convImg
def get_PSF(self, chip, pos_img_local=[1000, 1000], bandNo=1, galsimGSObject=True, folding_threshold=5.e-3, g_order='A', grating_split_pos=3685):
def get_PSF(self, chip, pos_img_local = [1000,1000], bandNo = 1, galsimGSObject=True, folding_threshold=5.e-3, g_order = 'A', grating_split_pos=3685):
""" """
Get the PSF at a given image position Get the PSF at a given image position
...@@ -365,8 +365,9 @@ class PSFInterpSLS(PSFModel): ...@@ -365,8 +365,9 @@ class PSFInterpSLS(PSFModel):
Returns: Returns:
PSF: A 'galsim.GSObject'. PSF: A 'galsim.GSObject'.
""" """
order_IDs = {'A': '1', 'B': '0' ,'C': '0', 'D': '0', 'E': '0'} order_IDs = {'A': '1', 'B': '0', 'C': '0', 'D': '0', 'E': '0'}
contam_order_sigma = {'C':0.28032344707964174,'D':0.39900182912061344,'E':1.1988309797685412} #arcsec contam_order_sigma = {'C': 0.28032344707964174,
'D': 0.39900182912061344, 'E': 1.1988309797685412} # arcsec
x_start = chip.x_cen/chip.pix_size - chip.npix_x / 2. x_start = chip.x_cen/chip.pix_size - chip.npix_x / 2.
y_start = chip.y_cen/chip.pix_size - chip.npix_y / 2. y_start = chip.y_cen/chip.pix_size - chip.npix_y / 2.
# print(pos_img.x - x_start) # print(pos_img.x - x_start)
...@@ -382,7 +383,6 @@ class PSFInterpSLS(PSFModel): ...@@ -382,7 +383,6 @@ class PSFInterpSLS(PSFModel):
# if grating_order in ['-2','-1','2']: # if grating_order in ['-2','-1','2']:
# grating_order = '1' # grating_order = '1'
# if grating_order in ['0', '1']: # if grating_order in ['0', '1']:
psf_order = psf_data['order'+grating_order] psf_order = psf_data['order'+grating_order]
psf_order_b = psf_order['band'+str(bandNo)] psf_order_b = psf_order['band'+str(bandNo)]
...@@ -396,31 +396,34 @@ class PSFInterpSLS(PSFModel): ...@@ -396,31 +396,34 @@ class PSFInterpSLS(PSFModel):
px = pos_img.x*chip.pix_size px = pos_img.x*chip.pix_size
py = pos_img.y*chip.pix_size py = pos_img.y*chip.pix_size
dist2=(pos_p[:,1] - px)*(pos_p[:,1] - px) + (pos_p[:,0] - py)*(pos_p[:,0] - py) dist2 = (pos_p[:, 1] - px)*(pos_p[:, 1] - px) + \
temp_sort_dist = np.zeros([dist2.shape[0],2]) (pos_p[:, 0] - py)*(pos_p[:, 0] - py)
temp_sort_dist[:, 0] = np.arange(0, dist2.shape[0],1) temp_sort_dist = np.zeros([dist2.shape[0], 2])
temp_sort_dist[:, 0] = np.arange(0, dist2.shape[0], 1)
temp_sort_dist[:, 1] = dist2 temp_sort_dist[:, 1] = dist2
# print(temp_sort_dist) # print(temp_sort_dist)
dits2_sortlist = sorted(temp_sort_dist, key=lambda x:x[1]) dits2_sortlist = sorted(temp_sort_dist, key=lambda x: x[1])
# print(dits2_sortlist) # print(dits2_sortlist)
nearest4p = np.zeros([4,2]) nearest4p = np.zeros([4, 2])
pc_coeff_4p = np.zeros([pc_coeff.data.shape[0],4]) pc_coeff_4p = np.zeros([pc_coeff.data.shape[0], 4])
for i in np.arange(4): for i in np.arange(4):
smaller_ids = int(dits2_sortlist[i][0]) smaller_ids = int(dits2_sortlist[i][0])
nearest4p[i, 0] = pos_p[smaller_ids, 1] nearest4p[i, 0] = pos_p[smaller_ids, 1]
nearest4p[i, 1] = pos_p[smaller_ids, 0] nearest4p[i, 1] = pos_p[smaller_ids, 0]
pc_coeff_4p[:,i] = pc_coeff[:,smaller_ids] pc_coeff_4p[:, i] = pc_coeff[:, smaller_ids]
idw_dist = 1/(np.sqrt((px-nearest4p[:,0]) * (px-nearest4p[:,0]) + (py-nearest4p[:,1]) * (py-nearest4p[:,1]))) idw_dist = 1/(np.sqrt((px-nearest4p[:, 0]) * (px-nearest4p[:, 0]) + (
py-nearest4p[:, 1]) * (py-nearest4p[:, 1])))
coeff_int = np.zeros(pc_coeff.data.shape[0]) coeff_int = np.zeros(pc_coeff.data.shape[0])
for i in np.arange(4): for i in np.arange(4):
coeff_int = coeff_int + pc_coeff_4p[:,i]*idw_dist[i] coeff_int = coeff_int + pc_coeff_4p[:, i]*idw_dist[i]
coeff_int = coeff_int / np.sum(coeff_int) coeff_int = coeff_int / np.sum(coeff_int)
npc = 10 npc = 10
m_size = int(pcs.shape[0]**0.5) m_size = int(pcs.shape[0]**0.5)
PSF_int = np.dot(pcs[:,0:npc],coeff_int[0:npc]).reshape(m_size,m_size) PSF_int = np.dot(pcs[:, 0:npc], coeff_int[0:npc]
).reshape(m_size, m_size)
# PSF_int = PSF_int/np.sum(PSF_int) # PSF_int = PSF_int/np.sum(PSF_int)
PSF_int_trans = np.flipud(np.fliplr(PSF_int)) PSF_int_trans = np.flipud(np.fliplr(PSF_int))
...@@ -434,7 +437,6 @@ class PSFInterpSLS(PSFModel): ...@@ -434,7 +437,6 @@ class PSFInterpSLS(PSFModel):
# from astropy.io import fits # from astropy.io import fits
# fits.writeto(str(bandNo) + '_' + g_order+ '_psf_o.fits', PSF_int_trans) # fits.writeto(str(bandNo) + '_' + g_order+ '_psf_o.fits', PSF_int_trans)
# if g_order in ['C','D','E']: # if g_order in ['C','D','E']:
# g_simgma = contam_order_sigma[g_order]/pixel_size_arc # g_simgma = contam_order_sigma[g_order]/pixel_size_arc
# PSF_int_trans = self.convolveWithGauss(PSF_int_trans,g_simgma) # PSF_int_trans = self.convolveWithGauss(PSF_int_trans,g_simgma)
...@@ -459,24 +461,24 @@ class PSFInterpSLS(PSFModel): ...@@ -459,24 +461,24 @@ class PSFInterpSLS(PSFModel):
pixel_size_arc = np.rad2deg(self.pixsize * 1e-3 / 28) * 3600 pixel_size_arc = np.rad2deg(self.pixsize * 1e-3 / 28) * 3600
img = galsim.ImageF(PSF_int_trans, scale=pixel_size_arc) img = galsim.ImageF(PSF_int_trans, scale=pixel_size_arc)
gsp = galsim.GSParams(folding_threshold=folding_threshold) gsp = galsim.GSParams(folding_threshold=folding_threshold)
############TEST: START # TEST: START
# Use sheared PSF to test the PSF orientation # Use sheared PSF to test the PSF orientation
# self.psf = galsim.InterpolatedImage(img, gsparams=gsp).shear(g1=0.8, g2=0.) # self.psf = galsim.InterpolatedImage(img, gsparams=gsp).shear(g1=0.8, g2=0.)
############TEST: END # TEST: END
self.psf = galsim.InterpolatedImage(img, gsparams=gsp) self.psf = galsim.InterpolatedImage(img, gsparams=gsp)
# if g_order in ['C','D','E']: # if g_order in ['C','D','E']:
# add_psf = galsim.Gaussian(sigma=contam_order_sigma[g_order], flux=1.0) # add_psf = galsim.Gaussian(sigma=contam_order_sigma[g_order], flux=1.0)
# self.psf = galsim.Convolve(self.psf, add_psf) # self.psf = galsim.Convolve(self.psf, add_psf)
wcs = chip.img.wcs.local(pos_img) wcs = chip.img.wcs.local(pos_img)
scale = galsim.PixelScale(0.074) scale = galsim.PixelScale(0.074)
self.psf = wcs.toWorld(scale.toImage(self.psf), image_pos=(pos_img)) self.psf = wcs.toWorld(scale.toImage(
self.psf), image_pos=(pos_img))
# return self.PSFspin(x=px/0.01, y=py/0.01) # return self.PSFspin(x=px/0.01, y=py/0.01)
return self.psf, galsim.Shear(e=0., beta=(np.pi/2)*galsim.radians) return self.psf, galsim.Shear(e=0., beta=(np.pi/2)*galsim.radians)
return PSF_int_trans, PSF_int return PSF_int_trans, PSF_int
# pixSize = np.rad2deg(self.pixsize*1e-3/28)*3600 #set psf pixsize # pixSize = np.rad2deg(self.pixsize*1e-3/28)*3600 #set psf pixsize
# #
# # assert self.iccd == int(chip.getChipLabel(chipID=chip.chipID)), 'ERROR: self.iccd != chip.chipID' # # assert self.iccd == int(chip.getChipLabel(chipID=chip.chipID)), 'ERROR: self.iccd != chip.chipID'
...@@ -547,24 +549,23 @@ class PSFInterpSLS(PSFModel): ...@@ -547,24 +549,23 @@ class PSFInterpSLS(PSFModel):
# PSFshear = galsim.Shear(e=ell, beta=beta*galsim.radians) # PSFshear = galsim.Shear(e=ell, beta=beta*galsim.radians)
# return self.psf.shear(PSFshear), PSFshear # return self.psf.shear(PSFshear), PSFshear
from ObservationSim.Instrument import Filter, FilterParam, Chip
import yaml
if __name__ == '__main__': if __name__ == '__main__':
configfn = '/Users/zhangxin/Work/SlitlessSim/CSST_SIM/CSST_new_sim/csst-simulation/config/config_C6_dev.yaml' configfn = '/Users/zhangxin/Work/SlitlessSim/CSST_SIM/CSST_new_sim/csst-simulation/config/config_C6_dev.yaml'
with open(configfn, "r") as stream: with open(configfn, "r") as stream:
try: try:
config = yaml.safe_load(stream) config = yaml.safe_load(stream)
for key, value in config.items(): for key, value in config.items():
print (key + " : " + str(value)) print(key + " : " + str(value))
except yaml.YAMLError as exc: except yaml.YAMLError as exc:
print(exc) print(exc)
chip = Chip(chipID=1,config=config) chip = Chip(chipID=1, config=config)
filter_id, filter_type = chip.getChipFilter() filter_id, filter_type = chip.getChipFilter()
filt = Filter(filter_id=filter_id, filt = Filter(filter_id=filter_id,
filter_type=filter_type, filter_type=filter_type,
filter_param=FilterParam()) filter_param=FilterParam())
psf_i = PSFInterpSLS(chip, filt,PSF_data_prefix="/Volumes/EAGET/CSST_PSF_data/SLS_PSF_PCA_fp/") psf_i = PSFInterpSLS(
chip, filt, PSF_data_prefix="/Volumes/EAGET/CSST_PSF_data/SLS_PSF_PCA_fp/")
pos_img = galsim.PositionD(x=25155, y=-22060) pos_img = galsim.PositionD(x=25155, y=-22060)
psf_im = psf_i.get_PSF(chip, pos_img = pos_img, g_order = '1') psf_im = psf_i.get_PSF(chip, pos_img=pos_img, g_order='1')
import galsim
import sep
import numpy as np
from scipy.interpolate import interp1d
import pylab as pl
import os
import sys
class PSFModel(object):
def __init__(self, sigSpin=0., psfRa=0.15):
# TODO: what are the nesseary fields in PSFModel class?
pass
def PSFspin(self, psf, sigSpin, sigGauss, dx, dy):
"""
The PSF profile at a given image position relative to the axis center
Parameters:
theta : spin angles in a given exposure in unit of [arcsecond]
dx, dy: relative position to the axis center in unit of [pixels]
Return:
Spinned PSF: g1, g2 and axis ratio 'a/b'
"""
a2Rad = np.pi/(60.0*60.0*180.0)
ff = sigGauss * 0.107 * (1000.0/10.0) # in unit of [pixels]
rc = np.sqrt(dx*dx + dy*dy)
cpix = rc*(sigSpin*a2Rad)
beta = (np.arctan2(dy, dx) + np.pi/2)
ell = cpix**2/(2.0*ff**2+cpix**2)
# ell *= 10.0
qr = np.sqrt((1.0+ell)/(1.0-ell))
# psfShape = galsim.Shear(e=ell, beta=beta)
# g1, g2 = psfShape.g1, psfShape.g2
# qr = np.sqrt((1.0+ell)/(1.0-ell))
# return ell, beta, qr
PSFshear = galsim.Shear(e=ell, beta=beta*galsim.radians)
return psf.shear(PSFshear), PSFshear
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment