__all__=["NoOffset","OffsetSNR","BaseOffset"]importnumpyasnpfrom..maf.utils.astrometry_utilsimportm52snr# from lsst.sims.selfcal.clouds.Arma import ArmaSf, Clouds
[docs]classBaseOffset:"""Base class for how to make offset classes"""def__init__(self,**kwargs):self.newkey="dmag_keyname"passdef__call__(self,stars,visit,**kwargs):pass
[docs]classNoOffset(BaseOffset):def__init__(self):"""Make no changes to the mags"""self.newkey="dmag_zero"def__call__(self,stars,visits,**kwargs):dmag=np.zeros(stars.size,dtype=list(zip([self.newkey],[float])))returndmag
classOffsetSys(BaseOffset):def__init__(self,error_sys=0.003):"""Systematic error floor for photometry"""self.error_sys=error_sysself.newkey="dmag_sys"def__call__(self,stars,visits,**kwargs):nstars=np.size(stars)dmag=np.random.randn(nstars)*self.error_sysreturndmagclassOffsetClouds(BaseOffset):"""Offset based on cloud structure. Not used, as not fully implemented in this version (ArmaSf). """def__init__(self,sampling=256,fov=3.5):self.fov=fovself.newkey="dmag_cloud"# self.SF = ArmaSf()self.SF=None# self.cloud = Clouds()self.cloud=Nonedef__call__(self,stars,visits,**kwargs):# XXX-Double check extinction is close to the Opsim transparencyextinc_mags=visits["transparency"]ifextinc_mags!=0.0:sf_theta,sf_sf=self.SF.CloudSf(500.0,300.0,5.0,extinc_mags,0.55)# Call the Cloudsself.cloud.makeCloudImage(sf_theta,sf_sf,extinc_mags,fov=self.fov)# Interpolate clouds to correct position.# Nearest neighbor for speed?nim=self.cloud.cloudimage[0,:].size# calc position in cloud image of each starstarx_interp=(np.degrees(stars["x"])+self.fov/2.0)*3600.0/self.cloud.pixscalestary_interp=(np.degrees(stars["y"])+self.fov/2.0)*3600.0/self.cloud.pixscale# Round off position and make it an intstarx_interp=np.round(starx_interp).astype(int)stary_interp=np.round(stary_interp).astype(int)# Handle any stars that are out of the field for some reasonstarx_interp[np.where(starx_interp<0)]=0starx_interp[np.where(starx_interp>nim-1)]=nim-1stary_interp[np.where(stary_interp<0)]=0stary_interp[np.where(stary_interp>nim-1)]=nim-1dmag=self.cloud.cloudimage[starx_interp,stary_interp]else:dmag=np.zeros(stars.size)returndmag
[docs]classOffsetSNR(BaseOffset):"""Generate offsets based on the 5-sigma limiting depth of an observation and the brightness of the star. Note that this takes into account previous offsets that have been applied (so run this after things like vignetting). """def__init__(self,lsst_filter="r"):self.lsst_filter=lsst_filterself.newkey="dmag_snr"defcalc_mag_errors(self,magnitudes,m5,err_only=False):""" """snr=m52snr(magnitudes,m5)# via good old https://www.eso.org/~ohainaut/ccd/sn.htmlmagnitude_errors=2.5*np.log10(1.0+1.0/snr)iferr_only:dmag=magnitude_errorselse:dmag=np.random.randn(len(magnitudes))*magnitude_errorsreturndmagdef__call__(self,stars,visit,dmags=None):ifdmagsisNone:dmags={}temp_mag=stars[self.lsst_filter+"mag"].copy()# calc what magnitude the star has when it hits the silicon.# Thus we compute the SNR noise# AFTER things like cloud extinction and vignetting.forkeyinlist(dmags.keys()):temp_mag=temp_mag+dmags[key]dmag=self.calc_mag_errors(temp_mag,visit["fiveSigmaDepth"])returndmag