Commit 29ac5666 authored by Fang Yuedong's avatar Fang Yuedong
Browse files

Baseline

parents
import numpy as np
import os
from datetime import datetime
from scipy.interpolate import InterpolatedUnivariateSpline, UnivariateSpline, interp1d
from scipy import interpolate
from astropy.table import Table
import galsim
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
def magToFlux(mag):
"""
flux of a given AB magnitude
Parameters:
mag: magnitude in unit of AB
Return:
flux: flux in unit of erg/s/cm^2/Hz
"""
flux = 10**(-0.4*(mag+48.6))
return flux
def extAv(nav, seed=1212123):
"""
Generate random intrinsic extinction Av
following the distribution from Holwerda et al, 2015
"""
np.random.seed(seed)
tau = 0.4
peak, a = 0.1, 0.5
b = a*(tau-peak)
pav = lambda av: (a*av+b)*np.exp(-av/tau)
avmin, avmax = 0., 3.
avs = np.linspace(avmin, avmax, int((avmax-avmin)/0.001)+1)
norm = np.trapz(pav(avs), avs)
pav_base = pav(avs)/np.sum(pav(avs))
rav = np.random.choice(avs, nav, p=pav_base)
return rav
###########################################
def seds(sedlistn, seddir="./", unit="A"):
"""
read SEDs and save into Python dictionary
Parameters:
sedlistn: filename of the sed template list and corresponding intrinsic
extinction model, see tmag_dz.py for detailes
listdir: directory of the list
unit: wavelength unit of the input templates
Return:
SED dictionary, the output wavelength unit is 'A'
"""
seds = {}
reds = {}
sedlist = seddir + sedlistn
sedn = open(sedlist).read().splitlines()
sedtype = range(1,len(sedn)+1)
for i in range(len(sedn)):
xxx = sedn[i].split()
isedn = seddir+xxx[0]
itype = sedtype[i]
ised = np.loadtxt(isedn)
if unit=="nm": ised[:,0] *= 10.0
seds[itype] = ised
reds[itype] = int(xxx[1])
return seds, reds
def sed_assign(phz, btt, rng):
"""
assign SED template to a galaxy.
"""
sedid = list(range(1, 34))
lzid = sedid[0:13] + sedid[23:28]
hzid = sedid[13:23]
if btt == 1.0:
sedtype = rng.sample(sedid[0:5] + sedid[28:33], 1)[0]
if phz > 2.0 and sedtype in sedid[0:5]:
sedtype = rng.sample(sedid[28:33], 1)[0]
elif btt > 0.3 and btt < 1.0:
sedtype = rng.sample(sedid, 1)[0]
if phz > 2.0 and sedtype in lzid:
sedtype = rng.sample(hzid, 1)[0]
elif btt >= 0.1 and btt < 0.3:
sedtype = rng.sample(sedid[5:28], 1)[0]
if phz > 1.5 and sedtype in lzid:
sedtype = rng.sample(hzid, 1)[0]
elif btt >= 0.0 and btt < 0.1:
sedtype = rng.sample(sedid[5:23], 1)[0]
if phz > 1.5 and sedtype in lzid:
sedtype = rng.sample(hzid, 1)[0]
else:
sedtype = 0
return sedtype
###########################################
def tflux(filt, sed, redshift=0.0, av=0.0, redden=0):
"""
calculate the theoretical SED for given filter set and template
Only AB magnitude is support!!!
Parameters:
filt: 2d array
fliter transmissions: lambda(A), T
sed: 2d array
sed templateL lambda (A), flux (erg s-1 cm-2 A-1)
redshift: float
redshift of the corresponding source, default is zero
av: float
extinction value for intrincal extinction
redden: int
reddening model, see Function 'reddening' for details
return:
tflux: float
theoretical flux
sedObs: array
SED in observed frame
"""
z = redshift + 1.0
sw, sf = sed[:,0], sed[:,1]
# reddening
sf = reddening(sw, sf, av=av, model=redden)
sw, sf = sw*z, sf*(z**3)
# lyman forest correction
sf = lyman_forest(sw, sf, redshift)
sedxx = (sw.copy(), sf.copy())
sw = vc_A/sw
sf = sf*(vc_A/sw**2) # convert flux unit to erg/s/cm^s/Hz
sw, sf = sw[::-1], sf[::-1]
sfun = interp1d(sw, sf, kind='linear')
fwave, fresp = filt[:,0], filt[:,1]
fwave = vc_A/fwave
fwave, fresp = fwave[::-1], fresp[::-1]
tflux = sfun(fwave)
zpflux = 3.631*1.0e-20
tflux = np.trapz(tflux*fresp/fwave,fwave)/np.trapz(zpflux*fresp/fwave,fwave)
#tflux = np.trapz(tflux*fresp,fwave)/np.trapz(zpflux*fresp,fwave)
return tflux, sedxx
###########################################
def lyman_forest(wavelen, flux, z):
"""
Compute the Lyman forest mean absorption of an input spectrum,
according to D_A and D_B evolution from Madau (1995).
The waveeln and flux are in observed frame
"""
if z<=0:
flux0 = flux
else:
nw = 200
istep = np.linspace(0,nw-1,nw)
w1a, w2a = 1050.0*(1.0+z), 1170.0*(1.0+z)
w1b, w2b = 920.0*(1.0+z), 1015.0*(1.0+z)
wstepa = (w2a-w1a)/float(nw)
wstepb = (w2b-w1b)/float(nw)
wtempa = w1a + istep*wstepa
ptaua = np.exp(-3.6e-03*(wtempa/1216.0)**3.46)
wtempb = w1b + istep*wstepb
ptaub = np.exp(-1.7e-3*(wtempb/1026.0)**3.46\
-1.2e-3*(wtempb/972.50)**3.46\
-9.3e-4*(wtempb/950.00)**3.46)
da = (1.0/(120.0*(1.0+z)))*np.trapz(ptaua, wtempa)
db = (1.0/(95.0*(1.0+z)))*np.trapz(ptaub, wtempb)
if da>1.0: da=1.0
if db>1.0: db=1.0
if da<0.0: da=0.0
if db<0.0: db=0.0
flux0 = flux.copy()
id0 = wavelen<=1026.0*(1.0+z)
id1 = np.logical_and(wavelen<1216.0*(1.0+z),wavelen>=1026.0*(1.0+z))
flux0[id0] = db*flux[id0]
flux0[id1] = da*flux[id1]
return flux0
###########################################
def reddening(sw, sf, av=0.0, model=0):
"""
calculate the intrinsic extinction of a given template
Parameters:
sw: array
wavelength
sf: array
flux
av: float or array
model: int
Five models will be used:
1: Allen (1976) for the Milky Way
2: Seaton (1979) fit by Fitzpatrick (1986) for the Milky Way
3: Fitzpatrick (1986) for the Large Magellanic Cloud (LMC)
4: Prevot et al (1984) and Bouchet (1985) for the Small Magellanic Cloud (SMC)
5: Calzetti et al (2000) for starburst galaxies
6: Reddy et al (2015) for star forming galaxies
Return:
reddening-corrected flux or observed flux
"""
if model==0 or av==0.0:
flux=sf
elif model==1: # Allen (1976) for the Milky Way
lambda0 = np.array([1000, 1110, 1250, 1430, 1670, \
2000, 2220, 2500, 2850, 3330, \
3650, 4000, 4400, 5000, 5530, \
6700, 9000, 10000, 20000, 100000], dtype=float)
kR = np.array([4.20, 3.70, 3.30, 3.00, 2.70, \
2.80, 2.90, 2.30, 1.97, 1.69, \
1.58, 1.45, 1.32, 1.13, 1.00, \
0.74, 0.46, 0.38, 0.11, 0.00],dtype=float)
ext0 = InterpolatedUnivariateSpline(lambda0, kR, k=1)
A_lambda = av*ext0(sw)
A_lambda[A_lambda<0.0] = 0.0
flux = sf*10**(-0.4*A_lambda)
elif model==2: # Seaton (1979) fit by Fitzpatrick (1986) for the Milky Way
Rv=3.1
al0, ga, c1, c2, c3, c4 = 4.595, 1.051, -0.38, 0.74, 3.96, 0.26
ff11 = __red(1100.0,al0,ga,c1,c2,c3,c4)
ff12 = __red(1200.0,al0,ga,c1,c2,c3,c4)
slope=(ff12-ff11)/100.0
lambda0 = np.array([3650, 4000, 4400, 5000, 5530, \
6700, 9000, 10000, 20000, 100000], dtype=float)
kR = np.array([1.58, 1.45, 1.32, 1.13, 1.00, \
0.74, 0.46, 0.38, 0.11, 0.00],dtype=float)
fun = interp1d(lambda0, kR, kind='linear')
sw0 = sw[sw<1200.0]
A_lambda0 = (ff11+(sw0-1100.0)*slope)/Rv+1.0
sw1 = sw[np.logical_and(sw>=1200.0, sw<=3650.0)]
ff = __red(sw1,al0,ga,c1,c2,c3,c4)
A_lambda1 = ff/Rv+1.0
sw2 = sw[np.logical_and(sw>3650.0, sw<=100000.0)]
A_lambda2 = fun(sw2)
A_lambda3 = sw[sw>100000.0]*0.0
A_lambda = av*np.hstack([A_lambda0,A_lambda1,A_lambda2,A_lambda3])
A_lambda[A_lambda<0.0] = 0.0
flux = sf*10**(-0.4*A_lambda)
elif model==3: # Fitzpatrick (1986) for the Large Magellanic Cloud (LMC)
Rv=3.1
al0, ga, c1, c2, c3, c4 = 4.608, 0.994, -0.69, 0.89, 2.55, 0.50
ff11 = __red(1100.0,al0,ga,c1,c2,c3,c4)
ff12 = __red(1200.0,al0,ga,c1,c2,c3,c4)
slope=(ff12-ff11)/100.0
lambda0 = np.array([3330, 3650, 4000, 4400, 5000, 5530, \
6700, 9000, 10000, 20000, 100000], dtype=float)
kR = np.array([1.682, 1.58, 1.45, 1.32, 1.13, 1.00, \
0.74, 0.46, 0.38, 0.11, 0.00],dtype=float)
fun = interp1d(lambda0, kR, kind='linear')
sw0 = sw[sw<1200.0]
A_lambda0 = (ff11+(sw0-1100.0)*slope)/Rv+1.0
sw1 = sw[np.logical_and(sw>=1200.0, sw<=3330.0)]
ff = __red(sw1,al0,ga,c1,c2,c3,c4)
A_lambda1 = ff/Rv+1.0
sw2 = sw[np.logical_and(sw>3330.0, sw<=100000.0)]
A_lambda2 = fun(sw2)
A_lambda3 = sw[sw>100000.0]*0.0
A_lambda = av*np.hstack([A_lambda0,A_lambda1,A_lambda2,A_lambda3])
A_lambda[A_lambda<0.0] = 0.0
flux = sf*10**(-0.4*A_lambda)
elif model==4: # Prevot et al (1984) and Bouchet (1985) for the Small Magellanic Cloud (SMC)
Rv = 2.72
lambda0 = np.array([1275, 1330, 1385, 1435, 1490, 1545, \
1595, 1647, 1700, 1755, 1810, 1860, \
1910, 2000, 2115, 2220, 2335, 2445, \
2550, 2665, 2778, 2890, 2995, 3105, \
3704, 4255, 5291, 12500, 16500, 22000], dtype=float)
kR = np.array([13.54, 12.52, 11.51, 10.80, 9.84, 9.28, \
9.06, 8.49, 8.01, 7.71, 7.17, 6.90, 6.76, \
6.38, 5.85, 5.30, 4.53, 4.24, 3.91, 3.49, \
3.15, 3.00, 2.65, 2.29, 1.81, 1.00, 0.00, \
-2.02, -2.36, -2.47],dtype=float)
kR = kR/Rv+1.0
ext0 = InterpolatedUnivariateSpline(lambda0, kR, k=1)
A_lambda = av*ext0(sw)
A_lambda[A_lambda<0.0] = 0.0
flux = sf*10**(-0.4*A_lambda)
elif model==5: # Calzetti et al (2000) for starburst galaxies
Rv = 4.05
sw = sw*1.0e-04 #wavelength in microns
fun1 = lambda x: 2.659*(-2.156+1.509/x-0.198/x**2+0.011/x**3)+Rv
fun2 = lambda x: 2.659*(-1.857+1.040/x)+Rv
ff11, ff12 = fun1(0.11), fun1(0.12)
slope1=(ff12-ff11)/0.01
ff99, ff100 = fun2(2.19), fun2(2.2)
slope2=(ff100-ff99)/0.01
sw0 = sw[sw<0.12]
sw1 = sw[np.logical_and(sw>=0.12, sw<=0.63)]
sw2 = sw[np.logical_and(sw>0.63, sw<=2.2)]
sw3 = sw[sw>2.2]
k_lambda0 = ff11+(sw0-0.11)*slope1
k_lambda1, k_lambda2 = fun1(sw1), fun2(sw2)
k_lambda3 = ff99+(sw3-2.19)*slope2
A_lambda = av*np.hstack([k_lambda0,k_lambda1,k_lambda2,k_lambda3])/Rv
A_lambda[A_lambda<0.0] = 0.0
flux = sf*10**(-0.4*A_lambda)
elif model==6: # Reddy et al (2015) for satr forming galaxies
Rv = 2.505
sw = sw*1.0e-04
fun1 = lambda x: -5.726+4.004/x-0.525/x**2+0.029/x**3+Rv
fun2 = lambda x: -2.672-0.010/x+1.532/x**2-0.412/x**3+Rv
ff11, ff12 = fun1(0.14), fun1(0.15)
slope1=(ff12-ff11)/0.01
ff99, ff100 = fun2(2.84), fun2(2.85)
slope2=(ff100-ff99)/0.01
sw0 = sw[sw<0.15]
sw1 = sw[np.logical_and(sw>=0.15, sw<0.60)]
sw2 = sw[np.logical_and(sw>=0.60, sw<2.85)]
sw3 = sw[sw>=2.85]
k_lambda0 = ff11+(sw0-0.14)*slope1
k_lambda1, k_lambda2 = fun1(sw1), fun2(sw2)
k_lambda3 = ff99+(sw3-2.84)*slope2
A_lambda = av*np.hstack([k_lambda0,k_lambda1,k_lambda2,k_lambda3])/Rv
A_lambda[A_lambda<0.0] = 0.0
flux = sf*10**(-0.4*A_lambda)
else:
print("!!! Please select a proper reddening model")
sys.exit(0)
return flux
###########################################
def __red(alan,al0,ga,c1,c2,c3,c4):
fun1 = lambda x: c3/(((x-(al0**2/x))**2)+ga*ga)
fun2 = lambda x,cc: cc*(0.539*((x-5.9)**2)+0.0564*((x-5.9)**3))
fun = lambda x,cc: c1+c2*x+fun1(x)+fun2(x,cc)
ala = alan*1.0e-04 #wavelength in microns
p = 1.0/ala
if np.size(p)>1:
p1, p2 = p[p>=5.9], p[p<5.9]
ff = np.append(fun(p1,c4), fun(p2,0.0))
elif np.size(p)==1:
if p<5.9: c4 = 0.0
ff = fun(p, c4)
else:
return
return ff
###########################################
def sed2mag(mag_i, sedCat, filter_list, redshift=0.0, av=0.0, redden=0):
# load the filters
nfilt = len(filter_list)
aflux = np.zeros(nfilt)
nid = -1
for k in range(nfilt):
if filter_list[k].filter_type == 'i':
nid = k
bandpass = filter_list[k].bandpass_full
ktrans = np.transpose(np.array([bandpass.wave_list*10.0, bandpass.func(bandpass.wave_list)]))
aflux[k], isedObs = tflux(ktrans, sedCat, redshift=redshift, av=av, redden=redden)
# normalize to i-band
aflux = aflux / aflux[nid]
# magnitudes in all filters
amag = -2.5*np.log10(aflux) + mag_i
spec = galsim.LookupTable(x=np.array(isedObs[0]), f=np.array(isedObs[1]), interpolant='nearest')
isedObs = galsim.SED(spec, wave_type='A', flux_type='1', fast=False)
return amag, isedObs
def eObs(e1,e2,g1,g2):
"""
Calculate the sheared (observed) ellipticity using the
intrinsic ellipticity and cosmic shear components.
Parameters:
e1, e2: scalar or numpy array
g1, g2: scalar or numpy array
Return:
Sheared (observed) ellipticity components, absolute value, and orientation
in format of scalar or numpy array
** NOTE: e1, e2, g1, and g2 should have the same dimensions.
"""
if np.isscalar(e1):
e1 = np.array([e1])
e2 = np.array([e2])
g1 = np.array([g1])
g2 = np.array([g2])
else:
e1 = e1.flatten()
e2 = e2.flatten()
g1 = g1.flatten()
g2 = g2.flatten()
# calculate the sheared (observed) ellipticity using complex rule
nobj = len(e1)
e1obs, e2obs = [], []
eeobs, theta = [], []
for i in range(nobj):
e = complex(e1[i], e2[i])
g = complex(g1[i], g2[i])
e, gg = abs(e), abs(g)
if gg<=1.0:
tt = e + g
bb = 1.0 + e*g.conjugate()
eobs = tt/bb
else:
tt = 1.0 + g*e.conjugate()
bb = e.conjugate() + g.conjugate()
eobs = tt/bb
# derive the orientation
dd = 0.5*np.arctan(abs(eobs.imag/eobs.real))*180.0/np.pi
if eobs.imag>0 and eobs.real>0: dd = dd
if eobs.imag>0 and eobs.real<0: dd = 90.0 - dd
if eobs.imag<0 and eobs.real>0: dd = 0.0 - dd
if eobs.imag<0 and eobs.real<0: dd = dd - 90.0
e1obs += [eobs.real]
e2obs += [eobs.imag]
eeobs += [abs(eobs)]
theta += [dd]
e1obs,e2obs,eeobs,theta = np.array(e1obs),np.array(e2obs),np.array(eeobs),np.array(theta)
if nobj == 1: e1obs,e2obs,eeobs,theta = e1obs[0],e2obs[0],eeobs[0],theta[0]
return e1obs, e2obs, eeobs, theta
def getObservedSED(sedCat, redshift=0.0, av=0.0, redden=0):
z = redshift + 1.0
sw, sf = sedCat[:,0], sedCat[:,1]
# reddening
sf = reddening(sw, sf, av=av, model=redden)
sw, sf = sw*z, sf*(z**3)
# lyman forest correction
sf = lyman_forest(sw, sf, redshift)
isedObs = (sw.copy(), sf.copy())
return isedObs
def integrate_sed_bandpass(sed, bandpass):
wave = np.linspace(bandpass.blue_limit, bandpass.red_limit, 1000) # in nm
flux_normalized = sed(wave)*bandpass(wave)
# print('in integrate_sed_bandpass', bandpass.blue_limit, bandpass.red_limit)
int_flux = np.trapz(y=flux_normalized, x=wave) * 10. # convert to photons s-1 m-2 A-1
return int_flux
def getABMAG(interFlux, bandpass):
throughtput = Table(np.array(np.array([bandpass.wave_list*10.0, bandpass.func(bandpass.wave_list)])).T, names=(['WAVELENGTH', 'SENSITIVITY']))
sWave = bandpass.blue_limit*10.0
eWave = bandpass.red_limit*10.0
# print('in getABMAG', sWave, eWave)
ABMAG_zero = getABMagAverageVal(
ABmag=0,
norm_thr=throughtput,
sWave=sWave,
eWave=eWave)
flux_ave = interFlux / (eWave-sWave)
ABMAG_spec = -2.5 * np.log10(flux_ave/ABMAG_zero)
return ABMAG_spec
def getABMagAverageVal(ABmag=20.,norm_thr=None, sWave=6840, eWave=8250):
"""
norm_thr: astropy.table, 2 colum, 'WAVELENGTH', 'SENSITIVITY'
Return:
the integerate flux of AB magnitude in the norm_thr(the throughtput of band), photos s-1 m-2 A-1
"""
inverseLambda = norm_thr['SENSITIVITY']/norm_thr['WAVELENGTH']
norm_thr_i = interpolate.interp1d(norm_thr['WAVELENGTH'], inverseLambda)
x = np.linspace(sWave,eWave, int(eWave)-int(sWave)+1)
y = norm_thr_i(x)
AverageLamdaInverse = np.trapz(y,x)/(eWave-sWave)
norm = 54798696332.52474 * pow(10.0, -0.4 * ABmag) * AverageLamdaInverse
# print('AverageLamdaInverse = ', AverageLamdaInverse)
# print('norm = ', norm)
return norm
def getNormFactorForSpecWithABMAG(ABMag=20., spectrum=None, norm_thr=None, sWave=6840, eWave=8250):
"""
Use AB magnitude system (zero point, fv = 3631 janskys) in the normal band(norm_thr) normalize the spectrum by inpute ABMag
Parameters
----------
spectrum: astropy.table, 2 colum, 'WAVELENGTH', 'FLUX'
norm_thr: astropy.table, 2 colum, 'WAVELENGTH', 'SENSITIVITY'
sWave: the start of norm_thr
eWave: the end of norm_thr
Return:
the normalization factor flux of AB system(fix a band and magnitude ) /the flux of inpute spectrum(fix a band)
"""
spectrumi = interpolate.interp1d(spectrum['WAVELENGTH'], spectrum['FLUX'])
norm_thri = interpolate.interp1d(norm_thr['WAVELENGTH'], norm_thr['SENSITIVITY'])
x = np.linspace(sWave,eWave, int(eWave)-int(sWave)+1)
y_spec = spectrumi(x)
y_thr = norm_thri(x)
y = y_spec*y_thr
specAve = np.trapz(y,x)/(eWave-sWave)
norm = getABMagAverageVal(ABmag=ABMag, norm_thr=norm_thr, sWave=sWave, eWave=eWave)
if specAve == 0:
return 0
# print('specAve = ', specAve)
return norm / specAve
def tag_sed(h5file, model_tag, teff=5000, logg=2, feh=0):
model_tag_str = model_tag.decode("utf-8").strip()
teff_grid = np.unique(h5file["teff"][model_tag_str])
logg_grid = np.unique(h5file["logg"][model_tag_str])
feh_grid = np.unique(h5file["feh"][model_tag_str])
close_teff = teff_grid[np.argmin(np.abs(teff_grid - teff))]
close_logg = logg_grid[np.argmin(np.abs(logg_grid - logg))]
if model_tag_str == "koester" or model_tag_str == "MC":
close_feh = 99
else:
close_feh = feh_grid[np.argmin(np.abs(feh_grid - feh))]
path = model_tag_str + f"_teff_{close_teff:.1f}_logg_{close_logg:.2f}_feh_{close_feh:.1f}"
wave = np.array(h5file["wave"][model_tag_str][()]).ravel()
flux = np.array(h5file["sed"][path][()]).ravel()
return path, wave, flux
\ No newline at end of file
from Config import ConfigDir, ReadConfig, ChipOutput
from Config.Header import generatePrimaryHeader, generateExtensionHeader
from Instrument import Telescope, Filter, FilterParam, FocalPlane, Chip
from MockObject import Catalog, MockObject, Star, Galaxy, Quasar, calculateSkyMap_split_g
from PSF import PSFGauss, PSFInterp, FieldDistortion
from _util import makeSubDir, getShearFiled, makeSubDir_PointingList
from astropy.time import Time as asTime
from astropy.io import fits
import numpy as np
import mpi4py.MPI as MPI
import galsim
import os, sys
import logging
import psutil
class Observation(object):
def __init__(self, input_cat_dir=None, work_dir=None, data_dir=None):
self.path_dict = ConfigDir(input_cat_dir, work_dir, data_dir)
self.config = ReadConfig(self.path_dict["config_file"])
self.tel = Telescope(optEffCurve_path=self.path_dict["mirror_file"]) # Currently the default values are hard coded in
self.focal_plane = FocalPlane(survey_type=self.config["survey_type"]) # Currently the default values are hard coded in
self.filter_param = FilterParam(filter_dir=self.path_dict["filter_dir"]) # Currently the default values are hard coded in
self.chip_list = []
self.filter_list = []
# if we want to apply field distortion?
if self.config["field_dist"].lower() == "y":
self.fd_model = FieldDistortion()
else:
self.fd_model = None
# Construct chips & filters:
nchips = self.focal_plane.nchip_x*self.focal_plane.nchip_y
for i in range(nchips):
chipID = i + 1
if self.focal_plane.isIgnored(chipID=chipID):
continue
# Make Chip & Filter lists
chip = Chip(chipID, ccdEffCurve_dir=self.path_dict["ccd_dir"], CRdata_dir=self.path_dict["CRdata_dir"], normalize_dir=self.path_dict["normalize_dir"], sls_dir=self.path_dict["sls_dir"], config=self.config) # currently there is no config file for chips
filter_id, filter_type = chip.getChipFilter()
filt = Filter(filter_id=filter_id, filter_type=filter_type, filter_param=self.filter_param, ccd_bandpass=chip.effCurve)
self.chip_list.append(chip)
self.filter_list.append(filt)
# Read catalog and shear(s)
self.g1_field, self.g2_field, self.nshear = getShearFiled(config=self.config)
def runOneChip(self, chip, filt, chip_output, wcs_fp=None, psf_model=None, pointing_ID=0, ra_cen=None, dec_cen=None, img_rot=None, exptime=150., input_cat_name=None, shear_cat_file=None, cat_dir=None, sed_dir=None):
if (ra_cen is None) or (dec_cen is None):
ra_cen = self.config["ra_center"]
dec_cen = self.config["dec_center"]
if img_rot is None:
img_rot = self.config["image_rot"]
if self.config["psf_model"] == "Gauss":
psf_model = PSFGauss(chip=chip)
elif self.config["psf_model"] == "Interp":
psf_model = PSFInterp(chip=chip)
else:
print("unrecognized PSF model type!!", flush=True)
# Get (extra) shear fields
if shear_cat_file is not None:
self.g1_field, self.g2_field, self.nshear = getShearFiled(config=self.config, shear_cat_file=shear_cat_file)
# Get WCS for the focal plane
if wcs_fp == None:
wcs_fp = self.focal_plane.getTanWCS(ra_cen, dec_cen, img_rot, chip.pix_scale)
# Create chip Image
chip.img = galsim.ImageF(chip.npix_x, chip.npix_y)
chip.img.setOrigin(chip.bound.xmin, chip.bound.ymin)
chip.img.wcs = wcs_fp
if chip.survey_type == "photometric":
sky_map = None
elif chip.survey_type == "spectroscopic":
skyfile = os.path.join(self.path_dict["data_dir"], 'skybackground/sky_emiss_hubble_50_50_A.dat')
sky_map = calculateSkyMap_split_g(xLen=chip.npix_x, yLen=chip.npix_y, blueLimit=filt.blue_limit, redLimit=filt.red_limit, skyfn=skyfile, conf=chip.sls_conf, pixelSize=chip.pix_scale, isAlongY=0)
# Load catalogues and templates
self.cat = Catalog(config=self.config, chip=chip, cat_dir=cat_dir, sed_dir=sed_dir, pRa=ra_cen, pDec=dec_cen, rotation=img_rot, template_dir=self.path_dict["template_dir"])
self.nobj = len(self.cat.objs)
# Loop over objects
missed_obj = 0
bright_obj = 0
dim_obj = 0
for j in range(self.nobj):
# if j >= 20:
# break
obj = self.cat.objs[j]
# Load SED
if obj.type == 'star':
normF = chip.normF_star
try:
obj.load_SED(
survey_type=chip.survey_type,
normFilter=normF,
target_filt=filt,
sed_lib=self.cat.tempSED_star)
except Exception as e:
print(e)
continue
elif obj.type == 'galaxy': # or obj.type == quasar
normF = chip.normF_galaxy
obj.load_SED(
sed_path=sed_dir,
survey_type=chip.survey_type,
sed_templates=self.cat.tempSed_gal,
normFilter=normF,
target_filt=filt)
elif obj.type == 'quasar':
normF = chip.normF_galaxy
obj.load_SED(
sed_path=sed_dir,
survey_type=chip.survey_type,
sed_templates=self.cat.tempSed_gal,
normFilter=normF,
target_filt=filt)
# Exclude very bright/dim objects (for now)
if filt.is_too_bright(mag=obj.getMagFilter(filt)):
# print("obj too birght!!", flush=True)
if obj.type != 'galaxy':
bright_obj += 1
obj.unload_SED()
continue
if filt.is_too_dim(mag=obj.getMagFilter(filt)):
# print("obj too dim!!", flush=True)
dim_obj += 1
obj.unload_SED()
# print(obj.getMagFilter(filt))
continue
if self.config["shear_method"] == "constant":
if obj.type == 'star':
g1, g2 = 0, 0
else:
g1, g2 = self.g1_field, self.g2_field
elif self.config["shear_method"] == "extra":
# TODO: every object with individual shear from input catalog(s)
g1, g2 = self.g1_field[j], self.g2_field[j]
pos_img, offset, local_wcs = obj.getPosImg_Offset_WCS(img=chip.img, fdmodel=self.fd_model, chip=chip, verbose=False)
if pos_img.x == -1 or pos_img.y == -1:
# Exclude object which is outside the chip area (after field distortion)
# print("obj missed!!")
missed_obj += 1
obj.unload_SED()
continue
# Draw object & update output catalog
try:
if chip.survey_type == "photometric":
isUpdated, pos_shear = obj.drawObj_multiband(
tel=self.tel,
pos_img=pos_img,
psf_model=psf_model,
bandpass_list=filt.bandpass_sub_list,
filt=filt,
chip=chip,
g1=g1,
g2=g2,
exptime=exptime)
elif chip.survey_type == "spectroscopic":
isUpdated, pos_shear = obj.drawObj_slitless(
tel=self.tel,
pos_img=pos_img,
psf_model=psf_model,
bandpass_list=filt.bandpass_sub_list,
filt=filt,
chip=chip,
g1=g1,
g2=g2,
exptime=exptime,
normFilter=normF)
if isUpdated:
# TODO: add up stats
chip_output.cat_add_obj(obj, pos_img, pos_shear, g1, g2)
pass
else:
# print("object omitted", flush=True)
continue
except Exception as e:
print(e)
pass
# Unload SED:
obj.unload_SED()
del obj
del psf_model
del self.cat
print("check running:1: pointing-{:} chip-{:} pid-{:} memory-{:6.2}GB".format(pointing_ID, chip.chipID, os.getpid(), (psutil.Process(os.getpid()).memory_info().rss / 1024 / 1024 / 1024) ), flush=True)
# Detector Effects
# ===========================================================
chip.img = chip.addNoise(config=self.config, tel=self.tel, filt=filt, img=chip.img, sky_map=sky_map)
chip.img = chip.addEffects(config=self.config, img=chip.img, chip_output=chip_output, filt=filt, pointing_ID=pointing_ID)
h_prim = generatePrimaryHeader(
xlen=chip.npix_x,
ylen=chip.npix_y,
pointNum = str(pointing_ID),
ra=ra_cen,
dec=dec_cen,
psize=chip.pix_scale,
row_num=chip.rowID,
col_num=chip.colID,
date=self.config["date_obs"],
time_obs=self.config["time_obs"])
h_ext = generateExtensionHeader(
xlen=chip.npix_x,
ylen=chip.npix_y,
ra=ra_cen,
dec=dec_cen,
pa=img_rot.deg,
gain=chip.gain,
readout=chip.read_noise,
dark=chip.dark_noise,
saturation=90000,
psize=chip.pix_scale,
row_num=chip.rowID,
col_num=chip.colID)
chip.img = galsim.Image(chip.img.array, dtype=np.uint16)
hdu1 = fits.PrimaryHDU(header=h_prim)
hdu2 = fits.ImageHDU(chip.img.array, header=h_ext)
hdu1 = fits.HDUList([hdu1, hdu2])
fname = os.path.join(chip_output.subdir, h_prim['FILENAME'] + '.fits')
hdu1.writeto(fname, output_verify='ignore', overwrite=True)
del chip.img
print("check running:2: pointing-{:} chip-{:} pid-{:} memory-{:6.2}GB".format(pointing_ID, chip.chipID, os.getpid(), (psutil.Process(os.getpid()).memory_info().rss / 1024 / 1024 / 1024) ), flush=True)
print("# objects that are too bright %d out of %d"%(bright_obj, self.nobj))
print("# objects that are too dim %d out of %d"%(dim_obj, self.nobj))
print("# objects that are missed %d out of %d"%(missed_obj, self.nobj))
def runExposure(self, ra_cen=None, dec_cen=None, pointing_ID=0, img_rot=None, exptime=150., input_cat_name=None, shear_cat_file=None, oneChip=None):
if (ra_cen == None) or (dec_cen == None):
ra_cen = self.config["ra_center"]
dec_cen = self.config["dec_center"]
if img_rot == None:
img_rot = self.config["image_rot"]
sub_img_dir, prefix = makeSubDir_PointingList(path_dict=self.path_dict, config=self.config, pointing_ID=pointing_ID)
# Loop over chips
for i in range(len(self.chip_list)):
chip = self.chip_list[i]
filt = self.filter_list[i]
# Just run one chip
if oneChip is not None:
if chip.chipID != oneChip:
continue
# Prepare output files
chip_output = ChipOutput(
config=self.config,
focal_plane=self.focal_plane,
chip=chip,
filt=filt,
exptime=exptime,
pointing_ID=pointing_ID,
subdir=sub_img_dir,
prefix=prefix)
self.runOneChip(
chip=chip,
filt=filt,
chip_output=chip_output,
pointing_ID = pointing_ID,
ra_cen=ra_cen,
dec_cen=dec_cen,
img_rot=img_rot,
exptime=exptime,
cat_dir=self.path_dict["cat_dir"],
sed_dir=self.path_dict["SED_dir"])
print("finished running chip#%d..."%(chip.chipID), flush=True)
def runExposure_MPI_PointingList(self, ra_cen=None, dec_cen=None, pRange=None, img_rot=None, exptime=150., input_cat_name=None, shear_cat_file=None):
comm = MPI.COMM_WORLD
ind_thread = comm.Get_rank()
num_thread = comm.Get_size()
nchips_per_fp = len(self.chip_list)
ra_cen = ra_cen[pRange]
dec_cen = dec_cen[pRange]
# The Starting pointing ID
if pRange is not None:
pStart = pRange[0]
else:
pStart = 0
for ipoint in range(len(ra_cen)):
for ichip in range(nchips_per_fp):
i = ipoint*nchips_per_fp + ichip
pointing_ID = pStart + ipoint
if i % num_thread != ind_thread:
continue
pid = os.getpid()
sub_img_dir, prefix = makeSubDir_PointingList(path_dict=self.path_dict, config=self.config, pointing_ID=pointing_ID)
chip = self.chip_list[ichip]
filt = self.filter_list[ichip]
print("running pointing#%d, chip#%d, at PID#%d..."%(pointing_ID, chip.chipID, pid), flush=True)
chip_output = ChipOutput(
config=self.config,
focal_plane=self.focal_plane,
chip=chip,
filt=filt,
exptime=exptime,
pointing_ID=pointing_ID,
subdir=sub_img_dir,
prefix=prefix)
self.runOneChip(
chip=chip,
filt=filt,
chip_output=chip_output,
pointing_ID = pointing_ID,
ra_cen=ra_cen[ipoint],
dec_cen=dec_cen[ipoint],
img_rot=img_rot,
exptime=exptime,
cat_dir=self.path_dict["cat_dir"],
sed_dir=self.path_dict["SED_dir"])
print("finished running chip#%d..."%(chip.chipID), flush=True)
\ No newline at end of file
import galsim
import numpy as np
class FieldDistortion(object):
def __init__(self, fdModel=None, fdModel_path=None):
if fdModel is None:
import pickle
if fdModel_path is not None:
with open(fdModel_path, "rb") as f:
self.fdModel = pickle.load(f)
else:
# with open("/data/simudata/CSSOSDataProductsSims/data/FieldDistModelv1.0.pickle", "rb") as f:
with open("/data/simudata/CSSOSDataProductsSims/data/FieldDistModelv2.0.pickle", "rb") as f:
self.fdModel = pickle.load(f)
else:
self.fdModel = fdModel
def isContainObj_FD(self, chip, pos_img):
ifdModel = self.fdModel["ccd" + chip.getChipLabel(chipID=chip.chipID)]["wave1"]
x, y = pos_img.x, pos_img.y
xLowI, xUpI, yLowI, yUpI = ifdModel["InterpLim"]
if (xLowI - x)*(xUpI - x) > 0 or (yLowI - y) * (yUpI - y) > 0:
return False
return True
def get_Distorted(self, chip, pos_img, bandpass=None):
""" Get the distored position for an undistorted image position
Parameters:
chip: A 'Chip' object representing the
chip we want to extract PSF from.
pos_img: A 'galsim.Position' object representing
the image position.
bandpass: A 'galsim.Bandpass' object representing
the wavelength range.
Returns:
pos_distorted: A 'galsim.Position' object representing
the distored position.
"""
if not self.isContainObj_FD(chip=chip, pos_img=pos_img):
return galsim.PositionD(-1, -1)
ifdModel = self.fdModel["ccd" + chip.getChipLabel(chipID=chip.chipID)]["wave1"]
x, y = pos_img.x, pos_img.y
x = ifdModel["xImagePos"](x, y)[0][0]
y = ifdModel["yImagePos"](x, y)[0][0]
return galsim.PositionD(x, y)
import galsim
import sep
import numpy as np
from scipy.interpolate import interp1d
from .PSFModel import PSFModel
import os, sys
class PSFGauss(PSFModel):
def __init__(self, chip, fwhm=0.187, sigSpin=0., psfRa=0.15):
self.pix_size = chip.pix_scale
self.chip = chip
self.fwhm = fwhm
self.sigSpin = sigSpin
self.sigGauss = psfRa # 80% light radius
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)
frac = flux.tolist()
return frac
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 sys
import numpy as np
import scipy.io
from itertools import islice
from PSF.PSFInterp.PSFUtil import *
###加载PSF信息###
def LoadPSF(iccd, iwave, ipsf, psfPath, InputMaxPixelPos=True, PSFCentroidWgt=False, PixSizeInMicrons=2.5, PSFBinning=False, PSFConvGauss=False):
"""
load psf informations from psf matrix.
Parameters:
iccd (int): ccd number [1,30].
iwave(int): wave-index [1,4].
ipsf (int): psf number [1, 100].
psfPath (int): path to psf matrix
InputMaxPixelPos(bool-optional): only True for 30*30 psf-matrix
PSFCentroidWgt(bool-optional): True for using psfMat with libCentroid.lib
Returns:
psfInfo (dirctionary)
"""
if iccd not in np.linspace(1, 30, 30, dtype='int'):
print('Error - iccd should be in [1, 30].')
sys.exit()
if iwave not in np.linspace(1, 4, 4, dtype='int'):
print('Error - iwave should be in [1, 4].')
sys.exit()
if ipsf not in np.linspace(1, 900, 900, dtype='int'):
print('Error - ipsf should be in [1, 900].')
sys.exit()
psfInfo = {}
fpath = psfPath +'/' +'ccd{:}'.format(iccd) +'/' + 'wave_{:}'.format(iwave)
#获取ipsf矩阵
'''
if not PSFCentroidWgt:
##读取PSF原数据
fpathMat = fpath +'/' +'5_psf_array' +'/' +'psf_{:}.mat'.format(ipsf)
data = scipy.io.loadmat(fpathMat)
psfInfo['psfMat'] = data['psf']
if PSFCentroidWgt:
##读取PSFCentroidWgt
ffpath = psfPath +'_proc/' +'ccd{:}'.format(iccd) +'/' + 'wave_{:}'.format(iwave)
ffpathMat = ffpath +'/' +'5_psf_array' +'/' +'psf_{:}_centroidWgt.mat'.format(ipsf)
data = scipy.io.loadmat(ffpathMat)
psfInfo['psfMat'] = data['psf']
'''
if not PSFCentroidWgt:
ffpath = fpath
ffpathMat = ffpath +'/5_psf_array/psf_{:}.mat'.format(ipsf)
if PSFCentroidWgt:
ffpath = psfPath +'_proc/ccd{:}/wave_{:}'.format(iccd, iwave)
ffpathMat = ffpath +'/5_psf_array/psf_{:}_centroidWgt.mat'.format(ipsf)
if PSFBinning and (not PSFConvGauss):
ffpath = psfPath +'_bin256x256/ccd{:}/wave_{:}'.format(iccd, iwave)
ffpathMat = ffpath +'/5_psf_array/psf_{:}_centroidWgt.mat'.format(ipsf)
if (not PSFBinning) and PSFConvGauss:
ffpath = psfPath +'_convGauss/ccd{:}/wave_{:}'.format(iccd, iwave)
ffpathMat = ffpath +'/5_psf_array/psf_{:}_centroidWgt.mat'.format(ipsf)
if PSFBinning and PSFConvGauss:
ffpath = psfPath +'_convGauss/ccd{:}/wave_{:}'.format(iccd, iwave)
ffpathMat = ffpath +'/5_psf_array/psf_{:}_centroidWgt_BC.mat'.format(ipsf)
data = scipy.io.loadmat(ffpathMat)
psfInfo['psfMat'] = data['psf']
psfInfo['pixsize'] = PixSizeInMicrons #microns
if PSFBinning:
psfInfo['pixsize'] = PixSizeInMicrons*2.0
#获取ipsf波长
fpathWave = fpath +'/' +'1_wavelength.txt'
f = open(fpathWave, 'r')
wavelength = np.float(f.readline())
f.close()
psfInfo['wavelength'] = wavelength
#获取ipsf位置
fpathCoordinate = fpath +'/' +'4_PSF_coordinate.txt'
f = open(fpathCoordinate, 'r')
header = f.readline()
for line in islice(f, ipsf-1, ipsf):
line = line.strip()
columns = line.split()
f.close()
icol = 0
psfInfo['field_x'] = float(columns[icol]) #deg, 视场采样位置
icol+= 1
psfInfo['field_y'] = float(columns[icol]) #deg
icol+= 1
psfInfo['centroid_x'] = float(columns[icol]) #mm, psf质心相对主光线的偏移量
icol+= 1
psfInfo['centroid_y'] = float(columns[icol]) #mm
icol+= 1
if InputMaxPixelPos == True:
psfInfo['max_x'] = float(columns[icol]) #mm, max pixel postion
icol+= 1
psfInfo['max_y'] = float(columns[icol]) #mm
icol+= 1
psfInfo['image_x'] = float(columns[icol]) #mm, 主光线位置
icol+= 1
psfInfo['image_y'] = float(columns[icol]) #mm
if PSFCentroidWgt:
psfInfo['centroid_x'] = data['cx'][0][0] #mm, psfCentroidWgt质心相对主光线的偏移量
psfInfo['centroid_y'] = data['cy'][0][0] #mm
if PSFBinning:
psfInfo['centroid_x'] = data['cx'][0][0] +0.0025/2 #binning引起的主光线漂移
psfInfo['centroid_y'] = data['cy'][0][0] +0.0025/2
return psfInfo
###插值PSF图像-IDW方法###
def psfMaker_IDW(px, py, PSFMat, cen_col, cen_row, IDWindex=2, OnlyNeighbors=True, hoc=None, hoclist=None, PSFCentroidWgt=False):
"""
psf interpolation by IDW
Parameters:
px, py (float, float): position of the target
PSFMat (numpy.array): image
cen_col, cen_row (numpy.array, numpy.array): potions of the psf centers
IDWindex (int-optional): the power index of IDW
OnlyNeighbors (bool-optional): only neighbors are used for psf interpolation
Returns:
psfMaker (numpy.array)
"""
minimum_psf_weight = 1e-8
ref_col = px
ref_row = py
ngy, ngx = PSFMat[0, :, :].shape
npsf = PSFMat[:, :, :].shape[0]
psfWeight = np.zeros([npsf])
if OnlyNeighbors == True:
if hoc is None:
neigh = findNeighbors(px, py, cen_col, cen_row, dr=5., dn=4, OnlyDistance=False)
if hoc is not None:
neigh = findNeighbors_hoclist(cen_col, cen_row, tx=px,ty=py, dn=4, hoc=hoc, hoclist=hoclist)
neighFlag = np.zeros(npsf)
neighFlag[neigh] = 1
for ipsf in range(npsf):
if OnlyNeighbors == True:
if neighFlag[ipsf] != 1:
continue
dist = np.sqrt((ref_col - cen_col[ipsf])**2 + (ref_row - cen_row[ipsf])**2)
if IDWindex == 1:
psfWeight[ipsf] = dist
if IDWindex == 2:
psfWeight[ipsf] = dist**2
if IDWindex == 3:
psfWeight[ipsf] = dist**3
if IDWindex == 4:
psfWeight[ipsf] = dist**4
psfWeight[ipsf] = max(psfWeight[ipsf], minimum_psf_weight)
psfWeight[ipsf] = 1./psfWeight[ipsf]
psfWeight /= np.sum(psfWeight)
psfMaker = np.zeros([ngy, ngx], dtype=np.float32)
for ipsf in range(npsf):
if OnlyNeighbors == True:
if neighFlag[ipsf] != 1:
continue
iPSFMat = PSFMat[ipsf, :, :].copy()
ipsfWeight = psfWeight[ipsf]
psfMaker += iPSFMat * ipsfWeight
psfMaker /= np.nansum(psfMaker)
return psfMaker
###TEST###
if __name__ == '__main__':
iccd = 1
iwave= 1
ipsf = 1
psfPath = '/data/simudata/CSSOSDataProductsSims/data/csstPSFdata/CSSOS_psf_20210108/CSST_psf_ciomp_2p5um_cycle3_ccr90'
psfInfo = LoadPSF(iccd, iwave, ipsf, psfPath, InputMaxPixelPos=True, PSFCentroidWgt=True)
print('psfInfo.keys:', psfInfo.keys())
print(psfInfo)
'''
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
'''
import galsim
import numpy as np
import os
import time
import copy
import PSF.PSFInterp.PSFConfig as myConfig
import PSF.PSFInterp.PSFUtil as myUtil
from PSF.PSFModel import PSFModel
LOG_DEBUG = False #***#
NPSF = 900 #***# 30*30
iccdTest = 1 #***#
class PSFInterp(PSFModel):
# def __init__(self, PSF_data=None, params=None, PSF_data_file=None):
def __init__(self, chip, PSF_data=None, PSF_data_file=None, sigSpin=0, psfRa=0.15):
"""
The PSF data matrix is either given by a object parameter or read in from a file.
Parameters:
PSF_data: The PSF data matrix object
params: Other parameters?
PSF_data_file: The file for PSF data matrix (optional).
"""
if LOG_DEBUG:
print('===================================================')
print('DEBUG: psf module for csstSim ' \
+time.strftime("(%Y-%m-%d %H:%M:%S)", time.localtime()), flush=True)
print('===================================================')
self.sigSpin = sigSpin
self.sigGauss = psfRa
self.iccd = int(chip.getChipLabel(chipID=chip.chipID))
if PSF_data_file == None:
PSF_data_file = '/data/simudata/CSSOSDataProductsSims/data/csstPSFdata/CSSOS_psf_20210108/CSST_psf_ciomp_2p5um_cycle3_ccr90'
self.nwave= self._getPSFwave(self.iccd, PSF_data_file)
self.PSF_data = self._loadPSF(self.iccd, PSF_data_file)
if LOG_DEBUG:
print('nwave-{:} on ccd-{:}::'.format(self.nwave, self.iccd), flush=True)
print('self.PSF_data ... ok', 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, NPSF, ngy, ngx], dtype=np.float32)
self.cen_col= np.zeros([self.nwave, NPSF], dtype=np.float32)
self.cen_row= np.zeros([self.nwave, NPSF], dtype=np.float32)
self.hoc =[]
self.hoclist=[]
for twave in range(self.nwave):
for tpsf in range(NPSF):
self.psfMat[twave, tpsf, :, :] = 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.cen_col[twave, tpsf] = self.PSF_data[twave][tpsf]['image_x'] +0.*self.pixsize + self.PSF_data[twave][tpsf]['centroid_x']
self.cen_row[twave, tpsf] = self.PSF_data[twave][tpsf]['image_y'] +0.*self.pixsize + self.PSF_data[twave][tpsf]['centroid_y']
#hoclist on twave for neighborsFinding
hoc,hoclist = myUtil.findNeighbors_hoclist(self.cen_col[twave], self.cen_row[twave])
self.hoc.append(hoc)
self.hoclist.append(hoclist)
if LOG_DEBUG:
print('ok', flush=True)
def _getPSFwave(self, iccd, PSF_data_file):
"""
Get # of sampling waves on iccd
Parameters:
iccd: The chip of i-th ccd
PSF_data_file: The file for PSF data matrix
Returns:
nwave: The number of the sampling waves
"""
strs = os.listdir(PSF_data_file + '/ccd{:}'.format(iccd))
nwave = 0
for _ in strs:
if 'wave_' in _:
nwave += 1
return nwave
def _loadPSF(self, iccd, PSF_data_file):
"""
load psf-matrix on iccd
Parameters:
iccd: The chip of i-th ccd
PSF_data_file: The file for PSF data matrix
Returns:
psfSet: The matrix of the csst-psf
"""
psfSet = []
for ii in range(self.nwave):
iwave = ii+1
if LOG_DEBUG:
print('self._loadPSF: iwave::', iwave, flush=True)
psfWave = []
for jj in range(NPSF):
ipsf = jj+1
psfInfo = myConfig.LoadPSF(iccd, iwave, ipsf, PSF_data_file, InputMaxPixelPos=True, PSFCentroidWgt=True, PSFBinning=True, PSFConvGauss=True)
psfWave.append(psfInfo)
psfSet.append(psfWave)
if LOG_DEBUG:
print('psfSet has been loaded:', flush=True)
print('psfSet[iwave][ipsf][keys]:', psfSet[0][0].keys(), flush=True)
return psfSet
def _preprocessPSF(self):
pass
def _findWave(self, bandpass):
for twave in range(self.nwave):
bandwave = self.PSF_data[twave][0]['wavelength']
if bandpass.blue_limit < bandwave and bandwave < bandpass.red_limit:
return twave
return -1
def get_PSF(self, chip, pos_img, bandpass, pixSize=0.0184, galsimGSObject=True, findNeighMode='treeFind', folding_threshold=5.e-3):
"""
Get the PSF at a given image position
Parameters:
chip: A 'Chip' object representing the chip we want to extract PSF from.
pos_img: A 'galsim.Position' object representing the image position.
bandpass: A 'galsim.Bandpass' object representing the wavelength range.
pixSize: The pixels size of psf matrix
findNeighMode: 'treeFind' or 'hoclistFind'
Returns:
PSF: A 'galsim.GSObject'.
"""
pixSize = np.rad2deg(self.pixsize*1e-3/28)*3600 #set psf pixsize
#***# assert self.iccd == chip.chipID, 'ERROR: self.iccd != chip.chipID'
# twave = bandpass-1 #***# ??? #self.findWave(bandpass) ###twave=iwave-1 as that in NOTE
assert self.iccd == int(chip.getChipLabel(chipID=chip.chipID)), 'ERROR: self.iccd != chip.chipID'
twave = self._findWave(bandpass)
if twave == -1:
print("!!!PSF bandpass does not match.")
exit()
PSFMat = self.psfMat[twave]
cen_col= self.cen_col[twave]
cen_row= self.cen_row[twave]
# px = pos_img[0]
# py = pos_img[1]
px = (pos_img.x - chip.cen_pix_x)*0.01
py = (pos_img.y - chip.cen_pix_y)*0.01
if findNeighMode == 'treeFind':
imPSF = myConfig.psfMaker_IDW(px, py, PSFMat, cen_col, cen_row, IDWindex=2, OnlyNeighbors=True, PSFCentroidWgt=True)
if findNeighMode == 'hoclistFind':
imPSF = myConfig.psfMaker_IDW(px, py, PSFMat, cen_col, cen_row, IDWindex=2, OnlyNeighbors=True, hoc=self.hoc[twave], hoclist=self.hoclist[twave], PSFCentroidWgt=True)
if galsimGSObject:
img = galsim.ImageF(imPSF, scale=pixSize)
gsp = galsim.GSParams(folding_threshold=folding_threshold)
self.psf = galsim.InterpolatedImage(img, gsparams=gsp)
gaussPSF = galsim.Gaussian(sigma=0.04, gsparams=gsp)
self.psf = galsim.Convolve(gaussPSF, self.psf)
return self.PSFspin(x=px/0.01, y=py/0.01)
return imPSF
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)
qr = np.sqrt((1.0+ell)/(1.0-ell))
PSFshear = galsim.Shear(e=ell, beta=beta*galsim.radians)
return self.psf.shear(PSFshear), PSFshear
if __name__ == '__main__':
if True:
psfPath = '/data/simudata/CSSOSDataProductsSims/data/csstPSFdata/CSSOS_psf_20210108/CSST_psf_ciomp_2p5um_cycle3_ccr90'
psfCSST = PSFInterp(PSF_data_file = psfPath)
iwave= 1
ipsf = 665
pos_img = [psfCSST.cen_col[iwave, ipsf], psfCSST.cen_row[iwave, ipsf]]
img = psfCSST.get_PSF(1, pos_img, iwave, galsimGSObject=True)
print('haha')
if False:
#old version (discarded)
#plot check-1
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(18,5))
ax = plt.subplot(1,3,1)
plt.imshow(img)
plt.colorbar()
ax = plt.subplot(1,3,2)
imgx = psfCSST.itpPSF_data[iwave][ipsf]['psfMat']
imgx/= np.sum(imgx)
plt.imshow(imgx)
plt.colorbar()
ax = plt.subplot(1,3,3)
plt.imshow(img - imgx)
plt.colorbar()
plt.savefig('test/figs/test1.jpg')
if False:
#old version (discarded)
#plot check-2: 注意图像坐标和全局坐标
fig = plt.figure(figsize=(8,8), dpi = 200)
img = psfCSST.PSF_data[iwave][ipsf]['psfMat']
npix = img.shape[0]
dng = 105
imgg = img[dng:-dng, dng:-dng]
plt.imshow(imgg)
imgX = psfCSST.PSF_data[iwave][ipsf]['image_x'] #in mm
imgY = psfCSST.PSF_data[iwave][ipsf]['image_y'] #in mm
deltX= psfCSST.PSF_data[iwave][ipsf]['centroid_x'] #in mm
deltY= psfCSST.PSF_data[iwave][ipsf]['centroid_y'] #in mm
maxX = psfCSST.PSF_data[iwave][ipsf]['max_x']
maxY = psfCSST.PSF_data[iwave][ipsf]['max_y']
cenPix_X = npix/2 + deltX/0.005
cenPix_Y = npix/2 - deltY/0.005
maxPix_X = npix/2 + maxX/0.005-1
maxPix_Y = npix/2 - maxY/0.005-1
plt.plot([cenPix_X-dng],[cenPix_Y-dng], 'rx', ms = 20)
plt.plot([maxPix_X-dng],[maxPix_Y-dng], 'b+', ms=20)
from scipy import ndimage
y, x = ndimage.center_of_mass(img)
plt.plot([x-dng],[y-dng], 'rx', ms = 10, mew=4)
x, y = myUtil.findMaxPix(img)
plt.plot([x-dng],[y-dng], 'b+', ms = 10, mew=4)
plt.savefig('test/figs/test2.jpg')
import os, sys
import numpy as np
import scipy.io
import mpi4py.MPI as MPI
#sys.path.append("/public/home/weichengliang/lnData/CSST_new_framwork/csstPSF_20201222")
import PSFConfig as myConfig
import PSFUtil as myUtil
def mkdir(path):
isExists = os.path.exists(path)
if not isExists:
os.mkdir(path)
############################################
comm = MPI.COMM_WORLD
ThisTask = comm.Get_rank()
NTasks = comm.Get_size()
npsf = 900
psfPath = '/data/simudata/CSSOSDataProductsSims/data/csstPSFdata/CSSOS_psf_20210108/CSST_psf_ciomp_2p5um_cycle3_ccr90'
npsfPerTasks = int(npsf/NTasks)
iStart= 0 + npsfPerTasks*ThisTask
iEnd = npsfPerTasks + npsfPerTasks*ThisTask
if ThisTask == NTasks:
iEnd = npsf
for iccd in range(1, 31):
iccdPath = psfPath + '_proc/ccd{:}'.format(iccd)
if ThisTask == 0:
mkdir(iccdPath)
comm.barrier()
for iwave in range(1, 5):
iwavePath = iccdPath + '/wave_{:}'.format(iwave)
if ThisTask == 0:
mkdir(iwavePath)
comm.barrier()
psfMatPath = iwavePath + '/5_psf_array'
if ThisTask == 0:
mkdir(psfMatPath)
comm.barrier()
for ii in range(iStart, iEnd):
ipsf = ii+1
if ThisTask ==0:
print('iccd-iwave-ipsf: {:4}{:4}{:4}'.format(iccd, iwave, ipsf), end='\r',flush=True)
#if iccd != 1 or iwave !=1 or ipsf != 1:
# continue
ipsfOutput = psfMatPath + '/psf_{:}_centroidWgt.mat'.format(ipsf)
psfInfo = myConfig.LoadPSF(iccd, iwave, ipsf, psfPath, InputMaxPixelPos=True)
ipsfMat = psfInfo['psfMat']
npix_y, npix_x = ipsfMat.shape
#if npsf == 100:
# ncut = 160
#if npsf == 900:
# ncut = 200
ncut = int(npix_y*0.90)
ncut = ncut + ncut%2 #even pixs
img, cx, cy = myUtil.centroidWgt(ipsfMat, nt=ncut)
dcx = cx - npix_x/2 #pixel coords -> global coords
dcy = cy - npix_y/2 #pixel coords -> global coords
dcx*= psfInfo['pixsize']*1e-3 #5e-3 #pixels -> mm
dcy*= psfInfo['pixsize']*1e-3 #5e-3 #pixels -> mm
nn = npix_y
dn = int((nn - ncut)/2)
imgt = np.zeros([nn, nn], dtype=np.float32)
imgt[dn:-dn, dn:-dn] = img
scipy.io.savemat(ipsfOutput, {'cx':dcx, 'cy':dcy, 'psf':imgt})
if iccd != 1 or iwave !=1 or ipsf != 1:
if ThisTask == 0:
print('CHECK::', dcx, dcy, psfInfo['centroid_x'],psfInfo['centroid_y'])
import sys
import ctypes
import numpy as np
from scipy import ndimage
import scipy.spatial as spatial
###定义PSF像素的全局坐标###
def psfPixelLayout(nrows, ncols, cenPosRow, cenPosCol, pixSizeInMicrons=5.0):
"""
convert psf pixels to physical position
Parameters:
nrows, ncols (int, int): psf sampling with [nrows, ncols].
cenPosRow, cenPosCol (float, float): A physical position of the chief ray for a given psf.
pixSizeInMicrons (float-optional): The pixel size in microns from the psf sampling.
Returns:
psfPixelPos (numpy.array-float): [posx, posy] in mm for [irow, icol]
Notes:
1. show positions on ccd, but not position on image only [+/- dy]
"""
psfPixelPos = np.zeros([2, nrows, ncols])
if nrows % 2 != 0:
sys.exit()
if ncols % 2 != 0:
sys.exit()
cenPix_row = nrows/2 + 1 #中心主光线对应pixle [由长光定义]
cenPix_col = ncols/2 + 1
for irow in range(nrows):
for icol in range(ncols):
delta_row = ((irow + 1) - cenPix_row)*pixSizeInMicrons*1e-3
delta_col = ((icol + 1) - cenPix_col)*pixSizeInMicrons*1e-3
psfPixelPos[0, irow, icol] = cenPosCol + delta_col
psfPixelPos[1, irow, icol] = cenPosRow - delta_row #note-1:in CCD全局坐标
return psfPixelPos
###查找最大pixel位置###
def findMaxPix(img):
"""
get the pixel position of the maximum-value
Parameters:
img (numpy.array-float): image
Returns:
imgMaxPix_x, imgMaxPix_y (int, int): pixel position in columns & rows
"""
maxIndx = np.argmax(img)
maxIndx = np.unravel_index(maxIndx, np.array(img).shape)
imgMaxPix_x = maxIndx[1]
imgMaxPix_y = maxIndx[0]
return imgMaxPix_x, imgMaxPix_y
###查找neighbors位置###
def findNeighbors(tx, ty, px, py, dr=0.1, dn=1, OnlyDistance=True):
"""
find nearest neighbors by 2D-KDTree
Parameters:
tx, ty (float, float): a given position
px, py (numpy.array, numpy.array): position data for tree
dr (float-optional): distance
dn (int-optional): nearest-N
OnlyDistance (bool-optional): only use distance to find neighbors. Default: True
Returns:
dataq (numpy.array): index
"""
datax = px
datay = py
tree = spatial.KDTree(list(zip(datax.ravel(), datay.ravel())))
dataq=[]
rr = dr
if OnlyDistance == True:
dataq = tree.query_ball_point([tx, ty], rr)
if OnlyDistance == False:
while len(dataq) < dn:
dataq = tree.query_ball_point([tx, ty], rr)
rr += dr
dd = np.hypot(datax[dataq]-tx, datay[dataq]-ty)
ddSortindx = np.argsort(dd)
dataq = np.array(dataq)[ddSortindx[0:dn]]
return dataq
###查找neighbors位置-hoclist###
def hocBuild(partx, party, nhocx, nhocy, dhocx, dhocy):
if np.max(partx) > nhocx*dhocx:
print('ERROR')
sys.exit()
if np.max(party) > nhocy*dhocy:
print('ERROR')
sys.exit()
npart = partx.size
hoclist= np.zeros(npart, dtype=np.int32)-1
hoc = np.zeros([nhocy, nhocx], dtype=np.int32)-1
for ipart in range(npart):
ix = int(partx[ipart]/dhocx)
iy = int(party[ipart]/dhocy)
hoclist[ipart] = hoc[iy, ix]
hoc[iy, ix] = ipart
return hoc, hoclist
def hocFind(px, py, dhocx, dhocy, hoc, hoclist):
ix = int(px/dhocx)
iy = int(py/dhocy)
neigh=[]
it = hoc[iy, ix]
while it != -1:
neigh.append(it)
it = hoclist[it]
return neigh
def findNeighbors_hoclist(px, py, tx=None,ty=None, dn=4, hoc=None, hoclist=None):
nhocy = nhocx = 20
pxMin = np.min(px)
pxMax = np.max(px)
pyMin = np.min(py)
pyMax = np.max(py)
dhocx = (pxMax - pxMin)/(nhocx-1)
dhocy = (pyMax - pyMin)/(nhocy-1)
partx = px - pxMin +dhocx/2
party = py - pyMin +dhocy/2
if hoc is None:
hoc, hoclist = hocBuild(partx, party, nhocx, nhocy, dhocx, dhocy)
return hoc, hoclist
if hoc is not None:
tx = tx - pxMin +dhocx/2
ty = ty - pyMin +dhocy/2
itx = int(tx/dhocx)
ity = int(ty/dhocy)
ps = [-1, 0, 1]
neigh=[]
for ii in range(3):
for jj in range(3):
ix = itx + ps[ii]
iy = ity + ps[jj]
if ix < 0:
continue
if iy < 0:
continue
if ix > nhocx-1:
continue
if iy > nhocy-1:
continue
#neightt = myUtil.hocFind(ppx, ppy, dhocx, dhocy, hoc, hoclist)
it = hoc[iy, ix]
while it != -1:
neigh.append(it)
it = hoclist[it]
#neigh.append(neightt)
#ll = [i for k in neigh for i in k]
if dn != -1:
ptx = np.array(partx[neigh])
pty = np.array(party[neigh])
dd = np.hypot(ptx-tx, pty-ty)
idx = np.argsort(dd)
neigh= np.array(neigh)[idx[0:dn]]
return neigh
###PSF中心对齐###
def psfCentering(img, apSizeInArcsec=0.5, psfSampleSizeInMicrons=5, focalLengthInMeters=28, CenteringMode=1):
"""
centering psf within an aperture
Parameters:
img (numpy.array): image
apSizeInArcsec (float-optional): aperture size in arcseconds.
psfSampleSizeInMicrons (float-optional): psf pixel size in microns.
focalLengthInMeters (float-optional): csst focal length im meters.
CenteringMode (int-optional): how to center psf images
Returns:
imgT (numpy.array)
"""
if CenteringMode == 1:
imgMaxPix_x, imgMaxPix_y = findMaxPix(img)
if CenteringMode == 2:
y,x = ndimage.center_of_mass(img) #y-rows, x-cols
imgMaxPix_x = int(x)
imgMaxPix_y = int(y)
apSizeInMicrons = np.deg2rad(apSizeInArcsec/3600.)*focalLengthInMeters*1e6
apSizeInPix = apSizeInMicrons/psfSampleSizeInMicrons
apSizeInPix = np.int(np.ceil(apSizeInPix))
imgT = np.zeros_like(img)
ngy, ngx = img.shape
cy = int(ngy/2)
cx = int(ngx/2)
imgT[cy-apSizeInPix:cy+apSizeInPix+1,
cx-apSizeInPix:cx+apSizeInPix+1] = \
img[imgMaxPix_y-apSizeInPix:imgMaxPix_y+apSizeInPix+1,
imgMaxPix_x-apSizeInPix:imgMaxPix_x+apSizeInPix+1]
return imgT
###插值对齐-fft###
def psfCentering_FFT(image):
"""
centering psf within an aperture by FFT
"""
ny, nx = image.shape
py, px = ndimage.center_of_mass(image)
dx = (px - nx/2)
dy = (py - ny/2)
k=np.zeros((nx,ny,2),dtype=float)
fg=np.fft.fft2(image)
ge =np.zeros_like(fg)
inx = int(nx/2)
jny = int(ny/2)
#prepare for the phase multiply matrix
#left bottom
for i in range(inx+1):
for j in range(jny+1):
k[i][j][0]=i;
k[i][j][1]=j;
#top right
for i in range(inx-1):
for j in range(jny-1):
k[i+inx+1][j+jny+1][0]=(-(nx/2-1)+i)
k[i+inx+1][j+jny+1][1]=(-(ny/2-1)+j)
#bottom right
for i in range(inx+1):
for j in range(jny-1):
k[i][j+jny+1][0]=i
k[i][j+jny+1][1]=(-(ny/2-1)+j)
#top left
for i in range(inx-1):
for j in range(int(jny+1)):
k[i+inx+1][j][0]=(-(nx/2-1)+i)
k[i+inx+1][j][1]=j
for i in range(nx):
for j in range(ny):
ge[i][j]=fg[i][j]*np.exp(2.*np.pi*(dx*k[i][j][0]/nx+dy*k[i][j][1]/ny)*1j)
get=np.fft.ifft2(ge).real
return(get)
###图像叠加###
def psfStack(*psfMat):
"""
stacked image from the different psfs
Parameters:
*psfMat (numpy.array): the different psfs for stacking
Returns:
img (numpy.array): image
"""
nn = len(psfMat)
img = np.zeros_like(psfMat[0])
for ii in range(nn):
img += psfMat[ii]/np.sum(psfMat[ii])
img /= np.sum(img)
return img
###计算PSF椭率-接口###
def psfSizeCalculator(psfMat, psfSampleSize=2.5, CalcPSFcenter=True, SigRange=True, TailorScheme=2, cenPix=None):
"""
calculate psf size & ellipticity
Parameters:
psfMat (numpy.array): image
psfSampleSize (float-optional): psf size in microns.
CalcPSFcenter (bool-optional): whether calculate psf center. Default: True
SigRange (bool-optional): whether use psf tailor. Default: False
TailorScheme (int-optional): which method for psf tailor. Default: 1
Returns:
cenX, cenY (float, float): the pixel position of the mass center
sz (float): psf size
e1, e2 (float, float): psf ellipticity
REE80 (float): radius of REE80 in arcseconds
"""
psfSampleSize = psfSampleSize*1e-3 #mm
REE80 = -1.0 ##encircling 80% energy
if SigRange is True:
if TailorScheme == 1:
psfMat = imSigRange(psfMat, fraction=0.80)
psfInfo['psfMat'] = psfMat #set on/off
if TailorScheme == 2:
#img = psfTailor(psfMat, apSizeInArcsec=0.5)
imgX, REE80 = psfEncircle(psfMat, cenPix=cenPix)
#psfMat = img
REE80 = REE80[0]
if CalcPSFcenter is True:
img = psfMat/np.sum(psfMat)
y,x = ndimage.center_of_mass(img) #y-rows, x-cols
cenX = x
cenY = y
if CalcPSFcenter is False:
cenPix_X = psfMat.shape[1]/2 #90
cenPix_Y = psfMat.shape[0]/2 #90
cenX = cenPix_X + psfInfo['centroid_x']/psfSampleSize
cenY = cenPix_Y - psfInfo['centroid_y']/psfSampleSize
pixSize = 1
sz, e1, e2 = psfSecondMoments(psfMat, cenX, cenY, pixSize=pixSize)
return cenX, cenY, sz, e1, e2, REE80
###计算PSF椭率###
def psfSecondMoments(psfMat, cenX, cenY, pixSize=1):
"""
estimate the psf ellipticity by the second moment of surface brightness
Parameters:
psfMat (numpy.array-float): image
cenX, cenY (float, float): pixel position of the psf center
pixSize (float-optional): pixel size
Returns:
sz (float): psf size
e1, e2 (float, float): psf ellipticity
"""
apr = 0.5 #arcsec, 0.5角秒内测量
fl = 28. #meters
pxs = 5.0 #microns
apr = np.deg2rad(apr/3600.)*fl*1e6
apr = apr/pxs
apr = np.int(np.ceil(apr))
I = psfMat
ncol = I.shape[1]
nrow = I.shape[0]
w = 0.0
w11 = 0.0
w12 = 0.0
w22 = 0.0
for icol in range(ncol):
for jrow in range(nrow):
x = icol*pixSize - cenX
y = jrow*pixSize - cenY
rr = np.sqrt(x*x + y*y)
wgt= 0.0
if rr <= apr:
wgt = 1.0
w += I[jrow, icol]*wgt
w11 += x*x*I[jrow, icol]*wgt
w12 += x*y*I[jrow, icol]*wgt
w22 += y*y*I[jrow, icol]*wgt
w11 /= w
w12 /= w
w22 /= w
sz = w11 + w22
e1 = (w11 - w22)/sz
e2 = 2.0*w12/sz
return sz, e1, e2
###计算REE80###
def psfEncircle(img, fraction=0.8, psfSampleSizeInMicrons=2.5, focalLengthInMeters=28, cenPix=None):
"""
psf tailor within a given percentage.
Parameters:
img (numpy.array-float): image
fraction (float-optional): a percentage for psf tailor.
psfSampleSizeInMicrons (float-optional): psf pixel size in microns.
focalLengthInMeters (float-optional): csst focal length im meters.
Returns:
img*wgt (numpy.array-float): image
REE80 (float): radius of REE80 in arcseconds.
"""
#imgMaxPix_x, imgMaxPix_y = findMaxPix(img)
y,x = ndimage.center_of_mass(img) #y-rows, x-cols
imgMaxPix_x = x #int(x)
imgMaxPix_y = y #int(y)
if cenPix != None:
imgMaxPix_x = cenPix[0]
imgMaxPix_y = cenPix[1]
im1 = img.copy()
im1size = im1.shape
dis = np.zeros_like(img)
for irow in range(im1size[0]):
for icol in range(im1size[1]):
dx = icol - imgMaxPix_x
dy = irow - imgMaxPix_y
dis[irow, icol] = np.hypot(dx, dy)
nn = im1size[1]*im1size[0]
disX = dis.reshape(nn)
disXsortId = np.argsort(disX)
imgX = img.reshape(nn)
imgY = imgX[disXsortId]
psfFrac = np.cumsum(imgY)/np.sum(imgY)
ind = np.where(psfFrac > fraction)[0][0]
wgt = np.ones_like(dis)
#wgt[np.where(dis > dis[np.where(img == imgY[ind])])] = 0
REE80 = np.rad2deg(dis[np.where(img == imgY[ind])]*psfSampleSizeInMicrons*1e-6/focalLengthInMeters)*3600
return img*wgt, REE80
###图像能量百分比查找###
def imSigRange(img, fraction=0.80):
"""
extract the image within x-percent (DISCARD)
Parameters:
img (numpy.array-float): image
fraction (float-optional): a percentage
Returns:
im1 (numpy.array-float): image
"""
im1 = img.copy()
im1size = im1.shape
im2 = np.sort(im1.reshape(im1size[0]*im1size[1]))
im2 = im2[::-1]
im3 = np.cumsum(im2)/np.sum(im2)
loc = np.where(im3 > fraction)
#print(im3[loc[0][0]], im2[loc[0][0]])
im1[np.where(im1 <= im2[loc[0][0]])]=0
return im1
###孔径内图像裁剪###
def psfTailor(img, apSizeInArcsec=0.5, psfSampleSizeInMicrons=5, focalLengthInMeters=28, cenPix=None):
"""
psf tailor within a given aperture size
Parameters:
img (numpy.array-float): image
apSizeInArcsec (float-optional): aperture size in arcseconds.
psfSampleSizeInMicrons (float-optional): psf pixel size in microns.
focalLengthInMeters (float-optional): csst focal length im meters.
Returns:
imgT (numpy.array-float): image
"""
#imgMaxPix_x, imgMaxPix_y = findMaxPix(img)
y,x = ndimage.center_of_mass(img) #y-rows, x-cols
imgMaxPix_x = int(x)
imgMaxPix_y = int(y)
if cenPix != None:
imgMaxPix_x = int(cenPix[0])
imgMaxPix_y = int(cenPix[1])
apSizeInMicrons = np.deg2rad(apSizeInArcsec/3600.)*focalLengthInMeters*1e6
apSizeInPix = apSizeInMicrons/psfSampleSizeInMicrons
apSizeInPix = np.int(np.ceil(apSizeInPix))
print('apSizeInPix=',apSizeInPix)
imgT = np.zeros_like(img)
imgT[imgMaxPix_y-apSizeInPix:imgMaxPix_y+apSizeInPix+1,
imgMaxPix_x-apSizeInPix:imgMaxPix_x+apSizeInPix+1] = \
img[imgMaxPix_y-apSizeInPix:imgMaxPix_y+apSizeInPix+1,
imgMaxPix_x-apSizeInPix:imgMaxPix_x+apSizeInPix+1]
return imgT
###centroid with a window###
def centroidWgt(img, nt=160):
#libCentroid = ctypes.CDLL('/public/home/weichengliang/lnData/CSST_new_framwork/csstPSF/libCentroid/libCentroid.so') # CDLL加载库
libCentroid = ctypes.CDLL('/public/home/weichengliang/lnData/CSST_new_framwork/csstPSF_20210108/libCentroid/libCentroid.so') # CDLL加载库
libCentroid.centroidWgt.argtypes = [ctypes.POINTER(ctypes.c_float), ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_double)]
libCentroid.imSplint.argtypes = [ctypes.POINTER(ctypes.c_float), ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_float)]
imx = img/np.sum(img)
ny, nx = imx.shape
#imx centroid
nn = nx*ny
arr = (ctypes.c_float*nn)()
arr[:] = imx.reshape(nn)
para = (ctypes.c_double*10)()
libCentroid.centroidWgt(arr, ny, nx, para)
imx_cy = para[3] #irow
imx_cx = para[4] #icol
#imx -> imy
nxt=nyt=nt
nn=nxt*nyt
yat = (ctypes.c_float*nn)()
libCentroid.imSplint(arr, ny, nx, para, nxt, nyt, yat)
imy = np.array(yat[:]).reshape([nxt, nyt])
return imy, imx_cx, imx_cy
'''
def psfCentering_wgt(ipsfMat, psf_image_x, psf_image_y, psfSampleSizeInMicrons=5.0):
img, cx, cy = centroidWgt(ipsfMat, nt=160)
nrows, ncols = ipsfMat.shape
cyt = (cy + nrows/2)*psfSampleSizeInMicrons*1e-3 +psf_image_y
cxt = (cx + ncols/2)*psfSampleSizeInMicrons*1e-3 +psf_image_x
return img, cxt, cyt
'''
###binning image###
def binningPSF(img, ngg):
imgX = img.reshape(ngg, img.shape[0]//ngg, ngg, img.shape[1]//ngg).mean(-1).mean(1)
return imgX
from .PSFInterp import PSFInterp
\ No newline at end of file
#OPTS += -D
CC = gcc
OPTIMIZE = -fPIC -g -O3 #-Wall -wd981 #-wd1419 -wd810
#GSLI = -I/home/alex/opt/gsl/include
#GSLL = -L/home/alex/opt/gsl/lib -lgsl -lgslcblas
#FFTWI = -I/home/alex/opt/fftw/include
#FFTWL = -L/home/alex/opt/fftw/lib -lfftw3 -lfftw3f
#HDF5I = -I/home/alex/opt/hdf5/include
#HDF5L = -L/home/alex/opt/hdf5/lib -lhdf5_hl -lhdf5
#FITSI = -I/home/alex/opt/cfitsio/include
#FITSL = -L/home/alex/opt/cfitsio/lib -lcfitsio
#EXTRACFLAGS =
#EXTRACLIB =
CLINK=$(CC)
CFLAGS=$(OPTIMIZE) #$(EXTRACFLAGS) $(OPTS)
CLIB= -shared -lm #$(EXTRACLIB)
OBJS = centroidWgt.o nrutil.o
EXEC = libCentroid.so
all: $(EXEC)
$(EXEC): $(OBJS)
$(CLINK) $(CFLAGS) -o $@ $(OBJS) $(CLIB)
$(OBJS): nrutil.h Makefile
.PHONY : clean
clean:
rm -f *.o $(EXEC)
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "nrutil.h"
//y is the input image, nx and ny are the pixels along x and y axis;
//yt and residu are the required matrix for the function
//para contains the needed parameters: centx=para[3], centy=para[4]
void star_gaus(float **y,int nx,int ny,double *para);
void Interp_bicubic(int nx,int ny,float **a0,int nbound, int nxt,int nyt, float **at,double *xcen);
void splie2(float **ya, int m, int n, float **y2a);
void spline(float y[], int n, float yp1, float ypn, float y2[]);
void splint(float ya[], float y2a[], int n, float x, float *y);
void centroidWgt(float *y, int nx, int ny, double *para)
{
int i, j, k;
float **yy;
double **basef;
double **coff;
double ccol, crow;
yy = matrix(0, nx-1, 0, ny-1);
for(i=0; i<nx; i++)
for(j=0; j<ny; j++)
{
k = j + i*nx;
yy[i][j] = y[k];
}
star_gaus(yy, nx, ny, para);
//ccol = para[4];
//crow = para[3];
}
void imSplint(float *y, int nx, int ny, double *para, int nxt, int nyt, float *yat)
{
int i, j, k;
float **yy;
double **basef;
double **coff;
double ccol, crow;
yy = matrix(0, nx-1, 0, ny-1);
for(i=0; i<nx; i++)
for(j=0; j<ny; j++)
{
k = j + i*nx;
yy[i][j] = y[k];
}
crow = para[3];
ccol = para[4];
int nbound;
float **at;
double xcen[2];
at = matrix(0, nxt-1, 0, nyt-1);
nbound = (int)((nx - nxt)/2);
xcen[0]= crow;
xcen[1]= ccol;
Interp_bicubic(nx, ny, yy, nbound, nxt, nyt, at, xcen);
for(i=0; i<nxt; i++)
for(j=0; j<nyt; j++)
{
k = j + i*nxt;
yat[k] = at[i][j];
}
}
//void star_gaus(float **y,int nx,int ny,float **yt,float **residu,double *para)
void star_gaus(float **y,int nx,int ny,double *para)
{
void gasfit_2D(double **x, double *y,int np,double *para,double bg0, int fbg);
double **xs,*ys,ymax;
int i,j,np,npt,im,jm,**xi,k;
double kc,bgc,sigmac,xc,yc,sigma2v,det;
double bg0=0;
int fbg=0;
np=nx*ny;
xs=dmatrix(0,np-1,0,1);
ys=dvector(0,np-1);
xi=imatrix(0,np-1,0,1);
ymax=y[0][0];
for(i=0;i<nx;i++)for(j=0;j<ny;j++){
if(ymax<y[i][j]){ymax=y[i][j];im=i;jm=j;}
}
int cutPix;
cutPix = 23;
npt=0;
for(i=-cutPix;i<=cutPix;i++){
for(j=-cutPix;j<=cutPix;j++){
xs[npt][0]=xi[npt][0]=i+im;
xs[npt][1]=xi[npt][1]=j+jm;
ys[npt]=y[im+i][jm+j];
npt++;
}
}
gasfit_2D(xs, ys,npt,para,bg0,fbg);
kc=para[0];sigmac=para[1];bgc=para[2];xc=para[3];yc=para[4];
// printf("%e %e %e %e %e\n",kc,sigmac,bgc,xc,yc);
/*
sigma2v=-1./(2.*sigmac*sigmac);
for(i=0;i<nx;i++){
for(j=0;j<ny;j++){
det=DSQR(i-xc)+DSQR(j-yc);
yt[i][j]=kc*exp(det*sigma2v)+bgc;
residu[i][j]=y[i][j]-yt[i][j];
}
}
*/
free_dmatrix(xs,0,np-1,0,1);
free_imatrix(xi,0,np-1,0,1);
free_dvector(ys,0,np-1);
}
void gasfit_2D(double **x, double *y,int np,double *para,double bg0,int fbg)
{
void search_2D(double **x,double *y,int np,double kc,double kd,double sigmac,
double sigmad,double bgc,double bgd,double xc, double xd,
double yc, double yd,double *para,double bg0,int fbg);
int i,j,k,imax=0,isigma;
double ymax,ymin,kc,kd,sigmac,sigmad,bgc,bgd,ysigma,xc,yc,xd,yd;
double det,dett;
ymin=ymax=y[imax];
for(i=1;i<np;i++){
if(ymax<y[i]){imax=i;ymax=y[i];}
if(ymin>y[i])ymin=y[i];
}
kc=ymax;kd=ymax/12.;
det=ysigma=kc*exp(-0.5);
for(i=0;i<np;i++){
dett=fabs(ysigma-y[i]);
if(dett<det && y[i]!=kc){det=dett;isigma=i;}
//if(dett<det){det=dett;isigma=i;}
}
xc=x[imax][0];yc=x[imax][1];
sigmac=sqrt(DSQR(xc-x[isigma][0])+DSQR(yc-x[isigma][1]))*1.;
xd=yd=sigmac*0.25;
sigmad=0.25*sigmac;
bgc=0.;bgd=fabs(ymin);
for(i=0;i<4;i++){
search_2D(x,y,np,kc,kd,sigmac,sigmad,bgc,bgd,xc,xd,yc,yd,para,bg0,fbg);
kd*=0.33;sigmad*=0.33;bgd*=0.33;xd*=0.33;yd*=0.33;
kc=para[0];sigmac=para[1];bgc=para[2];xc=para[3];yc=para[4];
}
if(fbg==0)para[2]=bg0;
}
void search_2D(double **x,double *y,int np,double kc,double kd,double sigmac,
double sigmad,double bgc,double bgd,double xc, double xd,
double yc, double yd,double *para,double bg0,int fbg)
{
double k,sigma,bg,k2,k20,sigma2v,det,xt,yt;
int i,j,l,m,p,q;
sigma2v=-1./(2.*sigmac*sigmac);
bg=bgc;
k20=0;
for(m=0;m<np;m++){
det=DSQR(x[m][0]-xc)+DSQR(x[m][1]-yc);
det=kc*exp(det*sigma2v)+bgc-y[m];
k20+=det*det;
}
for(i=-4;i<=4;i++){
k=kc+i*kd;
if(k>0){
for(j=-4;j<=4;j++){
sigma=sigmac+j*sigmad;
if(sigma>0){
sigma2v=-1./(2.*sigma*sigma);
for(p=-4;p<=4;p++){
xt=xc+p*xd;
for(q=-4;q<=4;q++){
yt=yc+q*yd;
k2=0;
if(fbg==0){
bg=bg0;
for(m=0;m<np;m++){
det=DSQR(x[m][0]-xt)+DSQR(x[m][1]-yt);
det=k*exp(det*sigma2v)+bg-y[m];
k2+=det*det;
}
}
else{
for(l=-4;l<=4;l++){
bg=bgc+l*bgd;
for(m=0;m<np;m++){
det=DSQR(x[m][0]-xt)+DSQR(x[m][1]-yt);
det=k*exp(det*sigma2v)+bg-y[m];
k2+=det*det;
}
}
}
//printf("k20=%e k2=%e\n",k20,k2);
if(k2<=k20){k20=k2;para[5]=k2;
para[0]=k;para[1]=sigma;para[2]=bg;para[3]=xt;para[4]=yt;}
}
}
}
}
}
}
}
/////////////////////////////
//#include <math.h>
//#include <stdio.h>
//#include <stdlib.h>
//#include "nrutil.h"
//nx,ny is the pixels of x and y direction
//a0 is the input image in nx*ny
//nbound is the boundary limit
//nxt,nyt is out put image dimentions
//at is the output image and cen represent the required center
void Interp_bicubic(int nx,int ny,float **a0,int nbound,
int nxt,int nyt, float **at,double *xcen)
{
void splie2(float **ya, int m, int n, float **y2a);
void spline(float y[], int n, float yp1, float ypn, float y2[]);
void splint(float ya[], float y2a[], int n, float x, float *y);
int i,j,m,n,ic,jc;
float *ytmp,*yytmp,**y2a,x1,x2,shift1,shift2;
y2a=matrix(0,nx,0,ny);
ytmp=vector(0,ny);
yytmp=vector(0,ny);
splie2(a0,nx,ny,y2a);
ic=nx*0.5;
jc=ny*0.5;
shift1=xcen[0]-ic;//-0.5;
shift2=xcen[1]-jc;//-0.5;
if(fabs(shift1)>nbound || fabs(shift2)>nbound){
printf("bicubic shifts too much %e %e\n",shift1,shift2);
getchar();
}
for (n=0;n<nyt;n++){
x2=n+nbound+shift2;
for(i=0;i<nx;i++){
splint(a0[i],y2a[i],ny,x2,&yytmp[i]);
spline(yytmp,ny,1.0e30,1.0e30,ytmp);
}
for (m=0;m<nxt;m++){
x1=m+nbound+shift1;
splint(yytmp,ytmp,ny,x1,&at[m][n]);
}
}
free_vector(yytmp,0,ny);
free_vector(ytmp,0,ny);
free_matrix(y2a,0,nx,0,ny);
}
void splie2(float **ya, int m, int n, float **y2a)
{
void spline(float y[], int n, float yp1, float ypn, float y2[]);
int j;
for (j=0;j<m;j++)spline(ya[j],n,1.0e30,1.0e30,y2a[j]);
}
void spline(float y[], int n, float yp1, float ypn, float y2[])
{
int i,k;
float p,qn,sig,un,*u;
u=vector(0,n-1);
if (yp1 > 0.99e30)
y2[0]=u[0]=0.0;
else {
y2[0] = -0.5;
u[0]=3.0*(y[1]-y[0]-yp1);
}
sig=0.5;
for (i=1;i<=n-2;i++) {
p=sig*y2[i-1]+2.0;
y2[i]=(sig-1.0)/p;
u[i]=(y[i+1]-2.*y[i]+y[i-1]);
u[i]=(3.0*u[i]-sig*u[i-1])/p;
}
if (ypn > 0.99e30)
qn=un=0.0;
else {
qn=0.5;
un=3.0*(ypn-y[n-1]+y[n-2]);
}
y2[n-1]=(un-qn*u[n-2])/(qn*y2[n-2]+1.0);
for (k=n-2;k>=0;k--)y2[k]=y2[k]*y2[k+1]+u[k];
free_vector(u,0,n-1);
}
void splint(float ya[], float y2a[], int n, float x, float *y)
{
void nrerror(char error_text[]);
int klo,khi,k;
float h,b,a;
klo=x;
if( klo<0)klo=0;
if(klo==n-1)klo=n-2;
khi=klo+1;
if (klo<0 || khi>=n) printf("error:klo, khi, n: %d %d %d\n", klo, khi, n);
if (klo<0 || khi>=n) nrerror("Bad xa input to routine splint");
a=(khi-x);
b=(x-klo);
*y=a*ya[klo]+b*ya[khi]+((a*a*a-a)*y2a[klo]+(b*b*b-b)*y2a[khi])/6.0;
}
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