#PH4100 Major Poject - Photometry - Star field simulation program (5) #Aaron Andrews #Last edited: 26/10/2016 #('*' indicates newest addition) #This program generates a set number of stars with random variables (positions, sigmas, fluxes, correlation) #*Background can be generated independently, then added to star field #Stars are assumed to have 2d gaussian profiles. Correlation coefficient for x and y is an adjustable variable #Mean value for each pixel (per star) calculated via integration over pixel area *(only if value of gaussian at pixel centre is not negligable) #Mean value used to generate random poisson value for each pixel #The output is a 2d array representing an image of a star field - each cell stores a grey value calculated using the cumulative gaussian profiles for all stars generated. #The star field representation generated by this particular program is not accurate. #Output image can be saved as FITS file #*randomly generated paramaters of stars, as returned by 'SimStarField' function, can be output to text file #*a seed can be set when simulating star fields - use to produce star fields with identical randomised parameters for stars import math import random as rm import numpy as np import matplotlib import matplotlib.pyplot as plt import matplotlib.image as mpimg import scipy.integrate as si #for integration of gaussian function over pixels from astropy.io import fits from textwrap import wrap #The first two functions are used for calculations of star gaussian profiles def Gaussian(x,y,xStar,yStar,xSig,ySig,corr,flux): #2d gaussian function, returns grey value contribution from a single star for any point in the star field return flux*(1/(2*math.pi*xSig*ySig*np.sqrt(1-corr**2)))*math.exp(-(1/(2*(1-corr**2)))*( (((x-xStar)**2)/(xSig**2)) + (((y-yStar)**2)/(ySig**2)) - 2*corr*((x-xStar)/xSig)*((y-yStar)/ySig) )) #normalisation: (1/(2*math.pi*xSig/8ySignp.sqrt(1-corr**2))) def IntGaussian(x1,y1,xStar,yStar,xSig,ySig,corr,flux): #returns integrated grey value contribution from a star for any pixel #integrate x and y components of gaussian seperately - define functions for integration first #GaussFuncX=lambda x:math.exp(-(((x-xStar)**2)/(2*xSig**2))) #GaussFuncY=lambda y:math.exp(-(((y-yStar)**2)/(2*ySig**2))) if corr==0: GaussFunc=lambda y,x:math.exp(-(((x-xStar)**2)/(2*xSig**2)))*math.exp(-(((y-yStar)**2)/(2*ySig**2))) #Failsafe for integration - without it, would cause integration to return value of 1 else: GaussFunc=lambda y,x:math.exp(-(1/(2*(1-corr**2)))*( (((x-xStar)**2)/(xSig**2)) + (((y-yStar)**2)/(ySig**2)) - 2*corr*((x-xStar)/xSig)*((y-yStar)/ySig) )) #Take pixel coordinates as centre of pixel - integrate between range of [-0.5,+0.5] pixels #xIntegral,xIntError=si.quad(GaussFuncX,x1-0.5,x1+0.5)#as numerical integration, returns error #yIntegral,yIntError=si.quad(GaussFuncY,y1-0.5,y1+0.5) Integral,IntError=si.dblquad(GaussFunc,x1-0.5,x1+0.5,lambda y:y1-0.5,lambda y:y1+0.5,epsabs=10,epsrel=10)#2d numerical integration return flux*(1/(2*math.pi*xSig*ySig*np.sqrt(1-corr**2)))*Integral #The following functions can be used to manually create a star field and generate stars with set parameters. #(Optional) Generated star images can be converted into array of discrete (poisson) pixel values,. def MakeField(nxPixel,nyPixel): #*Generate unfilled array for star field return np.zeros((nxPixel,nyPixel)) def AddStar(posX,posY,sigX,sigY,corr,flux,image): #*adds a star to an existing image Image1=image #Loop over all pixels in image pxlX=0 while pxlX0.1: #prevents integration for negligable gaussian values at pixel coordinates Image1[pxlX,pxlY]=Image1[pxlX,pxlY]+IntGaussian(pxlX,pxlY,posX,posY,sigX,sigY,corr,flux) pxlY=pxlY+1 pxlX=pxlX+1 return Image1 def MakePoisson(imageMeans): #Use calculated values to generate random poisson-distributed pixel values Image1=MakeField(len(imageMeans),len(imageMeans[0])) pxlX=0 while pxlX=0 and PosX[n]<=nxPixel-1 and PosY[n]>=0 and PosY[n]<=nyPixel-1: #test if star is in frame. stops once set number of stars appear in frame. Params[n+1]=str(n+1)+"\t"+str(PosX[n])+"\t"+str(PosY[n])+"\t"+str(flux[n])+"\t"+str(peak[n])+"\t"+str(sigX[n])+"\t"+str(sigY[n])+"\t"+str(corr[n]) n=n+1 print "added star (in frame): ", n #for keeping track of progress else: Params.append(str(nStars+nOut+1)+"\t"+str(PosX[n])+"\t"+str(PosY[n])+"\t"+str(flux[n])+"\t"+str(peak[n])+"\t"+str(sigX[n])+"\t"+str(sigY[n])+"\t"+str(corr[n])) nOut=nOut+1 print "added star (out frame): ", nOut nT=nT+1 Image1=MakePoisson(Image1Means) Image1=AddBackground(Image1,backMean,backErr) return Image1, Params def IntegrationTest(nxPixel,xStar,Sigma,peak): #demonstration of integrated pixel values vs centre-point calculation axisX=np.linspace(0,nxPixel-1,nxPixel) GaussInt=np.zeros(nxPixel) #Pixel values calculated by integration GaussCalc=np.zeros(nxPixel) #Pixel values calculated with gaussian by inputting bin midpoint GaussPois=np.zeros(nxPixel) #Calculation with integration, then used as mean for random distributed poisson variable GaussCurveX=np.linspace(0,nxPixel,1000) GaussCurveY=np.zeros(1000) n=0 while n<1000: GaussCurveY[n]=Gaussian(GaussCurveX[n],0,xStar,0,Sigma,Sigma,0,peak) n=n+1 pxlX=0 while pxlX