From 9ee13d7576da9a4b7fc906f5c55a67d0e7b45bc8 Mon Sep 17 00:00:00 2001 From: yan Date: Wed, 10 Apr 2024 14:59:01 +0800 Subject: [PATCH] update setup.py --- =5.9 | 3 + csst_ifs_sim/csst_ifs_sim.py | 6434 ++++++++++++++++++---------------- setup.py | 84 +- 3 files changed, 3415 insertions(+), 3106 deletions(-) create mode 100644 =5.9 diff --git a/=5.9 b/=5.9 new file mode 100644 index 0000000..fc57b70 --- /dev/null +++ b/=5.9 @@ -0,0 +1,3 @@ +Requirement already satisfied: PyQt5 in /home/yan/anaconda3/lib/python3.8/site-packages (5.15.10) +Requirement already satisfied: PyQt5-sip<13,>=12.13 in /home/yan/anaconda3/lib/python3.8/site-packages (from PyQt5) (12.13.0) +Requirement already satisfied: PyQt5-Qt5>=5.15.2 in /home/yan/anaconda3/lib/python3.8/site-packages (from PyQt5) (5.15.2) diff --git a/csst_ifs_sim/csst_ifs_sim.py b/csst_ifs_sim/csst_ifs_sim.py index 770638c..9e4dd91 100644 --- a/csst_ifs_sim/csst_ifs_sim.py +++ b/csst_ifs_sim/csst_ifs_sim.py @@ -117,67 +117,55 @@ Contact Information: zhaojunyan@shao.ac.cn 2024.1.19... add multiple exposure mode function; """ +import sys +import os +from scipy.interpolate import interp1d +import astropy.coordinates as coord +import ctypes +from support import IFSinstrumentModel +from support import cosmicrays +from support import logger as lg +from CTI import CTI +from optparse import OptionParser +import configparser as ConfigParser +import cmath +from scipy import ndimage +import galsim +from scipy.signal import fftconvolve +from astropy.io import fits +import scipy.io as sio +import numpy as np +from scipy import interpolate +from astropy.coordinates import SkyCoord, EarthLocation +from astropy import units as u +from astropy.time import Time +from astropy.coordinates import get_sun +from datetime import datetime, timedelta +import pandas as pd +from scipy.integrate import simps from astropy.utils.iers import conf conf.auto_max_age = None - - -from scipy.integrate import simps -import pandas as pd -from datetime import datetime, timedelta -###import julian -from astropy.coordinates import get_sun -from astropy.time import Time -from astropy import units as u - -from astropy.coordinates import SkyCoord, EarthLocation - -from scipy import interpolate - - -import numpy as np - -import scipy.io as sio - -from astropy.io import fits - -from scipy.signal import fftconvolve - -import galsim - -from scipy import ndimage -import cmath - -import os, sys - -import configparser as ConfigParser +###import julian -from optparse import OptionParser sys.path.append('../') -from CTI import CTI -from support import logger as lg -from support import cosmicrays -from support import IFSinstrumentModel #from joblib import Parallel, delayed # from astropy.table import Table ############################################################################### -import ctypes - -import astropy.coordinates as coord -from scipy.interpolate import interp1d #from sky_bkg import sky_bkg -filterPivotWave = {'nuv':2875.5,'u':3629.6,'g':4808.4,'r':6178.2, 'i':7609.0, 'z':9012.9,'y':9627.9} -filterIndex = {'nuv':0,'u':1,'g':2,'r':3, 'i':4, 'z':5,'y':6} +filterPivotWave = {'nuv': 2875.5, 'u': 3629.6, 'g': 4808.4, + 'r': 6178.2, 'i': 7609.0, 'z': 9012.9, 'y': 9627.9} +filterIndex = {'nuv': 0, 'u': 1, 'g': 2, 'r': 3, 'i': 4, 'z': 5, 'y': 6} # filterCCD = {'nuv':'UV0','u':'UV0','g':'Astro_MB','r':'Astro_MB', 'i':'Basic_NIR', 'z':'Basic_NIR','y':'Basic_NIR'} # bandRange = {'nuv':[2504.0,3230.0],'u':[3190.0,4039.0],'g':[3989.0,5498.0],'r':[5438.0,6956.0], 'i':[6886.0,8469.0], # 'z':[8379.0,10855.0],'y':[9217.0, 10900.0], 'GU':[2550, 4000],'GV':[4000, 6200],'GI':[6200,10000]} @@ -195,6 +183,7 @@ def transRaDec2D(ra, dec): return np.array([x1, y1, z1]) ############################################################################### + def flux2ill(wave, flux): # erg/s/cm^2/A/arcsec^2 to W/m^2 @@ -243,7 +232,9 @@ def flux2ill(wave, flux): return E ################################################################ -def ill2flux(path,E): + + +def ill2flux(path, E): # use template from sky_bkg (background_spec_hst.dat) filename = path+'IFS_inputdata/refs/background_spec_hst.dat' @@ -275,18 +266,19 @@ def ill2flux(path,E): ############################################################## - -########################################################################################## +########################################################################################## def earth_angle(time_jd, x_sat, y_sat, z_sat, ra_obj, dec_obj): ra_sat = np.arctan2(y_sat, x_sat) / np.pi * 180 dec_sat = np.arctan2(z_sat, np.sqrt(x_sat**2+y_sat**2)) / np.pi * 180 - radec_sat = SkyCoord(ra=ra_sat*u.degree, dec=dec_sat*u.degree, frame='gcrs') + radec_sat = SkyCoord(ra=ra_sat*u.degree, + dec=dec_sat*u.degree, frame='gcrs') lb_sat = radec_sat.transform_to('geocentrictrueecliptic') # get the obj location - radec_obj = SkyCoord(ra=ra_obj*u.degree, dec=dec_obj*u.degree, frame='gcrs') + radec_obj = SkyCoord(ra=ra_obj*u.degree, + dec=dec_obj*u.degree, frame='gcrs') lb_obj = radec_obj.transform_to('geocentrictrueecliptic') # calculate the angle between sub-satellite point and the earth side @@ -302,45 +294,51 @@ def earth_angle(time_jd, x_sat, y_sat, z_sat, ra_obj, dec_obj): return angle - -#################################################3 + +# 3 class StrayLight(object): - def __init__(self, path, jtime = 2460843., sat = np.array([0,0,0]), radec = np.array([0,0])): - self.path=path + def __init__(self, path, jtime=2460843., sat=np.array([0, 0, 0]), radec=np.array([0, 0])): + self.path = path self.jtime = jtime self.sat = sat - self.equator = coord.SkyCoord(radec[0]*u.degree, radec[1]*u.degree,frame='icrs') + self.equator = coord.SkyCoord( + radec[0]*u.degree, radec[1]*u.degree, frame='icrs') self.ecliptic = self.equator.transform_to('barycentrictrueecliptic') self.pointing = transRaDec2D(radec[0], radec[1]) - self.slcdll = ctypes.CDLL(self.path+'IFS_inputdata/refs/libstraylight.so') #dylib + self.slcdll = ctypes.CDLL( + self.path+'IFS_inputdata/refs/libstraylight.so') # dylib self.slcdll.Calculate.argtypes = [ctypes.c_double, ctypes.POINTER(ctypes.c_double), - ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), - ctypes.POINTER(ctypes.c_double), ctypes.c_char_p] - - self.slcdll.PointSource.argtypes = [ctypes.c_double ,ctypes.POINTER(ctypes.c_double), - ctypes.POINTER(ctypes.c_double),ctypes.POINTER(ctypes.c_double), - ctypes.POINTER(ctypes.c_double), ctypes.c_char_p] - - self.slcdll.EarthShine.argtypes = [ctypes.c_double ,ctypes.POINTER(ctypes.c_double), - ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), - ctypes.POINTER(ctypes.c_double)] - - self.slcdll.Zodiacal.argtypes = [ctypes.c_double ,ctypes.POINTER(ctypes.c_double), - ctypes.POINTER(ctypes.c_double)] + ctypes.POINTER(ctypes.c_double), ctypes.POINTER( + ctypes.c_double), + ctypes.POINTER(ctypes.c_double), ctypes.c_char_p] + + self.slcdll.PointSource.argtypes = [ctypes.c_double, ctypes.POINTER(ctypes.c_double), + ctypes.POINTER(ctypes.c_double), ctypes.POINTER( + ctypes.c_double), + ctypes.POINTER(ctypes.c_double), ctypes.c_char_p] + + self.slcdll.EarthShine.argtypes = [ctypes.c_double, ctypes.POINTER(ctypes.c_double), + ctypes.POINTER(ctypes.c_double), ctypes.POINTER( + ctypes.c_double), + ctypes.POINTER(ctypes.c_double)] + + self.slcdll.Zodiacal.argtypes = [ctypes.c_double, ctypes.POINTER(ctypes.c_double), + ctypes.POINTER(ctypes.c_double)] self.slcdll.ComposeY.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double), - ctypes.POINTER(ctypes.c_double)] - self.slcdll.Init.argtypes=[ctypes.c_char_p,ctypes.c_char_p,ctypes.c_char_p,ctypes.c_char_p] + ctypes.POINTER(ctypes.c_double)] + self.slcdll.Init.argtypes = [ + ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p] self.deFn = self.path+"IFS_inputdata/refs/DE405" self.PSTFn = self.path+"IFS_inputdata/refs/PST" - self.RFn =self.path+ "IFS_inputdata/refs/R" + self.RFn = self.path + "IFS_inputdata/refs/R" self.ZolFn = self.path+"IFS_inputdata/refs/Zodiacal" self.brightStarTabFn = self.path+"IFS_inputdata/refs/BrightGaia_with_csst_mag" - self.slcdll.Init(str.encode(self.deFn),str.encode(self.PSTFn),str.encode(self.RFn),str.encode(self.ZolFn)) - + self.slcdll.Init(str.encode(self.deFn), str.encode( + self.PSTFn), str.encode(self.RFn), str.encode(self.ZolFn)) def caculateStarLightFilter(self, filter='i'): @@ -354,9 +352,11 @@ class StrayLight(object): self.slcdll.ComposeY(ob, py1, py2) star_e1 = (ctypes.c_double*7)() - self.slcdll.PointSource(self.jtime, sat, ob, py1, star_e1, str.encode(self.brightStarTabFn)) + self.slcdll.PointSource(self.jtime, sat, ob, py1, + star_e1, str.encode(self.brightStarTabFn)) star_e2 = (ctypes.c_double*7)() - self.slcdll.PointSource(self.jtime, sat, ob, py2, star_e2, str.encode(self.brightStarTabFn)) + self.slcdll.PointSource(self.jtime, sat, ob, py2, + star_e2, str.encode(self.brightStarTabFn)) band_star_e1 = star_e1[:][filterIndex[filter]] band_star_e2 = star_e2[:][filterIndex[filter]] @@ -374,8 +374,9 @@ class StrayLight(object): self.slcdll.ComposeY(ob, py1, py2) earth_e1 = (ctypes.c_double*7)() - self.slcdll.EarthShine(self.jtime, sat, ob, py1, earth_e1) # e[7]代表7个波段的照度 - + self.slcdll.EarthShine(self.jtime, sat, ob, py1, + earth_e1) # e[7]代表7个波段的照度 + earth_e2 = (ctypes.c_double*7)() self.slcdll.EarthShine(self.jtime, sat, ob, py2, earth_e2) @@ -383,123 +384,137 @@ class StrayLight(object): band_earth_e2 = earth_e2[:][filterIndex[filter]] return max(band_earth_e1, band_earth_e2) - -############################################################################### + ############################################################################### +############################################################################### + def str2time(strTime): - if len(strTime)>20: #暂时未用到 - msec=int(float('0.'+strTime[20:])*1000000) #微秒 - str2=strTime[0:19]+' '+str(msec) - return datetime.strptime(str2,'%Y %m %d %H %M %S %f') - -#datetime类转mjd + if len(strTime) > 20: # 暂时未用到 + msec = int(float('0.'+strTime[20:])*1000000) # 微秒 + str2 = strTime[0:19]+' '+str(msec) + return datetime.strptime(str2, '%Y %m %d %H %M %S %f') + +# datetime类转mjd + + def time2mjd(dateT): - t0=datetime(1858,11,17,0,0,0,0)#简化儒略日起始日 - mjd=(dateT-t0).days - mjd_s=dateT.hour*3600.0+dateT.minute*60.0+dateT.second+dateT.microsecond/1000000.0 + t0 = datetime(1858, 11, 17, 0, 0, 0, 0) # 简化儒略日起始日 + mjd = (dateT-t0).days + mjd_s = dateT.hour*3600.0+dateT.minute*60.0 + \ + dateT.second+dateT.microsecond/1000000.0 return mjd+mjd_s/86400.0 + def time2jd(dateT): - t0=datetime(1858,11,17,0,0,0,0)#简化儒略日起始日 - mjd=(dateT-t0).days - mjd_s=dateT.hour*3600.0+dateT.minute*60.0+dateT.second+dateT.microsecond/1000000.0 + t0 = datetime(1858, 11, 17, 0, 0, 0, 0) # 简化儒略日起始日 + mjd = (dateT-t0).days + mjd_s = dateT.hour*3600.0+dateT.minute*60.0 + \ + dateT.second+dateT.microsecond/1000000.0 return mjd+mjd_s/86400.0++2400000.5 - -#mjd转datetime类 + +# mjd转datetime类 + + def mjd2time(mjd): - t0=datetime(1858,11,17,0,0,0,0)#简化儒略日起始日 + t0 = datetime(1858, 11, 17, 0, 0, 0, 0) # 简化儒略日起始日 return t0+timedelta(days=mjd) + def jd2time(jd): - mjd=jd2mjd(jd) + mjd = jd2mjd(jd) return mjd2time(mjd) - -#mjd和jd互转 + +# mjd和jd互转 + + def mjd2jd(mjd): return mjd+2400000.5 + def jd2mjd(jd): return jd-2400000.5 + def dt2hmd(dt): - ## dt is datetime - hour=dt.hour - minute=dt.minute - second=dt.second - if hour<10: - str_h='0'+str(hour) + ## dt is datetime + hour = dt.hour + minute = dt.minute + second = dt.second + if hour < 10: + str_h = '0'+str(hour) else: - str_h=str(hour) - - if minute<10: - str_m='0'+str(minute) + str_h = str(hour) + + if minute < 10: + str_m = '0'+str(minute) else: - str_m=str(minute) - - if second<10: - str_d='0'+str(second+dt.microsecond*1e-6) + str_m = str(minute) + + if second < 10: + str_d = '0'+str(second+dt.microsecond*1e-6) else: - str_d=str(second+dt.microsecond*1e-6) - + str_d = str(second+dt.microsecond*1e-6) + return str_h+':'+str_m+':'+str_d ############################################################################### + + def float2char(a, z): - ### a is input float value - ### transfer float a to chars and save z bis - b=str(a) - n=len(b) - - if z>=n: + # a is input float value + # transfer float a to chars and save z bis + b = str(a) + n = len(b) + + if z >= n: return b else: return b[:z] - + ############################################################################### def deg2HMS(ra0, dec0): '''convert deg to ra's HMS and dec's DMS''' c = SkyCoord(ra=ra0*u.degree, dec=dec0*u.degree) - ss=c.to_string('hmsdms') + ss = c.to_string('hmsdms') print(ss) - for k in range(5,len(ss)-1): + for k in range(5, len(ss)-1): - if ss[k]=='s': - s_idx=k - - if ss[k]=='d': - d_idx=k - - if ss[k]=='m': - m_idx=k - - if c.ra.hms.s<10 and c.ra.hms.s>0.1: - temp=str(c.ra.hms.s) - ra_ss='0'+temp[:3] - if c.ra.hms.s>10: - temp=str(c.ra.hms.s) - ra_ss=temp[:4] - - if c.ra.hms.s<0.1: - temp=str(c.ra.hms.s) - ra_ss='00.0' - - dms_d=ss[s_idx+2:d_idx] - dms_m=ss[d_idx+1:m_idx] - dms_s=ss[m_idx+1:m_idx+3] - - hhmmss=ss[0:2]+ss[3:5]+ra_ss + if ss[k] == 's': + s_idx = k + + if ss[k] == 'd': + d_idx = k + + if ss[k] == 'm': + m_idx = k + + if c.ra.hms.s < 10 and c.ra.hms.s > 0.1: + temp = str(c.ra.hms.s) + ra_ss = '0'+temp[:3] + if c.ra.hms.s > 10: + temp = str(c.ra.hms.s) + ra_ss = temp[:4] + + if c.ra.hms.s < 0.1: + temp = str(c.ra.hms.s) + ra_ss = '00.0' + + dms_d = ss[s_idx+2:d_idx] + dms_m = ss[d_idx+1:m_idx] + dms_s = ss[m_idx+1:m_idx+3] + + hhmmss = ss[0:2]+ss[3:5]+ra_ss return hhmmss+dms_d+dms_m+dms_s ############################################################################ - ########################################################### -def beta_angle( x_sat, y_sat, z_sat, vx_sat, vy_sat, vz_sat, ra_obj, dec_obj): +def beta_angle(x_sat, y_sat, z_sat, vx_sat, vy_sat, vz_sat, ra_obj, dec_obj): # get the vector for next motion x_sat2 = x_sat + vx_sat @@ -519,8 +534,8 @@ def beta_angle( x_sat, y_sat, z_sat, vx_sat, vy_sat, vz_sat, ra_obj, dec_obj): frame='gcrs') lb_normal = radec_normal.transform_to('geocentrictrueecliptic') - - radec_sun = SkyCoord(ra=ra_obj*u.degree, dec=dec_obj*u.degree, frame='gcrs') + radec_sun = SkyCoord(ra=ra_obj*u.degree, + dec=dec_obj*u.degree, frame='gcrs') lb_sun = radec_sun.transform_to('geocentrictrueecliptic') # get the angle between normal and solar @@ -531,50 +546,58 @@ def beta_angle( x_sat, y_sat, z_sat, vx_sat, vy_sat, vz_sat, ra_obj, dec_obj): ############################################################################### - ########################################################## -def LSR_velocity(ra,dec,velocity,Obstime): -# ''' -# 输入参数为ra,dec 原始视向速度in km/s,观测时间 -# local为观测地位置,c为利用输入坐标建立的坐标系对象。 -# barycorr为程序输出的地球坐标系与BSR间的修正,单位为m/s -# 修正后再将BSR中的速度转化为LSR中的速度。 -# ''' - local = EarthLocation.from_geodetic(lat=22.349368*u.deg, lon=113.584068*u.deg, height=10*u.m) - ### convert ra and dec to - source = SkyCoord(ra*u.deg, dec*u.deg,frame='icrs', unit=(u.hourangle,u.deg) ) - l = source.galactic.l.deg +def LSR_velocity(ra, dec, velocity, Obstime): + # ''' + # 输入参数为ra,dec 原始视向速度in km/s,观测时间 + # local为观测地位置,c为利用输入坐标建立的坐标系对象。 + # barycorr为程序输出的地球坐标系与BSR间的修正,单位为m/s + # 修正后再将BSR中的速度转化为LSR中的速度。 + # ''' + local = EarthLocation.from_geodetic( + lat=22.349368*u.deg, lon=113.584068*u.deg, height=10*u.m) + # convert ra and dec to + source = SkyCoord(ra*u.deg, dec*u.deg, frame='icrs', + unit=(u.hourangle, u.deg)) + l = source.galactic.l.deg b = source.galactic.b.deg c = SkyCoord(l=l*u.degree, b=b*u.degree, frame='galactic') c_icrs = c.transform_to('icrs') - barycorr = c_icrs.radial_velocity_correction(obstime=Time(Obstime), location=local) + barycorr = c_icrs.radial_velocity_correction( + obstime=Time(Obstime), location=local) velocity = velocity + barycorr.value/1000 - #print(barycorr.value/1000) + # print(barycorr.value/1000) l = l * np.pi / 180 b = b * np.pi / 180 return velocity + 9 * np.cos(l) * np.cos(b) + 12 * np.sin(l) * np.cos(b) + 7 * np.sin(b) - + ############################################################################### -def rotation_yan(x0,y0,x1,y1,angle): - #% point A (x0,y0) - #% point B(x1,y1) - #% roate angle ,point B rotate with point A - alpha=angle/180*3.1415926 #% in radians - x2=(x1-x0)*np.cos(alpha)-(y1-y0)*np.sin(alpha)+x0 - y2=(x1-x0)*np.sin(alpha)+(y1-y0)*np.cos(alpha)+y0 - return x2, y2 + + +def rotation_yan(x0, y0, x1, y1, angle): + # % point A (x0,y0) + # % point B(x1,y1) + # % roate angle ,point B rotate with point A + alpha = angle/180*3.1415926 # % in radians + x2 = (x1-x0)*np.cos(alpha)-(y1-y0)*np.sin(alpha)+x0 + y2 = (x1-x0)*np.sin(alpha)+(y1-y0)*np.cos(alpha)+y0 + return x2, y2 ###################################################################### + + def centroid(data): - h,w = np.shape(data) - x = np.arange(0,w) - y = np.arange(0,h) - x1=np.ones((1,h)) - y1=np.ones((w,1)) - cx=(np.dot(np.dot(x1,data),y)) /(np.dot(np.dot(x1,data),y1)) - cy=(np.dot(np.dot(x ,data),y1)) /(np.dot(np.dot(x1,data),y1)) - return float(cx),float(cy) - -#######################################################################33 + h, w = np.shape(data) + x = np.arange(0, w) + y = np.arange(0, h) + x1 = np.ones((1, h)) + y1 = np.ones((w, 1)) + cx = (np.dot(np.dot(x1, data), y)) / (np.dot(np.dot(x1, data), y1)) + cy = (np.dot(np.dot(x, data), y1)) / (np.dot(np.dot(x1, data), y1)) + return float(cx), float(cy) + +# 33 + + def centroidN(data): ''' calculate the centroid of the input two-dimentional image data @@ -591,69 +614,74 @@ def centroidN(data): ''' ### from scipy import ndimage - cy,cx=ndimage.center_of_mass(data) + cy, cx = ndimage.center_of_mass(data) return cx, cy #################################################################### -def SpecCube2photon(data,wave): + + +def SpecCube2photon(data, wave): # calcutle photons from original spec cube data, # data: input data, two-dimentional, unit : 1e-17 erg/s/A/cm^2 # wave: the relative wavefront, unit in nm; - planckh= 6.62620*10**-27 # % erg s; - cc=2.99792458*10**17 # in nm/s - # fov2=0.01 # 单个像素的面积 arcsec^2 + planckh = 6.62620*10**-27 # % erg s; + cc = 2.99792458*10**17 # in nm/s + # fov2=0.01 # 单个像素的面积 arcsec^2 # telarea=3.1415926*100*100 # in cm^2,望远镜聚光面积; - fluxlam=1e-17*data # convert original unit to unit of erg/s/A/cm^2 - lam=wave # wave in nm ;; - ephoton=planckh*cc/lam # in erg/photon, cc与lambda单位需要一致; - Nphoton =fluxlam/ephoton # in unit of photons/cm2/s/A + fluxlam = 1e-17*data # convert original unit to unit of erg/s/A/cm^2 + lam = wave # wave in nm ;; + ephoton = planckh*cc/lam # in erg/photon, cc与lambda单位需要一致; + Nphoton = fluxlam/ephoton # in unit of photons/cm2/s/A return Nphoton ###################################################################### #################################################################################### -def mag2flux(starmag,lam): - #starmag: input AB mag + +def mag2flux(starmag, lam): + # starmag: input AB mag # lambda: wavelength in nm - - planckh= 6.62620*10**-27 # % erg s; - cc=2.99792458*10**17 # % in nm/s - - iskyv0=starmag # mag/arcsec^2 unit - fluxnu= 10.0**( (iskyv0+48.6)/-2.5) # erg/s/cm2/Hz/arcsec^2 - fluxlam=fluxnu*cc/lam**2/10 # erg/s/cm2/A/arcsec^2 - - Ee=planckh*cc/lam ### single photon energy in erg/photon; - photonu=fluxlam/Ee ### photons/cm2/s/A/arcsec^2 - return fluxlam,photonu + planckh = 6.62620*10**-27 # % erg s; + cc = 2.99792458*10**17 # % in nm/s + + iskyv0 = starmag # mag/arcsec^2 unit + fluxnu = 10.0**((iskyv0+48.6)/-2.5) # erg/s/cm2/Hz/arcsec^2 + fluxlam = fluxnu*cc/lam**2/10 # erg/s/cm2/A/arcsec^2 + + Ee = planckh*cc/lam # single photon energy in erg/photon; + photonu = fluxlam/Ee # photons/cm2/s/A/arcsec^2 + + return fluxlam, photonu ############################################################################### -def flux2photons(flux,lam): + +def flux2photons(flux, lam): # flux: # erg/s/cm2/A/ # lam: # wavelength in nm - - planckh= 6.62620*10**-27 # % erg s; - cc=2.99792458*10**17 # % in nm/s - Ee=planckh*cc/lam ### singe photon energy in erg/photon; - photonu=flux/Ee # photons/cm2/s/A + + planckh = 6.62620*10**-27 # % erg s; + cc = 2.99792458*10**17 # % in nm/s + Ee = planckh*cc/lam # singe photon energy in erg/photon; + photonu = flux/Ee # photons/cm2/s/A return photonu ############################################################################### ################################################## + def fftrange(n, dtype=float): """FFT-aligned coordinate grid for n samples.""" - return np.arange(-n//2, -n//2+n, dtype=dtype) - -############################################################################### - - + return np.arange(-n//2, -n//2+n, dtype=dtype) + +############################################################################### + + def dft2(ary, Q, samples, shift=None): """Compute the two dimensional Discrete Fourier Transform of a matrix. - + Parameters ---------- ary : `numpy.ndarray` @@ -666,40 +694,41 @@ def dft2(ary, Q, samples, shift=None): shift : `float`, optional shift of the output domain, as a frequency. Same broadcast rules apply as with samples. - + Returns ------- `numpy.ndarray` 2D array containing the shifted transform. Equivalent to ifftshift(fft2(fftshift(ary))) modulo output sampling/grid differences - + """ - + # this is for dtype stabilization - Q = float(Q) ## Q=lambda*f/D/pixelsize + Q = float(Q) # Q=lambda*f/D/pixelsize + + n, m = ary.shape # ary maybe is the pupil function + N, M = samples, samples - n, m = ary.shape ###ary maybe is the pupil function - N, M = samples,samples - X, Y, U, V = (fftrange(n) for n in (m, n, M, N)) a = 1 / Q - - ################################################################### + + ################################################################### Eout_fwd = np.exp(-1j * 2 * np.pi * a / n * np.outer(Y, V).T) - Ein_fwd = np.exp(-1j * 2 * np.pi * a / m * np.outer(X, U)) + Ein_fwd = np.exp(-1j * 2 * np.pi * a / m * np.outer(X, U)) + + ############################################################################# + + out = Eout_fwd @ ary @ Ein_fwd # ary is the input pupil function - ############################################################################# - - out = Eout_fwd @ ary @ Ein_fwd #### ary is the input pupil function - return out ############################################################################## - + + def idft2(ary, Q, samples, shift=None): """Compute the two dimensional inverse Discrete Fourier Transform of a matrix. - + Parameters ---------- ary : `numpy.ndarray` @@ -712,18 +741,18 @@ def idft2(ary, Q, samples, shift=None): shift : `float`, optional shift of the output domain, as a frequency. Same broadcast rules apply as with samples. - + Returns ------- `numpy.ndarray` 2D array containing the shifted transform. Equivalent to ifftshift(ifft2(fftshift(ary))) modulo output sampling/grid differences - + """ # this is for dtype stabilization - Q = float(Q) ## Q=lambda*f/D/pixelsize - n, m = ary.shape ###ary maybe is the pupil function + Q = float(Q) # Q=lambda*f/D/pixelsize + n, m = ary.shape # ary maybe is the pupil function N, M = samples X, Y, U, V = (fftrange(n) for n in (m, n, M, N)) ############################################################################### @@ -731,15 +760,16 @@ def idft2(ary, Q, samples, shift=None): NM = N*M r = NM/nm a = 1 / Q - ################################################################### + ################################################################### Eout_rev = np.exp(1j * 2 * np.pi * a / n * np.outer(Y, V).T) * (1/r) - Ein_rev = np.exp(1j * 2 * np.pi * a / m * np.outer(X, U)) * (1/nm) - ########################################################################### + Ein_rev = np.exp(1j * 2 * np.pi * a / m * np.outer(X, U)) * (1/nm) + ########################################################################### out = Eout_rev @ ary @ Ein_rev return out ############################################################################### -def anySampledPSFnew(wavefront, pupil , Q , sizeout): + +def anySampledPSFnew(wavefront, pupil, Q, sizeout): ''' written on 2020.12.04 by Yan @Shao % wavefront sampled in the united circle; @@ -753,29 +783,33 @@ def anySampledPSFnew(wavefront, pupil , Q , sizeout): % pixelsize is the actural size of the detector; % make sure all the varia have the same unit; % the returned PSF has sum value of 1 - ''' + ''' + + m, n = np.shape(wavefront) + + phase = 2.0*np.pi*wavefront # % wavefront phase in radians + + # %generalized pupil function of channel1; + pk = pupil*np.exp(cmath.sqrt(-1)*(phase)) + + pf = dft2(pk, Q, sizeout) - m,n = np.shape(wavefront) - - phase=2.0*np.pi*wavefront ##% wavefront phase in radians - - #%generalized pupil function of channel1; - pk=pupil*np.exp(cmath.sqrt(-1)*(phase)) - - pf=dft2(pk, Q, sizeout) - pf2 = abs(pf)**2 - psfout=pf2/pf2.sum() - - cx,cy=centroid(psfout) - Nt=sizeout - #psf=ndimage.shift(psfout,[Nt/2-cy, Nt/2-cx],order=1, mode='nearest' ) ## for my fft method - psf=ndimage.shift(psfout,[Nt/2-cy-1, Nt/2-cx-1],order=1, mode='nearest' ) #for convolve method - psf=psf/psf.sum() - + psfout = pf2/pf2.sum() + + cx, cy = centroid(psfout) + Nt = sizeout + # psf=ndimage.shift(psfout,[Nt/2-cy, Nt/2-cx],order=1, mode='nearest' ) ## for my fft method + # for convolve method + psf = ndimage.shift( + psfout, [Nt/2-cy-1, Nt/2-cx-1], order=1, mode='nearest') + psf = psf/psf.sum() + return psf - + ########################################################################################### + + def zero_pad(image, shape, position='corner'): """ Extends image to a certain size with zeros @@ -827,47 +861,54 @@ def zero_pad(image, shape, position='corner'): ################################################################################ ############################################################################## + + def get_dx_dy_blue(wave): - #wave is the wavelength in nm; + # wave is the wavelength in nm; # dx is in dispersion direction, dy is in vertical direction; - dydl=np.array([-423.256, 0.001, 0.00075, 0.0000078, -0.0000000000007, 0.0, 0.0] ) #色散方向 - dxdl=0.2*np.array([-9.1519, -1.00000000e-06, 3.50000000e-08, -5.00000000e-09, -1.70000000e-11, 4.00949787e-12, -6.16873452e-15]) #垂直方向 - - dx=0.0 - dy=0.0 + dydl = np.array([-423.256, 0.001, 0.00075, + 0.0000078, -0.0000000000007, 0.0, 0.0]) # 色散方向 + dxdl = 0.2*np.array([-9.1519, -1.00000000e-06, 3.50000000e-08, -5.00000000e-09, - + 1.70000000e-11, 4.00949787e-12, -6.16873452e-15]) # 垂直方向 + + dx = 0.0 + dy = 0.0 for i in range(len(dxdl)): - dx=dx+dxdl[i]*wave**(i) - dy=dy+dydl[i]*wave**(i) - return dx,dy + dx = dx+dxdl[i]*wave**(i) + dy = dy+dydl[i]*wave**(i) + return dx, dy def get_dx_dy_red(wave): - #wave is the wavelength in nm; - dydl=np.array([-640.0239901372472, 0.0018, 0.00048, 0.0000028, -0.0000000000007, 0.0 , 0.0] ) #色散方向 - dxdl=0.00325*np.array([-1638.8, 4.0e-2, 5.500e-3, -5.2e-10, 1.7000e-10, 7.1e-13, -5.16e-15]) #垂直方向 - - dx=0.0 - dy=0.0 + # wave is the wavelength in nm; + dydl = np.array([-640.0239901372472, 0.0018, 0.00048, + 0.0000028, -0.0000000000007, 0.0, 0.0]) # 色散方向 + dxdl = 0.00325*np.array([-1638.8, 4.0e-2, 5.500e-3, - + 5.2e-10, 1.7000e-10, 7.1e-13, -5.16e-15]) # 垂直方向 + + dx = 0.0 + dy = 0.0 for i in range(len(dxdl)): - dx=dx+dxdl[i]*wave**(i) - dy=dy+dydl[i]*wave**(i) - return dx,dy + dx = dx+dxdl[i]*wave**(i) + dy = dy+dydl[i]*wave**(i) + return dx, dy ############################################################################################## -def getSpectrum(Spectrum0,lam,sigma): - #%获得输入波长lambda的光谱强度 - wave=Spectrum0[:,0] #%原始光谱数据给定的波长; - Qt =Spectrum0[:,1] #%原始光谱数据给定的光谱强度; - d=abs(lam-wave); # %计算波长距离; - if min(d)>3*sigma: - - SpmOut=1.0/20000 + +def getSpectrum(Spectrum0, lam, sigma): + + # %获得输入波长lambda的光谱强度 + wave = Spectrum0[:, 0] # %原始光谱数据给定的波长; + Qt = Spectrum0[:, 1] # %原始光谱数据给定的光谱强度; + d = abs(lam-wave) # %计算波长距离; + if min(d) > 3*sigma: + + SpmOut = 1.0/20000 else: - - column=np.where(d==min(d)) - SpmOut=Qt[column[0]]*np.exp(-(lam-wave[column[0]])**2/2/sigma**2) - + + column = np.where(d == min(d)) + SpmOut = Qt[column[0]]*np.exp(-(lam-wave[column[0]])**2/2/sigma**2) return SpmOut @@ -875,8 +916,6 @@ def getSpectrum(Spectrum0,lam,sigma): ##################################################################################### - - #################################################################################################################### def processArgs(printHelp=False): @@ -906,6 +945,8 @@ def processArgs(printHelp=False): else: return parser.parse_args() ############################################################################################## + + class IFSsimulator(): """ CSST IFS Simulator @@ -915,7 +956,7 @@ class IFSsimulator(): self.image self.image_b blue channel self.image_r red channel - + :param opts: OptionParser instance :type opts: OptionParser instance """ @@ -926,18 +967,17 @@ class IFSsimulator(): :param opts: OptionParser instance :type opts: OptionParser instance - + """ - - + #################################### - + self.configfile = opts.configfile if opts.section is None: ####self.section = 'DEFAULT' - self.section = 'TEST' #####simulation section; - + self.section = 'TEST' # simulation section; + else: self.section = opts.section @@ -951,10 +991,10 @@ class IFSsimulator(): except: self.random = False - #load instrument model, these values are also stored in the FITS header + # load instrument model, these values are also stored in the FITS header self.information = IFSinstrumentModel.IFSinformation() - #update settings with defaults + # update settings with defaults self.information.update(dict(quadrant=int(0), ccdx=int(0), ccdy=int(0), @@ -971,40 +1011,38 @@ class IFSsimulator(): bias=500.0, cosmic_bkgd=0.182758225257, scattered_light=2.96e-2, - e_adu=1.5, + e_adu=1.5, exposures=1, exptime=300.0, readouttime=0.13824, rdose=8.0e9, ra=0.0, dec=0.0, - injection=80000.0, - coveringfraction=0.5, #CR: 3.0% is for 565s exposure - ################################################### + injection=80000.0, + coveringfraction=0.5, # CR: 3.0% is for 565s exposure + ################################################### # cosmicraylengths=self.information['dir_path']+'IFS_inputdata/cdf_cr_length.dat', - # cosmicraydistance=self.information['dir_path']+'IFS_inputdata/cdf_cr_total.dat', + # cosmicraydistance=self.information['dir_path']+'IFS_inputdata/cdf_cr_total.dat', # parallelTrapfile=self.information['dir_path']+'IFS_inputdata/cdm_euclid_parallel.dat', # serialTrapfile=self.information['dir_path']+'IFS_inputdata/cdm_euclid_serial.dat', - #cosmeticsFile='../IFS_inputdata/cosmetics.dat', + # cosmeticsFile='../IFS_inputdata/cosmetics.dat', mode='same')) - + ##################################### -############################################################################3 - def readConfigs(self,simnumber): +# 3 + def readConfigs(self, simnumber): """ Reads the config file information using configParser and sets up a logger. """ - self.config = ConfigParser.RawConfigParser() + self.config = ConfigParser.RawConfigParser() - self.config.read_file(open(self.configfile)) + self.config.read_file(open(self.configfile)) + + # self.log.info(self.information) - - #self.log.info(self.information) - - -############################################################################### +############################################################################### def processConfigs(self): """ @@ -1013,14 +1051,14 @@ class IFSsimulator(): The configuration file may look as follows:: [TEST] - + For explanation of each field, see /data/test.config. Note that if an input field does not exist, then the values are taken from the default instrument model as described in support.IFSinstrumentModel.VISinformation(). Any of the defaults can be overwritten by providing a config file with a correct field name. """ - #parse options and update the information dictionary + # parse options and update the information dictionary options = self.config.options(self.section) settings = {} for option in options: @@ -1028,61 +1066,62 @@ class IFSsimulator(): settings[option] = self.config.getint(self.section, option) except ValueError: try: - settings[option] = self.config.getfloat(self.section, option) + settings[option] = self.config.getfloat( + self.section, option) except ValueError: settings[option] = self.config.get(self.section, option) self.information.update(settings) - #force gain to be float + # force gain to be float self.information['e_adu'] = float(self.information['e_adu']) # #name of the output file, include quadrants and CCDs ################################################################################################### #self.information['output'] = self.config.get(self.section, 'output') ################################################################################################## - + # #booleans to control the flow # self.chargeInjectionx = self.config.getboolean(self.section, 'chargeInjectionx') # self.chargeInjectiony = self.config.getboolean(self.section, 'chargeInjectiony') - + self.cosmicRays = self.config.getboolean(self.section, 'cosmicRays') self.darknoise = self.config.getboolean(self.section, 'darknoise') self.cosmetics = self.config.getboolean(self.section, 'cosmetics') - self.radiationDamage = self.config.getboolean(self.section, 'radiationDamage') - + self.radiationDamage = self.config.getboolean( + self.section, 'radiationDamage') + self.bleeding = self.config.getboolean(self.section, 'bleeding') - self.save_cosmicrays =self.config.getboolean(self.section, 'save_cosmicrays') - self.sky_noise=self.config.getboolean(self.section, 'sky_noise') - + self.save_cosmicrays = self.config.getboolean( + self.section, 'save_cosmicrays') + self.sky_noise = self.config.getboolean(self.section, 'sky_noise') + try: - self.nonlinearity = self.config.getboolean(self.section, 'nonlinearity') + self.nonlinearity = self.config.getboolean( + self.section, 'nonlinearity') except: self.nonlinearity = False - + try: - self.flatfieldM = self.config.getboolean(self.section, 'flatfieldM') + self.flatfieldM = self.config.getboolean( + self.section, 'flatfieldM') except: self.flatfieldM = False - try: - self.readoutNoise = self.config.getboolean(self.section, 'readoutnoise') + self.readoutNoise = self.config.getboolean( + self.section, 'readoutnoise') except: self.readoutNoise = True - - try: self.intscale = self.config.getboolean(self.section, 'intscale') except: self.intscale = True - - ############################################################################## - ###############################################3 + # 3 self.information['variablePSF'] = False @@ -1096,38 +1135,34 @@ class IFSsimulator(): bleeding=self.bleeding, sky_noise=self.sky_noise, intscale=self.intscale, - save_cosmicrays =self.save_cosmicrays ) - - ##################################################################### - - - ######################################################################################### + save_cosmicrays=self.save_cosmicrays) + ##################################################################### + ######################################################################################### def _createEmpty(self): """ Creates and empty array of a given x and y size full of zeros. add g r i channel images; - + Creates lensing parameters; - - - """ - self.imgtemp=dict() + """ + + self.imgtemp = dict() - self.pixel = 0.1 # arcsec, pixel scale size; - + self.pixel = 0.1 # arcsec, pixel scale size; ######################################################################################################### ########################################################## + def zodiacal(self, ra, dec, time): """ For given RA, DEC and TIME, return the interpolated zodical spectrum in Leinert-1998. - + :param ra: RA in unit of degree, ICRS frame :param dec: DEC in unit of degree, ICRS frame :param time: the specified string that in ISO format i.e., yyyy-mm-dd. @@ -1135,62 +1170,67 @@ class IFSsimulator(): wave_A: wavelength of the zodical spectrum spec_mjy: flux of the zodical spectrum, in unit of MJy/sr spec_erg: flux of the zodical spectrum, in unit of erg/s/cm^2/A/sr - + """ - + # get solar position dt = datetime.fromisoformat(time) - jd =time2jd(dt) + jd = time2jd(dt) ##jd = julian.to_jd(dt, fmt='jd') - + t = Time(jd, format='jd', scale='utc') - + astro_sun = get_sun(t) ra_sun, dec_sun = astro_sun.gcrs.ra.deg, astro_sun.gcrs.dec.deg - - radec_sun = SkyCoord(ra=ra_sun*u.degree, dec=dec_sun*u.degree, frame='gcrs') + + radec_sun = SkyCoord(ra=ra_sun*u.degree, + dec=dec_sun*u.degree, frame='gcrs') lb_sun = radec_sun.transform_to('geocentrictrueecliptic') - + # get offsets between the target and sun. radec_obj = SkyCoord(ra=ra*u.degree, dec=dec*u.degree, frame='icrs') lb_obj = radec_obj.transform_to('geocentrictrueecliptic') - + beta = abs(lb_obj.lat.degree) lamda = abs(lb_obj.lon.degree - lb_sun.lon.degree) - + # interpolated zodical surface brightness at 0.5 um - zodi = pd.read_csv(self.information['dir_path']+'IFS_inputdata/refs/zodi_map.dat', sep='\s+', header=None, comment='#') + zodi = pd.read_csv( + self.information['dir_path']+'IFS_inputdata/refs/zodi_map.dat', sep='\s+', header=None, comment='#') beta_angle = np.array([0, 5, 10, 15, 20, 25, 30, 45, 60, 75]) lamda_angle = np.array([0, 5, 10, 15, 20, 25, 30, 35, 40, 45, - 60, 75, 90, 105, 120, 135, 150, 165, 180]) + 60, 75, 90, 105, 120, 135, 150, 165, 180]) xx, yy = np.meshgrid(beta_angle, lamda_angle) #xx, yy = np.meshgrid(beta_angle, lamda_angle,indexing='ij', sparse=True) - + f = interpolate.interp2d(xx, yy, zodi, kind='linear') #f = interpolate.RegularGridInterpolator((xx, yy), zodi, method='linear') - - zodi_obj = f(beta, lamda) # - - # read the zodical spectrum in the ecliptic - cat_spec = pd.read_csv(self.information['dir_path']+'IFS_inputdata/refs/solar_spec.dat', sep='\s+', header=None, comment='#') + + zodi_obj = f(beta, lamda) # + + # read the zodical spectrum in the ecliptic + cat_spec = pd.read_csv( + self.information['dir_path']+'IFS_inputdata/refs/solar_spec.dat', sep='\s+', header=None, comment='#') wave = cat_spec[0].values # A - spec0 = cat_spec[1].values # - zodi_norm = 252 # - - spec = spec0 * (zodi_obj / zodi_norm) * 1e-8 # - + spec0 = cat_spec[1].values # + zodi_norm = 252 # + + spec = spec0 * (zodi_obj / zodi_norm) * 1e-8 # + # convert to the commonly used unit of MJy/sr, erg/s/cm^2/A/sr wave_A = wave # A - #spec_mjy = spec * 0.1 * wave_A**2 / 3e18 * 1e23 * 1e-6 # MJy/sr + # spec_mjy = spec * 0.1 * wave_A**2 / 3e18 * 1e23 * 1e-6 # MJy/sr spec_erg = spec * 0.1 # erg/s/cm^2/A/sr - spec_erg2 = spec_erg / 4.25452e10 # erg/s/cm^2/A/arcsec^2 - + # erg/s/cm^2/A/arcsec^2 + spec_erg2 = spec_erg / 4.25452e10 + # self.zodiacal_wave=wave_A # in A - + # self.zodiacal_flux=spec_erg2 - - return wave_A, spec_erg2 + + return wave_A, spec_erg2 ################################################################################### + def smoothingWithChargeDiffusion(self, image, sigma=(0.32, 0.32)): """ Smooths a given image with a gaussian kernel with widths given as sigmas. @@ -1221,8 +1261,10 @@ class IFSsimulator(): """ self.log.info('Reading in cosmic ray information from %s and %s' % (self.information['cosmicraylengths'], self.information['cosmicraydistance'])) - crLengths = np.loadtxt(self.information['dir_path']+self.information['cosmicraylengths']) - crDists = np.loadtxt(self.information['dir_path']+self.information['cosmicraydistance']) + crLengths = np.loadtxt( + self.information['dir_path']+self.information['cosmicraylengths']) + crDists = np.loadtxt( + self.information['dir_path']+self.information['cosmicraydistance']) self.cr = dict(cr_u=crLengths[:, 0], cr_cdf=crLengths[:, 1], cr_cdfn=np.shape(crLengths)[0], cr_v=crDists[:, 0], cr_cde=crDists[:, 1], cr_cden=np.shape(crDists)[0]) @@ -1240,19 +1282,20 @@ class IFSsimulator(): if os.path.isfile(filename): os.remove(filename) - #create a new FITS file, using HDUList instance + # create a new FITS file, using HDUList instance ofd = fits.HDUList(fits.PrimaryHDU()) - #new image HDU + # new image HDU hdu = fits.ImageHDU(data=image) - #update and verify the header - hdu.header.add_history('Created by IFSsim at %s' % datetime.isoformat(datetime.utcnow())) + # update and verify the header + hdu.header.add_history('Created by IFSsim at %s' % + datetime.isoformat(datetime.utcnow())) hdu.verify('fix') ofd.append(hdu) - #write the actual file + # write the actual file ofd.writeto(filename) ############################################################################### @@ -1272,15 +1315,15 @@ class IFSsimulator(): if os.path.isfile(filename): os.remove(filename) - #create a new FITS file, using HDUList instance + # create a new FITS file, using HDUList instance ofd = fits.HDUList(fits.PrimaryHDU()) - #new image HDU + # new image HDU hdu = fits.ImageHDU(data=data) - #add input keywords to the header + # add input keywords to the header for key, value in self.information.items(): - #truncate long keys + # truncate long keys if len(key) > 8: key = key[:7] try: @@ -1291,64 +1334,63 @@ class IFSsimulator(): except: pass - #write booleans + # write booleans for key, value in self.booleans.items(): - #truncate long keys + # truncate long keys if len(key) > 8: key = key[:7] hdu.header.set(key.upper(), str(value), 'Boolean Flags') - #update and verify the header - hdu.header.add_history('This is an itermediate data product no the final output!') + # update and verify the header + hdu.header.add_history( + 'This is an itermediate data product no the final output!') hdu.verify('fix') ofd.append(hdu) - #write the actual file + # write the actual file ofd.writeto(filename) ############################################################################### - def configure(self,simnumber): + def configure(self, simnumber): """ Configures the simulator with input information and creates and empty array to which the final image will be build on. """ self.readConfigs(simnumber) - + self.processConfigs() - + self._createEmpty() - + ############################################################ - - now=datetime.utcnow() - result_day=now.strftime("%Y-%m-%d") - - self.information['holemask'] - - if self.source =='LAMP' : - if self.information['holemask']=='yes' : - ss='_with_hole_' + now = datetime.utcnow() + + result_day = now.strftime("%Y-%m-%d") + + self.information['holemask'] + + if self.source == 'LAMP': + if self.information['holemask'] == 'yes': + ss = '_with_hole_' else: - ss='_no_hole_' - + ss = '_no_hole_' + else: - ss='_' - + ss = '_' # if currentpath =='/home/yan/IFS': - + # self.result_path='../IFS_simData_'+self.source+ss+result_day - + # else: # self.result_path='/data/ifspip/CCD_ima/IFS_simData_'+self.source+ss+result_day - - self.result_path=self.information['result_path']+'/'+result_day - - - if os.path.isdir(self.result_path)==False: + + self.result_path = self.information['result_path']+'/'+result_day + + if os.path.isdir(self.result_path) == False: os.mkdir(self.result_path) os.mkdir(self.result_path+'/calibration_Data') os.mkdir(self.result_path+'/log_file') @@ -1356,135 +1398,136 @@ class IFSsimulator(): os.mkdir(self.result_path+'/original_sky') os.mkdir(self.result_path+'/shift_rot_sky') os.mkdir(self.result_path+'/sky_Data') - - ############################################################################## - now=datetime.utcnow() - - data_time=now.strftime("%Y-%m-%d-%H-%M-%S") + + ############################################################################## + now = datetime.utcnow() + + data_time = now.strftime("%Y-%m-%d-%H-%M-%S") ############################################################ - - self.log = lg.setUpLogger(self.result_path+'/log_file/IFS_'+self.source+'_'+data_time+'_Num_'+str(simnumber)+'.log') - + + self.log = lg.setUpLogger(self.result_path+'/log_file/IFS_' + + self.source+'_'+data_time+'_Num_'+str(simnumber)+'.log') + self.log.info('STARTING A NEW SIMULATION') - - self.log.info('The exposure order is %i ' % self.simnumber ) - + + self.log.info('The exposure order is %i ' % self.simnumber) + ################################################################################ - # public system information - self.pixelscale=0.1 # the pixel size is 0.1 arcsec - self.pixelsize=15 # the pixel physical size is 15 micron - self.Fnum=15.469875 # the f number= focal_length/D; - self.telD=2 # tht telescope size is 2 meter, diamter size; - self.telarea=3.1415926*(self.telD/2)**2*100*100 # telescope square in cm^2 - self.fov2=0.01 # the pixel square - self.planckh= 6.62620*1e-27 # % erg s; - self.cc=2.99792458*1e17 # in nm/s - self.light_FWHM=0.175 - self.HgArsigma=self.light_FWHM/2.35; ## sigma value of the light source; - - #### load system optical and CCD efficiency data - matfn0=self.information['dir_path']+'IFS_inputdata/TotalQ200923.mat' - self.log.info('Optical optical efficiency file path is: %s'%(matfn0)) - da0=sio.loadmat(matfn0) - self.optical_blue_Q=da0['opticalQ_1'] # optical efficiency of blue channel - self.optical_red_Q =da0['opticalQ_2'] # optical efficiency of red channel - self.CCD_Qe=da0['ccdQE'] # red channel - - ############################################################# load all useful data; - ############### load wavefront data; - matfn2=self.information['dir_path']+'IFS_inputdata/opd/opd_638nm.mat' - self.log.info('OPD0 file path is: %s' %(matfn2)) - da2=sio.loadmat(matfn2) - opd0=da2['opd'] # opd unit is in meter - self.opd0=opd0*1e9 # convert opd to nm - self.pupil=abs(opd0)>0.0 - + # public system information + self.pixelscale = 0.1 # the pixel size is 0.1 arcsec + self.pixelsize = 15 # the pixel physical size is 15 micron + self.Fnum = 15.469875 # the f number= focal_length/D; + self.telD = 2 # tht telescope size is 2 meter, diamter size; + self.telarea = 3.1415926*(self.telD/2)**2 * \ + 100*100 # telescope square in cm^2 + self.fov2 = 0.01 # the pixel square + self.planckh = 6.62620*1e-27 # % erg s; + self.cc = 2.99792458*1e17 # in nm/s + self.light_FWHM = 0.175 + self.HgArsigma = self.light_FWHM/2.35 # sigma value of the light source + + # load system optical and CCD efficiency data + matfn0 = self.information['dir_path']+'IFS_inputdata/TotalQ200923.mat' + self.log.info('Optical optical efficiency file path is: %s' % (matfn0)) + da0 = sio.loadmat(matfn0) + # optical efficiency of blue channel + self.optical_blue_Q = da0['opticalQ_1'] + # optical efficiency of red channel + self.optical_red_Q = da0['opticalQ_2'] + self.CCD_Qe = da0['ccdQE'] # red channel + + # load all useful data; + # load wavefront data; + matfn2 = self.information['dir_path']+'IFS_inputdata/opd/opd_638nm.mat' + self.log.info('OPD0 file path is: %s' % (matfn2)) + da2 = sio.loadmat(matfn2) + opd0 = da2['opd'] # opd unit is in meter + self.opd0 = opd0*1e9 # convert opd to nm + self.pupil = abs(opd0) > 0.0 + #################### - matfn2=self.information['dir_path']+'IFS_inputdata/opd/opd1.fits' - da=fits.open(matfn2) - self.opd1=da[0].data - self.log.info('OPD1 file path is: %s' %(matfn2)) - - - matfn2=self.information['dir_path']+'IFS_inputdata/opd/opd2.fits' - self.log.info('OPD2 file path is: %s' %(matfn2)) - da=fits.open(matfn2) - self.opd2=da[0].data - - matfn2=self.information['dir_path']+'IFS_inputdata/opd/opd3.fits' - self.log.info('OPD3 file path is: %s' %(matfn2)) - da=fits.open(matfn2) - self.opd3=da[0].data - - + matfn2 = self.information['dir_path']+'IFS_inputdata/opd/opd1.fits' + da = fits.open(matfn2) + self.opd1 = da[0].data + self.log.info('OPD1 file path is: %s' % (matfn2)) + + matfn2 = self.information['dir_path']+'IFS_inputdata/opd/opd2.fits' + self.log.info('OPD2 file path is: %s' % (matfn2)) + da = fits.open(matfn2) + self.opd2 = da[0].data + + matfn2 = self.information['dir_path']+'IFS_inputdata/opd/opd3.fits' + self.log.info('OPD3 file path is: %s' % (matfn2)) + da = fits.open(matfn2) + self.opd3 = da[0].data ################################################################################ - ## slice information; the slice is put in vertial direction; - # the silce long size is 64 pixels - slice_blue=dict() - slice_red=dict() - - randRedpos=np.array([0.52835362, 1.1105926 , -0.81667794, 0.88860884, -2.78092636, - -0.15810022, -1.56726852, -0.71601855, -1.31768647, 1.73107581, - 0.4933876 , 2.83673377, 0.22226286, -0.02634998, 0.35539383, - -0.91989574, -2.44856212, 0.91020484, -3.03097852, -1.11638071, - 1.28360669, -0.12521128, -0.3907698 , 0.70183575, 1.00578099, - 1.67339662, 0.18067182, -0.56303075, 0.40959616, 1.45518379, - -0.93194744, 0.41492972]) - - randBluepos=np.array([ 0.97449008, -0.21371406, -1.62513338, -3.06938604, 1.72615283, - 0.73333374, 0.80923919, -0.9418576 , -0.16806578, -1.04416631, - 2.20155068, -0.0900156 , 0.07597706, 0.76208373, 0.29426592, - -0.89434703, 0.34017826, 1.16936499, 0.10977829, -1.31179539, - -0.50859787, -1.01891651, -0.95791581, -1.53018041, 0.88358827, - 0.07837641, -0.86157157, -1.18070438, 0.53970599, 1.4913733 , - 2.10938775, 1.23213412]) - + # slice information; the slice is put in vertial direction; + # the silce long size is 64 pixels + slice_blue = dict() + slice_red = dict() + + randRedpos = np.array([0.52835362, 1.1105926, -0.81667794, 0.88860884, -2.78092636, + -0.15810022, -1.56726852, -0.71601855, -1.31768647, 1.73107581, + 0.4933876, 2.83673377, 0.22226286, -0.02634998, 0.35539383, + -0.91989574, -2.44856212, 0.91020484, -3.03097852, -1.11638071, + 1.28360669, -0.12521128, -0.3907698, 0.70183575, 1.00578099, + 1.67339662, 0.18067182, -0.56303075, 0.40959616, 1.45518379, + -0.93194744, 0.41492972]) + + randBluepos = np.array([0.97449008, -0.21371406, -1.62513338, -3.06938604, 1.72615283, + 0.73333374, 0.80923919, -0.9418576, -0.16806578, -1.04416631, + 2.20155068, -0.0900156, 0.07597706, 0.76208373, 0.29426592, + -0.89434703, 0.34017826, 1.16936499, 0.10977829, -1.31179539, + -0.50859787, -1.01891651, -0.95791581, -1.53018041, 0.88358827, + 0.07837641, -0.86157157, -1.18070438, 0.53970599, 1.4913733, + 2.10938775, 1.23213412]) + ##################### for i in range(32): - if i==0: - slice_blue['py']=np.zeros(32) - slice_blue['px']=np.zeros(32) - - slice_red['py']=np.zeros(32) - slice_red['px']=np.zeros(32) - - if i<16: - slice_blue['py'][i]=50+randBluepos[i]*4 - slice_blue['px'][i]=3.55/0.015*i+166.0 - - - slice_red['py'][i]=50+randBluepos[i]*4 - slice_red['px'][i]=3.55/0.015*i+1190.0 - - else: - slice_blue['py'][i]=50+250+randBluepos[i]*4 - slice_blue['px'][i]=3.55/0.015*(i-16)+166.0+118 - - - slice_red['py'][i]=50+250+randBluepos[i]*4 - slice_red['px'][i]=3.55/0.015*(i-16)+1190.0+118 - ####### - - self.slice_blue=slice_blue - self.slice_red=slice_red - + if i == 0: + slice_blue['py'] = np.zeros(32) + slice_blue['px'] = np.zeros(32) + + slice_red['py'] = np.zeros(32) + slice_red['px'] = np.zeros(32) + + if i < 16: + slice_blue['py'][i] = 50+randBluepos[i]*4 + slice_blue['px'][i] = 3.55/0.015*i+166.0 + + slice_red['py'][i] = 50+randRedpos[i]*4 + slice_red['px'][i] = 3.55/0.015*i+1190.0 + + else: + slice_blue['py'][i] = 50+250+randBluepos[i]*4 + slice_blue['px'][i] = 3.55/0.015*(i-16)+166.0+118 + + slice_red['py'][i] = 50+250+randRedpos[i]*4 + slice_red['px'][i] = 3.55/0.015*(i-16)+1190.0+118 + ####### + + self.slice_blue = slice_blue + self.slice_red = slice_red + ############################################################################### - maskSlice=dict() - maskSlit=dict() - sizeout=100 + maskSlice = dict() + maskSlit = dict() + sizeout = 100 for k in range(32): - maskSlice[str(k)]=np.zeros((sizeout,sizeout)) - maskSlice[str(k)][2*k+18:2*k+20, int(sizeout/2)-32:int(sizeout/2)+32]=1 - - maskSlit[str(k)]=np.zeros((sizeout,sizeout)) - maskSlit[str(k)][2*k+18:2*k+20, int(sizeout/2)-37:int(sizeout/2)+37]=1 - - self.maskSlice=maskSlice - self.maskSlit =maskSlit + maskSlice[str(k)] = np.zeros((sizeout, sizeout)) + maskSlice[str(k)][2*k+18:2*k+20, int(sizeout/2) - + 32:int(sizeout/2)+32] = 1 + + maskSlit[str(k)] = np.zeros((sizeout, sizeout)) + maskSlit[str(k)][2*k+18:2*k+20, int(sizeout/2) - + 37:int(sizeout/2)+37] = 1 + + self.maskSlice = maskSlice + self.maskSlit = maskSlit ################################################################################################ -################################################################################################################# +################################################################################################################# def generateflat(self, ave=1.0, sigma=0.01): """ Creates a flat field image with given properties. @@ -1493,43 +1536,45 @@ class IFSsimulator(): :rtype: ndarray """ self.log.info('Generating a flat field...') - self.log.info('The flat field has mean value of 1 and a given fluctuations, usually either 1 or 2 percent defined by sigma= %d...' % sigma) - + self.log.info( + 'The flat field has mean value of 1 and a given fluctuations, usually either 1 or 2 percent defined by sigma= %d...' % sigma) + np.random.seed(5*self.simnumber) self.flat_b = np.random.normal(loc=ave, scale=sigma, size=(2048, 4096)) - + np.random.seed(55*self.simnumber) self.flat_r = np.random.normal(loc=ave, scale=sigma, size=(3072, 6144)) - - s1=self.flat_b - - hdu1=fits.PrimaryHDU(s1) + + s1 = self.flat_b + + hdu1 = fits.PrimaryHDU(s1) hdu1.header.set('sigma', sigma) - - dtime=datetime.utcnow().strftime('%Y -%m -%d %H: %M: %S') - hdu1.header.add_history('flat image of blue channel is generated on :'+dtime) - - f1='../flat_Blue_'+str(sigma)+'.fits' - fits.writeto(f1, s1,header=hdu1.header, overwrite=True) - - - s2=self.flat_r - - hdu1=fits.PrimaryHDU(s2) + + dtime = datetime.utcnow().strftime('%Y -%m -%d %H: %M: %S') + hdu1.header.add_history( + 'flat image of blue channel is generated on :'+dtime) + + f1 = '../flat_Blue_'+str(sigma)+'.fits' + fits.writeto(f1, s1, header=hdu1.header, overwrite=True) + + s2 = self.flat_r + + hdu1 = fits.PrimaryHDU(s2) hdu1.header.set('sigma', sigma) - - dtime=datetime.utcnow().strftime('%Y -%m -%d %H: %M: %S') - hdu1.header.add_history('flat image of red channel is generated on :'+dtime) - - f2='../flat_Red_'+str(sigma)+'.fits' - fits.writeto(f2, s2,header=hdu1.header, overwrite=True) - + + dtime = datetime.utcnow().strftime('%Y -%m -%d %H: %M: %S') + hdu1.header.add_history( + 'flat image of red channel is generated on :'+dtime) + + f2 = '../flat_Red_'+str(sigma)+'.fits' + fits.writeto(f2, s2, header=hdu1.header, overwrite=True) + return self.flat_b, self.flat_r - - + ######################################################################################################### + def addLampFlux(self): """ Include flux from the calibration source. @@ -1537,28 +1582,31 @@ class IFSsimulator(): self.image_b += fits.getdata(self.information['flatflux']) self.image_r += fits.getdata(self.information['flatflux']) - - self.log.info('Flux from the calibration unit included (%s)' % self.information['flatflux']) - - ############################################################################# + + self.log.info('Flux from the calibration unit included (%s)' % + self.information['flatflux']) + + ############################################################################# def MakeFlatMatrix(self, img, seed): #### - ysize, xsize=img.shape + ysize, xsize = img.shape np.random.seed(seed) - r1,r2,r3,r4 = np.random.random(4) + r1, r2, r3, r4 = np.random.random(4) a1 = -0.5 + 0.2*r1 a2 = -0.5 + 0.2*r2 a3 = r3+5 a4 = r4+5 - xmin,xmax,ymin,ymax = 0, xsize,0, ysize - Flty, Fltx = np.mgrid[ymin:ymax, xmin:xmax] + xmin, xmax, ymin, ymax = 0, xsize, 0, ysize + Flty, Fltx = np.mgrid[ymin:ymax, xmin:xmax] np.random.seed(seed) - p1,p2,bg=np.random.poisson(1000, 3) - Fltz = 1e-6*(a1 * (Fltx-p1) ** 2 + a2 * (Flty-p2) ** 2 - a3*Fltx - a4*Flty) + bg*20 + p1, p2, bg = np.random.poisson(1000, 3) + Fltz = 1e-6*(a1 * (Fltx-p1) ** 2 + a2 * (Flty-p2) + ** 2 - a3*Fltx - a4*Flty) + bg*20 FlatMat = Fltz/np.mean(Fltz) - + return FlatMat #################################################################### + def getFrameTransferImg(self): """ get frame transfer image from original image of self.image_b and self.image_r @@ -1567,44 +1615,44 @@ class IFSsimulator(): self.frame_b_3 = np.zeros((1024+320, 2048), dtype=float) self.frame_b_2 = np.zeros((1024+320, 2048), dtype=float) self.frame_b_1 = np.zeros((1024+320, 2048), dtype=float) - + self.frame_r_4 = np.zeros((1536+320, 3072), dtype=float) self.frame_r_3 = np.zeros((1536+320, 3072), dtype=float) self.frame_r_2 = np.zeros((1536+320, 3072), dtype=float) self.frame_r_1 = np.zeros((1536+320, 3072), dtype=float) - - #### blue channle - b_4=np.sum(self.image_b[0:1024,0:2048], axis=0) - b_3=np.sum(self.image_b[0:1024,2048:4096], axis=0) - - b_2=np.sum(self.image_b[1024:1024+1024,2048:2048+2048], axis=0) - b_1=np.sum(self.image_b[1024:1024+1024,0:2048], axis=0) - + + # blue channle + b_4 = np.sum(self.image_b[0:1024, 0:2048], axis=0) + b_3 = np.sum(self.image_b[0:1024, 2048:4096], axis=0) + + b_2 = np.sum(self.image_b[1024:1024+1024, 2048:2048+2048], axis=0) + b_1 = np.sum(self.image_b[1024:1024+1024, 0:2048], axis=0) + for k in range(1024+320): - ###part - self.frame_b_4[k,:]+=b_4*0.09216/self.information['exptime'] - self.frame_b_3[k,:]+=b_3*0.09216/self.information['exptime'] - self.frame_b_2[k,:]+=b_2*0.09216/self.information['exptime'] - self.frame_b_1[k,:]+=b_1*0.09216/self.information['exptime'] - + # part + self.frame_b_4[k, :] += b_4*0.09216/self.information['exptime'] + self.frame_b_3[k, :] += b_3*0.09216/self.information['exptime'] + self.frame_b_2[k, :] += b_2*0.09216/self.information['exptime'] + self.frame_b_1[k, :] += b_1*0.09216/self.information['exptime'] + ################### - #### red channle - r_4=np.sum(self.image_r[0:1536, 0:3072], axis=0) - r_3=np.sum(self.image_r[0:1536, 3072:6144], axis=0) - - r_2=np.sum(self.image_r[1536:1536+1536, 3072:6144], axis=0) - r_1=np.sum(self.image_r[1536:1536+1536, 0:3072], axis=0) - + # red channle + r_4 = np.sum(self.image_r[0:1536, 0:3072], axis=0) + r_3 = np.sum(self.image_r[0:1536, 3072:6144], axis=0) + + r_2 = np.sum(self.image_r[1536:1536+1536, 3072:6144], axis=0) + r_1 = np.sum(self.image_r[1536:1536+1536, 0:3072], axis=0) + for k in range(1536+320): - ###part 4, OSH zone; - self.frame_r_4[k,:]+=r_4*0.13824/self.information['exptime'] - self.frame_r_3[k,:]+=r_3*0.13824/self.information['exptime'] - self.frame_r_2[k,:]+=r_2*0.13824/self.information['exptime'] - self.frame_r_1[k,:]+=r_1*0.13824/self.information['exptime'] - #### end - + # part 4, OSH zone; + self.frame_r_4[k, :] += r_4*0.13824/self.information['exptime'] + self.frame_r_3[k, :] += r_3*0.13824/self.information['exptime'] + self.frame_r_2[k, :] += r_2*0.13824/self.information['exptime'] + self.frame_r_1[k, :] += r_1*0.13824/self.information['exptime'] + # end + ############################################################################### - def applyflatfield(self,simnumber): + def applyflatfield(self, simnumber): """ Applies multiplicative flat field to emulate pixel-to-pixel non-uniformity. @@ -1612,20 +1660,20 @@ class IFSsimulator(): before CTI and other effects, the flat field file must be the same size as the pixels that see the sky. """ - #### apply Flat field to image + # apply Flat field to image ### - flat_b=self.MakeFlatMatrix(self.image_b, 100) - - flat_r=self.MakeFlatMatrix(self.image_r, 200) - + flat_b = self.MakeFlatMatrix(self.image_b, 100) + + flat_r = self.MakeFlatMatrix(self.image_r, 200) + self.image_b *= flat_b - + self.image_r *= flat_r - + self.log.info('Applied flatfield to images.') - + return - + ################################################################################# def addChargeInjection(self): @@ -1635,58 +1683,65 @@ class IFSsimulator(): if self.chargeInjectionx: #self.image[1500:1511, :] = self.information['injection'] self.image_b[1500:1511, :] = self.information['injection'] - self.image_r[1500:1511, :] = self.information['injection'] + self.image_r[1500:1511, :] = self.information['injection'] self.log.info('Adding vertical charge injection line') - + if self.chargeInjectiony: #self.image[:, 1500:1511] = self.information['injection'] self.image_b[:, 1500:1511] = self.information['injection'] - self.image_r[:, 1500:1511] = self.information['injection'] + self.image_r[:, 1500:1511] = self.information['injection'] self.log.info('Adding horizontal charge injection line') ############################################################################### - def addCosmicRays(self,idk): + def addCosmicRays(self, idk): """ Add cosmic rays to the arrays based on a power-law intensity distribution for tracks. Cosmic ray properties (such as location and angle) are chosen from random Uniform distribution. For details, see the documentation for the cosmicrays class in the support package. """ self.readCosmicRayInformation() - self.cr['exptime'] = self.information['exptime'] #to scale the number of cosmics with exposure time + # to scale the number of cosmics with exposure time + self.cr['exptime'] = self.information['exptime'] - #cosmic ray image + # cosmic ray image crImage_b = np.zeros((2048, 4096), dtype=float) - + crImage_r = np.zeros((3072, 6144), dtype=float) - #cosmic ray instance + # cosmic ray instance cosmics_b = cosmicrays.cosmicrays(self.log, crImage_b, crInfo=self.cr) cosmics_r = cosmicrays.cosmicrays(self.log, crImage_r, crInfo=self.cr) - - CCD_cr_b = cosmics_b.addUpToFraction(self.information['coveringfraction']*self.information['exptime']/300.0, limit=None) - CCD_cr_r = cosmics_r.addUpToFraction(self.information['coveringfraction']*self.information['exptime']/300.0, limit=None) - - #paste the information + + CCD_cr_b = cosmics_b.addUpToFraction( + self.information['coveringfraction']*self.information['exptime']/300.0, limit=None) + CCD_cr_r = cosmics_r.addUpToFraction( + self.information['coveringfraction']*self.information['exptime']/300.0, limit=None) + + # paste the information #self.image += CCD_cr self.image_b += CCD_cr_b - self.image_r += CCD_cr_r - #count the covering factor + self.image_r += CCD_cr_r + # count the covering factor area_cr_b = np.count_nonzero(CCD_cr_b) - area_cr_r = np.count_nonzero(CCD_cr_r) - + area_cr_r = np.count_nonzero(CCD_cr_r) + #self.log.info('The cosmic ray covering factor is %i pixels ' % area_cr) - self.log.info('The cosmic ray in blue channel covering factor is %i pixels ' % area_cr_b) - self.log.info('The cosmic ray in red channel covering factor is %i pixels ' % area_cr_r) - - if self.save_cosmicrays : - + self.log.info( + 'The cosmic ray in blue channel covering factor is %i pixels ' % area_cr_b) + self.log.info( + 'The cosmic ray in red channel covering factor is %i pixels ' % area_cr_r) + + if self.save_cosmicrays: + self.log.info('Saved the cosmicRays fits...') - fits.writeto(self.result_path+'/calibration_Data/cosmicMap_B_SN_'+str(self.simnumber)+'_exp_'+str(idk)+'.fits',np.int32(CCD_cr_b), overwrite=True) - fits.writeto(self.result_path+'/calibration_Data/cosmicMap_R_SN_'+str(self.simnumber)+'_exp_'+str(idk)+'.fits',np.int32(CCD_cr_r), overwrite=True) - - ########################################################## -######################################################################### + fits.writeto(self.result_path+'/calibration_Data/cosmicMap_B_SN_'+str( + self.simnumber)+'_exp_'+str(idk)+'.fits', np.int32(CCD_cr_b), overwrite=True) + fits.writeto(self.result_path+'/calibration_Data/cosmicMap_R_SN_'+str( + self.simnumber)+'_exp_'+str(idk)+'.fits', np.int32(CCD_cr_r), overwrite=True) + + ########################################################## +######################################################################### def addReadoutTrails(self): """ @@ -1696,19 +1751,20 @@ class IFSsimulator(): 2 3 0 1 """ - flux_ratio = self.information['readouttime'] / float(self.information['bluesize']) / self.information['exptime'] - - #make a copy, this will be updated + flux_ratio = self.information['readouttime'] / float( + self.information['bluesize']) / self.information['exptime'] + + # make a copy, this will be updated data = self.image_b.copy() - #Amplifier at different positions depending on the quadrant number ! - #left side is 0, 2 and right side is 1, 3 starting from bottom i.e. - #going clock wise from lower left we have 0, 2, 3, and 1 quadrants. + # Amplifier at different positions depending on the quadrant number ! + # left side is 0, 2 and right side is 1, 3 starting from bottom i.e. + # going clock wise from lower left we have 0, 2, 3, and 1 quadrants. if self.information['quadrant'] in (2, 3): data = data[::-1, :] - + data_shift = data.copy() * flux_ratio size1, size2 = data.shape - + for i in range(1, size2, 1): data_shift2 = np.roll(data_shift, i, axis=0) data_shift2[:i, :] = 0.0 @@ -1718,20 +1774,21 @@ class IFSsimulator(): self.image_b = data[::-1, :] else: self.image_b = data - - #############################################################################3 - flux_ratio = self.information['readouttime'] / float(self.information['redsize']) / self.information['exptime'] - #make a copy, this will be updated + + # 3 + flux_ratio = self.information['readouttime'] / float( + self.information['redsize']) / self.information['exptime'] + # make a copy, this will be updated data = self.image_r.copy() - #Amplifier at different positions depending on the quadrant number ! - #left side is 0, 2 and right side is 1, 3 starting from bottom i.e. - #going clock wise from lower left we have 0, 2, 3, and 1 quadrants. + # Amplifier at different positions depending on the quadrant number ! + # left side is 0, 2 and right side is 1, 3 starting from bottom i.e. + # going clock wise from lower left we have 0, 2, 3, and 1 quadrants. if self.information['quadrant'] in (2, 3): data = data[::-1, :] - + data_shift = data.copy() * flux_ratio size1, size2 = data.shape - + for i in range(1, size2, 1): data_shift2 = np.roll(data_shift, i, axis=0) data_shift2[:i, :] = 0.0 @@ -1741,9 +1798,8 @@ class IFSsimulator(): self.image_r = data[::-1, :] else: self.image_r = data - -############################################################################################################## +############################################################################################################## def applyDarkCurrent(self): """ @@ -1751,36 +1807,44 @@ class IFSsimulator(): Additionally saves the image without noise to a FITS file. """ - - self.log.info('Added dark current to bule and red channel' ) - - ########## blue zone 4 - self.image_b[0:1024,0:2048] += self.information['exptime'] * self.information['dark4_b'] - + + self.log.info('Added dark current to bule and red channel') + + # blue zone 4 + self.image_b[0:1024, 0:2048] += self.information['exptime'] * \ + self.information['dark4_b'] + ########## zone 1 ################# - self.image_b[1024:2048,0:2048] += self.information['exptime'] * self.information['dark1_b'] - + self.image_b[1024:2048, 0:2048] += self.information['exptime'] * \ + self.information['dark1_b'] + ########## zone 3 ################### - self.image_b[0:1024,2048:4096] += self.information['exptime'] * self.information['dark3_b'] - - ########## zone 2 - self.image_b[1024:2048,2048:4096]+= self.information['exptime'] * self.information['dark2_b'] - - - ########## red zone 4 - self.image_r[0:1536, 0:3072] += self.information['exptime'] * self.information['dark4_r'] + self.image_b[0:1024, 2048:4096] += self.information['exptime'] * \ + self.information['dark3_b'] + + # zone 2 + self.image_b[1024:2048, 2048:4096] += self.information['exptime'] * \ + self.information['dark2_b'] + + # red zone 4 + self.image_r[0:1536, 0:3072] += self.information['exptime'] * \ + self.information['dark4_r'] ########## zone 1 ################# - self.image_r[1536:3712,0:3072] += self.information['exptime'] * self.information['dark1_r'] - + self.image_r[1536:3712, 0:3072] += self.information['exptime'] * \ + self.information['dark1_r'] + ########## zone 3 ################### - self.image_r[0:1536,3072:6144] += self.information['exptime'] * self.information['dark3_r'] - - ########## zone 2 - self.image_r[1536:3072,3072:6144] += self.information['exptime'] * self.information['dark2_r'] - + self.image_r[0:1536, 3072:6144] += self.information['exptime'] * \ + self.information['dark3_r'] + + # zone 2 + self.image_r[1536:3072, 3072:6144] += self.information['exptime'] * \ + self.information['dark2_r'] + + +# 3 -#######################################################################################################3 def applyCosmicBackground(self): """ @@ -1789,21 +1853,20 @@ class IFSsimulator(): Additionally saves the image without noise to a FITS file. """ - #add background + # add background bcgr = self.information['exptime'] * self.information['cosmic_bkgd'] - + self.image_b += bcgr - self.image_r += bcgr - + self.image_r += bcgr + self.log.info('Added cosmic background = %f' % bcgr) if self.cosmicRays: #self.imagenoCR += bcgr self.imagenoCR_b += bcgr self.imagenoCR_r += bcgr - - ########################################################################################## + ########################################################################################## def applyScatteredLight(self): """ @@ -1813,7 +1876,7 @@ class IFSsimulator(): self.image_b += sl self.image_r += sl - + self.log.info('Added scattered light = %f' % sl) ############################################################################## @@ -1821,90 +1884,94 @@ class IFSsimulator(): """ Add Poisson noise to the image. """ - - rounded = np.rint(self.image_b) ### round to - residual = self.image_b.copy() - rounded #ugly workaround for multiple rounding operations... + + rounded = np.rint(self.image_b) # round to + # ugly workaround for multiple rounding operations... + residual = self.image_b.copy() - rounded rounded[rounded < 0.0] = 0.0 - + np.random.seed() self.image_b = np.random.poisson(rounded).astype(float) self.log.info('Added Poisson noise on channel blue') self.image_b += residual - - rounded = np.rint(self.image_r) ### round to - residual = self.image_r.copy() - rounded #ugly workaround for multiple rounding operations... + + rounded = np.rint(self.image_r) # round to + # ugly workaround for multiple rounding operations... + residual = self.image_r.copy() - rounded rounded[rounded < 0.0] = 0.0 np.random.seed() self.image_r = np.random.poisson(rounded).astype(float) self.log.info('Added Poisson noise on channel red') - self.image_r += residual + self.image_r += residual ################################################################################################################### + def applyCosmetics(self): """ Apply cosmetic defects described in the input file. - + #Number of hot and dead pixels from MSSL/Euclid/TR/12003 Issue 2 Draft b .. Warning:: This method does not work if the input file has exactly one line. """ - cosmetics = np.loadtxt(self.information['dir_path']+self.information['cosmeticsfile_b']) - self.log.info('cosmeticsfile_b path is: %s' %(self.information['cosmeticsfile_b'])) - + cosmetics = np.loadtxt( + self.information['dir_path']+self.information['cosmeticsfile_b']) + self.log.info('cosmeticsfile_b path is: %s' % + (self.information['cosmeticsfile_b'])) + x = np.round(cosmetics[:, 0]).astype(int) y = np.round(cosmetics[:, 1]).astype(int) value = cosmetics[:, 2] - # cosmetics_b=np.zeros((1344,9642)) - - # cosmetics_r=np.zeros((1856,13768)) - - self.log.info('Adding cosmetic defects to blue channel:' ) + # cosmetics_b=np.zeros((1344,9642)) + + # cosmetics_r=np.zeros((1856,13768)) + + self.log.info('Adding cosmetic defects to blue channel:') for xc, yc, val in zip(x, y, value): - if 0 <= xc <= 1024 and 50 < yc%2418 <= 2048+50: + if 0 <= xc <= 1024 and 50 < yc % 2418 <= 2048+50: #self.image[yc, xc] = val - self.image_b[xc, yc] = val - #cosmetics_b[xc,yc]=val + self.image_b[xc, yc] = val + # cosmetics_b[xc,yc]=val self.log.info('x=%i, y=%i, value=%f' % (xc, yc, val)) ###################################################################################################### - cosmetics = np.loadtxt(self.information['dir_path']+self.information['cosmeticsfile_r']) - - self.log.info('cosmeticsfile_r path is: %s' %(self.information['cosmeticsfile_r'])) - + cosmetics = np.loadtxt( + self.information['dir_path']+self.information['cosmeticsfile_r']) + + self.log.info('cosmeticsfile_r path is: %s' % + (self.information['cosmeticsfile_r'])) + x = np.round(cosmetics[:, 0]).astype(int) y = np.round(cosmetics[:, 1]).astype(int) value = cosmetics[:, 2] - - - self.log.info('Adding cosmetic defects to red channel:' ) + + self.log.info('Adding cosmetic defects to red channel:') for xc, yc, val in zip(x, y, value): - if 0 <= xc <= 1536 and 50 < yc%3442 <= 3072+50: + if 0 <= xc <= 1536 and 50 < yc % 3442 <= 3072+50: #self.image[yc, xc] = val - self.image_r[xc, yc] = val - #cosmetics_r[yc,xc]=val + self.image_r[xc, yc] = val + # cosmetics_r[yc,xc]=val self.log.info('x=%i, y=%i, value=%f' % (xc, yc, val)) - - - ####### save cosmetics image code #### + + ####### save cosmetics image code #### # if self.simnumber<2: - # #save cosmic ray image map - + # #save cosmic ray image map + # obsid=self.simnumber - # bluefile=self.result_path+'/calibration_Data/IFS_cosmetics'+'_'+str(obsid)+'_B.fits' - # redfile =self.result_path+'/calibration_Data/IFS_cosmetics'+'_'+str(obsid)+'_R.fits' - - # fits.writeto(bluefile, cosmetics_b, overwrite=True) + # bluefile=self.result_path+'/calibration_Data/IFS_cosmetics'+'_'+str(obsid)+'_B.fits' + # redfile =self.result_path+'/calibration_Data/IFS_cosmetics'+'_'+str(obsid)+'_R.fits' + + # fits.writeto(bluefile, cosmetics_b, overwrite=True) # fits.writeto(redfile, cosmetics_r, overwrite=True) - + # #output information to a FITS file # self.log.info('Save cosmetics images fits file to calibration_Data file ') -################################################################################ - +################################################################################ def applyRadiationDamage(self): """ @@ -1913,37 +1980,37 @@ class IFSsimulator(): .. seealso:: Class :`CDM03` """ - self.log.debug('Starting to apply radiation damage model...') - #at this point we can give fake data... + # at this point we can give fake data... cti = CTI.CDM03bidir(self.information, [], log=self.log) - #here we need the right input data - self.image_b = cti.applyRadiationDamage(self.image_b.copy().transpose(), iquadrant=self.information['quadrant']).transpose() + # here we need the right input data + self.image_b = cti.applyRadiationDamage(self.image_b.copy( + ).transpose(), iquadrant=self.information['quadrant']).transpose() self.log.info('Radiation damage added.') - self.log.debug('Starting to apply radiation damage model...') - #at this point we can give fake data... + # at this point we can give fake data... cti = CTI.CDM03bidir(self.information, [], log=self.log) - #here we need the right input data - self.image_r = cti.applyRadiationDamage(self.image_r.copy().transpose(), iquadrant=self.information['quadrant']).transpose() + # here we need the right input data + self.image_r = cti.applyRadiationDamage(self.image_r.copy( + ).transpose(), iquadrant=self.information['quadrant']).transpose() self.log.info('Radiation damage added.') ################################################################################## - def applyNonlinearity(self): """ Applies a CCD273 non-linearity model to the image being constructed. """ self.log.debug('Starting to apply non-linearity model...') - self.image_b = IFSinstrumentModel.CCDnonLinearityModel(self.image_b.copy()) + self.image_b = IFSinstrumentModel.CCDnonLinearityModel( + self.image_b.copy()) self.log.info('Non-linearity effects included.') - - + self.log.debug('Starting to apply non-linearity model...') - self.image_r = IFSinstrumentModel.CCDnonLinearityModel(self.image_r.copy()) + self.image_r = IFSinstrumentModel.CCDnonLinearityModel( + self.image_r.copy()) self.log.info('Non-linearity effects included.') ######################################################################################## @@ -1954,131 +2021,144 @@ class IFSsimulator(): The noise is drawn from a Normal (Gaussian) distribution with average=0.0 and std=readout noise. """ - self.log.info('readnoise added in blue channel') - ########## blue zone 1 + self.log.info('readnoise added in blue channel') + # blue zone 1 np.random.seed() - prescan=50 - overscan=320 - ####zone 4 , OSH #### 1024, 2048 - self.image_b[0:1024+overscan,0:2048+prescan+overscan]+=np.random.normal(loc=0.0, scale=self.information['rn4_b'], size=(1344,2418)) - + prescan = 50 + overscan = 320 + # zone 4 , OSH #### 1024, 2048 + self.image_b[0:1024+overscan, 0:2048+prescan+overscan] += np.random.normal( + loc=0.0, scale=self.information['rn4_b'], size=(1344, 2418)) + ########## zone 3, OSG ################# np.random.seed() - self.image_b[0:1024+overscan,2418:2418+2048+prescan+overscan]+=np.random.normal(loc=0.0, scale=self.information['rn3_b'], size=(1344,2418)) - + self.image_b[0:1024+overscan, 2418:2418+2048+prescan+overscan] += np.random.normal( + loc=0.0, scale=self.information['rn3_b'], size=(1344, 2418)) + ########## zone 1, OSE ################### np.random.seed() - self.image_b[0:1024+overscan,2418*2:2418*2+2048+prescan+overscan]+=np.random.normal(loc=0.0, scale=self.information['rn1_b'], size=(1344,2418)) - + self.image_b[0:1024+overscan, 2418*2:2418*2+2048+prescan+overscan] += np.random.normal( + loc=0.0, scale=self.information['rn1_b'], size=(1344, 2418)) + ########## zone 2, OSF ############### np.random.seed() - self.image_b[0:1024+overscan,2418*3:2418*3+2048+prescan+overscan]+=np.random.normal(loc=0.0, scale=self.information['rn2_b'], size=(1344,2418)) - - - ############################################################################3 - - self.log.info('readnoise added in blue channel') + self.image_b[0:1024+overscan, 2418*3:2418*3+2048+prescan+overscan] += np.random.normal( + loc=0.0, scale=self.information['rn2_b'], size=(1344, 2418)) + # 3 - ########## red zone 4 , OSH### 1536* 3072 + self.log.info('readnoise added in blue channel') + + # red zone 4 , OSH### 1536* 3072 np.random.seed() - self.image_r[0:1536+overscan, 0:3072+prescan+overscan]+=np.random.normal(loc=0.0, scale=self.information['rn4_r'], size=(1856,3442)) - + self.image_r[0:1536+overscan, 0:3072+prescan+overscan] += np.random.normal( + loc=0.0, scale=self.information['rn4_r'], size=(1856, 3442)) + ########## zone 3 ,OSG ################# np.random.seed() - self.image_r[0:1536+overscan, 3442:3442+3072+prescan+overscan]+=np.random.normal(loc=0.0, scale=self.information['rn3_r'], size=(1856,3442)) - + self.image_r[0:1536+overscan, 3442:3442+3072+prescan+overscan] += np.random.normal( + loc=0.0, scale=self.information['rn3_r'], size=(1856, 3442)) + ########## zone 1 ,OSE ################### np.random.seed() - self.image_r[0:1536+overscan, 3442*2:3442*2+3072+prescan+overscan]+=np.random.normal(loc=0.0, scale=self.information['rn1_r'], size=(1856,3442)) - + self.image_r[0:1536+overscan, 3442*2:3442*2+3072+prescan+overscan] += np.random.normal( + loc=0.0, scale=self.information['rn1_r'], size=(1856, 3442)) + ########## zone 2,OSF ########### np.random.seed() - self.image_r[0:1536+overscan, 3442*3:3442*3+3072+prescan+overscan]+=np.random.normal(loc=0.0, scale=self.information['rn2_r'], size=(1856,3442)) - -########################################################################################## + self.image_r[0:1536+overscan, 3442*3:3442*3+3072+prescan+overscan] += np.random.normal( + loc=0.0, scale=self.information['rn2_r'], size=(1856, 3442)) + +########################################################################################## def appFrameTransferEffect(self): - """ apply frame transfer effect to the four part images """ - prescan=50 - overscan=8 - - ####zone 4 , OSH #### 1024, 2048 - self.image_b[0:1024+overscan, prescan:2048+prescan]+=self.frame_b_4[0:1024+overscan, 0:2048] - + prescan = 50 + overscan = 8 + + # zone 4 , OSH #### 1024, 2048 + self.image_b[0:1024+overscan, prescan:2048 + + prescan] += self.frame_b_4[0:1024+overscan, 0:2048] + ########## zone 3, OSG ################# - - self.image_b[0:1024+overscan, prescan+2418:2418+2048+prescan]+=self.frame_b_3[0:1024+overscan, 0:2048] - + + self.image_b[0:1024+overscan, prescan+2418:2418+2048 + + prescan] += self.frame_b_3[0:1024+overscan, 0:2048] + ########## zone 1, OSE ################### - - self.image_b[0:1024+overscan, prescan+2418*2:2418*2+2048+prescan]+=self.frame_b_1[0:1024+overscan, 0:2048] - + + self.image_b[0:1024+overscan, prescan+2418*2:2418*2 + + 2048+prescan] += self.frame_b_1[0:1024+overscan, 0:2048] + ########## zone 2, OSF ############### - - self.image_b[0:1024+overscan, prescan+2418*3:2418*3+2048+prescan]+=self.frame_b_2[0:1024+overscan, 0:2048] - - ############################################################################3 - - self.log.info('readnoise added in blue channel') + self.image_b[0:1024+overscan, prescan+2418*3:2418*3 + + 2048+prescan] += self.frame_b_2[0:1024+overscan, 0:2048] + + # 3 + + self.log.info('readnoise added in blue channel') + + # red zone 4 , OSH### 1536* 3072 + + self.image_r[0:1536+overscan, prescan+3442*0:3442*0 + + 3072+prescan] += self.frame_r_4[0:1536+overscan, 0:3072] - ########## red zone 4 , OSH### 1536* 3072 - - self.image_r[0:1536+overscan, prescan+3442*0:3442*0+3072+prescan]+=self.frame_r_4[0:1536+overscan, 0:3072] - ########## zone 3 ,OSG ################# - - self.image_r[0:1536+overscan, prescan+3442*1:3442*1+3072+prescan]+=self.frame_r_3[0:1536+overscan, 0:3072] - + + self.image_r[0:1536+overscan, prescan+3442*1:3442*1 + + 3072+prescan] += self.frame_r_3[0:1536+overscan, 0:3072] + ########## zone 1 ,OSE ################### - self.image_r[0:1536+overscan, prescan+3442*2:3442*2+3072+prescan]+=self.frame_r_1[0:1536+overscan, 0:3072] - + self.image_r[0:1536+overscan, prescan+3442*2:3442*2 + + 3072+prescan] += self.frame_r_1[0:1536+overscan, 0:3072] + ########## zone 2,OSF ########### - self.image_r[0:1536+overscan, prescan+3442*3:3442*3+3072+prescan]+=self.frame_r_2[0:1536+overscan, 0:3072] - - #############################################################################################3 - + self.image_r[0:1536+overscan, prescan+3442*3:3442*3 + + 3072+prescan] += self.frame_r_2[0:1536+overscan, 0:3072] + + # 3 + def electrons2ADU(self): """ Convert from electrons to ADUs using the value read from the configuration file. """ - self.log.info('Converting from electrons to ADUs using a factor of gain' ) + self.log.info( + 'Converting from electrons to ADUs using a factor of gain') + + # blue zone 4 + self.image_b[0:1344, 0:2418] /= self.information['gain4_b'] - ########## blue zone 4 - self.image_b[0:1344,0:2418] /= self.information['gain4_b'] - ########## zone 3 ################# - self.image_b[0:1344,2418:2418*2] /= self.information['gain3_b'] - + self.image_b[0:1344, 2418:2418*2] /= self.information['gain3_b'] + ########## zone 1 ################### - self.image_b[0:1344,2418*2:2418*3] /= self.information['gain1_b'] - - ########## zone 2 - self.image_b[0:1344,2418*3:2418*4]/= self.information['gain2_b'] - - ############################################################################ + self.image_b[0:1344, 2418*2:2418*3] /= self.information['gain1_b'] + + # zone 2 + self.image_b[0:1344, 2418*3:2418*4] /= self.information['gain2_b'] + + ############################################################################ + + # red zone 4 + self.image_r[0:1856, 0:3442] /= self.information['gain4_r'] - ########## red zone 4 - self.image_r[0:1856, 0:3442] /= self.information['gain4_r'] - ########## zone 3 ################# - self.image_r[0:1856, 3442:3442*2] /= self.information['gain3_r'] - + self.image_r[0:1856, 3442:3442*2] /= self.information['gain3_r'] + ########## zone 1 ################### - self.image_r[0:1856, 3442*2:3442*3] /= self.information['gain1_r'] - - ########## zone 2 - self.image_r[0:1856,3442*3:3442*4] /= self.information['gain2_r'] - - ##########################################################################3 - - #################################################################################### - + self.image_r[0:1856, 3442*2:3442*3] /= self.information['gain1_r'] + + # zone 2 + self.image_r[0:1856, 3442*3:3442*4] /= self.information['gain2_r'] + + # 3 + + #################################################################################### + def applyBias(self): """ Adds a bias level to the image being constructed. @@ -2087,41 +2167,41 @@ class IFSsimulator(): in the information dictionary (key bias). """ - ########## blue zone 4 - self.image_b[0:1344,0:2418] += self.information['bias4_b'] - + # blue zone 4 + self.image_b[0:1344, 0:2418] += self.information['bias4_b'] + ########## zone 3 ################# - self.image_b[0:1344,2418:2418*2] += self.information['bias3_b'] - + self.image_b[0:1344, 2418:2418*2] += self.information['bias3_b'] + ########## zone 1 ################### - self.image_b[0:1344,2418*2:2418*3] += self.information['bias1_b'] - - ########## zone 2 - self.image_b[0:1344,2418*3:2418*4] += self.information['bias2_b'] - - ############################################################################ + self.image_b[0:1344, 2418*2:2418*3] += self.information['bias1_b'] - self.log.info('Bias counts were added to the blue image' ) - - ############################################################################ + # zone 2 + self.image_b[0:1344, 2418*3:2418*4] += self.information['bias2_b'] + + ############################################################################ + + self.log.info('Bias counts were added to the blue image') + + ############################################################################ + + # red zone 4 + self.image_r[0:1856, 0:3442] += self.information['bias4_r'] - ########## red zone 4 - self.image_r[0:1856, 0:3442] += self.information['bias4_r'] - ########## zone 3 ################# - self.image_r[0:1856, 3442:3442*2] += self.information['bias3_r'] - + self.image_r[0:1856, 3442:3442*2] += self.information['bias3_r'] + ########## zone 1 ################### - self.image_r[0:1856, 3442*2:3442*3] += self.information['bias1_r'] - - ########## zone 2 - self.image_r[0:1856,3442*3:3442*4] += self.information['bias2_r'] - - ########################################################################## + self.image_r[0:1856, 3442*2:3442*3] += self.information['bias1_r'] + + # zone 2 + self.image_r[0:1856, 3442*3:3442*4] += self.information['bias2_r'] - self.log.info('Bias counts were added to the red image' ) - - ############################################################################################3 + ########################################################################## + + self.log.info('Bias counts were added to the red image') + + # 3 def addPreOverScans(self): """ @@ -2132,37 +2212,42 @@ class IFSsimulator(): The size of prescan and overscan regions are defined by the prescanx and overscanx keywords, respectively. """ self.log.info('Adding pre- and overscan regions') - + canvas = np.zeros((self.information['bluesize'], - (self.information['bluesize'] + self.information['prescanx'] + self.information['ovrscanx']))) + (self.information['bluesize'] + self.information['prescanx'] + self.information['ovrscanx']))) - #because the pre- and overscans are in x-direction this needs to be taken into account for the + # because the pre- and overscans are in x-direction this needs to be taken into account for the # 1st and 3rd quadrant if self.information['quadrant'] in (0, 2): - canvas[:, self.information['prescanx']: self.information['prescanx']+self.information['bluesize']] = self.image_b + canvas[:, self.information['prescanx']: self.information['prescanx'] + + self.information['bluesize']] = self.image_b self.image_b = canvas elif self.information['quadrant'] in (1, 3): - canvas[:, self.information['ovrscanx']: self.information['ovrscanx']+self.information['bluesize']] = self.image_b + canvas[:, self.information['ovrscanx']: self.information['ovrscanx'] + + self.information['bluesize']] = self.image_b self.image_b = canvas else: - self.log.error('Cannot include pre- and overscan because of an unknown quadrant!') - - - ##################################################################### - + self.log.error( + 'Cannot include pre- and overscan because of an unknown quadrant!') + + ##################################################################### + canvas = np.zeros((self.information['redsize'], - (self.information['redsize'] + self.information['prescanx'] + self.information['ovrscanx']))) + (self.information['redsize'] + self.information['prescanx'] + self.information['ovrscanx']))) - #because the pre- and overscans are in x-direction this needs to be taken into account for the + # because the pre- and overscans are in x-direction this needs to be taken into account for the # 1st and 3rd quadrant if self.information['quadrant'] in (0, 2): - canvas[:, self.information['prescanx']: self.information['prescanx']+self.information['redsize']] = self.image_r + canvas[:, self.information['prescanx']: self.information['prescanx'] + + self.information['redsize']] = self.image_r self.image_r = canvas elif self.information['quadrant'] in (1, 3): - canvas[:, self.information['ovrscanx']: self.information['ovrscanx']+self.information['redsize']] = self.image_r + canvas[:, self.information['ovrscanx']: self.information['ovrscanx'] + + self.information['redsize']] = self.image_r self.image_r = canvas else: - self.log.error('Cannot include pre- and overscan because of an unknown quadrant!') + self.log.error( + 'Cannot include pre- and overscan because of an unknown quadrant!') #################################################################################### @@ -2176,36 +2261,36 @@ class IFSsimulator(): :return: None """ self.log.info('Applying column bleeding...') - - #loop over each column, as bleeding is modelled column-wise + + # loop over each column, as bleeding is modelled column-wise for i, column in enumerate(self.image_b.T): sum = 0. for j, value in enumerate(column): - #first round - from bottom to top (need to half the bleeding) + # first round - from bottom to top (need to half the bleeding) overload = value - self.information['fullwellcapacity'] if overload > 0.: overload /= 2. #self.image[j, i] -= overload self.image_b[j, i] -= overload - + sum += overload - + elif sum > 0.: if -overload > sum: overload = -sum - - self.image_b[j, i] -= overload + + self.image_b[j, i] -= overload sum += overload for i, column in enumerate(self.image_b.T): sum = 0. for j, value in enumerate(column[::-1]): - #second round - from top to bottom (bleeding was half'd already, so now full) + # second round - from top to bottom (bleeding was half'd already, so now full) overload = value - self.information['fullwellcapacity'] if overload > 0.: #self.image[-j-1, i] -= overload self.image_b[-j-1, i] -= overload - + sum += overload elif sum > 0.: if -overload > sum: @@ -2213,39 +2298,37 @@ class IFSsimulator(): #self.image[-j-1, i] -= overload self.image_b[-j-1, i] -= overload - sum += overload print('Applying column bleeding to blue image finished.......') - ######################################################################3333 + # 3333 for i, column in enumerate(self.image_r.T): sum = 0. for j, value in enumerate(column): - #first round - from bottom to top (need to half the bleeding) + # first round - from bottom to top (need to half the bleeding) overload = value - self.information['fullwellcapacity'] if overload > 0.: overload /= 2. #self.image[j, i] -= overload self.image_r[j, i] -= overload - + sum += overload elif sum > 0.: if -overload > sum: overload = -sum #self.image[j, i] -= overload self.image_r[j, i] -= overload - - + sum += overload for i, column in enumerate(self.image_r.T): sum = 0. for j, value in enumerate(column[::-1]): - #second round - from top to bottom (bleeding was half'd already, so now full) + # second round - from top to bottom (bleeding was half'd already, so now full) overload = value - self.information['fullwellcapacity'] if overload > 0.: #self.image[-j-1, i] -= overload self.image_r[-j-1, i] -= overload - + sum += overload elif sum > 0.: if -overload > sum: @@ -2253,12 +2336,11 @@ class IFSsimulator(): #self.image[-j-1, i] -= overload self.image_r[-j-1, i] -= overload - sum += overload print('Applying column bleeding to red image finished.......') - + ############################################################################ - + ############################################################################ def discretise(self, max=2**16-1): @@ -2271,145 +2353,152 @@ class IFSsimulator(): :return: None """ - #avoid negative numbers in case bias level was not added + # avoid negative numbers in case bias level was not added self.image_b[self.image_b < 0.0] = 0. - #cut of the values larger than max + # cut of the values larger than max self.image_b[self.image_b > max] = max self.image_b = np.rint(self.image_b).astype(int) self.log.info('Maximum and total values of the image are %i and %i, respectively' % (np.max(self.image_b), np.sum(self.image_b))) - #avoid negative numbers in case bias level was not added + # avoid negative numbers in case bias level was not added self.image_r[self.image_r < 0.0] = 0. - #cut of the values larger than max + # cut of the values larger than max self.image_r[self.image_r > max] = max self.image_r = np.rint(self.image_r).astype(int) self.log.info('Maximum and total values of the image are %i and %i, respectively' % (np.max(self.image_r), np.sum(self.image_r))) - - ################################################################################################## - - def applyImageShift(self): + + ################################################################################################## + + def applyImageShift(self): np.random.seed(9*self.simnumber) - ud= np.random.random() # Choose a random rotation - dx= 2* (ud-0.5) * self.information['shiftmax'] - + ud = np.random.random() # Choose a random rotation + dx = 2 * (ud-0.5) * self.information['shiftmax'] + np.random.seed(99*self.simnumber) - ud= np.random.random() # Choose a random rotation - dy= 2* (ud-0.5) * self.information['shiftmax'] - - self.image_b= ndimage.shift(self.image_b.copy(), [dy+self.information['shift_b_y'] , dx+self.information['shift_b_x']], order=0, mode='nearest') - self.image_r= ndimage.shift(self.image_r.copy(), [dy+self.information['shift_r_y'] , dx+self.information['shift_r_x']], order=0, mode='nearest') - + ud = np.random.random() # Choose a random rotation + dy = 2 * (ud-0.5) * self.information['shiftmax'] + + self.image_b = ndimage.shift(self.image_b.copy(), [ + dy+self.information['shift_b_y'], dx+self.information['shift_b_x']], order=0, mode='nearest') + self.image_r = ndimage.shift(self.image_r.copy(), [ + dy+self.information['shift_r_y'], dx+self.information['shift_r_x']], order=0, mode='nearest') + self.log.info('Applied image shifting to g r i channels.') - self.information['ra'] = dx*self.information['pixel_size'] - self.information['dec'] = dy*self.information['pixel_size'] - - -######################################################################################################33 - - def applyImageRotate(self ): + self.information['ra'] = dx*self.information['pixel_size'] + self.information['dec'] = dy*self.information['pixel_size'] + + +# 33 + + + def applyImageRotate(self): np.random.seed(10*self.simnumber) ud = np.random.random() # Choose a random rotation - angle = 2* (ud-0.5) * self.information['tel_rotmax'] - - inputimg=self.image_b.copy() - rotimg=ndimage.rotate(inputimg,angle+self.information['rotate_b'],order=1,reshape=False) # here we choose reshape=False, the rotated image will - self.image_b=rotimg + angle = 2 * (ud-0.5) * self.information['tel_rotmax'] - inputimg=self.image_r.copy() - rotimg=ndimage.rotate(inputimg,angle+self.information['rotate_r'],order=1,reshape=False) # here we choose reshape=False, the rotated image will - self.image_r=rotimg - - self.information['Tel_rot']=angle - - self.log.info('Applied telescope rotation with angle (in degree)= %f.', angle) -############################################################################### - - def CCDreadout(self): - - imgb=self.image_b.copy() - prescan=int(self.information['prescan']) - overscan=int(self.information['overscan']) - - temp=np.zeros((1344,9672)) - ########## zone 4, OSH ######0:1024, 50:2048+50 - x1=0 - x2=x1+1024 - - y1=0+prescan - y2=y1+2048 - temp[x1:x2,y1:y2]=imgb[0:1024,0:2048] + inputimg = self.image_b.copy() + # here we choose reshape=False, the rotated image will + rotimg = ndimage.rotate( + inputimg, angle+self.information['rotate_b'], order=1, reshape=False) + self.image_b = rotimg + + inputimg = self.image_r.copy() + # here we choose reshape=False, the rotated image will + rotimg = ndimage.rotate( + inputimg, angle+self.information['rotate_r'], order=1, reshape=False) + self.image_r = rotimg + + self.information['Tel_rot'] = angle + + self.log.info( + 'Applied telescope rotation with angle (in degree)= %f.', angle) +############################################################################### + + def CCDreadout(self): + + imgb = self.image_b.copy() + prescan = int(self.information['prescan']) + overscan = int(self.information['overscan']) + + temp = np.zeros((1344, 9672)) + # zone 4, OSH ######0:1024, 50:2048+50 + x1 = 0 + x2 = x1+1024 + + y1 = 0+prescan + y2 = y1+2048 + temp[x1:x2, y1:y2] = imgb[0:1024, 0:2048] ########## zone 3, OSG , left to right ################# - ###np.fliplr(b2) ## left to right - ###np.flipud(b3) ## down to up - x1=0 - x2=x1+1024 - - y1=2418+prescan - y2=y1+2048 - temp[x1:x2,y1:y2]=np.fliplr(imgb[0:1024,2048:4096] ) + # np.fliplr(b2) ## left to right + # np.flipud(b3) ## down to up + x1 = 0 + x2 = x1+1024 + + y1 = 2418+prescan + y2 = y1+2048 + temp[x1:x2, y1:y2] = np.fliplr(imgb[0:1024, 2048:4096]) ########## zone 1, OSE,down to up ################### - x1=0 - x2=x1+1024 - - y1=2418*2+prescan - y2=y1+2048 - temp[x1:x2,y1:y2]=np.flipud(imgb[1024:2048,0:2048]) + x1 = 0 + x2 = x1+1024 + + y1 = 2418*2+prescan + y2 = y1+2048 + temp[x1:x2, y1:y2] = np.flipud(imgb[1024:2048, 0:2048]) ########## zone 2, OSF down to yp ,left to right ####### - x1=0 - x2=x1+1024 - - y1=2418*3+prescan - y2=y1+2048 - temp[x1:x2,y1:y2]=np.flipud(np.fliplr(imgb[1024:2048,2048:4096])) - - self.image_b=temp - + x1 = 0 + x2 = x1+1024 + + y1 = 2418*3+prescan + y2 = y1+2048 + temp[x1:x2, y1:y2] = np.flipud(np.fliplr(imgb[1024:2048, 2048:4096])) + + self.image_b = temp + ############################################################################## - imgr=self.image_r.copy() - temp=np.zeros((1856,13768)) - - ########## zone 4, OSH ######0:1024, 50:2048+50 - x1=0 - x2=x1+1536 - - y1=0+prescan - y2=y1+3072 - temp[x1:x2,y1:y2]=imgr[0:1536,0:3072] + imgr = self.image_r.copy() + temp = np.zeros((1856, 13768)) + + # zone 4, OSH ######0:1024, 50:2048+50 + x1 = 0 + x2 = x1+1536 + + y1 = 0+prescan + y2 = y1+3072 + temp[x1:x2, y1:y2] = imgr[0:1536, 0:3072] ########## zone 3, OSG , left to right ################# - ###np.fliplr(b2) ## left to right - ###np.flipud(b3) ## down to up - x1=0 - x2=x1+1536 - - y1=3442+prescan - y2=y1+3072 - temp[x1:x2,y1:y2]=np.fliplr(imgr[0:1536,3072:6144] ) + # np.fliplr(b2) ## left to right + # np.flipud(b3) ## down to up + x1 = 0 + x2 = x1+1536 + + y1 = 3442+prescan + y2 = y1+3072 + temp[x1:x2, y1:y2] = np.fliplr(imgr[0:1536, 3072:6144]) ########## zone 1, OSE,down to up ############################ - x1=0 - x2=x1+1536 - - y1=3442*2+prescan - y2=y1+3072 - temp[x1:x2,y1:y2]=np.flipud(imgr[1536:3072,0:3072]) + x1 = 0 + x2 = x1+1536 + + y1 = 3442*2+prescan + y2 = y1+3072 + temp[x1:x2, y1:y2] = np.flipud(imgr[1536:3072, 0:3072]) ########## zone 2, OSF down to yp ,left to right ################ - x1=0 - x2=x1+1536 - - y1=3442*3+prescan - y2=y1+3072 - temp[x1:x2,y1:y2]=np.flipud(np.fliplr(imgr[1536:3072,3072:6144])) - - - self.image_r=temp - + x1 = 0 + x2 = x1+1536 + + y1 = 3442*3+prescan + y2 = y1+3072 + temp[x1:x2, y1:y2] = np.flipud(np.fliplr(imgr[1536:3072, 3072:6144])) + + self.image_r = temp + return ############################################################################## - + def writeOutputs(self, obnum): """ Writes out a FITS file using PyFITS and converts the image array to 16bit unsigned integer as @@ -2417,1999 +2506,2241 @@ class IFSsimulator(): Updates header with the input values and flags used during simulation. """ - HeaderTest='no' - sim_ver=str(self.information['sim_ver']) - - ## Readout information - now=self.dt.utcnow() + HeaderTest = 'no' + sim_ver = str(self.information['sim_ver']) + + # Readout information + now = self.dt.utcnow() + + # exposre start time + exp_start_utc = now + exp_start_str = now.strftime("%Y%m%d%H%M%S") + + # exsposure end time,including mulipe exposure times and readout times; + # but minus one readout_time + tt = (self.information['exptime']+self.information['readouttime']) * \ + self.information['exposuretimes']-self.information['readouttime'] + end = self.dt.utcnow()+timedelta(seconds=tt) + + exp_end_str = end.strftime("%Y%m%d%H%M%S") + exp_end_utc = end + + # write the actual file + tt = (self.information['exptime']+self.information['readouttime'] + )*self.information['exposuretimes'] + write_end = self.dt.utcnow()+timedelta(seconds=tt) - ### exposre start time - exp_start_utc=now - exp_start_str=now.strftime("%Y%m%d%H%M%S") - - ### exsposure end time,including mulipe exposure times and readout times; - ### but minus one readout_time - tt=(self.information['exptime']+self.information['readouttime'])*self.information['exposuretimes']-self.information['readouttime'] - end=self.dt.utcnow()+timedelta(seconds=tt) - - - exp_end_str=end.strftime("%Y%m%d%H%M%S") - exp_end_utc=end - - ## write the actual file - tt=(self.information['exptime']+self.information['readouttime'])*self.information['exposuretimes'] - write_end=self.dt.utcnow()+timedelta(seconds=tt) - write_time_utc = write_end.strftime("%Y-%m-%dT%H:%M:%S") write_time_str = end.strftime("%Y-%m-%dT%H:%M:%S") - - if self.source=='SCI' or self.source=='COMP': - if self.source=='SCI': - obsid=30100000000+obnum ###3+OBSTYPE+8位曝光编号; + if self.source == 'SCI' or self.source == 'COMP': + if self.source == 'SCI': + obsid = 30100000000+obnum # 3+OBSTYPE+8位曝光编号; else: - obsid=30200000000+obnum ###3+OBSTYPE+8位曝光编号; - - filename_b='CSST_IFS_B_'+self.source+'_'+exp_start_str+'_'+exp_end_str+'_'+str(obsid)+'_B_L0_V'+sim_ver - self.file_b=self.result_path+'/sky_Data/'+filename_b+'.fits' - - filename_r='CSST_IFS_R_'+self.source+'_'+exp_start_str+'_'+exp_end_str+'_'+str(obsid)+'_R_L0_V'+sim_ver - self.file_r=self.result_path+'/sky_Data/'+filename_r +'.fits' - + obsid = 30200000000+obnum # 3+OBSTYPE+8位曝光编号; + + filename_b = 'CSST_IFS_B_'+self.source+'_'+exp_start_str + \ + '_'+exp_end_str+'_'+str(obsid)+'_B_L0_V'+sim_ver + self.file_b = self.result_path+'/sky_Data/'+filename_b+'.fits' + + filename_r = 'CSST_IFS_R_'+self.source+'_'+exp_start_str + \ + '_'+exp_end_str+'_'+str(obsid)+'_R_L0_V'+sim_ver + self.file_r = self.result_path+'/sky_Data/'+filename_r + '.fits' + else: - - if self.source=='BIAS': - obsid=30300000000+obnum ###3+OBSTYPE+8位曝光编号; - if self.source=='DARK': - obsid=30400000000+obnum ###3+OBSTYPE+8位曝光编号; - if self.source=='FLAT': - obsid=30500000000+obnum ###3+OBSTYPE+8位曝光编号; - if self.source=='LAMP': - obsid=30600000000+obnum ###3+OBSTYPE+8位曝光编号; - - filename_b='CSST_IFS_B_'+self.source+'_'+exp_start_str+'_'+exp_end_str+'_'+str(obsid)+'_B_L0_V'+sim_ver - self.file_b=self.result_path+'/calibration_Data/'+filename_b+'.fits' - - filename_r='CSST_IFS_R_'+self.source+'_'+exp_start_str+'_'+exp_end_str+'_'+str(obsid)+'_R_L0_V'+sim_ver - self.file_r=self.result_path+'/calibration_Data/'+filename_r+'.fits' - - - - #create a new FITS file, using HDUList instance + + if self.source == 'BIAS': + obsid = 30300000000+obnum # 3+OBSTYPE+8位曝光编号; + if self.source == 'DARK': + obsid = 30400000000+obnum # 3+OBSTYPE+8位曝光编号; + if self.source == 'FLAT': + obsid = 30500000000+obnum # 3+OBSTYPE+8位曝光编号; + if self.source == 'LAMP': + obsid = 30600000000+obnum # 3+OBSTYPE+8位曝光编号; + + filename_b = 'CSST_IFS_B_'+self.source+'_'+exp_start_str + \ + '_'+exp_end_str+'_'+str(obsid)+'_B_L0_V'+sim_ver + self.file_b = self.result_path+'/calibration_Data/'+filename_b+'.fits' + + filename_r = 'CSST_IFS_R_'+self.source+'_'+exp_start_str + \ + '_'+exp_end_str+'_'+str(obsid)+'_R_L0_V'+sim_ver + self.file_r = self.result_path+'/calibration_Data/'+filename_r+'.fits' + + # create a new FITS file, using HDUList instance ##### layer 0 #### - + ofd_b = fits.PrimaryHDU() - - ofd_b.header['SIMPLE']=( True, 'conforms to FITS standard') - ofd_b.header['BITPIX']=( 0, 'array data type') - ofd_b.header['NAXIS'] =( 0, 'number of array dimensions') - ofd_b.header['NEXTEND']=( np.int16(1), 'number of array dimensions') - - ############################################################################################ - temp=write_end.utcnow() - data_time=temp.strftime("%Y-%m-%dT%H:%M:%S.%f") - ofd_b.header['DATE'] =(data_time[:21], 'written date (yyyy-mm-ddThh:mm:ss.s)') - ofd_b.header['FILENAME']=(filename_b[:68],'') - ofd_b.header['FILETYPE'] =( self.source[:12], 'observation type') - ofd_b.header['TELESCOP']=('CSST', 'telescope name') - ofd_b.header['INSTRUME']=('IFS', 'instrument name') - ofd_b.header['RADECSYS']=('ICRS', 'coordinate system of the object') - ofd_b.header['EQUINOX'] =(float(2000.0), '') - ofd_b.header['FITSSWV']=('ifs_sim_0.8.03', 'FITS creating software version') - ######### Object information ############# - if self.source=='SCI' or self.source=='COMP': - ofd_b.header['OBJECT']=( self.information['name_obj'][:30], 'object name') - ofd_b.header['TARGET']=( (self.information['target']), 'target name (hhmmss.s+ddmmss)') - - ofd_b.header['OBSID'] =(str(obsid) , 'observation ID') - - ofd_b.header['RA_OBJ'] =(np.float64(self.information['ra_obj']) , 'object RA (deg)') - ofd_b.header['DEC_OBJ']=(np.float64(self.information['dec_obj']) , 'object Dec (deg)') - + + ofd_b.header['SIMPLE'] = (True, 'conforms to FITS standard') + ofd_b.header['BITPIX'] = (0, 'array data type') + ofd_b.header['NAXIS'] = (0, 'number of array dimensions') + ofd_b.header['NEXTEND'] = (np.int16(1), 'number of array dimensions') + + ############################################################################################ + temp = write_end.utcnow() + data_time = temp.strftime("%Y-%m-%dT%H:%M:%S.%f") + ofd_b.header['DATE'] = ( + data_time[:21], 'written date (yyyy-mm-ddThh:mm:ss.s)') + ofd_b.header['FILENAME'] = (filename_b[:68], '') + ofd_b.header['FILETYPE'] = (self.source[:12], 'observation type') + ofd_b.header['TELESCOP'] = ('CSST', 'telescope name') + ofd_b.header['INSTRUME'] = ('IFS', 'instrument name') + ofd_b.header['RADECSYS'] = ( + 'ICRS', 'coordinate system of the object') + ofd_b.header['EQUINOX'] = (float(2000.0), '') + ofd_b.header['FITSSWV'] = ( + 'ifs_sim_0.8.03', 'FITS creating software version') + ######### Object information ############# + if self.source == 'SCI' or self.source == 'COMP': + ofd_b.header['OBJECT'] = ( + self.information['name_obj'][:30], 'object name') + ofd_b.header['TARGET'] = ( + (self.information['target']), 'target name (hhmmss.s+ddmmss)') + + ofd_b.header['OBSID'] = (str(obsid), 'observation ID') + + ofd_b.header['RA_OBJ'] = (np.float64( + self.information['ra_obj']), 'object RA (deg)') + ofd_b.header['DEC_OBJ'] = (np.float64( + self.information['dec_obj']), 'object Dec (deg)') + else: - ofd_b.header['OBJECT']=(self.source , ' object name') - ofd_b.header['TARGET']=( 0, 'target name (hhmmss.s+ddmmss)') - - ofd_b.header['OBSID'] =(str(obsid) , 'observation ID') - - ofd_b.header['RA_OBJ'] =(np.float64(0) , 'object RA (deg)') - ofd_b.header['DEC_OBJ']=(np.float64(0) , 'object Dec (deg)') - - self.information['POSI0_X']=0.0 #, 'the orbital position of CSST in X direction at EXPSTART') - self.information['POSI0_Y']=0.0 #, 'the orbital position of CSST in Y direction at EXPSTART') - self.information['POSI0_Z']=0.0 #, 'the orbital position of CSST in Z direction at EXPSTART') - self.information['VELO0_X']=0.0 #, 'the orbital velocity of CSST in X direction at EXPSTART') - self.information['VELO0_Y']=0.0 #, 'the orbital velocity of CSST in Y direction at EXPSTART') - self.information['VELO0_Z']=0.0 #, 'the orbital velocity of CSST in Z direction at EXPSTART') - - self.information['POSI1_X']=0.0 #, 'the orbital position of CSST in X direction at EXPSTART') - self.information['POSI1_Y']=0.0 #, 'the orbital position of CSST in Y direction at EXPSTART') - self.information['POSI1_Z']=0.0 #, 'the orbital position of CSST in Z direction at EXPSTART') - self.information['VELO1_X']=0.0 #, 'the orbital velocity of CSST in X direction at EXPSTART') - self.information['VELO1_Y']=0.0 #, 'the orbital velocity of CSST in Y direction at EXPSTART') - self.information['VELO1_Z']=0.0 #, 'the orbital velocity of CSST in Z direction at EXPSTART') - - - - ####################################################################### + ofd_b.header['OBJECT'] = (self.source, ' object name') + ofd_b.header['TARGET'] = (0, 'target name (hhmmss.s+ddmmss)') + + ofd_b.header['OBSID'] = (str(obsid), 'observation ID') + + ofd_b.header['RA_OBJ'] = (np.float64(0), 'object RA (deg)') + ofd_b.header['DEC_OBJ'] = (np.float64(0), 'object Dec (deg)') + + # , 'the orbital position of CSST in X direction at EXPSTART') + self.information['POSI0_X'] = 0.0 + # , 'the orbital position of CSST in Y direction at EXPSTART') + self.information['POSI0_Y'] = 0.0 + # , 'the orbital position of CSST in Z direction at EXPSTART') + self.information['POSI0_Z'] = 0.0 + # , 'the orbital velocity of CSST in X direction at EXPSTART') + self.information['VELO0_X'] = 0.0 + # , 'the orbital velocity of CSST in Y direction at EXPSTART') + self.information['VELO0_Y'] = 0.0 + # , 'the orbital velocity of CSST in Z direction at EXPSTART') + self.information['VELO0_Z'] = 0.0 + + # , 'the orbital position of CSST in X direction at EXPSTART') + self.information['POSI1_X'] = 0.0 + # , 'the orbital position of CSST in Y direction at EXPSTART') + self.information['POSI1_Y'] = 0.0 + # , 'the orbital position of CSST in Z direction at EXPSTART') + self.information['POSI1_Z'] = 0.0 + # , 'the orbital velocity of CSST in X direction at EXPSTART') + self.information['VELO1_X'] = 0.0 + # , 'the orbital velocity of CSST in Y direction at EXPSTART') + self.information['VELO1_Y'] = 0.0 + # , 'the orbital velocity of CSST in Z direction at EXPSTART') + self.information['VELO1_Z'] = 0.0 + ####################################################################### ######## Telescope information ############### - - ofd_b.header['REFFRAME']=('CSSTGSC-1.0' , 'guiding catalog version') - ofd_b.header['DATE-OBS']=(data_time[:21] , 'observation date (yyyy-mm-ddThh:mm:ss.s)') - ofd_b.header['SATESWV']=('softwave-1.0', 'satellite software version') - ofd_b.header['EXPSTART']=(np.float64(time2mjd(exp_start_utc)), 'exposure start time (MJD)') - ofd_b.header['CABSTART']=(np.float64(time2jd(exp_start_utc)), 'first cabin time after exposure start (MJD)') - ofd_b.header['SUNANGL0']=(np.float32(0.0) , 'angle between the Sun and opt axis at CABSTART') - ofd_b.header['MOONANG0']=(np.float32(0.0) , 'angle between the Moon and opt axis at CABSTART') - ofd_b.header['TEL_ALT0']=(np.float64(0.0), 'angle between opt axis and Elimb at CABSTART') - ofd_b.header['POS_ANG0']=(np.float64(0.0), 'angle between y axis and North Pole at CABSTART') - ofd_b.header['POSI0_X'] =(np.float64(self.information['POSI0_X']) , 'orbital position in X at CABSTART (km)') - ofd_b.header['POSI0_Y'] =(np.float64(self.information['POSI0_Y']) , 'orbital position in Y at CABSTART (km)') - ofd_b.header['POSI0_Z'] =(np.float64(self.information['POSI0_Z']) , 'orbital position in Z at CABSTART (km)') - ofd_b.header['VELO0_X']=( np.float64(self.information['VELO0_X']) , 'orbital velocity in X at CABSTART (km/s)') - ofd_b.header['VELO0_Y']=( np.float64(self.information['VELO0_Y']) , 'orbital velocity in Y at CABSTART (km/s)') - ofd_b.header['VELO0_Z']=( np.float64(self.information['VELO0_Z']) , 'orbital velocity in Z at CABSTART (km/s)') - ofd_b.header['Euler0_1']=( np.float64(0.0), 'Euler angle 1 at CABSTART (deg)') - ofd_b.header['Euler0_2']=( np.float64(0.0), 'Euler angle 2 at CABSTART (deg)') - ofd_b.header['Euler0_3']=( np.float64(0.0), 'Euler angle 3 at CABSTART (deg)') - + + ofd_b.header['REFFRAME'] = ('CSSTGSC-1.0', 'guiding catalog version') + ofd_b.header['DATE-OBS'] = (data_time[:21], + 'observation date (yyyy-mm-ddThh:mm:ss.s)') + ofd_b.header['SATESWV'] = ( + 'softwave-1.0', 'satellite software version') + ofd_b.header['EXPSTART'] = (np.float64( + time2mjd(exp_start_utc)), 'exposure start time (MJD)') + ofd_b.header['CABSTART'] = (np.float64( + time2jd(exp_start_utc)), 'first cabin time after exposure start (MJD)') + ofd_b.header['SUNANGL0'] = (np.float32( + 0.0), 'angle between the Sun and opt axis at CABSTART') + ofd_b.header['MOONANG0'] = (np.float32( + 0.0), 'angle between the Moon and opt axis at CABSTART') + ofd_b.header['TEL_ALT0'] = (np.float64( + 0.0), 'angle between opt axis and Elimb at CABSTART') + ofd_b.header['POS_ANG0'] = (np.float64( + 0.0), 'angle between y axis and North Pole at CABSTART') + ofd_b.header['POSI0_X'] = (np.float64( + self.information['POSI0_X']), 'orbital position in X at CABSTART (km)') + ofd_b.header['POSI0_Y'] = (np.float64( + self.information['POSI0_Y']), 'orbital position in Y at CABSTART (km)') + ofd_b.header['POSI0_Z'] = (np.float64( + self.information['POSI0_Z']), 'orbital position in Z at CABSTART (km)') + ofd_b.header['VELO0_X'] = (np.float64( + self.information['VELO0_X']), 'orbital velocity in X at CABSTART (km/s)') + ofd_b.header['VELO0_Y'] = (np.float64( + self.information['VELO0_Y']), 'orbital velocity in Y at CABSTART (km/s)') + ofd_b.header['VELO0_Z'] = (np.float64( + self.information['VELO0_Z']), 'orbital velocity in Z at CABSTART (km/s)') + ofd_b.header['Euler0_1'] = (np.float64( + 0.0), 'Euler angle 1 at CABSTART (deg)') + ofd_b.header['Euler0_2'] = (np.float64( + 0.0), 'Euler angle 2 at CABSTART (deg)') + ofd_b.header['Euler0_3'] = (np.float64( + 0.0), 'Euler angle 3 at CABSTART (deg)') + ##### - if self.source=='SCI' or self.source=='COMP': + if self.source == 'SCI' or self.source == 'COMP': - ofd_b.header['RA_PNT0']=( np.float64(self.information['ra_pnt0']) , 'pointing RA at CABSTART (deg)') - ofd_b.header['DEC_PNT0']=(np.float64(self.information['dec_pnt0']) , 'pointing Dec at CABSTART (deg)') + ofd_b.header['RA_PNT0'] = (np.float64( + self.information['ra_pnt0']), 'pointing RA at CABSTART (deg)') + ofd_b.header['DEC_PNT0'] = (np.float64( + self.information['dec_pnt0']), 'pointing Dec at CABSTART (deg)') else: - ofd_b.header['RA_PNT0']=( np.float64(0.0) , 'pointing RA at CABSTART (deg)') - ofd_b.header['DEC_PNT0']=(np.float64(0.0) , 'pointing Dec at CABSTART (deg)') - - - ofd_b.header['EXPEND'] =(np.float64(time2mjd(exp_end_utc)) , 'exposure end time (MJD)') - - ofd_b.header['CABEND'] =(np.float64(time2jd(exp_end_utc)) , 'first cabin time after exposure end (MJD)') - - ofd_b.header['SUNANGL1']=(np.float32(0.0), 'angle between the Sun and opt axis at CABEND') - ofd_b.header['MOONANG1']=(np.float32(0.0) , 'angle between the Moon and opt axis at CABEND') - - ofd_b.header['TEL_ALT1']=(np.float64(0.0) , 'angle between opt axis and Elimb at CABEND') - ofd_b.header['POS_ANG1']=(np.float64(self.information['sky_rot']) , 'angle between y axis and North Pole at CABEND') - - ofd_b.header['POSI1_X'] =(np.float64(self.information['POSI1_X']) , 'orbital position in X at CABEND (km)') - ofd_b.header['POSI1_Y'] =(np.float64(self.information['POSI1_Y']) , 'orbital position in Y at CABEND (km)') - ofd_b.header['POSI1_Z'] =(np.float64(self.information['POSI1_Z']) , 'orbital position in Z at CABEND (km)') - ofd_b.header['VELO1_X']=(np.float64(self.information['VELO1_X']) , 'orbital velocity in X at CABEND (km/s)') - ofd_b.header['VELO1_Y']=(np.float64(self.information['VELO1_Y']) , 'orbital velocity in Y at CABEND (km/s)') - ofd_b.header['VELO1_Z']=(np.float64(self.information['VELO1_Z']) , 'orbital velocity in Z at CABEND (km/s)') - ofd_b.header['Euler1_1']=( np.float64(0.0), 'Euler angle 1 at CABEND (deg)') - ofd_b.header['Euler1_2']=( np.float64(0.0), 'Euler angle 2 at CABEND (deg)') - ofd_b.header['Euler1_3']=( np.float64(0.0), 'Euler angle 3 at CABEND (deg)') - ofd_b.header['RA_PNT1']=(np.float64(ofd_b.header['RA_PNT0']), 'pointing RA at CABEND (deg)') - ofd_b.header['DEC_PNT1']=(np.float64(ofd_b.header['DEC_PNT0']), 'pointing Dec at CABEND (deg)') - ofd_b.header['EPOCH'] =(np.float32(time2jd(end.utcnow())), 'equinox of pointing RA and Dec') - ofd_b.header['EXPTIME']=(np.float32(self.information['exptime']*self.information['exposuretimes']), 'exposure time (s)') - ss1='HDU checksum' - ss2='data unit checksum' - ofd_b.header['CHECKSUM']=( data_time[:19] , ss1) - ofd_b.header['DATASUM']=( data_time[:19] , ss2) - + ofd_b.header['RA_PNT0'] = (np.float64( + 0.0), 'pointing RA at CABSTART (deg)') + ofd_b.header['DEC_PNT0'] = (np.float64( + 0.0), 'pointing Dec at CABSTART (deg)') + + ofd_b.header['EXPEND'] = (np.float64( + time2mjd(exp_end_utc)), 'exposure end time (MJD)') + + ofd_b.header['CABEND'] = (np.float64( + time2jd(exp_end_utc)), 'first cabin time after exposure end (MJD)') + + ofd_b.header['SUNANGL1'] = (np.float32( + 0.0), 'angle between the Sun and opt axis at CABEND') + ofd_b.header['MOONANG1'] = (np.float32( + 0.0), 'angle between the Moon and opt axis at CABEND') + + ofd_b.header['TEL_ALT1'] = (np.float64( + 0.0), 'angle between opt axis and Elimb at CABEND') + ofd_b.header['POS_ANG1'] = (np.float64( + self.information['sky_rot']), 'angle between y axis and North Pole at CABEND') + + ofd_b.header['POSI1_X'] = (np.float64( + self.information['POSI1_X']), 'orbital position in X at CABEND (km)') + ofd_b.header['POSI1_Y'] = (np.float64( + self.information['POSI1_Y']), 'orbital position in Y at CABEND (km)') + ofd_b.header['POSI1_Z'] = (np.float64( + self.information['POSI1_Z']), 'orbital position in Z at CABEND (km)') + ofd_b.header['VELO1_X'] = (np.float64( + self.information['VELO1_X']), 'orbital velocity in X at CABEND (km/s)') + ofd_b.header['VELO1_Y'] = (np.float64( + self.information['VELO1_Y']), 'orbital velocity in Y at CABEND (km/s)') + ofd_b.header['VELO1_Z'] = (np.float64( + self.information['VELO1_Z']), 'orbital velocity in Z at CABEND (km/s)') + ofd_b.header['Euler1_1'] = (np.float64( + 0.0), 'Euler angle 1 at CABEND (deg)') + ofd_b.header['Euler1_2'] = (np.float64( + 0.0), 'Euler angle 2 at CABEND (deg)') + ofd_b.header['Euler1_3'] = (np.float64( + 0.0), 'Euler angle 3 at CABEND (deg)') + ofd_b.header['RA_PNT1'] = (np.float64( + ofd_b.header['RA_PNT0']), 'pointing RA at CABEND (deg)') + ofd_b.header['DEC_PNT1'] = (np.float64( + ofd_b.header['DEC_PNT0']), 'pointing Dec at CABEND (deg)') + ofd_b.header['EPOCH'] = (np.float32( + time2jd(end.utcnow())), 'equinox of pointing RA and Dec') + ofd_b.header['EXPTIME'] = (np.float32( + self.information['exptime']*self.information['exposuretimes']), 'exposure time (s)') + ss1 = 'HDU checksum' + ss2 = 'data unit checksum' + ofd_b.header['CHECKSUM'] = (data_time[:19], ss1) + ofd_b.header['DATASUM'] = (data_time[:19], ss2) + ########## - ########## finish header for 0 layer ###################### + ########## finish header for 0 layer ###################### ############################################################# - - #############################################################################3 - ##### header - #new image HDU, blue channel, layer 1 - if HeaderTest=='yes': - hdu_b =fits.ImageHDU(data=np.zeros((10,10,3))) - else: - hdu_b =fits.ImageHDU(data=np.uint16(self.image_b_N)) - - + + # 3 + # header + # new image HDU, blue channel, layer 1 + if HeaderTest == 'yes': + hdu_b = fits.ImageHDU(data=np.zeros((10, 10, 3))) + else: + hdu_b = fits.ImageHDU(data=np.uint16(self.image_b_N)) + ##### - - hdu_b.header['XTENSION']=('IMAGE','extension type') - hdu_b.header['BITPIX']=(np.int16(16),'bits per data value') - hdu_b.header['NAXIS'] =(np.int16(2),'number of data axies') - - hdu_b.header['NAXIS1'] =(np.int32(1344),'length of first data axis') - - hdu_b.header['NAXIS2'] =(np.int32(9672),'length of second data axis') - - hdu_b.header['NAXIS3'] =(np.int32(self.information['exposuretimes']),'length of third data axis') - - - if self.source =='SCI' or self.source =='COMP': - hdu_b.header['EXTNAME']=('SCI','') - + + hdu_b.header['XTENSION'] = ('IMAGE', 'extension type') + hdu_b.header['BITPIX'] = (np.int16(16), 'bits per data value') + hdu_b.header['NAXIS'] = (np.int16(2), 'number of data axies') + + hdu_b.header['NAXIS1'] = (np.int32(1344), 'length of first data axis') + + hdu_b.header['NAXIS2'] = (np.int32(9672), 'length of second data axis') + + hdu_b.header['NAXIS3'] = ( + np.int32(self.information['exposuretimes']), 'length of third data axis') + + if self.source == 'SCI' or self.source == 'COMP': + hdu_b.header['EXTNAME'] = ('SCI', '') + else: - - hdu_b.header['EXTNAME']=('CAL','') - hdu_b.header['EXTVER']=(np.int16(1),'') - hdu_b.header['BSCALE']=(np.float64(1),'') - hdu_b.header['BZERO'] =(np.float64(32768),'') - hdu_b.header['BUNIT'] =('ADU','physical unit of array values') - + hdu_b.header['EXTNAME'] = ('CAL', '') + + hdu_b.header['EXTVER'] = (np.int16(1), '') + hdu_b.header['BSCALE'] = (np.float64(1), '') + hdu_b.header['BZERO'] = (np.float64(32768), '') + hdu_b.header['BUNIT'] = ('ADU', 'physical unit of array values') + ########################################################################### ######### instrument information ######################################## - if self.source =='SCI' or self.source =='COMP': - - - hdu_b.header['CMIRRPOS']=(bool(False), 'position of calibration switch mirror') + if self.source == 'SCI' or self.source == 'COMP': + + hdu_b.header['CMIRRPOS'] = ( + bool(False), 'position of calibration switch mirror') else: - - hdu_b.header['CMIRRPOS']=(bool(True), 'position of calibration switch mirror') - - - - if self.source=='FLAT': - hdu_b.header['FLAMP'] =(np.int16(1), 'status of flat lamp') + + hdu_b.header['CMIRRPOS'] = ( + bool(True), 'position of calibration switch mirror') + + if self.source == 'FLAT': + hdu_b.header['FLAMP'] = (np.int16(1), 'status of flat lamp') else: - hdu_b.header['FLAMP'] =(np.int16(0), 'status of flat lamp') - - - if self.source=='LAMP': - hdu_b.header['ALAMP'] =(np.int16(1),'status of flat atomic emission line lamp') + hdu_b.header['FLAMP'] = (np.int16(0), 'status of flat lamp') + + if self.source == 'LAMP': + hdu_b.header['ALAMP'] = ( + np.int16(1), 'status of flat atomic emission line lamp') else: - hdu_b.header['ALAMP'] =(np.int16(0),'status of flat atomic emission line lamp') - + hdu_b.header['ALAMP'] = ( + np.int16(0), 'status of flat atomic emission line lamp') + ############# - hdu_b.header['IFSMODE'] =(np.int32(0), 'IFS working mode') - hdu_b.header['IFSTEMP'] =(np.float32(0), 'IFS components temperature in degC') - hdu_b.header['IFSSTAT'] =(np.int32(0), 'IFS components status parameter') - - ############################################################################## + hdu_b.header['IFSMODE'] = (np.int32(0), 'IFS working mode') + hdu_b.header['IFSTEMP'] = (np.float32( + 0), 'IFS components temperature in degC') + hdu_b.header['IFSSTAT'] = ( + np.int32(0), 'IFS components status parameter') + + ############################################################################## #################### detector information############################# - hdu_b.header['CAMERA'] =('Blue','camera of IFS') - hdu_b.header['DETSN'] =('CCD231-c4-00','detector serial number') - hdu_b.header['DETNAME'] =('blue','detector name') - hdu_b.header['DETSIZE'] =('2048*4096', 'detector size') - hdu_b.header['DATASECT'] =('data-section', 'data section') - hdu_b.header['PIXSCAL1']=(np.float32(1344), 'pixel scale for axis 1') - hdu_b.header['PIXSCAL2']=(np.float32(9672), 'pixel scale for axis 2') - hdu_b.header['PIXSIZE1']=(np.float32(15), 'pixel size for axis 1 (micron)') - hdu_b.header['PIXSIZE2']=(np.float32(15), 'pixel size for axis 2 (micron)') - - hdu_b.header['NCHAN'] =(np.int16(4), 'number of readout channels') - hdu_b.header['PSCAN1'] =(np.int32(50), 'horizontal prescan width, per readout channel') - hdu_b.header['PSCAN2'] =(np.int32(0), 'vertical prescan height, per readout channel') - hdu_b.header['OSCAN1'] =(np.int32(320), 'horizontal overscan width, per readout channel') - hdu_b.header['OSCAN2'] =(np.int32(320), 'vertical overscan height, per readout channel') + hdu_b.header['CAMERA'] = ('Blue', 'camera of IFS') + hdu_b.header['DETSN'] = ('CCD231-c4-00', 'detector serial number') + hdu_b.header['DETNAME'] = ('blue', 'detector name') + hdu_b.header['DETSIZE'] = ('2048*4096', 'detector size') + hdu_b.header['DATASECT'] = ('data-section', 'data section') + hdu_b.header['PIXSCAL1'] = (np.float32(1344), 'pixel scale for axis 1') + hdu_b.header['PIXSCAL2'] = (np.float32(9672), 'pixel scale for axis 2') + hdu_b.header['PIXSIZE1'] = (np.float32( + 15), 'pixel size for axis 1 (micron)') + hdu_b.header['PIXSIZE2'] = (np.float32( + 15), 'pixel size for axis 2 (micron)') + + hdu_b.header['NCHAN'] = (np.int16(4), 'number of readout channels') + hdu_b.header['PSCAN1'] = ( + np.int32(50), 'horizontal prescan width, per readout channel') + hdu_b.header['PSCAN2'] = ( + np.int32(0), 'vertical prescan height, per readout channel') + hdu_b.header['OSCAN1'] = ( + np.int32(320), 'horizontal overscan width, per readout channel') + hdu_b.header['OSCAN2'] = ( + np.int32(320), 'vertical overscan height, per readout channel') ####################################################################### - ######## Readout information, revised on 2024.2.27 - - frame_time_b=0.09216; ### data frame transfer time in Bule camera - exptimes=self.information['exposuretimes'] + # Readout information, revised on 2024.2.27 + + frame_time_b = 0.09216 # data frame transfer time in Bule camera + exptimes = self.information['exposuretimes'] for k in range(exptimes): - - - tt=(self.information['exptime']+frame_time_b)*(k) - temp=self.dt+timedelta(seconds=tt) - read_start=temp.strftime("%Y-%m-%dT%H:%M:%S.%f") - - temp2=temp+timedelta(seconds=self.information['exptime']) - read_end=temp2.strftime("%Y-%m-%dT%H:%M:%S.%f") - - str1='EXPT0_'+str(k+1) - str2='EXPT1_'+str(k+1) - - if k==0: - com1='exposure start time of the 1st frame (UTC)' - com2='exposure end time of the 1st frame (UTC)' - if k==1: - com1='exposure start time of the 2nd frame (UTC)' - com2='exposure end time of the 2nd frame (UTC)' - if k==2: - com1='exposure start time of the 3rd frame (UTC)' - com2='exposure end time of the 3rd frame (UTC)' - if k>2: - com1='exposure start time of the '+str(k+1)+'th frame' - com2='exposure end time of the '+str(k+1)+'th frame' - - hdu_b.header[str1] =(read_start[:21],com1) - hdu_b.header[str2] =(read_end[:21], com2) - - hdu_b.header['DETTEMP0']=(np.float32(0.0), 'detector temperature at EXPT0_1 (K)') - hdu_b.header['DETTEMP1']=(np.float32(0.0), 'detector temperature at EXPT1_'+str(k+1)+' (K)') - + + tt = (self.information['exptime']+frame_time_b)*(k) + temp = self.dt+timedelta(seconds=tt) + read_start = temp.strftime("%Y-%m-%dT%H:%M:%S.%f") + + temp2 = temp+timedelta(seconds=self.information['exptime']) + read_end = temp2.strftime("%Y-%m-%dT%H:%M:%S.%f") + + str1 = 'EXPT0_'+str(k+1) + str2 = 'EXPT1_'+str(k+1) + + if k == 0: + com1 = 'exposure start time of the 1st frame (UTC)' + com2 = 'exposure end time of the 1st frame (UTC)' + if k == 1: + com1 = 'exposure start time of the 2nd frame (UTC)' + com2 = 'exposure end time of the 2nd frame (UTC)' + if k == 2: + com1 = 'exposure start time of the 3rd frame (UTC)' + com2 = 'exposure end time of the 3rd frame (UTC)' + if k > 2: + com1 = 'exposure start time of the '+str(k+1)+'th frame' + com2 = 'exposure end time of the '+str(k+1)+'th frame' + + hdu_b.header[str1] = (read_start[:21], com1) + hdu_b.header[str2] = (read_end[:21], com2) + + hdu_b.header['DETTEMP0'] = (np.float32( + 0.0), 'detector temperature at EXPT0_1 (K)') + hdu_b.header['DETTEMP1'] = (np.float32( + 0.0), 'detector temperature at EXPT1_'+str(k+1)+' (K)') + ###################################################### end revised on 2024.2.27 ### - - hdu_b.header['BIN_X'] =(np.int16(1), 'bin number in X (wavelength)') - hdu_b.header['BIN_Y'] =(np.int16(1), 'bin number in Y (spatial)') - - hdu_b.header['GAIN1'] =(np.float32(self.information['gain1_b']),'CCD gain (e-/ADU, channel 1)') - hdu_b.header['GAIN2'] =(np.float32(self.information['gain2_b']),'CCD gain (e-/ADU, channel 2)') - hdu_b.header['GAIN3'] =(np.float32(self.information['gain3_b']),'CCD gain (e-/ADU, channel 3)') - hdu_b.header['GAIN4'] =(np.float32(self.information['gain4_b']),'CCD gain (e-/ADU, channel 4)') - - hdu_b.header['DARK1'] =(np.float32(self.information['dark1_b']),'CCD dark (e-/s, channel 1)') - hdu_b.header['DARK2'] =(np.float32(self.information['dark2_b']),'CCD dark (e-/s, channel 2)') - hdu_b.header['DARK3'] =(np.float32(self.information['dark3_b']),'CCD dark (e-/s, channel 3)') - hdu_b.header['DARK4'] =(np.float32(self.information['dark4_b']),'CCD dark (e-/s, channel 4)') - - - hdu_b.header['RON1'] =(np.float32(self.information['rn1_b']),'read noise (e-, channel 1)') - hdu_b.header['RON2'] =(np.float32(self.information['rn2_b']),'read noise (e-, channel 2)') - hdu_b.header['RON3'] =(np.float32(self.information['rn3_b']),'read noise (e-, channel 3)') - hdu_b.header['RON4'] =(np.float32(self.information['rn4_b']),'read noise (e-, channel 4)') - - hdu_b.header['DETBIA1'] =(np.float32(self.information['bias1_b']),'amplifier bias voltage (ADU, channel1)') - hdu_b.header['DETBIA2'] =(np.float32(self.information['bias2_b']),'amplifier bias voltage (ADU, channel2)') - hdu_b.header['DETBIA3'] =(np.float32(self.information['bias3_b']),'amplifier bias voltage (ADU, channel3)') - hdu_b.header['DETBIA4'] =(np.float32(self.information['bias4_b']),'amplifier bias voltage (ADU, channel4)') - - hdu_b.header['ROSPEED'] =(np.float32(100),'readout speed (MHz)') - - hdu_b.header['TOML_TAG']=('csst-ifs-l0-c09','the tag of toml file') - - tt=write_end.utcnow() - date_time=tt.strftime("%Y-%m-%dT%H:%M:%S") - - hdu_b.header['CHECKSUM'] =(date_time,'HDU checksum') - - hdu_b.header['DATASUM'] =(data_time,'data unit checksum') - - if self.source=='LAMP' and self.information['holemask']=='yes': - hdu_b.header['Hole'] =('yes', 'apply hole to LAMP') + + hdu_b.header['BIN_X'] = ( + np.int16(1), 'bin number in X (wavelength)') + hdu_b.header['BIN_Y'] = (np.int16(1), 'bin number in Y (spatial)') + + hdu_b.header['GAIN1'] = (np.float32( + self.information['gain1_b']), 'CCD gain (e-/ADU, channel 1)') + hdu_b.header['GAIN2'] = (np.float32( + self.information['gain2_b']), 'CCD gain (e-/ADU, channel 2)') + hdu_b.header['GAIN3'] = (np.float32( + self.information['gain3_b']), 'CCD gain (e-/ADU, channel 3)') + hdu_b.header['GAIN4'] = (np.float32( + self.information['gain4_b']), 'CCD gain (e-/ADU, channel 4)') + + hdu_b.header['DARK1'] = (np.float32( + self.information['dark1_b']), 'CCD dark (e-/s, channel 1)') + hdu_b.header['DARK2'] = (np.float32( + self.information['dark2_b']), 'CCD dark (e-/s, channel 2)') + hdu_b.header['DARK3'] = (np.float32( + self.information['dark3_b']), 'CCD dark (e-/s, channel 3)') + hdu_b.header['DARK4'] = (np.float32( + self.information['dark4_b']), 'CCD dark (e-/s, channel 4)') + + hdu_b.header['RON1'] = (np.float32( + self.information['rn1_b']), 'read noise (e-, channel 1)') + hdu_b.header['RON2'] = (np.float32( + self.information['rn2_b']), 'read noise (e-, channel 2)') + hdu_b.header['RON3'] = (np.float32( + self.information['rn3_b']), 'read noise (e-, channel 3)') + hdu_b.header['RON4'] = (np.float32( + self.information['rn4_b']), 'read noise (e-, channel 4)') + + hdu_b.header['DETBIA1'] = (np.float32( + self.information['bias1_b']), 'amplifier bias voltage (ADU, channel1)') + hdu_b.header['DETBIA2'] = (np.float32( + self.information['bias2_b']), 'amplifier bias voltage (ADU, channel2)') + hdu_b.header['DETBIA3'] = (np.float32( + self.information['bias3_b']), 'amplifier bias voltage (ADU, channel3)') + hdu_b.header['DETBIA4'] = (np.float32( + self.information['bias4_b']), 'amplifier bias voltage (ADU, channel4)') + + hdu_b.header['ROSPEED'] = (np.float32(100), 'readout speed (MHz)') + + hdu_b.header['TOML_TAG'] = ('csst-ifs-l0-c09', 'the tag of toml file') + + tt = write_end.utcnow() + date_time = tt.strftime("%Y-%m-%dT%H:%M:%S") + + hdu_b.header['CHECKSUM'] = (date_time, 'HDU checksum') + + hdu_b.header['DATASUM'] = (data_time, 'data unit checksum') + + if self.source == 'LAMP' and self.information['holemask'] == 'yes': + hdu_b.header['Hole'] = ('yes', 'apply hole to LAMP') ###################################################################################################### #################### red camera ###################### - #create a new FITS file, using HDUList instance + # create a new FITS file, using HDUList instance ofd_r = fits.PrimaryHDU() - ofd_r.header['SIMPLE']=( True, 'conforms to FITS standard') - ofd_r.header['BITPIX']=( 0, 'array data type') - ofd_r.header['NAXIS'] =( 0, 'number of array dimensions') - ofd_r.header['NEXTEND']=( np.int16(1), 'number of array dimensions') - + ofd_r.header['SIMPLE'] = (True, 'conforms to FITS standard') + ofd_r.header['BITPIX'] = (0, 'array data type') + ofd_r.header['NAXIS'] = (0, 'number of array dimensions') + ofd_r.header['NEXTEND'] = (np.int16(1), 'number of array dimensions') - temp=write_end.utcnow() - data_time=temp.strftime("%Y-%m-%dT%H:%M:%S.%f") - - ofd_r.header['DATE'] =(data_time[:21], 'written date (yyyy-mm-ddThh:mm:ss.s)') - ofd_r.header['FILENAME']=(filename_r[:68],'') - - ofd_r.header['FILETYPE'] =( self.source[:12], 'observation type') - - - ofd_r.header['TELESCOP']=('CSST', 'telescope name') - - - ofd_r.header['INSTRUME']=( 'IFS', 'instrument name') - - - ofd_r.header['RADECSYS']=('ICRS', 'coordinate system of the object') - - - ofd_r.header['EQUINOX'] =(float(2000.0), '') - ofd_r.header['FITSSWV']=('ifs_sim_0.8.03', 'FITS creating software version') - + temp = write_end.utcnow() + data_time = temp.strftime("%Y-%m-%dT%H:%M:%S.%f") + + ofd_r.header['DATE'] = ( + data_time[:21], 'written date (yyyy-mm-ddThh:mm:ss.s)') + ofd_r.header['FILENAME'] = (filename_r[:68], '') + + ofd_r.header['FILETYPE'] = (self.source[:12], 'observation type') + + ofd_r.header['TELESCOP'] = ('CSST', 'telescope name') + + ofd_r.header['INSTRUME'] = ('IFS', 'instrument name') + + ofd_r.header['RADECSYS'] = ( + 'ICRS', 'coordinate system of the object') + + ofd_r.header['EQUINOX'] = (float(2000.0), '') + ofd_r.header['FITSSWV'] = ( + 'ifs_sim_0.8.03', 'FITS creating software version') + + ######### Object information ############# + if self.source == 'SCI' or self.source == 'COMP': + ofd_r.header['OBJECT'] = ( + self.information['name_obj'][:30], 'object name') + ofd_r.header['TARGET'] = ( + (self.information['target']), 'target name (hhmmss.s+ddmmss)') + + ofd_r.header['OBSID'] = (str(obsid), 'observation ID') + + ofd_r.header['RA_OBJ'] = (np.float64( + self.information['ra_obj']), 'object RA (deg)') + ofd_r.header['DEC_OBJ'] = (np.float64( + self.information['dec_obj']), 'object Dec (deg)') - - ######### Object information ############# - if self.source=='SCI' or self.source=='COMP': - ofd_r.header['OBJECT']=( self.information['name_obj'][:30], 'object name') - ofd_r.header['TARGET']=( (self.information['target']), 'target name (hhmmss.s+ddmmss)') - - ofd_r.header['OBSID'] =(str(obsid) , 'observation ID') - - ofd_r.header['RA_OBJ'] =(np.float64(self.information['ra_obj']) , 'object RA (deg)') - ofd_r.header['DEC_OBJ']=(np.float64(self.information['dec_obj']) , 'object Dec (deg)') - else: - ofd_r.header['OBJECT']=(self.source , ' object name') - ofd_r.header['TARGET']=( 0, 'target name (hhmmss.s+ddmmss)') - - ofd_r.header['OBSID'] =(str(obsid) , 'observation ID') - - ofd_r.header['RA_OBJ'] =(np.float64(0) , 'object RA (deg)') - ofd_r.header['DEC_OBJ']=(np.float64(0) , 'object Dec (deg)') - - self.information['POSI0_X']=0.0 #, 'the orbital position of CSST in X direction at EXPSTART') - self.information['POSI0_Y']=0.0 #, 'the orbital position of CSST in Y direction at EXPSTART') - self.information['POSI0_Z']=0.0 #, 'the orbital position of CSST in Z direction at EXPSTART') - self.information['VELO0_X']=0.0 #, 'the orbital velocity of CSST in X direction at EXPSTART') - self.information['VELO0_Y']=0.0 #, 'the orbital velocity of CSST in Y direction at EXPSTART') - self.information['VELO0_Z']=0.0 #, 'the orbital velocity of CSST in Z direction at EXPSTART') - - self.information['POSI1_X']=0.0 #, 'the orbital position of CSST in X direction at EXPSTART') - self.information['POSI1_Y']=0.0 #, 'the orbital position of CSST in Y direction at EXPSTART') - self.information['POSI1_Z']=0.0 #, 'the orbital position of CSST in Z direction at EXPSTART') - self.information['VELO1_X']=0.0 #, 'the orbital velocity of CSST in X direction at EXPSTART') - self.information['VELO1_Y']=0.0 #, 'the orbital velocity of CSST in Y direction at EXPSTART') - self.information['VELO1_Z']=0.0 #, 'the orbital velocity of CSST in Z direction at EXPSTART') - - - + ofd_r.header['OBJECT'] = (self.source, ' object name') + ofd_r.header['TARGET'] = (0, 'target name (hhmmss.s+ddmmss)') + + ofd_r.header['OBSID'] = (str(obsid), 'observation ID') + + ofd_r.header['RA_OBJ'] = (np.float64(0), 'object RA (deg)') + ofd_r.header['DEC_OBJ'] = (np.float64(0), 'object Dec (deg)') + + # , 'the orbital position of CSST in X direction at EXPSTART') + self.information['POSI0_X'] = 0.0 + # , 'the orbital position of CSST in Y direction at EXPSTART') + self.information['POSI0_Y'] = 0.0 + # , 'the orbital position of CSST in Z direction at EXPSTART') + self.information['POSI0_Z'] = 0.0 + # , 'the orbital velocity of CSST in X direction at EXPSTART') + self.information['VELO0_X'] = 0.0 + # , 'the orbital velocity of CSST in Y direction at EXPSTART') + self.information['VELO0_Y'] = 0.0 + # , 'the orbital velocity of CSST in Z direction at EXPSTART') + self.information['VELO0_Z'] = 0.0 + + # , 'the orbital position of CSST in X direction at EXPSTART') + self.information['POSI1_X'] = 0.0 + # , 'the orbital position of CSST in Y direction at EXPSTART') + self.information['POSI1_Y'] = 0.0 + # , 'the orbital position of CSST in Z direction at EXPSTART') + self.information['POSI1_Z'] = 0.0 + # , 'the orbital velocity of CSST in X direction at EXPSTART') + self.information['VELO1_X'] = 0.0 + # , 'the orbital velocity of CSST in Y direction at EXPSTART') + self.information['VELO1_Y'] = 0.0 + # , 'the orbital velocity of CSST in Z direction at EXPSTART') + self.information['VELO1_Z'] = 0.0 + ####################################################################### - ######## Telescope information ############### - - ofd_r.header['REFFRAME']=('CSSTGSC-1.0' , 'guiding catalog version') - ofd_r.header['DATE-OBS']=(data_time[:21] , 'observation date (yyyy-mm-ddThh:mm:ss.s) ') - - ofd_r.header['SATESWV']=('softwave-1.0', 'satellite software version') - - ofd_r.header['EXPSTART']=(np.float64(time2mjd(exp_start_utc)), 'exposure start time (MJD)') - - ofd_r.header['CABSTART']=(np.float64(time2jd(exp_start_utc)), 'first cabin time after exposure start (MJD)') - - ofd_r.header['SUNANGL0']=(np.float32(0.0) , 'angle between the Sun and opt axis at CABSTART') - ofd_r.header['MOONANG0']=(np.float32(0.0) , 'angle between the Moon and opt axis at CABSTART') - - - ofd_r.header['TEL_ALT0']=(np.float64(0.0), 'angle between opt axis and Elimb at CABSTART') - ofd_r.header['POS_ANG0']=(np.float64(0.0), 'angle between y axis and North Pole at CABSTART') - - - ofd_r.header['POSI0_X'] =(np.float64(self.information['POSI0_X']) , 'orbital position in X at CABSTART (km)') - ofd_r.header['POSI0_Y'] =(np.float64(self.information['POSI0_Y']) , 'orbital position in Y at CABSTART (km)') - ofd_r.header['POSI0_Z'] =(np.float64(self.information['POSI0_Z']) , 'orbital position in Z at CABSTART (km)') - ofd_r.header['VELO0_X']=( np.float64(self.information['VELO0_X']) , 'orbital velocity in X at CABSTART (km/s)') - ofd_r.header['VELO0_Y']=( np.float64(self.information['VELO0_Y']) , 'orbital velocity in Y at CABSTART (km/s)') - ofd_r.header['VELO0_Z']=( np.float64(self.information['VELO0_Z']) , 'orbital velocity in Z at CABSTART (km/s)') - - ofd_r.header['Euler0_1']=( np.float64(0.0), 'Euler angle 1 at CABSTART (deg)') - ofd_r.header['Euler0_2']=( np.float64(0.0), 'Euler angle 2 at CABSTART (deg)') - ofd_r.header['Euler0_3']=( np.float64(0.0), 'Euler angle 3 at CABSTART (deg)') - + + ofd_r.header['REFFRAME'] = ('CSSTGSC-1.0', 'guiding catalog version') + ofd_r.header['DATE-OBS'] = (data_time[:21], + 'observation date (yyyy-mm-ddThh:mm:ss.s) ') + + ofd_r.header['SATESWV'] = ( + 'softwave-1.0', 'satellite software version') + + ofd_r.header['EXPSTART'] = (np.float64( + time2mjd(exp_start_utc)), 'exposure start time (MJD)') + + ofd_r.header['CABSTART'] = (np.float64( + time2jd(exp_start_utc)), 'first cabin time after exposure start (MJD)') + + ofd_r.header['SUNANGL0'] = (np.float32( + 0.0), 'angle between the Sun and opt axis at CABSTART') + ofd_r.header['MOONANG0'] = (np.float32( + 0.0), 'angle between the Moon and opt axis at CABSTART') + + ofd_r.header['TEL_ALT0'] = (np.float64( + 0.0), 'angle between opt axis and Elimb at CABSTART') + ofd_r.header['POS_ANG0'] = (np.float64( + 0.0), 'angle between y axis and North Pole at CABSTART') + + ofd_r.header['POSI0_X'] = (np.float64( + self.information['POSI0_X']), 'orbital position in X at CABSTART (km)') + ofd_r.header['POSI0_Y'] = (np.float64( + self.information['POSI0_Y']), 'orbital position in Y at CABSTART (km)') + ofd_r.header['POSI0_Z'] = (np.float64( + self.information['POSI0_Z']), 'orbital position in Z at CABSTART (km)') + ofd_r.header['VELO0_X'] = (np.float64( + self.information['VELO0_X']), 'orbital velocity in X at CABSTART (km/s)') + ofd_r.header['VELO0_Y'] = (np.float64( + self.information['VELO0_Y']), 'orbital velocity in Y at CABSTART (km/s)') + ofd_r.header['VELO0_Z'] = (np.float64( + self.information['VELO0_Z']), 'orbital velocity in Z at CABSTART (km/s)') + + ofd_r.header['Euler0_1'] = (np.float64( + 0.0), 'Euler angle 1 at CABSTART (deg)') + ofd_r.header['Euler0_2'] = (np.float64( + 0.0), 'Euler angle 2 at CABSTART (deg)') + ofd_r.header['Euler0_3'] = (np.float64( + 0.0), 'Euler angle 3 at CABSTART (deg)') + ##### - if self.source=='SCI' or self.source=='COMP': + if self.source == 'SCI' or self.source == 'COMP': - ofd_r.header['RA_PNT0']=( np.float64(self.information['ra_pnt0']) , 'pointing RA at CABSTART (deg)') - ofd_r.header['DEC_PNT0']=(np.float64(self.information['dec_pnt0']) , 'pointing Dec at CABSTART (deg)') + ofd_r.header['RA_PNT0'] = (np.float64( + self.information['ra_pnt0']), 'pointing RA at CABSTART (deg)') + ofd_r.header['DEC_PNT0'] = (np.float64( + self.information['dec_pnt0']), 'pointing Dec at CABSTART (deg)') else: - ofd_r.header['RA_PNT0']=( np.float64(0.0) , 'pointing RA at CABSTART (deg)') - ofd_r.header['DEC_PNT0']=(np.float64(0.0) , 'pointing Dec at CABSTART (deg)') - - - ofd_r.header['EXPEND'] =(np.float64(time2mjd(exp_end_utc)) , 'exposure end time (MJD)') - - ofd_r.header['CABEND'] =(np.float64(time2jd(exp_end_utc)) , 'first cabin time after exposure end (MJD)') - - ofd_r.header['SUNANGL1']=(np.float32(0.0), 'angle between the Sun and opt axis at CABEND') - ofd_r.header['MOONANG1']=(np.float32(0.0) , 'angle between the Moon and opt axis at CABEND') - - ofd_r.header['TEL_ALT1']=(np.float64(0.0) , 'angle between opt axis and Elimb at CABEND') - ofd_r.header['POS_ANG1']=(np.float64(self.information['sky_rot']) , 'angle between y axis and North Pole at CABEND') - - - ofd_r.header['POSI1_X'] =(np.float64(self.information['POSI1_X']) , 'orbital position in X at CABEND (km)') - ofd_r.header['POSI1_Y'] =(np.float64(self.information['POSI1_Y']) , 'orbital position in Y at CABEND (km)') - ofd_r.header['POSI1_Z'] =(np.float64(self.information['POSI1_Z']) , 'orbital position in Z at CABEND (km)') - - ofd_r.header['VELO1_X']=(np.float64(self.information['VELO1_X']) , 'orbital velocity in X at CABEND (km/s)') - ofd_r.header['VELO1_Y']=(np.float64(self.information['VELO1_Y']) , 'orbital velocity in Y at CABEND (km/s)') - ofd_r.header['VELO1_Z']=(np.float64(self.information['VELO1_Z']) , 'orbital velocity in Z at CABEND (km/s)') - - - ofd_r.header['Euler1_1']=( np.float64(0.0), 'Euler angle 1 at CABEND (deg)') - ofd_r.header['Euler1_2']=( np.float64(0.0), 'Euler angle 2 at CABEND (deg)') - ofd_r.header['Euler1_3']=( np.float64(0.0), 'Euler angle 3 at CABEND (deg)') - - ofd_r.header['RA_PNT1']=(np.float64(ofd_r.header['RA_PNT0']), 'pointing RA at CABEND (deg)') - ofd_r.header['DEC_PNT1']=(np.float64(ofd_r.header['DEC_PNT0']), 'pointing Dec at CABEND (deg)') - - - ofd_r.header['EPOCH'] =(np.float32(time2jd(end.utcnow())), 'equinox of pointing RA and Dec') - ofd_r.header['EXPTIME']=(np.float32(self.information['exptime']*self.information['exposuretimes']), 'exposure time (s)') - - + ofd_r.header['RA_PNT0'] = (np.float64( + 0.0), 'pointing RA at CABSTART (deg)') + ofd_r.header['DEC_PNT0'] = (np.float64( + 0.0), 'pointing Dec at CABSTART (deg)') + + ofd_r.header['EXPEND'] = (np.float64( + time2mjd(exp_end_utc)), 'exposure end time (MJD)') + + ofd_r.header['CABEND'] = (np.float64( + time2jd(exp_end_utc)), 'first cabin time after exposure end (MJD)') + + ofd_r.header['SUNANGL1'] = (np.float32( + 0.0), 'angle between the Sun and opt axis at CABEND') + ofd_r.header['MOONANG1'] = (np.float32( + 0.0), 'angle between the Moon and opt axis at CABEND') + + ofd_r.header['TEL_ALT1'] = (np.float64( + 0.0), 'angle between opt axis and Elimb at CABEND') + ofd_r.header['POS_ANG1'] = (np.float64( + self.information['sky_rot']), 'angle between y axis and North Pole at CABEND') + + ofd_r.header['POSI1_X'] = (np.float64( + self.information['POSI1_X']), 'orbital position in X at CABEND (km)') + ofd_r.header['POSI1_Y'] = (np.float64( + self.information['POSI1_Y']), 'orbital position in Y at CABEND (km)') + ofd_r.header['POSI1_Z'] = (np.float64( + self.information['POSI1_Z']), 'orbital position in Z at CABEND (km)') + + ofd_r.header['VELO1_X'] = (np.float64( + self.information['VELO1_X']), 'orbital velocity in X at CABEND (km/s)') + ofd_r.header['VELO1_Y'] = (np.float64( + self.information['VELO1_Y']), 'orbital velocity in Y at CABEND (km/s)') + ofd_r.header['VELO1_Z'] = (np.float64( + self.information['VELO1_Z']), 'orbital velocity in Z at CABEND (km/s)') + + ofd_r.header['Euler1_1'] = (np.float64( + 0.0), 'Euler angle 1 at CABEND (deg)') + ofd_r.header['Euler1_2'] = (np.float64( + 0.0), 'Euler angle 2 at CABEND (deg)') + ofd_r.header['Euler1_3'] = (np.float64( + 0.0), 'Euler angle 3 at CABEND (deg)') + + ofd_r.header['RA_PNT1'] = (np.float64( + ofd_r.header['RA_PNT0']), 'pointing RA at CABEND (deg)') + ofd_r.header['DEC_PNT1'] = (np.float64( + ofd_r.header['DEC_PNT0']), 'pointing Dec at CABEND (deg)') + + ofd_r.header['EPOCH'] = (np.float32( + time2jd(end.utcnow())), 'equinox of pointing RA and Dec') + ofd_r.header['EXPTIME'] = (np.float32( + self.information['exptime']*self.information['exposuretimes']), 'exposure time (s)') + + ss1 = 'HDU checksum' + ss2 = 'data unit checksum' + ofd_r.header['CHECKSUM'] = (data_time[:19], ss1) + ofd_r.header['DATASUM'] = (data_time[:19], ss2) - ss1='HDU checksum' - ss2='data unit checksum' - ofd_r.header['CHECKSUM']=( data_time[:19] , ss1) - ofd_r.header['DATASUM']=( data_time[:19] , ss2) - ########## - ########## finish header for 0 layer ###################### + ########## finish header for 0 layer ###################### ############################################################# - #############################################################################3 - ##### header + # 3 + # header # new image HDU, red channel, layer 1 - if HeaderTest=='yes': - hdu_r =fits.ImageHDU(data=np.zeros((10,10,3))) - else: - hdu_r =fits.ImageHDU(data=np.uint16(self.image_r_N)) + if HeaderTest == 'yes': + hdu_r = fits.ImageHDU(data=np.zeros((10, 10, 3))) + else: + hdu_r = fits.ImageHDU(data=np.uint16(self.image_r_N)) # - hdu_r.header['XTENSION']=('IMAGE','extension type') - hdu_r.header['BITPIX']=(np.int16(16),'bits per data value') - hdu_r.header['NAXIS'] =(np.int16(2),'number of data axies') - - hdu_r.header['NAXIS1'] =(np.int32(1856),'length of first data axis') - - hdu_r.header['NAXIS2'] =(np.int32(13768),'length of second data axis') - - hdu_r.header['NAXIS3'] =(np.int32(self.information['exposuretimes']),'length of third data axis') - + hdu_r.header['XTENSION'] = ('IMAGE', 'extension type') + hdu_r.header['BITPIX'] = (np.int16(16), 'bits per data value') + hdu_r.header['NAXIS'] = (np.int16(2), 'number of data axies') + + hdu_r.header['NAXIS1'] = (np.int32(1856), 'length of first data axis') + + hdu_r.header['NAXIS2'] = ( + np.int32(13768), 'length of second data axis') + + hdu_r.header['NAXIS3'] = ( + np.int32(self.information['exposuretimes']), 'length of third data axis') + + if self.source == 'SCI' or self.source == 'COMP': + hdu_r.header['EXTNAME'] = ('SCI', '') - if self.source =='SCI' or self.source =='COMP': - hdu_r.header['EXTNAME']=('SCI','') - else: - - hdu_r.header['EXTNAME']=('CAL','') - - hdu_r.header['EXTVER']=(np.int16(1),'') - hdu_r.header['BSCALE']=(np.float64(1),'') - hdu_r.header['BZERO'] =(np.float64(32768),'') - hdu_r.header['BUNIT'] =('ADU','physical unit of array values') - + + hdu_r.header['EXTNAME'] = ('CAL', '') + + hdu_r.header['EXTVER'] = (np.int16(1), '') + hdu_r.header['BSCALE'] = (np.float64(1), '') + hdu_r.header['BZERO'] = (np.float64(32768), '') + hdu_r.header['BUNIT'] = ('ADU', 'physical unit of array values') + ######### instrument information ###### ##hdu_r.header['PMIRRPOS']=(bool(False), 'FSM pointing,T: to MCI, F: not to MCI') - if self.source =='SCI' or self.source =='COMP': - - hdu_r.header['CMIRRPOS']=(bool(False), 'position of calibration switch mirror') + if self.source == 'SCI' or self.source == 'COMP': + + hdu_r.header['CMIRRPOS'] = ( + bool(False), 'position of calibration switch mirror') else: - - hdu_r.header['CMIRRPOS']=(bool(True), 'position of calibration switch mirror') - - - if self.source=='FLAT': - hdu_r.header['FLAMP'] =(np.int16(1), 'status of flat lamp') + + hdu_r.header['CMIRRPOS'] = ( + bool(True), 'position of calibration switch mirror') + + if self.source == 'FLAT': + hdu_r.header['FLAMP'] = (np.int16(1), 'status of flat lamp') else: - hdu_r.header['FLAMP'] =(np.int16(0), 'status of flat lamp') - - - if self.source=='LAMP': - hdu_r.header['ALAMP'] =(np.int16(1),'status of flat atomic emission line lamp') + hdu_r.header['FLAMP'] = (np.int16(0), 'status of flat lamp') + + if self.source == 'LAMP': + hdu_r.header['ALAMP'] = ( + np.int16(1), 'status of flat atomic emission line lamp') else: - hdu_r.header['ALAMP'] =(np.int16(0),'status of flat atomic emission line lamp') - + hdu_r.header['ALAMP'] = ( + np.int16(0), 'status of flat atomic emission line lamp') + ############# - hdu_r.header['IFSMODE'] =(np.int32(0), 'IFS working mode') - hdu_r.header['IFSTEMP'] =(np.float32(0), 'IFS components temperature in degC') - hdu_r.header['IFSSTAT'] =(np.int32(0), 'IFS components status parameter') - + hdu_r.header['IFSMODE'] = (np.int32(0), 'IFS working mode') + hdu_r.header['IFSTEMP'] = (np.float32( + 0), 'IFS components temperature in degC') + hdu_r.header['IFSSTAT'] = ( + np.int32(0), 'IFS components status parameter') + ################### detector information############################# - - hdu_r.header['CAMERA'] =('Red','camera of IFS') - hdu_r.header['DETSN'] =('CCD231-c6-00','detector serial number') - hdu_r.header['DETNAME'] =('red','detector name') - - hdu_r.header['DETSIZE'] =('3072*6144', 'detector size') - hdu_r.header['DATASECT'] =('data-section', 'data section') - hdu_r.header['PIXSCAL1']=(np.float32(1856), 'pixel scale for axis 1') - hdu_r.header['PIXSCAL2']=(np.float32(13768), 'pixel scale for axis 2') - hdu_r.header['PIXSIZE1']=(np.float32(15), 'pixel size for axis 1 (micron)') - hdu_r.header['PIXSIZE2']=(np.float32(15), 'pixel size for axis 2 (micron)') - - hdu_r.header['NCHAN'] =(np.int16(4), 'number of readout channels') - hdu_r.header['PSCAN1'] =(np.int32(50), 'horizontal prescan width, per readout channel') - hdu_r.header['PSCAN2'] =(np.int32(0), 'vertical prescan height, per readout channel') - hdu_r.header['OSCAN1'] =(np.int32(320), 'horizontal overscan width, per readout channel') - hdu_r.header['OSCAN2'] =(np.int32(320), 'vertical overscan height, per readout channel') + hdu_r.header['CAMERA'] = ('Red', 'camera of IFS') + hdu_r.header['DETSN'] = ('CCD231-c6-00', 'detector serial number') + hdu_r.header['DETNAME'] = ('red', 'detector name') + + hdu_r.header['DETSIZE'] = ('3072*6144', 'detector size') + hdu_r.header['DATASECT'] = ('data-section', 'data section') + hdu_r.header['PIXSCAL1'] = (np.float32(1856), 'pixel scale for axis 1') + hdu_r.header['PIXSCAL2'] = ( + np.float32(13768), 'pixel scale for axis 2') + hdu_r.header['PIXSIZE1'] = (np.float32( + 15), 'pixel size for axis 1 (micron)') + hdu_r.header['PIXSIZE2'] = (np.float32( + 15), 'pixel size for axis 2 (micron)') + + hdu_r.header['NCHAN'] = (np.int16(4), 'number of readout channels') + + hdu_r.header['PSCAN1'] = ( + np.int32(50), 'horizontal prescan width, per readout channel') + hdu_r.header['PSCAN2'] = ( + np.int32(0), 'vertical prescan height, per readout channel') + hdu_r.header['OSCAN1'] = ( + np.int32(320), 'horizontal overscan width, per readout channel') + hdu_r.header['OSCAN2'] = ( + np.int32(320), 'vertical overscan height, per readout channel') ##################################################################################################### - ####### Readout information - frame_time_r=0.13824; ### data frame transfer time in red camera - + # Readout information + frame_time_r = 0.13824 # data frame transfer time in red camera + for k in range(exptimes): - tt=(self.information['exptime']+frame_time_r)*(k) - - temp=self.dt+timedelta(seconds=tt) - read_start=temp.strftime("%Y-%m-%dT%H:%M:%S.%f") - - temp2=temp+timedelta(seconds=self.information['exptime']) - read_end=temp2.strftime("%Y-%m-%dT%H:%M:%S.%f") - - str1='EXPT0_'+str(k+1) - str2='EXPT1_'+str(k+1) - - if k==0: - com1='exposure start time of the 1st frame (UTC)' - com2='exposure end time of the 1st frame (UTC)' - if k==1: - com1='exposure start time of the 2nd frame (UTC)' - com2='exposure end time of the 2nd frame (UTC)' - if k==2: - com1='exposure start time of the 3rd frame (UTC)' - com2='exposure end time of the 3rd frame (UTC)' - if k>2: - com1='exposure start time of the '+str(k+1)+'th frame' - com2='exposure end time of the '+str(k+1)+'th frame' - - hdu_r.header[str1] =(read_start[:21],com1) - hdu_r.header[str2] =(read_end[:21], com2) + tt = (self.information['exptime']+frame_time_r)*(k) + + temp = self.dt+timedelta(seconds=tt) + read_start = temp.strftime("%Y-%m-%dT%H:%M:%S.%f") + + temp2 = temp+timedelta(seconds=self.information['exptime']) + read_end = temp2.strftime("%Y-%m-%dT%H:%M:%S.%f") + + str1 = 'EXPT0_'+str(k+1) + str2 = 'EXPT1_'+str(k+1) + + if k == 0: + com1 = 'exposure start time of the 1st frame (UTC)' + com2 = 'exposure end time of the 1st frame (UTC)' + if k == 1: + com1 = 'exposure start time of the 2nd frame (UTC)' + com2 = 'exposure end time of the 2nd frame (UTC)' + if k == 2: + com1 = 'exposure start time of the 3rd frame (UTC)' + com2 = 'exposure end time of the 3rd frame (UTC)' + if k > 2: + com1 = 'exposure start time of the '+str(k+1)+'th frame' + com2 = 'exposure end time of the '+str(k+1)+'th frame' + + hdu_r.header[str1] = (read_start[:21], com1) + hdu_r.header[str2] = (read_end[:21], com2) #################################################################################### - hdu_r.header['DETTEMP0']=(np.float32(0.0), 'detector temperature at EXPT0_1 (K)') - hdu_r.header['DETTEMP1']=(np.float32(0.0), 'detector temperature at EXPT1_'+str(k+1)+' (K)') - - hdu_r.header['BIN_X'] =(np.int16(1), 'bin number in X (wavelength)') - hdu_r.header['BIN_Y'] =(np.int16(1), 'bin number in Y (spatial)') - - hdu_r.header['GAIN1'] =(np.float32(self.information['gain1_r']),'CCD gain (e-/ADU, channel 1)') - hdu_r.header['GAIN2'] =(np.float32(self.information['gain2_r']),'CCD gain (e-/ADU, channel 2)') - hdu_r.header['GAIN3'] =(np.float32(self.information['gain3_r']),'CCD gain (e-/ADU, channel 3)') - hdu_r.header['GAIN4'] =(np.float32(self.information['gain4_r']),'CCD gain (e-/ADU, channel 4)') - - hdu_r.header['DARK1'] =(np.float32(self.information['dark1_r']),'CCD dark (e-/s, channel 1)') - hdu_r.header['DARK2'] =(np.float32(self.information['dark2_r']),'CCD dark (e-/s, channel 2)') - hdu_r.header['DARK3'] =(np.float32(self.information['dark3_r']),'CCD dark (e-/s, channel 3)') - hdu_r.header['DARK4'] =(np.float32(self.information['dark4_r']),'CCD dark (e-/s, channel 4)') - - - hdu_r.header['RON1'] =(np.float32(self.information['rn1_r']),'read noise (e-, channel 1)') - hdu_r.header['RON2'] =(np.float32(self.information['rn2_r']),'read noise (e-, channel 2)') - hdu_r.header['RON3'] =(np.float32(self.information['rn3_r']),'read noise (e-, channel 3)') - hdu_r.header['RON4'] =(np.float32(self.information['rn4_r']),'read noise (e-, channel 4)') - - hdu_r.header['DETBIA1'] =(np.float32(self.information['bias1_r']),'amplifier bias voltage (ADU, channel1)') - hdu_r.header['DETBIA2'] =(np.float32(self.information['bias2_r']),'amplifier bias voltage (ADU, channel2)') - hdu_r.header['DETBIA3'] =(np.float32(self.information['bias3_r']),'amplifier bias voltage (ADU, channel3)') - hdu_r.header['DETBIA4'] =(np.float32(self.information['bias4_r']),'amplifier bias voltage (ADU, channel4)') - - hdu_r.header['ROSPEED'] =(np.float32(100),'readout speed (MHz)') - hdu_r.header['TOML_TAG']=('csst-ifs-l0-c09','the tag of toml file') - - date_timer=write_end.strftime("%Y-%m-%dT%H:%M:%S") - - hdu_r.header['CHECKSUM'] =(date_timer,'HDU checksum') - - hdu_r.header['DATASUM'] =(date_timer,'data unit checksum') - - - if self.source=='LAMP' and self.information['holemask']=='yes': - hdu_r.header['Hole'] =('yes', 'apply hole to LAMP') - - + hdu_r.header['DETTEMP0'] = (np.float32( + 0.0), 'detector temperature at EXPT0_1 (K)') + hdu_r.header['DETTEMP1'] = (np.float32( + 0.0), 'detector temperature at EXPT1_'+str(k+1)+' (K)') + + hdu_r.header['BIN_X'] = ( + np.int16(1), 'bin number in X (wavelength)') + hdu_r.header['BIN_Y'] = (np.int16(1), 'bin number in Y (spatial)') + + hdu_r.header['GAIN1'] = (np.float32( + self.information['gain1_r']), 'CCD gain (e-/ADU, channel 1)') + hdu_r.header['GAIN2'] = (np.float32( + self.information['gain2_r']), 'CCD gain (e-/ADU, channel 2)') + hdu_r.header['GAIN3'] = (np.float32( + self.information['gain3_r']), 'CCD gain (e-/ADU, channel 3)') + hdu_r.header['GAIN4'] = (np.float32( + self.information['gain4_r']), 'CCD gain (e-/ADU, channel 4)') + + hdu_r.header['DARK1'] = (np.float32( + self.information['dark1_r']), 'CCD dark (e-/s, channel 1)') + hdu_r.header['DARK2'] = (np.float32( + self.information['dark2_r']), 'CCD dark (e-/s, channel 2)') + hdu_r.header['DARK3'] = (np.float32( + self.information['dark3_r']), 'CCD dark (e-/s, channel 3)') + hdu_r.header['DARK4'] = (np.float32( + self.information['dark4_r']), 'CCD dark (e-/s, channel 4)') + + hdu_r.header['RON1'] = (np.float32( + self.information['rn1_r']), 'read noise (e-, channel 1)') + hdu_r.header['RON2'] = (np.float32( + self.information['rn2_r']), 'read noise (e-, channel 2)') + hdu_r.header['RON3'] = (np.float32( + self.information['rn3_r']), 'read noise (e-, channel 3)') + hdu_r.header['RON4'] = (np.float32( + self.information['rn4_r']), 'read noise (e-, channel 4)') + + hdu_r.header['DETBIA1'] = (np.float32( + self.information['bias1_r']), 'amplifier bias voltage (ADU, channel1)') + hdu_r.header['DETBIA2'] = (np.float32( + self.information['bias2_r']), 'amplifier bias voltage (ADU, channel2)') + hdu_r.header['DETBIA3'] = (np.float32( + self.information['bias3_r']), 'amplifier bias voltage (ADU, channel3)') + hdu_r.header['DETBIA4'] = (np.float32( + self.information['bias4_r']), 'amplifier bias voltage (ADU, channel4)') + + hdu_r.header['ROSPEED'] = (np.float32(100), 'readout speed (MHz)') + hdu_r.header['TOML_TAG'] = ('csst-ifs-l0-c09', 'the tag of toml file') + + date_timer = write_end.strftime("%Y-%m-%dT%H:%M:%S") + + hdu_r.header['CHECKSUM'] = (date_timer, 'HDU checksum') + + hdu_r.header['DATASUM'] = (date_timer, 'data unit checksum') + + if self.source == 'LAMP' and self.information['holemask'] == 'yes': + hdu_r.header['Hole'] = ('yes', 'apply hole to LAMP') + ######################### - + hdu1 = fits.PrimaryHDU(header=ofd_b.header) hdu2 = fits.PrimaryHDU(header=ofd_r.header) ##################################################################### - hdu1.header.add_comment('========================================================================',after='FITSSWV') - hdu1.header.add_comment('OBJECT INFORMATION',after='FITSSWV') - hdu1.header.add_comment('========================================================================',after='FITSSWV') - - hdu1.header.add_comment('========================================================================',after='DEC_OBJ') - hdu1.header.add_comment('TELESCOPE INFORMATION',after='DEC_OBJ') - hdu1.header.add_comment('========================================================================',after='DEC_OBJ') - - hdu1.header.add_comment('========================================================================',after='EPOCH') - hdu1.header.add_comment('VERIFICATION INFORMATION',after='EPOCH') - hdu1.header.add_comment('========================================================================',after='EPOCH') - + hdu1.header.add_comment( + '========================================================================', after='FITSSWV') + hdu1.header.add_comment('OBJECT INFORMATION', after='FITSSWV') + hdu1.header.add_comment( + '========================================================================', after='FITSSWV') + + hdu1.header.add_comment( + '========================================================================', after='DEC_OBJ') + hdu1.header.add_comment('TELESCOPE INFORMATION', after='DEC_OBJ') + hdu1.header.add_comment( + '========================================================================', after='DEC_OBJ') + + hdu1.header.add_comment( + '========================================================================', after='EPOCH') + hdu1.header.add_comment('VERIFICATION INFORMATION', after='EPOCH') + hdu1.header.add_comment( + '========================================================================', after='EPOCH') + ######################################################################################################################### - hdu2.header.add_comment('========================================================================',after='FITSSWV') - hdu2.header.add_comment('OBJECT INFORMATION',after='FITSSWV') - hdu2.header.add_comment('========================================================================',after='FITSSWV') - - - hdu2.header.add_comment('========================================================================',after='DEC_OBJ') - hdu2.header.add_comment('TELESCOPE INFORMATION',after='DEC_OBJ') - hdu2.header.add_comment('========================================================================',after='DEC_OBJ') - - hdu2.header.add_comment('========================================================================',after='EPOCH') - hdu2.header.add_comment('VERIFICATION INFORMATION',after='EPOCH') - hdu2.header.add_comment('========================================================================',after='EPOCH') - - - - hdulist_b=fits.HDUList([hdu1, hdu_b]) - - - - hdu_b.header.add_comment('========================================================================',before='CMIRRPOS') - hdu_b.header.add_comment('INSTRUMENT INFORMATION',before='CMIRRPOS') - hdu_b.header.add_comment('========================================================================',before='CMIRRPOS') - - hdu_b.header.add_comment('========================================================================',before='CAMERA') - hdu_b.header.add_comment('DETECTOR INFORMATION',before='CAMERA') - hdu_b.header.add_comment('========================================================================',before='CAMERA') - - - hdu_b.header.add_comment('========================================================================',before='EXPT0_1') - hdu_b.header.add_comment('READOUT INFORMATION',before='EXPT0_1') - hdu_b.header.add_comment('========================================================================',before='EXPT0_1') - - - hdulist_b.writeto(self.file_b, output_verify='ignore',checksum=True) + hdu2.header.add_comment( + '========================================================================', after='FITSSWV') + hdu2.header.add_comment('OBJECT INFORMATION', after='FITSSWV') + hdu2.header.add_comment( + '========================================================================', after='FITSSWV') + + hdu2.header.add_comment( + '========================================================================', after='DEC_OBJ') + hdu2.header.add_comment('TELESCOPE INFORMATION', after='DEC_OBJ') + hdu2.header.add_comment( + '========================================================================', after='DEC_OBJ') + + hdu2.header.add_comment( + '========================================================================', after='EPOCH') + hdu2.header.add_comment('VERIFICATION INFORMATION', after='EPOCH') + hdu2.header.add_comment( + '========================================================================', after='EPOCH') + + hdulist_b = fits.HDUList([hdu1, hdu_b]) + + hdu_b.header.add_comment( + '========================================================================', before='CMIRRPOS') + hdu_b.header.add_comment('INSTRUMENT INFORMATION', before='CMIRRPOS') + hdu_b.header.add_comment( + '========================================================================', before='CMIRRPOS') + + hdu_b.header.add_comment( + '========================================================================', before='CAMERA') + hdu_b.header.add_comment('DETECTOR INFORMATION', before='CAMERA') + hdu_b.header.add_comment( + '========================================================================', before='CAMERA') + + hdu_b.header.add_comment( + '========================================================================', before='EXPT0_1') + hdu_b.header.add_comment('READOUT INFORMATION', before='EXPT0_1') + hdu_b.header.add_comment( + '========================================================================', before='EXPT0_1') + + hdulist_b.writeto(self.file_b, output_verify='ignore', checksum=True) ##################################################################################################### - hdulist_r=fits.HDUList([hdu2, hdu_r]) - - hdu_r.header.add_comment('========================================================================',before='CMIRRPOS') - hdu_r.header.add_comment('INSTRUMENT INFORMATION',before='CMIRRPOS') - hdu_r.header.add_comment('========================================================================',before='CMIRRPOS') - - hdu_r.header.add_comment('========================================================================',before='CAMERA') - hdu_r.header.add_comment('DETECTOR INFORMATION',before='CAMERA') - hdu_r.header.add_comment('========================================================================',before='CAMERA') - - - hdu_r.header.add_comment('========================================================================',before='EXPT0_1') - hdu_r.header.add_comment('READOUT INFORMATION',before='EXPT0_1') - hdu_r.header.add_comment('========================================================================',before='EXPT0_1') - - - hdulist_r.writeto(self.file_r, output_verify='ignore',checksum=True) + hdulist_r = fits.HDUList([hdu2, hdu_r]) + hdu_r.header.add_comment( + '========================================================================', before='CMIRRPOS') + hdu_r.header.add_comment('INSTRUMENT INFORMATION', before='CMIRRPOS') + hdu_r.header.add_comment( + '========================================================================', before='CMIRRPOS') - ################################################################################## - - def earthshine(self,theta): + hdu_r.header.add_comment( + '========================================================================', before='CAMERA') + hdu_r.header.add_comment('DETECTOR INFORMATION', before='CAMERA') + hdu_r.header.add_comment( + '========================================================================', before='CAMERA') + + hdu_r.header.add_comment( + '========================================================================', before='EXPT0_1') + hdu_r.header.add_comment('READOUT INFORMATION', before='EXPT0_1') + hdu_r.header.add_comment( + '========================================================================', before='EXPT0_1') + + hdulist_r.writeto(self.file_r, output_verify='ignore', checksum=True) + + ################################################################################## + + def earthshine(self, theta): """ For given theta angle, return the earth-shine spectrum. - + :param theta: angle (in degree) from the target to earth limb. :return: the scaled solar spectrum template_wave: unit in A template_flux: unit in erg/s/cm^2/A/arcsec^2 - + """ - + # read solar template solar_template = pd.read_csv(self.information['dir_path']+'IFS_inputdata/refs/solar_spec.dat', sep='\s+', - header=None, comment='#') + header=None, comment='#') template_wave = solar_template[0].values template_flux = solar_template[1].values - + # read earth shine surface brightness earthshine_curve = pd.read_csv(self.information['dir_path']+'IFS_inputdata/refs/earthshine.dat', - header=None, comment='#') + header=None, comment='#') angle = earthshine_curve[0].values surface_brightness = earthshine_curve[1].values - + # read V-band throughtput cat_filter_V = pd.read_csv(self.information['dir_path']+'IFS_inputdata/refs/filter_Bessell_V.dat', sep='\s+', header=None, comment='#') filter_wave = cat_filter_V[0].values filter_response = cat_filter_V[1].values - + # interplate to the target wavelength in V-band - ind_filter = (template_wave >= np.min(filter_wave)) & (template_wave <= np.max(filter_wave)) + ind_filter = (template_wave >= np.min(filter_wave)) & ( + template_wave <= np.max(filter_wave)) filter_wave_interp = template_wave[ind_filter] - filter_response_interp = np.interp(filter_wave_interp, filter_wave, filter_response) - - filter_constant = simps(filter_response_interp * filter_wave_interp, filter_wave_interp) + filter_response_interp = np.interp( + filter_wave_interp, filter_wave, filter_response) + + filter_constant = simps( + filter_response_interp * filter_wave_interp, filter_wave_interp) template_constant = simps(filter_response_interp * template_wave[ind_filter] * template_flux[ind_filter], template_wave[ind_filter]) dwave = filter_wave_interp[1:] - filter_wave_interp[:-1] wave_eff = np.nansum(dwave * filter_wave_interp[1:] * filter_response_interp[1:]) / \ - np.nansum(dwave * filter_response_interp[1:]) - + np.nansum(dwave * filter_response_interp[1:]) + # get the normalized value at theta. u0 = np.interp(theta, angle, surface_brightness) # mag/arcsec^2 - u0 = 10**((u0 + 48.6)/(-2.5)) # target flux in erg/s/cm^2/Hz unit + # target flux in erg/s/cm^2/Hz unit + u0 = 10**((u0 + 48.6)/(-2.5)) u0 = u0 * 3e18 / wave_eff**2 # erg/s/cm^2/A/arcsec^2 - + factor = u0 * filter_constant / template_constant norm_flux = template_flux * factor # erg/s/cm^2/A/arcsec^2 - - self.earthshine_wave=template_wave # A - self.earthshine_flux=norm_flux - - return + + self.earthshine_wave = template_wave # A + self.earthshine_flux = norm_flux + + return ######################################################################################################################################################################################################################################################## - ################################################################################### ################################################################################## + def CalskyNoise(self, lam): - - + # calculate the reference flux # calculate sky noise; - planckh= 6.62620*10**-27 # % erg s; - cc=2.99792458*10**17 # in nm/s - fov2=0.01 # 单个像素的面积 arcsec^2 - #telarea=3.1415926*100*100 # in cm^2,望远镜聚光面积; - # lam is input wavelength in nm - + planckh = 6.62620*10**-27 # % erg s; + cc = 2.99792458*10**17 # in nm/s + fov2 = 0.01 # 单个像素的面积 arcsec^2 + # telarea=3.1415926*100*100 # in cm^2,望远镜聚光面积; + # lam is input wavelength in nm + ########################################## - #self.earthshine_wave # A - #self.earthshine_flux # erg/s/cm^2/A/arcsec^2 - earthshine_flux=np.interp(lam*10.0, self.earthshine_wave,self.earthshine_flux) # flux from zodiacal - - #self.zodiacal_wave # in A - #self.zodiacal_flux # erg/s/cm^2/A/arcsec^2 - zodiacal_flux=np.interp(lam*10.0, self.zodiacal_wave,self.zodiacal_flux) # flux from zodiacal - fluxlam_sky=(earthshine_flux+zodiacal_flux)*fov2 # erg/s/cm2/A + # self.earthshine_wave # A + # self.earthshine_flux # erg/s/cm^2/A/arcsec^2 + earthshine_flux = np.interp( + lam*10.0, self.earthshine_wave, self.earthshine_flux) # flux from zodiacal + + # self.zodiacal_wave # in A + # self.zodiacal_flux # erg/s/cm^2/A/arcsec^2 + zodiacal_flux = np.interp( + lam*10.0, self.zodiacal_wave, self.zodiacal_flux) # flux from zodiacal + fluxlam_sky = (earthshine_flux+zodiacal_flux) * \ + fov2 # erg/s/cm2/A ############### - - ephoton=planckh*cc/lam # in erg/photon, cc与lambda单位需要一致; - Ns_skynoise=fluxlam_sky/ephoton # in unit of photons/cm2/s/A - - - return Ns_skynoise - - - ################################################################################# + + ephoton = planckh*cc/lam # in erg/photon, cc与lambda单位需要一致; + Ns_skynoise = fluxlam_sky/ephoton # in unit of photons/cm2/s/A + + return Ns_skynoise + + ################################################################################# ############## + def sim_lamp_hole_img(self, exposuretime): - - - sizeout=1000 ### here image has the pixelscale =0.01 arcsec - ################# create the slicer and slit file for high resolution 0.01arcsec simulation ################### - - maskSlice=dict() - maskSlit=dict() - - for k in range(32): - maskSlice[str(k)]=np.zeros((sizeout,sizeout)) - maskSlice[str(k)][20*k+180:20*k+200, int(sizeout/2)-320:int(sizeout/2)+320]=1 - - maskSlit[str(k)]=np.zeros((sizeout,sizeout)) - maskSlit[str(k)][20*k+180:20*k+200, int(sizeout/2)-370:int(sizeout/2)+370]=1 - - self.maskSliceHole=maskSlice - self.maskSlitHole =maskSlit - ######################################################################### - ##### load slicer_Qe1K.fits #### - slicerfile=self.information['dir_path']+'IFS_inputdata/Flatfield/slicer_QE_1K_230625.fits' - da=fits.open(slicerfile) - self.log.info('hole Sim and slicer 1K QE file:%s'%(slicerfile)) - slicer_Qe=da[0].data - - ##### load hole mask ###### - ### load hole mask matrix - file=self.information['dir_path']+'IFS_inputdata/Hole/holemask_230612.fits' - self.log.info('hole mask file is %s' %(file)) - da=fits.open(file) - HoleMask=da[self.simnumber].data - - ############### load HgAr data; - - matfn3=self.information['dir_path']+'IFS_inputdata/HgAr.mat' - self.log.info('lamp flux file is : %s'%(matfn3)) - da3=sio.loadmat(matfn3) - HgArst=da3['HgArst'] # opd unit is in meter - ############################### load flat data - - - exptime=self.information['exptime'] #exposure time - - blue_img=galsim.Image(np.zeros((2048,4096)),copy=True) - blue_img.scale=self.pixelscale - blue_img.setOrigin=(0,0) - - red_img=galsim.Image(np.zeros((3072,6144)),copy=True) - red_img.scale=self.pixelscale - red_img.setOrigin=(0,0) - - slice_image=np.zeros((sizeout,sizeout)) - - width_blue=0 - - LightSt=np.zeros(6000) - flux_1=np.zeros(6000) - Width_lambda=(1000-350)/6000 - Wave=np.zeros(6000) - + + sizeout = 1000 # here image has the pixelscale =0.01 arcsec + ################# create the slicer and slit file for high resolution 0.01arcsec simulation ################### + + maskSlice = dict() + maskSlit = dict() + + for k in range(32): + maskSlice[str(k)] = np.zeros((sizeout, sizeout)) + maskSlice[str(k)][20*k+180:20*k+200, int(sizeout/2) - + 320:int(sizeout/2)+320] = 1 + + maskSlit[str(k)] = np.zeros((sizeout, sizeout)) + maskSlit[str(k)][20*k+180:20*k+200, int(sizeout/2) - + 370:int(sizeout/2)+370] = 1 + + self.maskSliceHole = maskSlice + self.maskSlitHole = maskSlit + ######################################################################### + ##### load slicer_Qe1K.fits #### + slicerfile = self.information['dir_path'] + \ + 'IFS_inputdata/Flatfield/slicer_QE_1K_230625.fits' + da = fits.open(slicerfile) + self.log.info('hole Sim and slicer 1K QE file:%s' % (slicerfile)) + slicer_Qe = da[0].data + + ##### load hole mask ###### + # load hole mask matrix + file = self.information['dir_path'] + \ + 'IFS_inputdata/Hole/holemask_230612.fits' + self.log.info('hole mask file is %s' % (file)) + da = fits.open(file) + HoleMask = da[self.simnumber].data + + # load HgAr data; + + matfn3 = self.information['dir_path']+'IFS_inputdata/HgAr.mat' + self.log.info('lamp flux file is : %s' % (matfn3)) + da3 = sio.loadmat(matfn3) + HgArst = da3['HgArst'] # opd unit is in meter + # load flat data + + exptime = self.information['exptime'] # exposure time + + blue_img = galsim.Image(np.zeros((2048, 4096)), copy=True) + blue_img.scale = self.pixelscale + blue_img.setOrigin = (0, 0) + + red_img = galsim.Image(np.zeros((3072, 6144)), copy=True) + red_img.scale = self.pixelscale + red_img.setOrigin = (0, 0) + + slice_image = np.zeros((sizeout, sizeout)) + + width_blue = 0 + + LightSt = np.zeros(6000) + flux_1 = np.zeros(6000) + Width_lambda = (1000-350)/6000 + Wave = np.zeros(6000) + + if self.debug: + + alfa = 1000 + else: + + alfa = 1 + + # 3 + + for klam in range(6000): + + ilam = klam*alfa + if self.debug: - - alfa=1000 - else: - - alfa=1 - - #############################3 - - for klam in range(6000): - - ilam=klam*alfa - - if self.debug: - print(ilam) - - if ilam%100==0: - self.log.info('ilam = %i' % ilam) - self.log.info('blue image max value = %i' % blue_img.array.max()) - self.log.info('red image max value = %i' % red_img.array.max()) - - if ilam>=6000: - continue - - lam=350.0+(1000-350)/6000.0 *ilam # the wavelength of the i-th frame data - - Wave[ilam]=lam - - #print('i = ',ilam ) - ############################################### - - sumt=0.0 - - for k in range(11): - t=getSpectrum(HgArst,lam+(k-5)*Width_lambda/11, self.HgArsigma) - sumt=sumt+t[0]/11 - #print('t=', t) - - LightSt[ilam]=sumt ## the normalized HgAr light source in the range of 0 and 1.0 - - skymag=6 # mag/arcsec^2 unit - - - if ilam==0: - ##fluxnu1,fluxlam1,fluxphoton1=mag2flux(skymag,633) - fluxlam1,fluxphoton1=mag2flux(skymag,633) - - ### save flux information - flux_1[ilam]=LightSt[ilam]*fluxlam1*self.fov2 # erg/s/cm2/A - - nphoton=flux2photons(flux_1[ilam], lam) - - ns=nphoton*np.ones((sizeout,sizeout)) ### photons/cm2/s/A/arcsec2 - - slice_image=ns*self.telarea*Width_lambda*10*exptime - - ############################################################# - - - if slice_image.max()<0.1: - continue - - if slice_image.min()<0: - self.log.error('Error in datacube, negative values !!!!!!!') - continue - - ######################## - ############## - ### here Q is 10 times - Q=10*lam*1e-3*self.Fnum/self.pixelsize - - ### for calibration , there is no primay CSST system, but diffraction effect should consider - ################ opd0 rms = 0.0 @632.8nm - wavefront0=self.opd0/lam/100000.0 - - psf0=anySampledPSFnew(wavefront0, self.pupil , Q , 256) - - ##### do convolve with psf0 - conv = fftconvolve(slice_image, psf0, mode='same') - - conv[conv < 0.0] = 0.0 - - slice_image2=conv - - ############################################3 - - ###applyHoleMask only for lamp - - img0=slice_image2*HoleMask - - ################ opd1 rms =0.075 @632.8nm - wavefront=self.opd1/lam - - psf1=anySampledPSFnew(wavefront, self.pupil , Q , 256) - - - ##### do convolve with psf1 - conv = fftconvolve(img0, psf1, mode='same') - conv[conv < 0.0] = 0.0 - img0=conv - - ####################################################### - - #energy=energy+img0[500-302:500+320,500-320:500+320].sum() ## calculate the slice image energy; - - CCD_Qe_lam=np.interp(lam,self.CCD_Qe[:,0],self.CCD_Qe[:,1]) ## CCD quantum efficiency - - Qe_blue = np.interp(lam, self.optical_blue_Q[:,0], self.optical_blue_Q[:,1]) # optical efficiency , convert the wavelength to A - - Qe_red = np.interp(lam, self.optical_red_Q[:,0], self.optical_red_Q[:,1]) # optical efficiency, convert the wavelength to A - - Qe_blue=Qe_blue*CCD_Qe_lam - Qe_red =Qe_red *CCD_Qe_lam - - ######## consider the slice optical efficiency in different slicer channel - - img0=img0*slicer_Qe - ########## do the slice effect ################### - for k in range(32): - - #### do slice effect to get slice image - img1=img0*self.maskSliceHole[str(k)] - - ############ get opd2 and PSF2 ###################### - wavefront2=self.opd2/lam - psf2=anySampledPSFnew(wavefront2, self.pupil , Q , 256) - ##### do convolve - ################## - conv = fftconvolve(img1, psf2, mode='same') - #suppress negative numbers - conv[conv < 0.0] = 0.0 - img2=conv - - ##############do Slit Mask ########################### - - img2=img2*self.maskSlitHole[str(k)] - - ######### get opd3 and PSF3 ########################## - - wavefront3=self.opd3/lam - psf3=anySampledPSFnew(wavefront3, self.pupil , Q , 256) - - ##### do convolve - ######################################## - conv = fftconvolve(img2, psf3, mode='same') - #suppress negative numbers - conv[conv < 0.0] = 0.0 - - img3=conv - - ######################## get subimage ##################### - subimage = galsim.Image(800,800) - subimage.array[:,:]=img3[int(sizeout/2)-400:int(sizeout/2)+400,int(sizeout/2)-400:int(sizeout/2)+400] - - #fits.writeto('subimage.fits',subimage.array,overwrite=True) - - ######################## get photons from sub-image ##################### - subimage.scale = 0.01 ## here pixelscale=0.01arcsec - - subimage.setOrigin(0,0) - - photons=galsim.PhotonArray.makeFromImage(subimage, max_flux=max(img3.max()/10000.0, 1)) - - ############################################################################# - ###### do something for each photons; - ############################################################################## - idx0=np.where( photons.flux>1e-3) - #energy=energy+sum(photons.flux[idx0]) ### totla energy for slice image - p_num=len(idx0[0]) - - ############################################################################################### - - ############### find photons for blue channel, and make the flux multiple the optical and CCD efficiency - - if (lam>=350.0 and lam<=650.0): - ## bulue channel - photons_blue=galsim.PhotonArray(N=p_num, x=photons.x[idx0], y=photons.y[idx0], flux = Qe_blue*photons.flux[idx0],wavelength=lam) - - dx_blue, dy_blue = get_dx_dy_blue(lam) - - photons_blue.x=photons_blue.x/(self.pixelscale)+dx_blue+self.slice_blue['px'][k] - - photons_blue.y=photons_blue.y/(self.pixelscale)+dy_blue+self.slice_blue['py'][k] - - photons_blue.addTo(blue_img) - - #zblue=blue_img.array - - #energy_blue=energy_blue+sum(photons_blue.flux) - - width_blue=width_blue+Width_lambda/32.0 - - #fits.writeto('blueImg.fits',blue_img.array,overwrite=True) - - if (lam>=560.0) & (lam<=1000.0 ): - ## red channel - photons_red=galsim.PhotonArray(N=p_num,x=photons.x[idx0],y=photons.y[idx0], flux = Qe_red*photons.flux[idx0],wavelength=lam) - - dx_red, dy_red = get_dx_dy_red(lam) - - photons_red.x=photons_red.x/(self.pixelscale)+dx_red+self.slice_red['px'][k] - - photons_red.y=photons_red.y/(self.pixelscale)+dy_red+self.slice_red['py'][k] - - #red_sensor.accumulate(photons_red, red_img) - - photons_red.addTo(red_img) - - #energy_red=energy_red+sum(photons_red.flux) - - #################################################################################### - - self.image_b=blue_img.array - self.image_r=red_img.array - - now=datetime.utcnow() - - data_time=now.strftime("%Y-%m-%d") - #write the actual file - - bluefile=self.result_path+'/original_Calibration/IFS_'+self.source+'_'+data_time+'_'+str(self.simnumber)+'_B_original.fits' - redfile =self.result_path+'/original_Calibration/IFS_'+self.source+'_'+data_time+'_'+str(self.simnumber)+'_R_original.fits' - - fits.writeto(bluefile, blue_img.array, overwrite=True) - fits.writeto(redfile, red_img.array, overwrite=True) - - #### save flux #### - Flux=flux_1 - - hdu1=fits.PrimaryHDU(Flux) - - dtime=datetime.utcnow().strftime('%Y -%m -%d %H: %M: %S') - hdu1.header.add_history('Flux data is generated on :'+dtime) - hdu1.header['FluxUnit']=('erg/s/cm2/A','erg/s/cm2/A') - - hdu2=fits.ImageHDU(Wave) - - hdu2.header.append(('WaveUnit', 'nm')) - - newd=fits.HDUList([hdu1,hdu2]) - - filename=self.result_path+'/calibration_Data/'+self.source+'_flux.fits' - - if self.simnumber ==1: - newd.writeto(filename,overwrite=True) - - - return + print(ilam) + + if ilam % 100 == 0: + self.log.info('ilam = %i' % ilam) + self.log.info('blue image max value = %i' % + blue_img.array.max()) + self.log.info('red image max value = %i' % red_img.array.max()) + + if ilam >= 6000: + continue + + # the wavelength of the i-th frame data + lam = 350.0+(1000-350)/6000.0 * ilam + + Wave[ilam] = lam + + #print('i = ',ilam ) + ############################################### + + sumt = 0.0 + + for k in range(11): + t = getSpectrum(HgArst, lam+(k-5) * + Width_lambda/11, self.HgArsigma) + sumt = sumt+t[0]/11 + #print('t=', t) + + # the normalized HgAr light source in the range of 0 and 1.0 + LightSt[ilam] = sumt + + skymag = 6 # mag/arcsec^2 unit + + if ilam == 0: + # fluxnu1,fluxlam1,fluxphoton1=mag2flux(skymag,633) + fluxlam1, fluxphoton1 = mag2flux(skymag, 633) + + # save flux information + flux_1[ilam] = LightSt[ilam]*fluxlam1*self.fov2 # erg/s/cm2/A + + nphoton = flux2photons(flux_1[ilam], lam) + + ns = nphoton*np.ones((sizeout, sizeout)) # photons/cm2/s/A/arcsec2 + + slice_image = ns*self.telarea*Width_lambda*10*exptime + + ############################################################# + + if slice_image.max() < 0.1: + continue + + if slice_image.min() < 0: + self.log.error('Error in datacube, negative values !!!!!!!') + continue + + ######################## + ############## + # here Q is 10 times + Q = 10*lam*1e-3*self.Fnum/self.pixelsize + + # for calibration , there is no primay CSST system, but diffraction effect should consider + # opd0 rms = 0.0 @632.8nm + wavefront0 = self.opd0/lam/100000.0 + + psf0 = anySampledPSFnew(wavefront0, self.pupil, Q, 256) + + # do convolve with psf0 + conv = fftconvolve(slice_image, psf0, mode='same') + + conv[conv < 0.0] = 0.0 + + slice_image2 = conv + + # 3 + + # applyHoleMask only for lamp + + img0 = slice_image2*HoleMask + + # opd1 rms =0.075 @632.8nm + wavefront = self.opd1/lam + + psf1 = anySampledPSFnew(wavefront, self.pupil, Q, 256) + + # do convolve with psf1 + conv = fftconvolve(img0, psf1, mode='same') + conv[conv < 0.0] = 0.0 + img0 = conv + + ####################################################### + + # energy=energy+img0[500-302:500+320,500-320:500+320].sum() ## calculate the slice image energy; + + # CCD quantum efficiency + CCD_Qe_lam = np.interp(lam, self.CCD_Qe[:, 0], self.CCD_Qe[:, 1]) + + # optical efficiency , convert the wavelength to A + Qe_blue = np.interp( + lam, self.optical_blue_Q[:, 0], self.optical_blue_Q[:, 1]) + + # optical efficiency, convert the wavelength to A + Qe_red = np.interp( + lam, self.optical_red_Q[:, 0], self.optical_red_Q[:, 1]) + + Qe_blue = Qe_blue*CCD_Qe_lam + Qe_red = Qe_red * CCD_Qe_lam + + # consider the slice optical efficiency in different slicer channel + + img0 = img0*slicer_Qe + ########## do the slice effect ################### + for k in range(32): + + # do slice effect to get slice image + img1 = img0*self.maskSliceHole[str(k)] + + ############ get opd2 and PSF2 ###################### + wavefront2 = self.opd2/lam + psf2 = anySampledPSFnew(wavefront2, self.pupil, Q, 256) + # do convolve + ################## + conv = fftconvolve(img1, psf2, mode='same') + # suppress negative numbers + conv[conv < 0.0] = 0.0 + img2 = conv + + ##############do Slit Mask ########################### + + img2 = img2*self.maskSlitHole[str(k)] + + ######### get opd3 and PSF3 ########################## + + wavefront3 = self.opd3/lam + psf3 = anySampledPSFnew(wavefront3, self.pupil, Q, 256) + + # do convolve + ######################################## + conv = fftconvolve(img2, psf3, mode='same') + # suppress negative numbers + conv[conv < 0.0] = 0.0 + + img3 = conv + + ######################## get subimage ##################### + subimage = galsim.Image(800, 800) + subimage.array[:, :] = img3[int( + sizeout/2)-400:int(sizeout/2)+400, int(sizeout/2)-400:int(sizeout/2)+400] + + # fits.writeto('subimage.fits',subimage.array,overwrite=True) + + ######################## get photons from sub-image ##################### + subimage.scale = 0.01 # here pixelscale=0.01arcsec + + subimage.setOrigin(0, 0) + + photons = galsim.PhotonArray.makeFromImage( + subimage, max_flux=max(img3.max()/10000.0, 1)) + + ############################################################################# + # do something for each photons; + ############################################################################## + idx0 = np.where(photons.flux > 1e-3) + # energy=energy+sum(photons.flux[idx0]) ### totla energy for slice image + p_num = len(idx0[0]) + + ############################################################################################### + + # find photons for blue channel, and make the flux multiple the optical and CCD efficiency + + if (lam >= 350.0 and lam <= 650.0): + # bulue channel + photons_blue = galsim.PhotonArray( + N=p_num, x=photons.x[idx0], y=photons.y[idx0], flux=Qe_blue*photons.flux[idx0], wavelength=lam) + + dx_blue, dy_blue = get_dx_dy_blue(lam) + + photons_blue.x = photons_blue.x / \ + (self.pixelscale)+dx_blue+self.slice_blue['px'][k] + + photons_blue.y = photons_blue.y / \ + (self.pixelscale)+dy_blue+self.slice_blue['py'][k] + + photons_blue.addTo(blue_img) + + # zblue=blue_img.array + + # energy_blue=energy_blue+sum(photons_blue.flux) + + width_blue = width_blue+Width_lambda/32.0 + + # fits.writeto('blueImg.fits',blue_img.array,overwrite=True) + + if (lam >= 560.0) & (lam <= 1000.0): + # red channel + photons_red = galsim.PhotonArray( + N=p_num, x=photons.x[idx0], y=photons.y[idx0], flux=Qe_red*photons.flux[idx0], wavelength=lam) + + dx_red, dy_red = get_dx_dy_red(lam) + + photons_red.x = photons_red.x / \ + (self.pixelscale)+dx_red+self.slice_red['px'][k] + + photons_red.y = photons_red.y / \ + (self.pixelscale)+dy_red+self.slice_red['py'][k] + + #red_sensor.accumulate(photons_red, red_img) + + photons_red.addTo(red_img) + + # energy_red=energy_red+sum(photons_red.flux) + + #################################################################################### + + self.image_b = blue_img.array + self.image_r = red_img.array + + now = datetime.utcnow() + + data_time = now.strftime("%Y-%m-%d") + # write the actual file + + bluefile = self.result_path+'/original_Calibration/IFS_'+self.source + \ + '_'+data_time+'_'+str(self.simnumber)+'_B_original.fits' + redfile = self.result_path+'/original_Calibration/IFS_'+self.source + \ + '_'+data_time+'_'+str(self.simnumber)+'_R_original.fits' + + fits.writeto(bluefile, blue_img.array, overwrite=True) + fits.writeto(redfile, red_img.array, overwrite=True) + + #### save flux #### + Flux = flux_1 + + hdu1 = fits.PrimaryHDU(Flux) + + dtime = datetime.utcnow().strftime('%Y -%m -%d %H: %M: %S') + hdu1.header.add_history('Flux data is generated on :'+dtime) + hdu1.header['FluxUnit'] = ('erg/s/cm2/A', 'erg/s/cm2/A') + + hdu2 = fits.ImageHDU(Wave) + + hdu2.header.append(('WaveUnit', 'nm')) + + newd = fits.HDUList([hdu1, hdu2]) + + filename = self.result_path+'/calibration_Data/'+self.source+'_flux.fits' + + if self.simnumber == 1: + newd.writeto(filename, overwrite=True) + + return ################################################################################## - def sim_sky_img(self,skyfitsfilename, skyRa, skyDec, sky_rot, telRa, telDec, exposuretime, simnumber): - - ## load the input original data cube simulated by Fengshuai - + + def sim_sky_img(self, skyfitsfilename, skyRa, skyDec, sky_rot, telRa, telDec, exposuretime, simnumber): + + # load the input original data cube simulated by Fengshuai + ############################################################################ - ######## consider the slice optical efficiency in different slicer channel - slicer_QE_file=self.information['dir_path']+'IFS_inputdata/Flatfield/slicer_QE230625.fits' - da=fits.open(slicer_QE_file) - self.log.info('slicer_QE_file path is: %s' %(slicer_QE_file)) - slicer_Qe=da[0].data - - ####################################################################### - - indatafile=skyfitsfilename # 'CSSTMock-M49_HST-FOV10R01-Z00.v202012.fits' - - self.log.info('skyfitsin file is:%s'%(skyfitsfilename)) - a=fits.open(indatafile) + # consider the slice optical efficiency in different slicer channel + slicer_QE_file = self.information['dir_path'] + \ + 'IFS_inputdata/Flatfield/slicer_QE230625.fits' + da = fits.open(slicer_QE_file) + self.log.info('slicer_QE_file path is: %s' % (slicer_QE_file)) + slicer_Qe = da[0].data + + ####################################################################### + + indatafile = skyfitsfilename # 'CSSTMock-M49_HST-FOV10R01-Z00.v202012.fits' + + self.log.info('skyfitsin file is:%s' % (skyfitsfilename)) + a = fits.open(indatafile) # hdr = a[0].header # print(a.info()) # hdr = a[1].header ####################################################################### - self.information['name_obj']=a[0].header['OBJECT'] - self.information['ra_obj'] =a[0].header['RA'] ### in degree - self.information['dec_obj'] =a[0].header['DEC'] ### in degree - - disRa =(telRa-skyRa)/3600.0 ##convert unit of arcsec to degree - disDec=(telDec-skyDec)/3600.0 ##convert unit of arcsec to degree - ### RA_PNT0 =OBJ_RA + DIS_RA/cos(OBJ_DEC), DEC_PNT0= OBJ_DEC DIS_DEC - self.information['ra_pnt0'] =a[0].header['RA'] + disRa/np.cos(a[0].header['DEC']/180.0*np.pi) - self.information['dec_pnt0']=a[0].header['DEC']+ disDec - - + self.information['name_obj'] = a[0].header['OBJECT'] + self.information['ra_obj'] = a[0].header['RA'] # in degree + self.information['dec_obj'] = a[0].header['DEC'] # in degree + + disRa = (telRa-skyRa)/3600.0 # convert unit of arcsec to degree + disDec = (telDec-skyDec)/3600.0 # convert unit of arcsec to degree + # RA_PNT0 =OBJ_RA + DIS_RA/cos(OBJ_DEC), DEC_PNT0= OBJ_DEC DIS_DEC + self.information['ra_pnt0'] = a[0].header['RA'] + \ + disRa/np.cos(a[0].header['DEC']/180.0*np.pi) + self.information['dec_pnt0'] = a[0].header['DEC'] + disDec + ############### calculate the earthshine and zodiacal noise ,new code 2023.11.1 ############ ############### - - ra = self.information['ra_pnt0'] - dec = self.information['dec_pnt0'] - - time_jd=time2jd(self.dt) - - x_sat=float(self.orbit_pars[self.orbit_exp_num,1]) - y_sat=float(self.orbit_pars[self.orbit_exp_num,2]) - z_sat=float(self.orbit_pars[self.orbit_exp_num,3]) - - wave0, zodi0 = self.zodiacal(ra, dec, self.TianCe_day) # erg/s/cm^2/A/arcsec^2 - + ra = self.information['ra_pnt0'] + dec = self.information['dec_pnt0'] + + time_jd = time2jd(self.dt) + + x_sat = float(self.orbit_pars[self.orbit_exp_num, 1]) + y_sat = float(self.orbit_pars[self.orbit_exp_num, 2]) + z_sat = float(self.orbit_pars[self.orbit_exp_num, 3]) + + wave0, zodi0 = self.zodiacal( + ra, dec, self.TianCe_day) # erg/s/cm^2/A/arcsec^2 + # EarthShine from straylight - sl = StrayLight(self.information['dir_path'],jtime=time_jd, sat=np.array([x_sat, y_sat, z_sat]), + sl = StrayLight(self.information['dir_path'], jtime=time_jd, sat=np.array([x_sat, y_sat, z_sat]), radec=np.array([(ra*u.degree).value, (dec*u.degree).value])) earth_e = sl.caculateEarthShineFilter(filter='r') - star_e = sl.caculateStarLightFilter(filter='r') + star_e = sl.caculateStarLightFilter(filter='r') angle_earth = earth_angle(time_jd, x_sat, y_sat, z_sat, ra, dec) - + if angle_earth < 0: earth_e = 0 - - earthshine_wave0, earthshine_flux0 = ill2flux(self.information['dir_path'],earth_e+star_e) - + + earthshine_wave0, earthshine_flux0 = ill2flux( + self.information['dir_path'], earth_e+star_e) + # sample as ifs wavelength wave_ifs = np.arange(3500, 10000, 1.0) f1 = interp1d(wave0, zodi0) zodi_ifs = f1(wave_ifs) - + f2 = interp1d(earthshine_wave0, earthshine_flux0) earthshine_ifs = f2(wave_ifs) - self.zodiacal_wave = wave_ifs # in A self.zodiacal_flux = zodi_ifs - + self.earthshine_wave = wave_ifs # A self.earthshine_flux = earthshine_ifs - + ############################################################################# - - - self.information['target']=deg2HMS(self.information['ra_obj'], self.information['dec_obj']) - - - ### main input data - SpecCube=a[1].data ## spectrum data cube; - # Cubesize=len(SpecCube[:,0,0]) - # #print('SpecCube data header', hdr) + + self.information['target'] = deg2HMS( + self.information['ra_obj'], self.information['dec_obj']) + + # main input data + SpecCube = a[1].data # spectrum data cube; + # Cubesize=len(SpecCube[:,0,0]) + # #print('SpecCube data header', hdr) # hdr = a[2].header - ### the main input data - Wave=0.1*a[2].data # the relatived wavelength which is converted from Unit A to nm + # the main input data + # the relatived wavelength which is converted from Unit A to nm + Wave = 0.1*a[2].data #print('Wave data header', hdr) - - ###################################################################################### - - exptime=self.information['exptime'] #exposure time - dis_dx=((telRa-skyRa)) # image shift Ra in arcsec - dis_dy=((telDec-skyDec)) # image shift Dec in arcsec - - sizeout= len(SpecCube[:,0,0]) - - blue_img=galsim.Image(np.zeros((2048,4096)),copy=True) - blue_img.scale=self.pixelscale - blue_img.setOrigin=(0,0) - - red_img=galsim.Image(np.zeros((3072,6144)),copy=True) - red_img.scale=self.pixelscale - red_img.setOrigin=(0,0) - - blue_sensor=galsim.Sensor() - - red_sensor=galsim.Sensor() - - deltalam=np.mean(np.diff(Wave)) - - energy=0.0 - - energy_blue=0.0 - energy_red=0.0 - - width_blue=0 + ###################################################################################### + + exptime = self.information['exptime'] # exposure time + + dis_dx = ((telRa-skyRa)) # image shift Ra in arcsec + dis_dy = ((telDec-skyDec)) # image shift Dec in arcsec + + sizeout = len(SpecCube[:, 0, 0]) + + blue_img = galsim.Image(np.zeros((2048, 4096)), copy=True) + blue_img.scale = self.pixelscale + blue_img.setOrigin = (0, 0) + + red_img = galsim.Image(np.zeros((3072, 6144)), copy=True) + red_img.scale = self.pixelscale + red_img.setOrigin = (0, 0) + + blue_sensor = galsim.Sensor() + + red_sensor = galsim.Sensor() + + deltalam = np.mean(np.diff(Wave)) + + energy = 0.0 + + energy_blue = 0.0 + energy_red = 0.0 + + width_blue = 0 ################################ ############## doppler effect to photons.wavelength ############# - - #self.orbit_pars - x_sat=float(self.orbit_pars[self.orbit_exp_num,1]) - y_sat=float(self.orbit_pars[self.orbit_exp_num,2]) - z_sat=float(self.orbit_pars[self.orbit_exp_num,3]) - vx_sat=float(self.orbit_pars[self.orbit_exp_num,4]) - vy_sat=float(self.orbit_pars[self.orbit_exp_num,5]) - vz_sat=float(self.orbit_pars[self.orbit_exp_num,6]) - - self.information['POSI0_X']=x_sat - self.information['POSI0_Y']=y_sat - self.information['POSI0_Z']=z_sat - self.information['VELO0_X']=vx_sat - self.information['VELO0_Y']=vy_sat - self.information['VELO0_Z']=vz_sat - - theta1=beta_angle( x_sat,y_sat,z_sat,vx_sat,vy_sat,vz_sat, self.information['ra_obj'], self.information['dec_obj']) - - v1=np.sqrt(vx_sat**2+vy_sat**2+vz_sat**2)*np.cos(theta1/180.0*np.pi) # velocity at stat exposure time - vv1=LSR_velocity(self.information['ra_obj'],self.information['dec_obj'],v1, self.TianCe_day) - - - ################################################# - ### exposure end time is t2 ; - t2=self.dt+timedelta(seconds=self.information['exptime']) + # self.orbit_pars + x_sat = float(self.orbit_pars[self.orbit_exp_num, 1]) + y_sat = float(self.orbit_pars[self.orbit_exp_num, 2]) + z_sat = float(self.orbit_pars[self.orbit_exp_num, 3]) + vx_sat = float(self.orbit_pars[self.orbit_exp_num, 4]) + vy_sat = float(self.orbit_pars[self.orbit_exp_num, 5]) + vz_sat = float(self.orbit_pars[self.orbit_exp_num, 6]) + + self.information['POSI0_X'] = x_sat + self.information['POSI0_Y'] = y_sat + self.information['POSI0_Z'] = z_sat + self.information['VELO0_X'] = vx_sat + self.information['VELO0_Y'] = vy_sat + self.information['VELO0_Z'] = vz_sat + + theta1 = beta_angle(x_sat, y_sat, z_sat, vx_sat, vy_sat, vz_sat, + self.information['ra_obj'], self.information['dec_obj']) + + v1 = np.sqrt(vx_sat**2+vy_sat**2+vz_sat**2)*np.cos(theta1 / + 180.0*np.pi) # velocity at stat exposure time + vv1 = LSR_velocity( + self.information['ra_obj'], self.information['dec_obj'], v1, self.TianCe_day) + + ################################################# + # exposure end time is t2 ; + t2 = self.dt+timedelta(seconds=self.information['exptime']) ### data read time is the exposure end time plus readouttime ### - ### data read end time is t3 - - t2jd=time2jd(t2) - - if self.orbit_pars[-1,0]=6000: + + ilam = klam*alfa + + if ilam >= 6000: continue - - #print(ilam) - + + # print(ilam) + if self.debug: print(ilam) - - if ilam%100==0: - + + if ilam % 100 == 0: + self.log.info('ilam = %i' % ilam) - self.log.info('blue image max value = %i' % blue_img.array.max()) - self.log.info('red image max value = %i' % red_img.array.max()) - - ##print('ilam=',ilam) - - lam=Wave[ilam] # the wavelength of the i-th frame data - - - - if lam<350: - continue - + self.log.info('blue image max value = %i' % + blue_img.array.max()) + self.log.info('red image max value = %i' % red_img.array.max()) + + # print('ilam=',ilam) + + # the wavelength of the i-th frame data + lam = Wave[ilam] + + if lam < 350: + continue + ############################################### - Specimg=SpecCube[:,:,ilam] # get the i-th frame of the input SpecCube data; - Nspecimg=SpecCube2photon(Specimg,lam) # convert to photons/cm2/s/A - Nskynoise=self.CalskyNoise(lam) - + # get the i-th frame of the input SpecCube data; + Specimg = SpecCube[:, :, ilam] + # convert to photons/cm2/s/A + Nspecimg = SpecCube2photon(Specimg, lam) + Nskynoise = self.CalskyNoise(lam) + if self.sky_noise: - ### add sky noise - Nimg=Nspecimg+Nskynoise - + # add sky noise + Nimg = Nspecimg+Nskynoise + else: - Nimg=Nspecimg+0.0 - - # multipe the tel area, exposure time, and bandwidh; - Nimg=Nimg*self.telarea*exptime*deltalam*10.0 # photons/cm2/s/A to photons, here Nimg size is 100*100 - - if Nimg.max()<0.1: + Nimg = Nspecimg+0.0 + + # multipe the tel area, exposure time, and bandwidh; + # photons/cm2/s/A to photons, here Nimg size is 100*100 + Nimg = Nimg*self.telarea*exptime*deltalam*10.0 + + if Nimg.max() < 0.1: continue - - if Nimg.min()<0: + + if Nimg.min() < 0: self.log.error('Error in datacube, negative values !!!!!!!') continue - + ############################################################################## # if ilam==100: # fits.writeto('/media/yan//IFSsim/IFSsim Data/original_Img.fits', Nimg, overwrite=True) - + ########################################################################## - ### shift image with photons position and rotate them round the image true center - img=galsim.Image(Nimg,copy=True) + # shift image with photons position and rotate them round the image true center + img = galsim.Image(Nimg, copy=True) img.scale = self.pixelscale - img.setOrigin(0,0) - - photons=galsim.PhotonArray.makeFromImage(img, max_flux=max(Nimg.max()/10000.0, 1)) - - ### now shift and rotated photons - self.information['shift_dx']=dis_dx - self.information['shift_dy']=dis_dy - - - photons.x=photons.x-dis_dx ### apply shift to photons position in ra direction - photons.y=photons.y-dis_dy ### apply shift to photons position in dec direction + img.setOrigin(0, 0) + + photons = galsim.PhotonArray.makeFromImage( + img, max_flux=max(Nimg.max()/10000.0, 1)) + + # now shift and rotated photons + self.information['shift_dx'] = dis_dx + self.information['shift_dy'] = dis_dy + + photons.x = photons.x-dis_dx # apply shift to photons position in ra direction + photons.y = photons.y-dis_dy # apply shift to photons position in dec direction # print(dis_dx) - # print(dis_dy) - - x2,y2=rotation_yan(img.true_center.x, img.true_center.y, photons.x/img.scale, photons.y/img.scale, sky_rot) - - #print('rotation time=', t2-t1) - - photons2=galsim.PhotonArray(N=len(x2), x=x2*img.scale, y=y2*img.scale, flux = photons.flux) - photons=photons2 - ## convert the photon image to galsim photons; + # print(dis_dy) + + x2, y2 = rotation_yan(img.true_center.x, img.true_center.y, + photons.x/img.scale, photons.y/img.scale, sky_rot) + + #print('rotation time=', t2-t1) + + photons2 = galsim.PhotonArray( + N=len(x2), x=x2*img.scale, y=y2*img.scale, flux=photons.flux) + photons = photons2 + # convert the photon image to galsim photons; ################################################################### - - image0 = galsim.Image(sizeout,sizeout) + + image0 = galsim.Image(sizeout, sizeout) image0.scale = self.pixelscale - image0.setOrigin(0,0) + image0.setOrigin(0, 0) #image.setCenter(int(np.mean(photons.x)), int(np.mean(photons.y))) - - rotphotons=galsim.PhotonArray(N=len(photons.x), x=x2, y=y2, flux = photons2.flux) - + + rotphotons = galsim.PhotonArray( + N=len(photons.x), x=x2, y=y2, flux=photons2.flux) + sensor = galsim.Sensor() sensor.accumulate(rotphotons, image0) - - + ##################################### - + # ####### - if ilam==1000: - hdu1=fits.PrimaryHDU(image0.array[50-32:50+32,50-32:50+32]) - - hdu1.header['dis_Ra'] =(dis_dx, 'image shift Ra in arcsec') - - hdu1.header['dis_Dec'] =(dis_dy, 'image shift Ra in arcsec') - - hdu1.header['rotAngle'] =(sky_rot,'sky rotation relative to telescope anticlockwise in degree') - - #PSFfilename='/media/yan//IFSsim/IFSsim Data/rot_shift_Img.fits' - + if ilam == 1000: + hdu1 = fits.PrimaryHDU(image0.array[50-32:50+32, 50-32:50+32]) + + hdu1.header['dis_Ra'] = (dis_dx, 'image shift Ra in arcsec') + + hdu1.header['dis_Dec'] = (dis_dy, 'image shift Ra in arcsec') + + hdu1.header['rotAngle'] = ( + sky_rot, 'sky rotation relative to telescope anticlockwise in degree') + + #PSFfilename='/media/yan//IFSsim/IFSsim Data/rot_shift_Img.fits' + #fits.writeto('/media/yan//IFSsim/IFSsim Data/rot_shift_subImg.fits',image0.array[50-32:50+32,50-32:50+32],overwrite=True ) - hdu1.writeto(self.result_path+'/shift_rot_sky/rot_shift_subImg_'+str(simnumber)+'.fits', overwrite=True ) - fits.writeto(self.result_path+'/shift_rot_sky/original_Img_' +str(simnumber)+'.fits', Nimg, overwrite=True) - + hdu1.writeto(self.result_path+'/shift_rot_sky/rot_shift_subImg_' + + str(simnumber)+'.fits', overwrite=True) + fits.writeto(self.result_path+'/shift_rot_sky/original_Img_' + + str(simnumber)+'.fits', Nimg, overwrite=True) + ##################################################################### ### do convolve image0 with PSF0 from primay CSST ### - ### calculate the PSF0 at this wavelength - - Q=lam*1e-3*self.Fnum/self.pixelsize - wavefront0=self.opd0/lam - wavefront=ndimage.rotate(wavefront0, -sky_rot, order=1, reshape=False) # here we choose reshape=False, rotate the wavefront - - psf0=anySampledPSFnew(wavefront, self.pupil , Q , 64) - + # calculate the PSF0 at this wavelength + + Q = lam*1e-3*self.Fnum/self.pixelsize + wavefront0 = self.opd0/lam + # here we choose reshape=False, rotate the wavefront + wavefront = ndimage.rotate( + wavefront0, -sky_rot, order=1, reshape=False) + + psf0 = anySampledPSFnew(wavefront, self.pupil, Q, 64) + + #psf01=anySampledPSFnew(wavefront, self.pupil , Q , 64) + + conv = fftconvolve(image0.array, psf0, mode='same') + conv[conv < 0.0] = 0.0 + img0 = conv + + # opd1 rms =0.075 @632.8nm + wavefront = self.opd1/lam + # here we choose reshape=False, rotate the wavefront + wavefront = ndimage.rotate( + wavefront, -sky_rot, order=1, reshape=False) + psf1 = anySampledPSFnew(wavefront, self.pupil, Q, 32) + # psf1=ndimage.rotate(psf1, -sky_rot, order=1, reshape=False) # here we choose reshape=False, the rotated image will + + # do convolve with psf1 + conv = fftconvolve(img0, psf1, mode='same') + conv[conv < 0.0] = 0.0 + img0 = conv + + ####################################################### + + # energy=energy+img0[50-32:50+32,50-32:50+32].sum() ## calculate the slice image energy; + + # CCD quantum efficiency + CCD_Qe_lam = np.interp(lam, self.CCD_Qe[:, 0], self.CCD_Qe[:, 1]) + + # optical efficiency , convert the wavelength to A + Qe_blue = np.interp( + lam, self.optical_blue_Q[:, 0], self.optical_blue_Q[:, 1]) + + # optical efficiency, convert the wavelength to A + Qe_red = np.interp( + lam, self.optical_red_Q[:, 0], self.optical_red_Q[:, 1]) + + Qe_blue = Qe_blue*CCD_Qe_lam + + Qe_red = Qe_red * CCD_Qe_lam + + lam1 = lam*(1+vv1/(3.0*1e5)) + + lam2 = lam*(1+vv2/(3.0*1e5)) + + img0 = img0*slicer_Qe + ########## do the slice effect ################### + for k in range(32): + + # do slice effect to get slice image + img1 = img0*self.maskSlice[str(k)] + + ############ get opd2 and PSF2 ###################### + wavefront2 = self.opd2/lam + psf2 = anySampledPSFnew(wavefront2, self.pupil, Q, 64) + # here we choose reshape=False, the rotated image will + psf2 = ndimage.rotate(psf2, -sky_rot, order=1, reshape=False) + # do convolve + ################## + conv = fftconvolve(img1, psf2, mode='same') + # suppress negative numbers + conv[conv < 0.0] = 0.0 + img2 = conv + + ##############do Slit Mask ########################### + + img2 = img2*self.maskSlit[str(k)] + + ######### get opd3 and PSF3 ########################## + + wavefront3 = self.opd3/lam + psf3 = anySampledPSFnew(wavefront3, self.pupil, Q, 64) + # here we choose reshape=False, the rotated image will + psf3 = ndimage.rotate(psf3, -sky_rot, order=1, reshape=False) + + # do convolve + ######################################## + conv = fftconvolve(img2, psf3, mode='same') + # suppress negative numbers + conv[conv < 0.0] = 0.0 + + img3 = conv + + #print('covtime =', t2-t1) + + ######################## get subimage ##################### + subimage = galsim.Image(80, 80) + subimage.array[:, :] = img3[int( + sizeout/2)-40:int(sizeout/2)+40, int(sizeout/2)-40:int(sizeout/2)+40] + + # fits.writeto('subimage.fits',subimage.array,overwrite=True) + + ######################## get photons from sub-image ##################### + subimage.scale = self.pixelscale + + subimage.setOrigin(0, 0) + + photons = galsim.PhotonArray.makeFromImage( + subimage, max_flux=max(img3.max()/10000.0, 1)) + + ############################################################################# + # do something for each photons; + ############################################################################## + idx0 = np.where(photons.flux > 1e-3) + # totla energy for slice image + energy = energy+sum(photons.flux[idx0]) + p_num = len(idx0[0]) + + ############################################################################################### + ####################### code for test slice is right or not ################################### + ############################################################################################### + # photons_2=galsim.PhotonArray(N=p_num, x=photons.x[idx0], y=photons.y[idx0], flux = photons.flux[idx0], wavelength=lam) + # if k==0: + # sliceimage = galsim.Image(100,100) + # sliceimage.scale = pixelscale + # sliceimage.setOrigin(0,0) + # #image.setCenter(int(np.mean(photons.x)), int(np.mean(photons.y))) + + # rotphotons=galsim.PhotonArray(N=p_num, x=photons_2.x/pixelscale, y=photons_2.y/pixelscale, flux = photons_2.flux) + + # sensor = galsim.Sensor() + # sensor.accumulate(rotphotons, sliceimage) + ######################### finish testing ####################################################### + ####################################################################################################### + ##################################### + # find photons for blue channel, and make the flux multiple the optical and CCD efficiency + + np.random.seed(100*self.simnumber) + wavesample = lam1+(lam2-lam1)*np.random.rand(p_num) + + if (lam >= 350.0 and lam <= 650.0): + # bulue channel + photons_blue = galsim.PhotonArray( + N=p_num, x=photons.x[idx0], y=photons.y[idx0], flux=Qe_blue*photons.flux[idx0], wavelength=wavesample) + + dx_blue, dy_blue = get_dx_dy_blue(wavesample) + + photons_blue.x = photons_blue.x/self.pixelscale + \ + dx_blue+self.slice_blue['px'][k] + + photons_blue.y = photons_blue.y/self.pixelscale + \ + dy_blue+self.slice_blue['py'][k] + + blue_sensor.accumulate(photons_blue, blue_img) + + energy_blue = energy_blue+sum(photons_blue.flux) + + width_blue = width_blue+deltalam/32.0 + + ################# + + # fits.writeto('blueImg.fits',blue_img.array,overwrite=True) + + if (lam >= 560.0) & (lam <= 1000.0): + # red channel + photons_red = galsim.PhotonArray( + N=p_num, x=photons.x[idx0], y=photons.y[idx0], flux=Qe_red*photons.flux[idx0], wavelength=wavesample) + + dx_red, dy_red = get_dx_dy_red(wavesample) + + photons_red.x = photons_red.x/self.pixelscale + \ + dx_red+self.slice_red['px'][k] + + photons_red.y = photons_red.y/self.pixelscale + \ + dy_red+self.slice_red['py'][k] + + red_sensor.accumulate(photons_red, red_img) + + energy_red = energy_red+sum(photons_red.flux) + + ######################################################## + + ########################### test code ################################ + ###################################################################### + # fits.writeto('originalImg.fits',Nimg,overwrite=True) + # fits.writeto('PSFedImg.fits',temp,overwrite=True) + # fits.writeto('rotedphotonsImg.fits',image.array,overwrite=True) + # fits.writeto('newsub_rotedphotonsImg.fits',newimage.array,overwrite=True) + # fits.writeto('slicephotonsImg.fits',sliceimage.array,overwrite=True) + + # pause() + ###################################################################### + ###################### finish test code ########################### + + #################################################################################### + # stray light will cover 2% of input total light; + if self.sky_noise: + + blue_img.array[:, :] = 0.99 * \ + blue_img.array[:, :]+0.01*energy/2048/4096 + + red_img.array[:, :] = 0.99 * \ + red_img.array[:, :] + 0.01*energy/3072/6144 + + self.image_b = blue_img.array + self.image_r = red_img.array + + obsid = simnumber + bluefile = self.result_path+'/original_sky/IFS_' + \ + self.source+'_'+str(obsid)+'_B.fits' + redfile = self.result_path+'/original_sky/IFS_' + \ + self.source+'_'+str(obsid)+'_R.fits' + + fits.writeto(bluefile, blue_img.array, overwrite=True) + fits.writeto(redfile, red_img.array, overwrite=True) + + return + +################################################################################################# + def sim_calibration_img(self, exposuretime, source): + + sizeout = 100 + ################# load the hole mask file ################### + + # load HgAr data; + if self.source == 'LAMP': + matfn3 = self.information['dir_path']+'IFS_inputdata/HgAr.mat' + self.log.info('lamp flux file is : %s' % (matfn3)) + da3 = sio.loadmat(matfn3) + HgArst = da3['HgArst'] # opd unit is in meter + # load flat data + if self.source == 'FLAT': + matfn3 = self.information['dir_path'] + \ + 'IFS_inputdata/flat_light.mat' + self.log.info('flat flux file is : %s' % (matfn3)) + da3 = sio.loadmat(matfn3) + flat_light = da3['flat_light'] # opd unit is in meter + + exptime = self.information['exptime'] # exposure time + + blue_img = galsim.Image(np.zeros((2048, 4096)), copy=True) + blue_img.scale = self.pixelscale + # blue_img.setOrigin=(0,0) + + red_img = galsim.Image(np.zeros((3072, 6144)), copy=True) + red_img.scale = self.pixelscale + # red_img.setOrigin=(0,0) + + blue_sensor = galsim.Sensor() + + red_sensor = galsim.Sensor() + + slice_image = np.zeros((sizeout, sizeout)) + + LightSt = np.zeros(6000) + flux_1 = np.zeros(6000) + Width_lambda = (1000-350)/6000 + Wave = np.zeros(6000) + + # code for slicer position #########33 + #### + + if self.debug: + + alfa = 1000 + else: + + alfa = 1 + + for klam in range(6000): + + ilam = klam*alfa + + if self.debug: + print(ilam) + + # ilam=ilam*200 + if ilam % 100 == 0: + self.log.info('ilam = %i' % ilam) + self.log.info('blue image max value = %i' % + blue_img.array.max()) + self.log.info('red image max value = %i' % red_img.array.max()) + + if ilam >= 6000: + continue + + # the wavelength of the i-th frame data + lam = 350.0+(1000-350)/6000.0 * ilam + + Wave[ilam] = lam + + # tab['wavelength'][ilam]=lam + #print('i = ',ilam ) + ############################################### + if self.source == 'LAMP': + + sumt = 0.0 + + for k in range(11): + t = getSpectrum(HgArst, lam+(k-5) * + Width_lambda/11, self.HgArsigma) + sumt = sumt+t[0]/11 + #print('t=', t) + + # the normalized HgAr light source in the range of 0 and 1.0 + LightSt[ilam] = sumt + + skymag = 9 # mag/arcsec^2 unit + + if ilam == 0: + # fluxnu1,fluxlam1,fluxphoton1=mag2flux(skymag,633) + fluxlam1, fluxphoton1 = mag2flux(skymag, 633) + + # save flux information + flux_1[ilam] = LightSt[ilam] * \ + fluxlam1*self.fov2 # erg/s/cm2/A + + nphoton = flux2photons(flux_1[ilam], lam) + + # photons/cm2/s/A/arcsec2 + ns = nphoton*np.ones((sizeout, sizeout)) + + slice_image = ns*self.telarea*Width_lambda*10*exptime + +# #####################3 transfer: photons/cm2/s/A/arcsec2 to photons + if self.source == 'FLAT': + ########## + flatS = np.interp(lam, flat_light[:, 0], flat_light[:, 1]) + + # the normalized HgAr light source in the range of 0 and 1.0 + LightSt[ilam] = flatS + + skymag = 9 # mag/arcsec^2 unit + + if ilam == 0: + fluxlam1, fluxphoton1 = mag2flux(skymag, 633) + + # save flux information + flux_1[ilam] = LightSt[ilam] * \ + fluxlam1*self.fov2 # erg/s/cm2/A + + nphoton = flux2photons(flux_1[ilam], lam) + + # photons/cm2/s/A/arcsec2 + ns = nphoton*np.ones((sizeout, sizeout)) + + slice_image = ns*self.telarea*Width_lambda*10*exptime + +################################################################################################## + + if slice_image.max() < 0.1: + continue + + if slice_image.min() < 0: + self.log.error('Error in datacube, negative values !!!!!!!') + continue +################################################################################################## + + # for calibration , there is no primay CSST system, but diffraction effect should consider ; + + Q = lam*1e-3*self.Fnum/self.pixelsize + + wavefront0 = self.opd0/lam/100000.0 + + psf0 = anySampledPSFnew(wavefront0, self.pupil, Q, 64) + #psf01=anySampledPSFnew(wavefront, self.pupil , Q , 64) - - conv = fftconvolve(image0.array, psf0, mode='same') - conv[conv < 0.0] = 0.0 - img0=conv - - ################ opd1 rms =0.075 @632.8nm - wavefront=self.opd1/lam - wavefront=ndimage.rotate(wavefront, -sky_rot, order=1, reshape=False) # here we choose reshape=False, rotate the wavefront - psf1=anySampledPSFnew(wavefront, self.pupil , Q , 32) - #psf1=ndimage.rotate(psf1, -sky_rot, order=1, reshape=False) # here we choose reshape=False, the rotated image will - - - ##### do convolve with psf1 - conv = fftconvolve(img0, psf1, mode='same') - conv[conv < 0.0] = 0.0 - img0=conv - + + conv = fftconvolve(slice_image, psf0, mode='same') + + conv[conv < 0.0] = 0.0 + + slice_image2 = conv + + img0 = slice_image2 + + ########################################## + # opd1 rms =0.075 @632.8nm + wavefront = self.opd1/lam + + psf1 = anySampledPSFnew(wavefront, self.pupil, Q, 64) + + # do convolve with psf1 + conv = fftconvolve(img0, psf1, mode='same') + conv[conv < 0.0] = 0.0 + img0 = conv + + # temp=img0*maskSlice['31']*maskSlit['31'] + # print(image0.array.sum()) + # print(img1.sum()) + # fits.writeto('img.fits',image0.array,overwrite=True) + # fits.writeto('convimg.fits',img0,overwrite=True) + + ####### + ####################################################### - - #energy=energy+img0[50-32:50+32,50-32:50+32].sum() ## calculate the slice image energy; - - CCD_Qe_lam=np.interp(lam,self.CCD_Qe[:,0], self.CCD_Qe[:,1]) ## CCD quantum efficiency - - Qe_blue = np.interp(lam, self.optical_blue_Q[:,0], self.optical_blue_Q[:,1]) # optical efficiency , convert the wavelength to A - - Qe_red = np.interp(lam, self.optical_red_Q[:,0], self.optical_red_Q[:,1]) # optical efficiency, convert the wavelength to A - - Qe_blue=Qe_blue*CCD_Qe_lam - - Qe_red =Qe_red *CCD_Qe_lam - - lam1=lam*(1+vv1/(3.0*1e5)) - - lam2=lam*(1+vv2/(3.0*1e5)) - - - img0=img0*slicer_Qe + + # energy=energy+img0[50-32:50+32,50-32:50+32].sum() ## calculate the slice image energy; + + # CCD quantum efficiency + CCD_Qe_lam = np.interp(lam, self.CCD_Qe[:, 0], self.CCD_Qe[:, 1]) + + # optical efficiency , convert the wavelength to A + Qe_blue = np.interp( + lam, self.optical_blue_Q[:, 0], self.optical_blue_Q[:, 1]) + + # optical efficiency, convert the wavelength to A + Qe_red = np.interp( + lam, self.optical_red_Q[:, 0], self.optical_red_Q[:, 1]) + + Qe_blue = Qe_blue*CCD_Qe_lam + Qe_red = Qe_red * CCD_Qe_lam + + # print('time=',(end-start)) + # consider the slice optical efficiency in different slicer channel + da = fits.open( + self.information['dir_path']+'IFS_inputdata/Flatfield/slicer_QE230625.fits') + slicer_Qe = da[0].data + img0 = img0*slicer_Qe ########## do the slice effect ################### - for k in range(32): - - - #### do slice effect to get slice image - img1=img0*self.maskSlice[str(k)] - - ############ get opd2 and PSF2 ###################### - wavefront2=self.opd2/lam - psf2=anySampledPSFnew(wavefront2, self.pupil , Q , 64) - psf2=ndimage.rotate(psf2, -sky_rot, order=1, reshape=False) # here we choose reshape=False, the rotated image will - ##### do convolve - ################## - conv = fftconvolve(img1, psf2, mode='same') - #suppress negative numbers - conv[conv < 0.0] = 0.0 - img2=conv - + for k in range(32): + + # do slice effect to get slice image + img1 = img0*self.maskSlice[str(k)] + + ############ get opd2 and PSF2 ###################### + wavefront2 = self.opd2/lam + psf2 = anySampledPSFnew(wavefront2, self.pupil, Q, 64) + # do convolve + ################## + conv = fftconvolve(img1, psf2, mode='same') + # suppress negative numbers + conv[conv < 0.0] = 0.0 + img2 = conv + ##############do Slit Mask ########################### - - img2=img2*self.maskSlit[str(k)] - - ######### get opd3 and PSF3 ########################## - - wavefront3=self.opd3/lam - psf3=anySampledPSFnew(wavefront3, self.pupil , Q , 64) - psf3=ndimage.rotate(psf3, -sky_rot, order=1, reshape=False) # here we choose reshape=False, the rotated image will - - ##### do convolve + + img2 = img2*self.maskSlit[str(k)] + + ######### get opd3 and PSF3 ########################## + + wavefront3 = self.opd3/lam + psf3 = anySampledPSFnew(wavefront3, self.pupil, Q, 64) + + # do convolve ######################################## - conv = fftconvolve(img2, psf3, mode='same') - #suppress negative numbers - conv[conv < 0.0] = 0.0 - - img3=conv - - #print('covtime =', t2-t1) - - ######################## get subimage ##################### - subimage = galsim.Image(80,80) - subimage.array[:,:]=img3[int(sizeout/2)-40:int(sizeout/2)+40,int(sizeout/2)-40:int(sizeout/2)+40] - - #fits.writeto('subimage.fits',subimage.array,overwrite=True) - + conv = fftconvolve(img2, psf3, mode='same') + # suppress negative numbers + conv[conv < 0.0] = 0.0 + + img3 = conv + + ######################## get subimage ##################### + subimage = galsim.Image(80, 80) + subimage.array[:, :] = img3[int( + sizeout/2)-40:int(sizeout/2)+40, int(sizeout/2)-40:int(sizeout/2)+40] + + # fits.writeto('subimage.fits',subimage.array,overwrite=True) + ######################## get photons from sub-image ##################### subimage.scale = self.pixelscale - - subimage.setOrigin(0,0) - - photons=galsim.PhotonArray.makeFromImage(subimage, max_flux=max(img3.max()/10000.0, 1)) - + + subimage.setOrigin(0, 0) + + photons = galsim.PhotonArray.makeFromImage( + subimage, max_flux=max(img3.max()/10000.0, 1)) + ############################################################################# - ###### do something for each photons; + # do something for each photons; ############################################################################## - idx0=np.where( photons.flux>1e-3) - energy=energy+sum(photons.flux[idx0]) ### totla energy for slice image - p_num=len(idx0[0]) - - ############################################################################################### + idx0 = np.where(photons.flux > 1e-2) + # energy=energy+sum(photons.flux[idx0]) ### totla energy for slice image + p_num = len(idx0[0]) + + ############################################################################################### ####################### code for test slice is right or not ################################### - ############################################################################################### - # photons_2=galsim.PhotonArray(N=p_num, x=photons.x[idx0], y=photons.y[idx0], flux = photons.flux[idx0], wavelength=lam) + ############################################################################################### + # photons_2=galsim.PhotonArray(N=p_num, x=photons.x[idx0], y=photons.y[idx0], flux = photons.flux[idx0], wavelength=lam) # if k==0: # sliceimage = galsim.Image(100,100) # sliceimage.scale = pixelscale # sliceimage.setOrigin(0,0) # #image.setCenter(int(np.mean(photons.x)), int(np.mean(photons.y))) - - # rotphotons=galsim.PhotonArray(N=p_num, x=photons_2.x/pixelscale, y=photons_2.y/pixelscale, flux = photons_2.flux) - + + # rotphotons=galsim.PhotonArray(N=p_num, x=photons_2.x/pixelscale, y=photons_2.y/pixelscale, flux = photons_2.flux) + # sensor = galsim.Sensor() # sensor.accumulate(rotphotons, sliceimage) - ######################### finish testing ####################################################### - ####################################################################################################### + # ######################## finish testing ####################################################### + # ###################################################################################################### + ##################################### - ############### find photons for blue channel, and make the flux multiple the optical and CCD efficiency - - np.random.seed(100*self.simnumber) - wavesample=lam1+(lam2-lam1)*np.random.rand(p_num) - - if (lam>=350.0 and lam<=650.0): - ## bulue channel - photons_blue=galsim.PhotonArray(N=p_num, x=photons.x[idx0], y=photons.y[idx0], flux = Qe_blue*photons.flux[idx0],wavelength=wavesample) - - dx_blue, dy_blue = get_dx_dy_blue(wavesample) - - photons_blue.x=photons_blue.x/self.pixelscale+dx_blue+self.slice_blue['px'][k] - - photons_blue.y=photons_blue.y/self.pixelscale+dy_blue+self.slice_blue['py'][k] - + # find photons for blue channel, and make the flux multiple the optical and CCD efficiency + + if (lam >= 350.0 and lam <= 650.0): + # bulue channel + photons_blue = galsim.PhotonArray( + N=p_num, x=photons.x[idx0], y=photons.y[idx0], flux=Qe_blue*photons.flux[idx0], wavelength=lam) + + dx_blue, dy_blue = get_dx_dy_blue(lam) + + photons_blue.x = photons_blue.x/self.pixelscale + \ + dx_blue+self.slice_blue['px'][k] + + photons_blue.y = photons_blue.y/self.pixelscale + \ + dy_blue+self.slice_blue['py'][k] + blue_sensor.accumulate(photons_blue, blue_img) - - energy_blue=energy_blue+sum(photons_blue.flux) - - width_blue=width_blue+deltalam/32.0 - - ################# - #fits.writeto('blueImg.fits',blue_img.array,overwrite=True) - - if (lam>=560.0) & (lam<=1000.0 ): - ## red channel - photons_red=galsim.PhotonArray(N=p_num,x=photons.x[idx0],y=photons.y[idx0], flux = Qe_red*photons.flux[idx0],wavelength=wavesample) - - dx_red, dy_red = get_dx_dy_red(wavesample) - - photons_red.x=photons_red.x/self.pixelscale+dx_red+self.slice_red['px'][k] - - photons_red.y=photons_red.y/self.pixelscale+dy_red+self.slice_red['py'][k] - + # energy_blue=energy_blue+sum(photons_blue.flux) + + # width_blue=width_blue+Width_lambda/32.0 + + # fits.writeto('blueImg.fits',blue_img.array,overwrite=True) + + if (lam >= 560.0) & (lam <= 1000.0): + # red channel + photons_red = galsim.PhotonArray( + N=p_num, x=photons.x[idx0], y=photons.y[idx0], flux=Qe_red*photons.flux[idx0], wavelength=lam) + + dx_red, dy_red = get_dx_dy_red(lam) + + photons_red.x = photons_red.x/self.pixelscale + \ + dx_red+self.slice_red['px'][k] + + photons_red.y = photons_red.y/self.pixelscale + \ + dy_red+self.slice_red['py'][k] + red_sensor.accumulate(photons_red, red_img) - - energy_red=energy_red+sum(photons_red.flux) - - ######################################################## - - ########################### test code ################################ - ###################################################################### - # fits.writeto('originalImg.fits',Nimg,overwrite=True) - # fits.writeto('PSFedImg.fits',temp,overwrite=True) - # fits.writeto('rotedphotonsImg.fits',image.array,overwrite=True) - # fits.writeto('newsub_rotedphotonsImg.fits',newimage.array,overwrite=True) - # fits.writeto('slicephotonsImg.fits',sliceimage.array,overwrite=True) - - # pause() - ###################################################################### - ###################### finish test code ########################### - + # energy_red=energy_red+sum(photons_red.flux) + #################################################################################### - ## stray light will cover 2% of input total light; - if self.sky_noise: - - blue_img.array[:,:]=0.99*blue_img.array[:,:]+0.01*energy/2048/4096 - - red_img.array[:,:] =0.99*red_img.array[:,:]+ 0.01*energy/3072/6144 - - - - self.image_b=blue_img.array - self.image_r=red_img.array - - obsid=simnumber - bluefile=self.result_path+'/original_sky/IFS_'+self.source+'_'+str(obsid)+'_B.fits' - redfile =self.result_path+'/original_sky/IFS_'+self.source+'_'+str(obsid)+'_R.fits' - - fits.writeto(bluefile, blue_img.array, overwrite=True) + self.image_b = blue_img.array + self.image_r = red_img.array + + now = datetime.utcnow() + + data_time = now.strftime("%Y-%m-%d") + # write the actual file + + bluefile = self.result_path+'/original_Calibration/IFS_'+self.source + \ + '_'+data_time+'_'+str(self.simnumber)+'_B_original.fits' + redfile = self.result_path+'/original_Calibration/IFS_'+self.source + \ + '_'+data_time+'_'+str(self.simnumber)+'_R_original.fits' + + fits.writeto(bluefile, blue_img.array, overwrite=True) fits.writeto(redfile, red_img.array, overwrite=True) - - return - -################################################################################################# - def sim_calibration_img(self, exposuretime, source): - - - sizeout=100 - ################# load the hole mask file ################### - - ############### load HgAr data; - if self.source=='LAMP': - matfn3=self.information['dir_path']+'IFS_inputdata/HgAr.mat' - self.log.info('lamp flux file is : %s'%(matfn3)) - da3=sio.loadmat(matfn3) - HgArst=da3['HgArst'] # opd unit is in meter - ############################### load flat data - if self.source=='FLAT': - matfn3=self.information['dir_path']+'IFS_inputdata/flat_light.mat' - self.log.info('flat flux file is : %s'%(matfn3)) - da3=sio.loadmat(matfn3) - flat_light=da3['flat_light'] # opd unit is in meter - - exptime=self.information['exptime'] #exposure time - - blue_img=galsim.Image(np.zeros((2048,4096)),copy=True) - blue_img.scale=self.pixelscale - #blue_img.setOrigin=(0,0) - - red_img=galsim.Image(np.zeros((3072,6144)),copy=True) - red_img.scale=self.pixelscale - #red_img.setOrigin=(0,0) - - blue_sensor=galsim.Sensor() - - red_sensor=galsim.Sensor() - - slice_image=np.zeros((sizeout,sizeout)) - - - LightSt=np.zeros(6000) - flux_1=np.zeros(6000) - Width_lambda=(1000-350)/6000 - Wave=np.zeros(6000) - - - - ##################code for slicer position #########33 - #### - if self.debug: - - alfa=1000 - else: - - alfa=1 - - for klam in range(6000): - - ilam=klam*alfa - - - if self.debug: - print(ilam) - - #ilam=ilam*200 - if ilam%100==0: - self.log.info('ilam = %i' % ilam) - self.log.info('blue image max value = %i' % blue_img.array.max()) - self.log.info('red image max value = %i' % red_img.array.max()) - - if ilam>=6000: - continue - - lam=350.0+(1000-350)/6000.0 *ilam # the wavelength of the i-th frame data - - Wave[ilam]=lam - - - #tab['wavelength'][ilam]=lam - #print('i = ',ilam ) - ############################################### - if self.source=='LAMP': - - sumt=0.0 - - for k in range(11): - t=getSpectrum(HgArst,lam+(k-5)*Width_lambda/11, self.HgArsigma) - sumt=sumt+t[0]/11 - #print('t=', t) - - LightSt[ilam]=sumt ## the normalized HgAr light source in the range of 0 and 1.0 - - skymag=9 # mag/arcsec^2 unit - - if ilam==0: - ##fluxnu1,fluxlam1,fluxphoton1=mag2flux(skymag,633) - fluxlam1,fluxphoton1=mag2flux(skymag,633) - - ### save flux information - flux_1[ilam]=LightSt[ilam]*fluxlam1*self.fov2 # erg/s/cm2/A - - nphoton=flux2photons(flux_1[ilam], lam) - - ns=nphoton*np.ones((sizeout,sizeout)) ### photons/cm2/s/A/arcsec2 - - slice_image=ns*self.telarea*Width_lambda*10*exptime - -# #####################3 transfer: photons/cm2/s/A/arcsec2 to photons - if self.source=='FLAT': - ########## - flatS=np.interp(lam,flat_light[:,0],flat_light[:,1]) - - LightSt[ilam]=flatS ## the normalized HgAr light source in the range of 0 and 1.0 - - skymag=9 # mag/arcsec^2 unit - - if ilam==0: - fluxlam1,fluxphoton1=mag2flux(skymag,633) - - ### save flux information - flux_1[ilam]=LightSt[ilam]*fluxlam1*self.fov2 # erg/s/cm2/A - - nphoton=flux2photons(flux_1[ilam], lam) - - ns=nphoton*np.ones((sizeout,sizeout)) ### photons/cm2/s/A/arcsec2 - - slice_image=ns*self.telarea*Width_lambda*10*exptime - -################################################################################################## + #### save flux #### + Flux = flux_1 + hdu1 = fits.PrimaryHDU(Flux) - - if slice_image.max()<0.1: - continue - - if slice_image.min()<0: - self.log.error('Error in datacube, negative values !!!!!!!') - continue -################################################################################################## - - - ### for calibration , there is no primay CSST system, but diffraction effect should consider ; - - Q=lam*1e-3*self.Fnum/self.pixelsize - - wavefront0=self.opd0/lam/100000.0 - - psf0=anySampledPSFnew(wavefront0, self.pupil , Q , 64) - - #psf01=anySampledPSFnew(wavefront, self.pupil , Q , 64) - - conv = fftconvolve(slice_image, psf0, mode='same') - - conv[conv < 0.0] = 0.0 - - slice_image2=conv - - img0=slice_image2 - - ########################################## - ################ opd1 rms =0.075 @632.8nm - wavefront=self.opd1/lam - - psf1=anySampledPSFnew(wavefront, self.pupil , Q , 64) - - ##### do convolve with psf1 - conv = fftconvolve(img0, psf1, mode='same') - conv[conv < 0.0] = 0.0 - img0=conv - - #temp=img0*maskSlice['31']*maskSlit['31'] - # print(image0.array.sum()) - # print(img1.sum()) - # fits.writeto('img.fits',image0.array,overwrite=True) - # fits.writeto('convimg.fits',img0,overwrite=True) - - ####### + dtime = datetime.utcnow().strftime('%Y -%m -%d %H: %M: %S') + hdu1.header.add_history('Flux data is generated on :'+dtime) + hdu1.header['FluxUnit'] = ('erg/s/cm2/A', 'erg/s/cm2/A') - - ####################################################### - - #energy=energy+img0[50-32:50+32,50-32:50+32].sum() ## calculate the slice image energy; - - CCD_Qe_lam=np.interp(lam,self.CCD_Qe[:,0],self.CCD_Qe[:,1]) ## CCD quantum efficiency - - Qe_blue = np.interp(lam, self.optical_blue_Q[:,0], self.optical_blue_Q[:,1]) # optical efficiency , convert the wavelength to A - - Qe_red = np.interp(lam, self.optical_red_Q[:,0], self.optical_red_Q[:,1]) # optical efficiency, convert the wavelength to A - - Qe_blue=Qe_blue*CCD_Qe_lam - Qe_red =Qe_red *CCD_Qe_lam - - #print('time=',(end-start)) - ######## consider the slice optical efficiency in different slicer channel - da=fits.open(self.information['dir_path']+'IFS_inputdata/Flatfield/slicer_QE230625.fits') - slicer_Qe=da[0].data - img0=img0*slicer_Qe - ########## do the slice effect ################### - for k in range(32): - - #### do slice effect to get slice image - img1=img0*self.maskSlice[str(k)] - - ############ get opd2 and PSF2 ###################### - wavefront2=self.opd2/lam - psf2=anySampledPSFnew(wavefront2, self.pupil , Q , 64) - ##### do convolve - ################## - conv = fftconvolve(img1, psf2, mode='same') - #suppress negative numbers - conv[conv < 0.0] = 0.0 - img2=conv - - ##############do Slit Mask ########################### - - img2=img2*self.maskSlit[str(k)] - - ######### get opd3 and PSF3 ########################## - - wavefront3=self.opd3/lam - psf3=anySampledPSFnew(wavefront3, self.pupil , Q , 64) - - ##### do convolve - ######################################## - conv = fftconvolve(img2, psf3, mode='same') - #suppress negative numbers - conv[conv < 0.0] = 0.0 - - img3=conv - - ######################## get subimage ##################### - subimage = galsim.Image(80,80) - subimage.array[:,:]=img3[int(sizeout/2)-40:int(sizeout/2)+40,int(sizeout/2)-40:int(sizeout/2)+40] - - #fits.writeto('subimage.fits',subimage.array,overwrite=True) - - ######################## get photons from sub-image ##################### - subimage.scale = self.pixelscale - - subimage.setOrigin(0,0) - - photons=galsim.PhotonArray.makeFromImage(subimage, max_flux=max(img3.max()/10000.0, 1) ) - - ############################################################################# - ###### do something for each photons; - ############################################################################## - idx0=np.where( photons.flux>1e-2) - #energy=energy+sum(photons.flux[idx0]) ### totla energy for slice image - p_num=len(idx0[0]) - - ############################################################################################### - ####################### code for test slice is right or not ################################### - ############################################################################################### - # photons_2=galsim.PhotonArray(N=p_num, x=photons.x[idx0], y=photons.y[idx0], flux = photons.flux[idx0], wavelength=lam) - # if k==0: - # sliceimage = galsim.Image(100,100) - # sliceimage.scale = pixelscale - # sliceimage.setOrigin(0,0) - # #image.setCenter(int(np.mean(photons.x)), int(np.mean(photons.y))) - - # rotphotons=galsim.PhotonArray(N=p_num, x=photons_2.x/pixelscale, y=photons_2.y/pixelscale, flux = photons_2.flux) - - # sensor = galsim.Sensor() - # sensor.accumulate(rotphotons, sliceimage) - # ######################## finish testing ####################################################### - # ###################################################################################################### - - ##################################### - ############### find photons for blue channel, and make the flux multiple the optical and CCD efficiency - - if (lam>=350.0 and lam<=650.0): - ## bulue channel - photons_blue=galsim.PhotonArray(N=p_num, x=photons.x[idx0], y=photons.y[idx0], flux = Qe_blue*photons.flux[idx0],wavelength=lam) - - dx_blue, dy_blue = get_dx_dy_blue(lam) - - photons_blue.x=photons_blue.x/self.pixelscale+dx_blue+self.slice_blue['px'][k] - - photons_blue.y=photons_blue.y/self.pixelscale+dy_blue+self.slice_blue['py'][k] - - blue_sensor.accumulate(photons_blue, blue_img) - - #energy_blue=energy_blue+sum(photons_blue.flux) - - #width_blue=width_blue+Width_lambda/32.0 - - #fits.writeto('blueImg.fits',blue_img.array,overwrite=True) - - - - if (lam>=560.0) & (lam<=1000.0 ): - ## red channel - photons_red=galsim.PhotonArray(N=p_num,x=photons.x[idx0],y=photons.y[idx0], flux = Qe_red*photons.flux[idx0],wavelength=lam) - - dx_red, dy_red = get_dx_dy_red(lam) - - photons_red.x=photons_red.x/self.pixelscale+dx_red+self.slice_red['px'][k] - - photons_red.y=photons_red.y/self.pixelscale+dy_red+self.slice_red['py'][k] - - red_sensor.accumulate(photons_red, red_img) - - #energy_red=energy_red+sum(photons_red.flux) - - #################################################################################### - - self.image_b=blue_img.array - self.image_r=red_img.array - - now=datetime.utcnow() - - data_time=now.strftime("%Y-%m-%d") - #write the actual file - - bluefile=self.result_path+'/original_Calibration/IFS_'+self.source+'_'+data_time+'_'+str(self.simnumber)+'_B_original.fits' - redfile =self.result_path+'/original_Calibration/IFS_'+self.source+'_'+data_time+'_'+str(self.simnumber)+'_R_original.fits' - - fits.writeto(bluefile, blue_img.array, overwrite=True) - fits.writeto(redfile, red_img.array, overwrite=True) - - #### save flux #### - Flux=flux_1 - - hdu1=fits.PrimaryHDU(Flux) - - dtime=datetime.utcnow().strftime('%Y -%m -%d %H: %M: %S') - hdu1.header.add_history('Flux data is generated on :'+dtime) - hdu1.header['FluxUnit']=('erg/s/cm2/A','erg/s/cm2/A') - - hdu2=fits.ImageHDU(Wave) - - hdu2.header.append(('WaveUnit', 'nm')) - - newd=fits.HDUList([hdu1,hdu2]) - - filename=self.result_path+'/calibration_Data/'+self.source+'_flux.fits' - - if self.simnumber ==1: - newd.writeto(filename,overwrite=True) - - - return - - ########################################################################## + hdu2 = fits.ImageHDU(Wave) + + hdu2.header.append(('WaveUnit', 'nm')) + + newd = fits.HDUList([hdu1, hdu2]) + + filename = self.result_path+'/calibration_Data/'+self.source+'_flux.fits' + + if self.simnumber == 1: + newd.writeto(filename, overwrite=True) + + return + + ########################################################################## # def saveCCDfullimage(self): - - # # - # bluefile=self.result_path+'/original_sky/IFS_CCD_'+self.source+'_'+str(self.simnumber)+'_B.fits' - # redfile =self.result_path+'/original_sky/IFS_CCD_'+self.source+'_'+str(self.simnumber)+'_R.fits' - - # fits.writeto(bluefile, self.image_b, overwrite=True) - # fits.writeto(redfile, self.image_r, overwrite=True) -################################################################################################# - - def simulate(self,sourcein,simnumber): - #def simulate(self, skyfitsfilename, skyRa, skyDec, sky_rot, telRa, telDec, exposuretime,simnumber): + + # # + # bluefile=self.result_path+'/original_sky/IFS_CCD_'+self.source+'_'+str(self.simnumber)+'_B.fits' + # redfile =self.result_path+'/original_sky/IFS_CCD_'+self.source+'_'+str(self.simnumber)+'_R.fits' + + # fits.writeto(bluefile, self.image_b, overwrite=True) + # fits.writeto(redfile, self.image_r, overwrite=True) +################################################################################################# + + def simulate(self, sourcein, simnumber): + # def simulate(self, skyfitsfilename, skyRa, skyDec, sky_rot, telRa, telDec, exposuretime,simnumber): """ Create a single simulated image of a quadrant defined by the configuration file. Will do all steps defined in the config file sequentially. @@ -4417,390 +4748,360 @@ class IFSsimulator(): :return: None """ - - self.debug=True - - self.source=sourcein - - self.simnumber=simnumber - self.configure(simnumber) #print the configfile name and path; - - self.dt=datetime.utcnow() - - if self.source =='SCI' or self.source =='COMP': - - if simnumber<=50: - self.information['exptime']=300 - - if simnumber<=100 and simnumber>50: - self.information['exptime']=600 - - if simnumber<=150 and simnumber>100: - self.information['exptime']=900 - - if simnumber<=200 and simnumber>150: - self.information['exptime']=1200 - - - self.skyfilepath=self.information['skyfilepath'] + self.debug = True + + self.source = sourcein + + self.simnumber = simnumber + self.configure(simnumber) # print the configfile name and path; + + self.dt = datetime.utcnow() + + if self.source == 'SCI' or self.source == 'COMP': + + if simnumber <= 50: + self.information['exptime'] = 300 + + if simnumber <= 100 and simnumber > 50: + self.information['exptime'] = 600 + + if simnumber <= 150 and simnumber > 100: + self.information['exptime'] = 900 + + if simnumber <= 200 and simnumber > 150: + self.information['exptime'] = 1200 + + self.skyfilepath = self.information['skyfilepath'] print(self.skyfilepath) - - #self.earthshine_theta=30.0 # in degree - + + # self.earthshine_theta=30.0 # in degree + ################################################################## #### load orbit parameters ##### - flag=0 - - self.dt_num=int(self.simnumber*(self.information['exptime']+self.information['readouttime']+125)/120) - now_dt=datetime.utcnow() - now_jd=time2jd(now_dt) - - - for k in range(1,50,1): - - ##fn=father_path+'/IFS_inputdata/TianCe/orbit20160925/'+str(k)+'.txt'; - - fn=self.information['dir_path']+'IFS_inputdata/TianCe/orbit20160925/'+str(k)+'.txt'; - d=np.loadtxt(fn); - - for kk in range(len(d[:,0])): - if now_jd-d[kk,0]<=0: - flag=1 + flag = 0 + + self.dt_num = int( + self.simnumber*(self.information['exptime']+self.information['readouttime']+125)/120) + now_dt = datetime.utcnow() + now_jd = time2jd(now_dt) + + for k in range(1, 50, 1): + + # fn=father_path+'/IFS_inputdata/TianCe/orbit20160925/'+str(k)+'.txt'; + + fn = self.information['dir_path'] + \ + 'IFS_inputdata/TianCe/orbit20160925/'+str(k)+'.txt' + d = np.loadtxt(fn) + + for kk in range(len(d[:, 0])): + if now_jd-d[kk, 0] <= 0: + flag = 1 break - if flag==1: + if flag == 1: break - - + ################################ - - - if kk +self.dt_num < len(d[:,0]): - - exptime_start_jd=d[kk+self.dt_num, 0] - - self.orbit_pars=d - self.orbit_file_num=k - self.orbit_exp_num =kk - - - + + if kk + self.dt_num < len(d[:, 0]): + + exptime_start_jd = d[kk+self.dt_num, 0] + + self.orbit_pars = d + self.orbit_file_num = k + self.orbit_exp_num = kk + else: - - fn=self.information['dir_path']+'IFS_inputdata/TianCe/orbit20160925/'+str(k+1)+'.txt'; - d=np.loadtxt(fn); - - self.orbit_pars=d - self.orbit_file_num=k+1 - self.orbit_exp_num =self.dt_num - + + fn = self.information['dir_path'] + \ + 'IFS_inputdata/TianCe/orbit20160925/'+str(k+1)+'.txt' + d = np.loadtxt(fn) + + self.orbit_pars = d + self.orbit_file_num = k+1 + self.orbit_exp_num = self.dt_num ########################################## ######################################################################## #self.dt=julian.from_jd(exptime_start_jd, fmt='jd') - self.dt=jd2time(exptime_start_jd) + self.dt = jd2time(exptime_start_jd) ################################################################## - self.TianCe_day=self.dt.strftime("%Y-%m-%d") ###str(self.dt.year)+'-'+str(self.dt.month)+'-'+str(self.dt.day) - - self.TianCe_exp_start=dt2hmd(self.dt) - - self.zodiacal_time=self.TianCe_day - - skyRa=0 - skyDec=0 - - - if simnumber>1: + # str(self.dt.year)+'-'+str(self.dt.month)+'-'+str(self.dt.day) + self.TianCe_day = self.dt.strftime("%Y-%m-%d") + + self.TianCe_exp_start = dt2hmd(self.dt) + + self.zodiacal_time = self.TianCe_day + + skyRa = 0 + skyDec = 0 + + if simnumber > 1: np.random.seed(self.simnumber) ud = np.random.random() # Choose a random rotation in degree - sky_rot = 2* (ud-0.5) * 5 - - - dsmax=np.floor(50*np.cos(sky_rot/180*np.pi))-34 + sky_rot = 2 * (ud-0.5) * 5 + + dsmax = np.floor(50*np.cos(sky_rot/180*np.pi))-34 np.random.seed(11*self.simnumber) - ud= np.random.random() # Choose a random shift in arcsec - telRa= 2* (ud-0.5) * dsmax *0.1 # in arcsec - + ud = np.random.random() # Choose a random shift in arcsec + telRa = 2 * (ud-0.5) * dsmax * 0.1 # in arcsec + np.random.seed(123*self.simnumber) - ud= np.random.random() # Choose a random shift in arcsec - telDec= 2* (ud-0.5) * dsmax *0.1 # in arcsec - - sky_rot=0.0; - telRa=0; - telDec=0; - - self.sim_sky_img(self.skyfilepath, skyRa, skyDec, 0*sky_rot, 0*telRa, 0*telDec, self.information['exptime'], simnumber) - - self.skyRa=skyRa - self.skyDec=skyDec - self.sky_rot=sky_rot - - self.telRa=telRa - self.telDec=telDec - - self.information['sky_rot']=sky_rot - + ud = np.random.random() # Choose a random shift in arcsec + telDec = 2 * (ud-0.5) * dsmax * 0.1 # in arcsec + + sky_rot = 0.0 + telRa = 0 + telDec = 0 + + self.sim_sky_img(self.skyfilepath, skyRa, skyDec, 0*sky_rot, + 0*telRa, 0*telDec, self.information['exptime'], simnumber) + + self.skyRa = skyRa + self.skyDec = skyDec + self.sky_rot = sky_rot + + self.telRa = telRa + self.telDec = telDec + + self.information['sky_rot'] = sky_rot + ####################################################################### - elif self.source=='FLAT': - self.information['exptime']=200+simnumber*100 - self.sim_calibration_img(self.information['exptime'], 'FLAT' ) - self.information['sky_rot']=0 - - ######## - - elif self.source=='LAMP': - self.information['exptime']=200+simnumber*100 - self.information['sky_rot']=0 - - if self.information['holemask']=='yes': - self.information['exptime']=300 + elif self.source == 'FLAT': + self.information['exptime'] = 200+simnumber*100 + self.sim_calibration_img(self.information['exptime'], 'FLAT') + self.information['sky_rot'] = 0 + + ######## + + elif self.source == 'LAMP': + self.information['exptime'] = 200+simnumber*100 + self.information['sky_rot'] = 0 + + if self.information['holemask'] == 'yes': + self.information['exptime'] = 300 self.sim_lamp_hole_img(self.information['exptime']) else: - self.sim_calibration_img(self.information['exptime'], 'LAMP') - - ######### - elif self.source=='DARK': - self.information['sky_rot']=0 - self.information['exptime']=simnumber*3600*24 - self.image_b=np.zeros((2048,4096)) - self.image_r=np.zeros((3072,6144)) - - elif self.source =='BIAS': - self.information['sky_rot']=0 - self.information['exptime']=0 - self.image_b=np.zeros((2048,4096)) - self.image_r=np.zeros((3072,6144)) - + self.sim_calibration_img(self.information['exptime'], 'LAMP') + + ######### + elif self.source == 'DARK': + self.information['sky_rot'] = 0 + self.information['exptime'] = simnumber*3600*24 + self.image_b = np.zeros((2048, 4096)) + self.image_r = np.zeros((3072, 6144)) + + elif self.source == 'BIAS': + self.information['sky_rot'] = 0 + self.information['exptime'] = 0 + self.image_b = np.zeros((2048, 4096)) + self.image_r = np.zeros((3072, 6144)) + else: - print('Souce is not correct and programe will return') + print('Souce is not correct and programe will return') exit(1) -############################################################################### - ### save the original image firstly; - self.image_b_ori=self.image_b+10.0 - self.image_r_ori=self.image_r+10.0 - - - exptimes=self.information['exposuretimes'] - - if self.source =='SCI' or self.source =='COMP': - exptimes=self.information['exposuretimes'] +############################################################################### + # save the original image firstly; + self.image_b_ori = self.image_b+10.0 + self.image_r_ori = self.image_r+10.0 + + exptimes = self.information['exposuretimes'] + + if self.source == 'SCI' or self.source == 'COMP': + exptimes = self.information['exposuretimes'] else: - exptimes=1 + exptimes = 1 # if self.debug: # exptimes=1 - - - self.image_b_N=np.zeros((1344,9672, exptimes)) - self.image_r_N=np.zeros((1856,13768,exptimes)) - + self.image_b_N = np.zeros((1344, 9672, exptimes)) + + self.image_r_N = np.zeros((1856, 13768, exptimes)) + for idk in range(exptimes): - - -############ add some effect to images ####################################### - self.image_b=self.image_b_ori-10.0 - self.image_r=self.image_r_ori-10.0 - - if self.information['exptime']>0.09216: - + ############ add some effect to images ####################################### + + self.image_b = self.image_b_ori-10.0 + self.image_r = self.image_r_ori-10.0 + + if self.information['exptime'] > 0.09216: + self.getFrameTransferImg() print('Applying getFrameTransferImg finished.......') - - + if self.flatfieldM: - self.applyflatfield(simnumber) + self.applyflatfield(simnumber) print('Applying flatfieldM finished.......') - - - if self.source =='SCI' or self.source =='COMP': - + + if self.source == 'SCI' or self.source == 'COMP': + # if self.debug: # print('Debug mode, no cosmicrays') # else: - - if self.cosmicRays : + + if self.cosmicRays: self.addCosmicRays(idk) print('Applying cosmicRays finished.......') - + if self.bleeding: self.applyBleeding_yan() print('Applying bleeding finished.......') - - + if self.darknoise: - self.applyDarkCurrent() + self.applyDarkCurrent() print('Applying dark noise finished.......') - + ################################## - - if self.source !='SCI' and self.source !='COMP': + + if self.source != 'SCI' and self.source != 'COMP': self.applyPoissonNoise() print('Applying Possion noise finished.......') - + ################################## - + if self.nonlinearity: self.applyNonlinearity() print('Applying nonlinearity finished.......') - - ##### cut original CCD image to four parts by four read out channels and zones - self.CCDreadout() - - + + # cut original CCD image to four parts by four read out channels and zones + self.CCDreadout() + if self.radiationDamage: self.applyRadiationDamage() print('Applying radiationDamage finished.......') - - + if self.readoutNoise: self.applyReadoutNoise() print('Applying readoutNoise finished.......') - - if self.information['exptime']>0.09216: + + if self.information['exptime'] > 0.09216: self.appFrameTransferEffect() print('Applying Frame Transfer Effect finished.......') - - + self.electrons2ADU() - self.applyBias() - - + if self.cosmetics: self.applyCosmetics() - print('Applying cosmetics finished.......') - - - self.discretise() - - - self.image_b_N[:,:,idk]=self.image_b[:,:] - self.image_r_N[:,:,idk]=self.image_r[:,:] - - - self.writeOutputs(simnumber) + print('Applying cosmetics finished.......') + + self.discretise() + + self.image_b_N[:, :, idk] = self.image_b[:, :] + self.image_r_N[:, :, idk] = self.image_r[:, :] + + self.writeOutputs(simnumber) - ################################################# - + self.log.info('Using the following input values:') - + for key, value in self.information.items(): self.log.info('%s = %s' % (key, value)) self.log.info('Using the following booleans:') - + for key, value in self.booleans.items(): - self.log.info('%s = %s' % (key, value)) - - + self.log.info('%s = %s' % (key, value)) + self.log.info('Finished the ith_Exposure = %i' % (simnumber)) - #print('The iLoop= % d simlaiton finished. ' %simnumber) + #print('The iLoop= % d simlaiton finished. ' %simnumber) ############################################################################################## ############################################################################################## + + def runIFSsim(sourcein, skyfitsin, configfile, iLoop, CSST_unittest, applyhole='no'): - - - opts, args = processArgs() - - opts.configfile=configfile - simulate=dict() - simulate[iLoop] = IFSsimulator(opts) - - if applyhole=='yes' and sourcein =='LAMP': - simulate[iLoop].information['holemask']='yes' + opts, args = processArgs() + + opts.configfile = configfile + + simulate = dict() + simulate[iLoop] = IFSsimulator(opts) + + if applyhole == 'yes' and sourcein == 'LAMP': + simulate[iLoop].information['holemask'] = 'yes' else: - simulate[iLoop].information['holemask']='no' - - - if CSST_unittest: - dir_path=os.path.join(os.environ['UNIT_TEST_DATA_ROOT'],'ifs_sim') + simulate[iLoop].information['holemask'] = 'no' + + if CSST_unittest: + dir_path = os.path.join(os.environ['UNIT_TEST_DATA_ROOT'], 'ifs_sim') else: - dir_path='../' - - simulate[iLoop].information['dir_path']=dir_path - - + dir_path = '../' + + simulate[iLoop].information['dir_path'] = dir_path + ############### - - if sourcein=='SCI': - simulate[iLoop].information['skyfilepath']=skyfitsin - - ############## - simulate[iLoop].simulate(sourcein, iLoop) - + if sourcein == 'SCI': + simulate[iLoop].information['skyfilepath'] = skyfitsin + + ############## + simulate[iLoop].simulate(sourcein, iLoop) + return 1 - + ########################## begin main fucntion ####################################### ############################################################################################## ############################################################################################## if __name__ == "__main__": - - CSST_unittest=True - - sourcein='SCI' - - applyhole='no' - - if CSST_unittest: - dir_path=os.path.join(os.environ['UNIT_TEST_DATA_ROOT'],'ifs_sim') + + CSST_unittest = True + + sourcein = 'SCI' + + applyhole = 'no' + + if CSST_unittest: + dir_path = os.path.join(os.environ['UNIT_TEST_DATA_ROOT'], 'ifs_sim') else: - dir_path='../' - + dir_path = '../' - configfile0=dir_path+'IFS_data/IFS_sim_C90.config' - - skyfitsin =dir_path+'IFS_inputdata/FengshuaiData/NGC6397_S6102.fits' - - if len(sys.argv[:])<2: - configfile=configfile0 - - - if len(sys.argv[:])>=2: - configfile=sys.argv[1]+'IFS_inputdata/configData/IFS_sim_C90.config' + configfile0 = dir_path+'IFS_data/IFS_sim_C90.config' + + skyfitsin = dir_path+'IFS_inputdata/FengshuaiData/NGC6397_S6102.fits' + + if len(sys.argv[:]) < 2: + configfile = configfile0 + + if len(sys.argv[:]) >= 2: + configfile = sys.argv[1]+'IFS_inputdata/configData/IFS_sim_C90.config' if not os.path.exists(configfile): print('The given input fonfigfile path is wrong......') sys.exit(1) - - - configfile=configfile0 - - if len(sys.argv[:])>=3: - sourcein=sys.argv[2] - - if sourcein not in ['BIAS', 'DARK','LAMP','FLAT' ,'SCI']: + configfile = configfile0 + + if len(sys.argv[:]) >= 3: + sourcein = sys.argv[2] + + if sourcein not in ['BIAS', 'DARK', 'LAMP', 'FLAT', 'SCI']: print('The input sourcein parameter input is wrong......') - sys.exit(1) - - - if len(sys.argv[:])>=4: - applyhole=sys.argv[3] + sys.exit(1) + + if len(sys.argv[:]) >= 4: + applyhole = sys.argv[3] if sourcein not in ['yes', 'no']: print('The input applyhole parameter should be yes or no!') - sys.exit(1) + sys.exit(1) ############################################################# ################## sky test ############################ - - runIFSsim(sourcein, skyfitsin, configfile, 1, CSST_unittest, applyhole) - - + + runIFSsim(sourcein, skyfitsin, configfile, 1, CSST_unittest, applyhole) + ############################################################################ ############################################################################ # it=range(1, exposureNum+1,1) - + # if exposureNum>1: # Parallel(n_jobs=min(5,exposureNum))(delayed(runIFSsim)(sourcein, skyfitsin, configfile, iLoop, applyhole) for iLoop in it) # else: - # runIFSsim(sourcein, skyfitsin, configfile, 1, applyhole) - + # runIFSsim(sourcein, skyfitsin, configfile, 1, applyhole) # pause # # ############################################################ @@ -4809,66 +5110,61 @@ if __name__ == "__main__": # applyhole='no' # exposureNum=5 # it=range(1,exposureNum+1,1) - + # if exposureNum>1: # Parallel(n_jobs=exposureNum)(delayed(runIFSsim)(sourcein, skyfitsin, configfile, iLoop, applyhole) for iLoop in it) # else: # runIFSsim(sourcein, skyfitsin, configfile, 1, applyhole) - + # pause() - + # # # ########################################################## # # ############### dark , no mask ########### # sourcein ='DARK' # applyhole='no' # exposureNum=5 # it=range(1,exposureNum+1,1) - + # if exposureNum>1: # Parallel(n_jobs=exposureNum)(delayed(runIFSsim)(sourcein, skyfitsin, configfile, iLoop, applyhole) for iLoop in it) # else: # runIFSsim(sourcein, skyfitsin, configfile, 1, applyhole) # # ############################################################################### - ################# lamp , no mask ############# - + # sourcein ='LAMP' # applyhole='no' # exposureNum=5 # it=range(1,exposureNum+1,1) - + # if exposureNum>1: # Parallel(n_jobs=exposureNum)(delayed(runIFSsim)(sourcein, skyfitsin, configfile, iLoop, applyhole) for iLoop in it) # else: # runIFSsim(sourcein, skyfitsin, configfile, 1, applyhole) - + ############################################################ - ########################################################### # # ############### flat, no mask ################ # sourcein ='FLAT' # applyhole='no' # exposureNum=5 # it=range(1,exposureNum+1,1) - + # if exposureNum>1: # Parallel(n_jobs=exposureNum)(delayed(runIFSsim)(sourcein, skyfitsin, configfile, iLoop, applyhole) for iLoop in it) # else: # runIFSsim(sourcein, skyfitsin, configfile, 1, applyhole) - - - # ############################################################ + + # ############################################################ # ################## hole Mask simulation ############### # sourcein ='LAMP' # applyhole='yes' # exposureNum=2 # it=range(1,exposureNum+1,1) - + # if exposureNum>1: # Parallel(n_jobs=exposureNum)(delayed(runIFSsim)(sourcein, skyfitsin, configfile, iLoop, applyhole) for iLoop in it) # else: - # runIFSsim(sourcein, skyfitsin, configfile, 1, applyhole) - - + # runIFSsim(sourcein, skyfitsin, configfile, 1, applyhole) diff --git a/setup.py b/setup.py index cf6fbda..06de70b 100644 --- a/setup.py +++ b/setup.py @@ -1,37 +1,47 @@ -import setuptools - -with open("README.md", "r") as fh: - long_description = fh.read() - -setuptools.setup( - name='csst_ifs_sim', - # Internal_Version = '0.7.02', - version='1.0.0', - author='CSST Team', - author_email='zhaojunyan@shao.ac.cn', - description='The CSST - ifs - sim', # short description - long_description=long_description, - long_description_content_type="text/markdown", - url='https://csst-tb.bao.ac.cn/', - # project_urls={ - # 'Source': 'https://csst-tb.bao.ac.cn/code/csst-l1/ifs/csst_ifs_sim', - # }, - packages=setuptools.find_packages(), - license='MIT', - classifiers=["Development Status :: 5 - Production/Stable", - "Intended Audience :: Science/Research", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", - "Programming Language :: Python :: 3.8", - "Topic :: Scientific/Engineering :: Physics", - "Topic :: Scientific/Engineering :: Astronomy"], - package_dir={'csst_ifs_sim': 'csst_ifs_sim'}, - # include_package_data=True, - package_data={"": ["LICENSE", "README.md"], - "csst_ifs_sim": ["ifs_so/*", "ifs_data/*", "ifs_data/refs/*", "ifs_data/refs/orbit20160925/*"]}, - # install_requires=['sphinx', - # 'numpy', - # 'scipy', 'matplotlib', - # 'astropy', 'healpy', 'ccdproc', 'deepCR', 'photutils'], - python_requires='>=3.8', -) +import setuptools + +# 读取README.md作为长描述 +with open("README.md", "r") as f: + long_description = f.read() + +# 读取依赖列表requirements.txt +# 忽略#开头或者版本号不明确指定的条目 +with open("requirements.txt", "r") as f: + requirements = [ + req.strip() + for req in f.readlines() + if not req.startswith("#") and req.__contains__("~=") + ] + +setuptools.setup( + name='csst_ifs_sim', + # Internal_Version = '0.7.02', + version='1.0.0', + author='CSST Team', + author_email='zhaojunyan@shao.ac.cn', + description='The CSST - ifs - sim', # short description + long_description=long_description, + long_description_content_type="text/markdown", + url='https://csst-tb.bao.ac.cn/', + # project_urls={ + # 'Source': 'https://csst-tb.bao.ac.cn/code/csst-l1/ifs/csst_ifs_sim', + # }, + packages=setuptools.find_packages(), + license='MIT', + classifiers=["Development Status :: 5 - Production/Stable", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3.8", + "Topic :: Scientific/Engineering :: Physics", + "Topic :: Scientific/Engineering :: Astronomy"], + package_dir={'csst_ifs_sim': 'csst_ifs_sim'}, + # include_package_data=True, + package_data={"": ["LICENSE", "README.md"], + "csst_ifs_sim": ["ifs_so/*", "ifs_data/*", "ifs_data/refs/*", "ifs_data/refs/orbit20160925/*"]}, + # install_requires=['sphinx', + # 'numpy', + # 'scipy', 'matplotlib', + # 'astropy', 'healpy', 'ccdproc', 'deepCR', 'photutils'], + python_requires='>=3.8', +) -- GitLab