Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Script for masking known sources using the Gaia database. #91

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 189 additions & 0 deletions tools/masking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import os
import astropy.units as u
import numpy as np
import numpy.ma as ma
import math
import sys
import matplotlib.pyplot as plt
from photutils import centroid_sources
from astropy.wcs import WCS
from astropy.io import fits
from astropy.coordinates import SkyCoord
from regions import CirclePixelRegion, PixCoord
from astropy.wcs.utils import skycoord_to_pixel, pixel_to_skycoord
from astropy.coordinates import ICRS, FK5, SkyCoord
from astroquery.gaia import Gaia
from matplotlib.colors import LogNorm
CRVAL1 =[]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These arrays look like they could be moved locally into the function to me; they might have side effects if global declarations. LMK if this is not the case.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as a smaller point, SCREAMING_SNAKE_CASE is used for constants; use snake_case instead.

CRVAL2 = []
CD1_1 =[]
CD1_2 =[]
CD2_1 =[]
CD2_2 =[]
VALS = []
Big_Fudge = 1.5 #Arbitrary constant to scale large, bright sources.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are constants, so SCREAMING_SNAKE_CASE is appropriate.

small_fudge = .2 #Arbitrary constant to sclae smaller, dim sources.

def get_wcs(images): #extracts necessary WCS info from science images.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this possible to do using astropy.wcs?

L = int(len(images))
weight = np.ones(L)
weight[0] = 10
for W in images:
CRVAL1.append(W.header['CRVAL1'])
CRVAL2.append(W.header['CRVAL2'])
CD1_1.append(W.header['CD1_1'])
CD1_2.append(W.header['CD1_2'])
CD2_1.append(W.header['CD2_1'])
CD2_2.append(W.header['CD2_2'])
NAXIS = images[0].header['NAXIS']
NAXIS1 = images[0].header['NAXIS1']
NAXIS2 = images[0].header['NAXIS2']
CRPIX1 = images[0].header['CRPIX1']
CRPIX2 = images[0].header['CRPIX2']
CTYPE1 = images[0].header['CTYPE1']
CTYPE2 = images[0].header['CTYPE2']
CUNIT1 = images[0].header['CUNIT1']
CUNIT2 = images[0].header['CUNIT2']
VAL1 = np.average(CRVAL1, weights=weight) #need to add weighting back into this but letting it go until can get things working again.
VAL2 = np.average(CRVAL2, weights=weight)
VALS.append(VAL1)
VALS.append(VAL2)
CD11 = np.average(CD1_1, weights=weight)
CD12 = np.average(CD1_2, weights=weight)
CD21 = np.average(CD2_1, weights=weight)
CD22 = np.average(CD2_2, weights=weight)
total_wcs = WCS(naxis = int(NAXIS))
total_wcs.wcs.crpix = [CRPIX1, CRPIX2]
total_wcs.wcs.crval = [VAL1, VAL2]
total_wcs.wcs.cunit = [CUNIT1, CUNIT2]
total_wcs.wcs.ctype = [CTYPE1, CTYPE2]
total_wcs.wcs.cd = [(CD11, CD12), (CD21, CD22)]
total_wcs.array_shape = [NAXIS2, NAXIS1]
return total_wcs



def reference(im): #runs GAIA cone search
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be appropriate to leave reference to be done by a different script (like ref) and have this script draw reference data from a BinTable instead. This might be better to stay modular and avoid replication of efforts (like the rather tricky optimizations to referencing done in ref).

ra = VALS[0]
dec = VALS[1]
coord = SkyCoord(ra, dec, unit = (u.deg, u.deg), frame = 'icrs')
radius = u.Quantity(.3, u.deg) #.3 deg is good enough for normal sized images can be adjusted.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good, I think this should be patched in ref. See Issue #71.

Gaia.ROW_LIMIT = -1 # -1 returns all objects in search.
j = Gaia.cone_search_async(coord, radius)
r = j.get_results()
print('done searching')
return r



def mask(image, scis): # WILL REQUIRE TWO ARGS: image to be masked (i.e. template image) and list of science images passed from main.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be best to have this conform to the standard pipeline format of hduls, args with an eye towards pipeline integration.

data = image
w = get_wcs(scis)
empty_mask = ma.zeros([data.shape[0]+100, data.shape[1]+100]) #adds padding to the image so that all sources in the frame can be masked
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments should be above lines as per pep8

#print(w)
f = reference(image)
for source in f:
if source['ra_error'] > .3 and source['dec_error'] > .3: #filters out ra & dec error greater than .3 degrees
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These magic numbers should be global constants to make them easier to tweak later.

continue
print('STEP1')
if source['phot_g_mean_mag'] >18 and source['phot_bp_mean_mag'] > 18 and source['phot_rp_mean_mag'] > 18:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above; global constnats.

continue #filters out sources with RGB mag greater than 18 -> sources dimmer than mag 18 (should be or?)
print('STEP2')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove now-unneccessary prints.

point = SkyCoord(ra = source['ra'], dec= source['dec'], unit = (u.deg, u.deg))
center = skycoord_to_pixel(point, w, origin =1, mode = 'all') #This and previous line convert GAIA output source coordinates to pixel value
print(center)
if (center[0] <= 0) or (center[0] >= 3054):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be better to pull out these numbers from image dimensions rather than assuming LCO dimensions.

continue #makes sure sources are in frame
print('STEP3')
if (center[1] <= 0) or (center[1] >= 2042):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

continue
print('STEP4')
x_cent = float(center[0])
y_cent = float(center[1])
x, y = centroid_sources(data, x_cent, y_cent, box_size = 30)
if math.isnan(x[0]) == True: #sometimes centroid sources returns unusable NAN values, this will reset them to GAIA centers if NAN.
x[0] = center[0]
if math.isnan(y[0]) == True:
y[0] = center[1]
bk_list = []
i = 0
while i != 100:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this loop calculate a background? If so, can sep.Background do the job, and/or can we pull this out into a separate function?

x_back = np.random.random(100) * 60 #use random smaples instead
y_back = np.random.random(100) * 60
back = np.stack((x_back, y_back), axis = -1)
avlist = []
for pnt in back:
if (x[0]+pnt[0]-30 <= 0) or (x[0]+pnt[0]-30 >= data.shape[1]): #making sure to exclude points outside the frame. Come up with better way for background sampling? Photutils????
continue
if (y[0]+pnt[1]-30 <= 0) or (y[0]+pnt[1]-30 >= data.shape[0]):
continue
avlist.append(data[int((y[0]-30)+pnt[1]), int((x[0]-30)+pnt[0])])
bk_list.append(np.sum(avlist)/(int(len(avlist))))
i +=1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a lot of magic with really short variable names happening below, some descriptions would be helpful to the reader.

AV = np.sum(bk_list)/(int(len(bk_list)))
C = 1
if data[int(y[0]), int(x[0])] > 10000:
C = Big_Fudge
if data[int(y[0]), int(x[0])] - AV < 20:
C = small_fudge
print('Step5')
Rs = 4
R1 = 0
while data[int(y[0]), int(x[0]+R1)] > AV:
R1 += .1
if (x[0]+R1) > data.shape[1]:
R1 =0
Rs -= 1
break
if R1 >= 17.5:
break
R2 = 0
while data[int(y[0]+R2), int(x[0])] > AV:
R2 += .1
if (y[0]+R2) > data.shape[0]:
R2 =0
Rs -= 1
break
if R2 >= 17.5:
break
R3 = 0
while data[int(y[0]), int(x[0]-R3)] > AV:
R3 += .1
if (x[0]-R3) < 0:
R3 =0
Rs -= 1
break
if R3 >= 17.5:
break
R4 = 0
while data[int(y[0]-R4), int(x[0])] > AV:
R4 += .1
if (y[0]-R4) > 0:
R4 =0
Rs -= 1
break
if R4 >= 17.5:
break
R = float(((R1+R2+R3+R4)/Rs)*C)
#print(R)
center_2 = PixCoord(x[0]+50, y[0]+50)
circle = CirclePixelRegion(center_2, R)
mask = circle.to_mask()
#data[mask.bbox.slices] *= 1 - mask.data
empty_mask[mask.bbox.slices] += mask
print('Step6')
dlt = np.arange(0, 50, 1)
np.delete(empty_mask, [i for i in dlt], axis= 0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this cropping out borders?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

empty_mask = empty_mask[50:-50,50:-50]

np.delete(empty_mask, [i+data.shape[0] for i in dlt], axis= 0)
np.delete(empty_mask, [i for i in dlt], axis= 1)
np.delete(empty_mask, [i+data.shape[1] for i in dlt], axis= 1)
#print(empty_mask.data)
print('Step7')
plt.imshow(empty_mask.data, norm=LogNorm(vmin=10, vmax=100))
lg = np.log(empty_mask.data+.001)
plt.imsave(fname='new_mask.png', arr=lg, cmap='viridis', dpi = 300)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should return as opposed to imsaving.

#plt.show()
#temp_im = fits.PrimaryHDU(data).writeto('/home/luca/Desktop/mask_test')
#return data

#mask(img)