-
Notifications
You must be signed in to change notification settings - Fork 1
/
functions.py
202 lines (153 loc) · 8 KB
/
functions.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
import numpy as np
import matplotlib.pyplot as plt
import sys, pdb, glob
from tqdm import tqdm
from photutils import CircularAperture, CircularAnnulus, aperture_photometry
from astropy.io import fits, ascii
from astropy.table import Table, Column
from astropy.modeling import models, fitting
from astropy.wcs import WCS
from astropy.wcs.wcs import NoConvergence
from astropy import units as u
from astropy.coordinates import SkyCoord
def photometry(image2d, cen_x, cen_y, index = 0, shape = 'Circ', rad = None, r_in = None, r_out = None, ht = None, wid = None, w_in = None, w_out = None, h_out = None, ang = 0.0):
"""
PARAMETERS
----------
image2d = 2 dimensional image array. Type = ndarray
cen_x, cen_y = x & y center position. Type = ndarray/list
index = if cen_x and cen_Y is a list of more than 1 element, specify the desired index. Type = Integer
shape = 'Circ':CircularAperture, 'Rect':RectangularAperture, 'CircAnn':CircularAnnulus, 'RectAnn':RectangularAnnulus
rad, r_in, r_out, ht, wid, w_in, w_out, h_out, ang = Astropy's aperture parameters
RETURNS
-------
flux = flux of the image extracted by the aperture described in the "shape" parameter. Type = Float
aperture = aperture object created by astropy
"""
mask = np.isnan(image2d) == True
if shape == 'Circ':
aperture = CircularAperture((cen_x[index], cen_y[index]), r = rad)
elif shape == 'Rect':
aperture = RectangularAperture((cen_x[index], cen_y[index]), w = wid, h = ht, theta = ang)
elif shape == 'CircAnn':
aperture = CircularAnnulus((cen_x[index], cen_y[index]), r_in = r_in, r_out = r_out)
elif shape == 'RectAnn':
aperture = RectangularAnnulus((cen_x[index], cen_y[index]), w_in = w_in, w_out = w_out, h_out = h_out, theta = ang)
phot_table = aperture_photometry(image2d, aperture, mask = mask)
flux = phot_table['aperture_sum']
return flux, aperture
def gen_center_g2d(image, center_x, center_y, box_width, amp, x_std, y_std, Theta, model_plotting = False):
"""
PARAMETERS:
center_x = x coordinate of the circular aperture; Type = float
center_y = y coordinate of the circular aperture; Type = float
amp = amplitude of the gaussian. Find from the projection curve along the center; Type = float
x_std = Standard deviation of the Gaussian in x before rotating by theta; Type = float
y_std = Standard deviation of the Gaussian in y before rotating by theta; Type = float
Theta = Rotation angle in radians. The rotation angle increases counterclockwise; Type = float
RETURNS:
seperate_centers = Center of each image; Type = Array [of tuples]
x_values = x_value of center of each image; Type = Array
y_values = y_value of center of each image; Type = Array
"""
#Creating a mesh grid with the shape of image to create model
y_pos, x_pos = np.mgrid[:image.shape[0],:image.shape[1]]
#defining starting and stopping points for drawing a box to fit the gaussian to
xA, yA = int(center_x-box_width), int(center_y-box_width)
xB, yB = int(center_x+box_width), int(center_y+box_width)
# fitting the gaussian model
fit_g = fitting.LevMarLSQFitter()
gauss2D = models.Gaussian2D(amplitude = amp, x_mean = center_x, y_mean = center_y, x_stddev = x_std, y_stddev = y_std, theta = Theta)
g = fit_g(gauss2D,x_pos[yA:yB,xA:xB],y_pos[yA:yB,xA:xB],image[yA:yB,xA:xB])
g1 = fit_g(g,x_pos[yA:yB,xA:xB],y_pos[yA:yB,xA:xB],image[yA:yB,xA:xB])
#pdb.set_trace()
new_xCen = g1.x_mean[0]
new_yCen = g1.y_mean[0]
fwhm_x = g1.x_fwhm
fwhm_y = g1.y_fwhm
if model_plotting == True:
plt.subplot(131)
plt.imshow(image[yA:yB,xA:xB])
plt.title('Data')
plt.subplot(132)
plt.imshow(g1(x_pos[yA:yB,xA:xB],y_pos[yA:yB,xA:xB]))
plt.title('Model')
plt.subplot(133)
plt.imshow(image[yA:yB,xA:xB] - g1(x_pos[yA:yB,xA:xB],y_pos[yA:yB,xA:xB]))
plt.title('Residual')
#Results
return new_xCen, new_yCen, fwhm_x, fwhm_y
def ap_overflow(x, y, r, img):
xlim, ylim = img.shape
if ((x+r)>xlim) | ((x-r)<0) | ((y+r)>ylim) | ((y-r)<0):
return True
else:
return False
def single_target_phot(fnames, targetCrd, src_r, bkg_rIn, bkg_rOut):
"""
For a set of images.
"""
data = Table(names = ('File#', 'Coord Conversion Issue', 'Centroiding Issue', 'Bad Center Guess', 'Not In FOV', 'Ap Out Of Bound', 'Xc', 'Yc', 'Fx', 'Fy', 'Time[MJD]', 'Raw_Flux', 'Bkg_Flux', 'Res_Flux'),
dtype = ('S25', 'S5', 'S5', 'S5', 'S5', 'S5', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8'))
for i, fn in tqdm(enumerate(fnames)):
#Issues list
#Initializing values to False
(crd_conversion, centroiding, bad_cen_guess, not_in_fov, ap_out_of_bound) = ('N', 'N', 'N', 'N', 'N')
#setting default value to NaN
(raw_flux, bkg_flux, res_flux, cenX, cenY, fx, fy) = (np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan)
#Extracting header and image data regardless of filetype
hdu = fits.open(fn)
header = hdu[0].header
image = hdu[0].data
hdu.close()
#Extracting header and image data of bcd files for subarray data
if header['READMODE'] == 'SUB':
bcd_fn = fn.replace('sub2d', 'bcd')
bcd_hdu = fits.open(bcd_fn)
bcd_header = bcd_hdu[0].header
bcd_image = bcd_hdu[0].data
image = np.median(bcd_image[14:], axis = 0) #taking a median of the last 50 bcd frames
bcd_hdu.close()
Time = header['MJD_OBS']
try:
w = WCS(header)
pix = targetCrd.to_pixel(w)
except (ValueError, NoConvergence):
crd_conversion = 'Y'
data.add_row([i+1, crd_conversion, centroiding, bad_cen_guess, not_in_fov, ap_out_of_bound, cenX, cenY, fx, fy, Time, raw_flux, bkg_flux, res_flux])
continue
if (pix[0]>0) & (pix[0]<image.shape[0]) & (pix[1]>0) & (pix[1]<image.shape[1]):
try:
cenX, cenY, fx, fy = gen_center_g2d(image, pix[0], pix[1], 7, 5, 4, 4, 0)
except TypeError:
centroiding = 'Y'
data.add_row([i+1, crd_conversion, centroiding, bad_cen_guess, not_in_fov, ap_out_of_bound, cenX, cenY, fx, fy, Time, raw_flux, bkg_flux, res_flux])
continue
if (ap_overflow(cenX, cenY, bkg_rIn, image) == True) | (ap_overflow(cenX, cenY, bkg_rOut, image) == True):
ap_out_of_bound = 'Y'
data.add_row([i+1, crd_conversion, centroiding, bad_cen_guess, not_in_fov, ap_out_of_bound, cenX, cenY, fx, fy, Time, raw_flux, bkg_flux, res_flux])
continue
if (np.abs(cenX - pix[0]) <= 2) & (np.abs(cenY-pix[1]) <= 2):
# Extracting raw flux
raw_flux, src_ap = photometry(image, [cenX], [cenY], rad = src_r)
# Extrating a mean background flux
bkg, bkg_ap = photometry(image, [cenX], [cenY], shape = 'CircAnn', r_in = bkg_rIn, r_out = bkg_rOut)
bkg_mean = bkg/bkg_ap.area()
bkg_flux = bkg_mean*src_ap.area()
# Subtracting background
res_flux = raw_flux - bkg_flux
else:
bad_cen_guess = 'Y'
else:
not_in_fov = 'Y'
ap_out_of_bound = 'Y'
data.add_row([i+1, crd_conversion, centroiding, bad_cen_guess, not_in_fov, ap_out_of_bound, cenX, cenY, fx, fy, Time, raw_flux, bkg_flux, res_flux])
return data, header
def sigma_clipping(array, N):
stdev = np.std(array)
median = np.median(array)
upr_lim = median + (N*stdev)
lwr_lim = median - (N*stdev)
mask = ((array>lwr_lim) & (array<upr_lim))
new_array = array[mask]
return new_array, mask