In [1]:
import warnings
import time
from datetime import datetime
import os
import sys
import numpy as np
import matplotlib
%matplotlib ipympl
import matplotlib.pyplot as plt
import pandas as pd

import multiprocessing
from multiprocessing import Pool

import photutils

from pathlib import Path

import astropy.units as u
from astropy import stats
from astropy.io import fits
from astropy.table import Table, hstack, vstack

from astropy.modeling.models import Gaussian2D, Polynomial2D, Moffat2D
from astropy.modeling.fitting import LevMarLSQFitter

In [2]:
%cd "/Volumes/LACIE SHARE/bino_gdr"
root = Path(".")


/Volumes/LACIE SHARE/bino_gdr

In [3]:
%ls


GDR1/ GDR2/

In [4]:
hdr_keys = ['DATE-OBS', 'RA', 'DEC', 'AZ', 'EL', 'ROT', 'TEMP', 'FOCUS', 'EXPTIME']
guiders = ['GDR1', 'GDR2']
darks = {}
darks['GDR1'] = fits.open(root / "GDR1" / "box1_median_dark.fits")[0].data
darks['GDR2'] = fits.open(root / "GDR2" / "box1_median_dark.fits")[0].data

# 13 um pixels binned 2x2 and 0.167 mm/arcsec plate scale
pix_scale = 2 * 0.013 / 0.167  # arcsec/pixel

apsize = int(5. / pix_scale)  # 5" arcsec aperture width
print(apsize)


32

In [5]:
def process_image(fitsfile, retall=False):    
    with fits.open(fitsfile) as hdu:
        hdr = hdu[0].header
        data = hdu[0].data

    try:
        mean, median, std = stats.sigma_clipped_stats(data, sigma=4.0, iters=5)
    except:
        if retall:
            return None, data, None, None, None
        else:
            return None
    
    # in some images there's a big step in the background so we take the median along each row and subtract that vector
    m = np.median(data, axis=1)
    data = data - m[:, None]
    
    daofind = photutils.DAOStarFinder(fwhm=8.0, threshold=4.*std, sharphi=0.9, exclude_border=True)
    srcs = daofind(data)
    nsrcs = len(srcs)
    if nsrcs == 0:
        print(f"No star detected in {fitsfile}")
        if retall:
            return None, data, None, None, None
        else:
            return None

    srcs.sort('flux')
    srcs.reverse()
    
    apers = photutils.CircularAperture(
        (srcs['xcentroid'][0], srcs['ycentroid'][0]),
        r=apsize/2.
    )
    masks = apers.to_mask(method="subpixel")
    
    subim = masks[0].cutout(data)
    props = photutils.data_properties(subim)
    tline = hstack([srcs[0], props.to_table()])
    tline['filename'] = fitsfile
    try:
        for k in hdr_keys:
            tline[k] = hdr[k]
    except:
        if retall:
            return None, data, None, None, None
        else:
            return None

    y, x = np.mgrid[:data.shape[0], :data.shape[1]]
    sigma = (tline['semimajor_axis_sigma'][0].value + tline['semiminor_axis_sigma'][0].value) / 2.
    
    fitter = LevMarLSQFitter()
    gauss_model = Gaussian2D(
        amplitude=data.max(),
        x_mean=data.shape[1]/2.,
        y_mean=data.shape[0]/2.,
        x_stddev = sigma,
        y_stddev = sigma
    )
    moffat_model = Moffat2D(
        amplitude=data.max(),
        x_0=data.shape[1]/2.,
        y_0=data.shape[0]/2.,
        gamma=sigma
    )
    gauss_fit = fitter(gauss_model, x, y, data)
    moffat_fit = fitter(moffat_model, x, y, data)
    if retall:
        print(gauss_fit)
        print(moffat_fit)
    
    gamma = moffat_fit.gamma.value
    alpha = moffat_fit.alpha.value
    moffat_fwhm = pix_scale * 2. * gamma * np.sqrt(2.**(1./alpha) - 1.)
    gauss_fwhm = pix_scale * 0.5 * (gauss_fit.x_stddev.value + gauss_fit.y_stddev.value) * stats.gaussian_sigma_to_fwhm
    moment_fwhm = pix_scale * 0.5 * (tline['semimajor_axis_sigma'] + tline['semiminor_axis_sigma']) * stats.gaussian_sigma_to_fwhm
    
    tline['gauss_x'] = gauss_fit.x_mean.value
    tline['gauss_y'] = gauss_fit.y_mean.value
    tline['gauss_sigx'] = gauss_fit.x_stddev.value
    tline['gauss_sigy'] = gauss_fit.y_stddev.value
    tline['gauss_amplitude'] = gauss_fit.amplitude.value
    tline['gauss_theta'] = gauss_fit.theta.value
    tline['moffat_amplitude'] = moffat_fit.amplitude.value
    tline['moffat_gamma'] = gamma
    tline['moffat_alpha'] = alpha
    tline['moffat_x'] = moffat_fit.x_0.value
    tline['moffat_y'] = moffat_fit.y_0.value
    tline['stats_mean'] = mean
    tline['stats_median'] = median
    tline['stats_std'] = std
    tline['moment_fwhm'] = moment_fwhm
    tline['gauss_fwhm'] = gauss_fwhm
    tline['moffat_fwhm'] = moffat_fwhm
    resid = data - moffat_fit(x, y)
    if retall:
        return tline, data, resid, gauss_fit, moffat_fit
    else:
        del data
        del hdr
        del x
        del y
        del resid
        return tline

In [6]:
fdir = root / "GDR2" / "2018.0412"

In [7]:
files = sorted(list(fdir.glob("gdr*.fits")))

In [8]:
len(files)


Out[8]:
13068

In [9]:
t, i, resid, gf, mf = process_image("GDR2/2018.0412/gdr2_raw_box_img_2018.0412.111604.1.fits", retall=True)


Model: Gaussian2D
Inputs: ('x', 'y')
Outputs: ('z',)
Model set size: 1
Parameters:
      amplitude       x_mean        y_mean    ...   y_stddev       theta     
    ------------- ------------- ------------- ... ------------ --------------
    1336.89284083 64.5485862821 62.9145300226 ... 3.8739389863 0.168222944992
Model: Moffat2D
Inputs: ('x', 'y')
Outputs: ('z',)
Model set size: 1
Parameters:
     amplitude       x_0           y_0          gamma         alpha    
    ----------- ------------- ------------- ------------- -------------
    1539.627951 64.5477076039 62.8847691132 5.39650671914 1.93707481882

In [10]:
t


Out[10]:
QTable length=1
id_1xcentroid_1ycentroid_1sharpnessroundness1roundness2npixskypeakfluxmagid_2xcentroid_2ycentroid_2sky_centroidsky_centroid_icrssource_sumsource_sum_errbackground_sumbackground_meanbackground_at_centroidxminxmaxyminymaxmin_valuemax_valueminval_xposminval_yposmaxval_xposmaxval_yposareaequivalent_radiusperimetersemimajor_axis_sigmasemiminor_axis_sigmaeccentricityorientationellipticityelongationcovar_sigx2covar_sigxycovar_sigy2cxxcxycyyfilenameDATE-OBSRADECAZELROTTEMPFOCUSEXPTIMEgauss_xgauss_ygauss_sigxgauss_sigygauss_amplitudegauss_thetamoffat_amplitudemoffat_gammamoffat_alphamoffat_xmoffat_ystats_meanstats_medianstats_stdmoment_fwhmgauss_fwhmmoffat_fwhm
pixpixpixpixpixpixpixpixpixpixpix2pixpixpixpixradpix2pix2pix21 / pix21 / pix21 / pix2pix
int64float64float64float64float64float64float64float64float64float64float64int64float64float64objectobjectfloat64objectobjectobjectobjectfloat64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64str55str23float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64
164.526967238462.84586364010.440630002176-0.1075378980120.147596747858121.00.01479.018.7203354816-3.18078406833115.95588123154909616.125881921472224NoneNone137655.0NoneNoneNoneNone0.032.00.032.0-14.51479.00.025.015.016.01089.018.61825625707596128.05.6017884024877845.2954035868235580.32618517613106646-1.54456626786853750.054694107247635241.057858633556580528.043595723069668-0.0875350304986412131.3777367305207730.035659075881396950.00019895751702163140.031870007593742825GDR2/2018.0412/gdr2_raw_box_img_2018.0412.111604.1.fits2018-04-12T11:16:04.52617.6684388968.87654.0689646252.65605322-66.168519688.30.01.064.548586282162.91453002263.41181207823.87393898631336.892840830.1682229449921539.6279515.396506719141.9370748188264.547707603962.88476911322553.326005262555.034.8339218781.99755712396858321.335546254171.1021672785

In [11]:
%matplotlib ipympl
plt.imshow(resid)
plt.show()



In [12]:
nproc = 8
with Pool(processes=nproc) as pool:  # my mac's i7 has 4 cores + hyperthreading so 8 virtual cores. 
    plines = pool.map(process_image, files)  # plines comes out in same order as fitslines!
plines = list(filter(None.__ne__, plines))  # trim out any None entries
df = Table(vstack(plines)).to_pandas()


WARNING: The fit may be unsuccessful; check fit_info['message'] for more information. [astropy.modeling.fitting]
WARNING: The fit may be unsuccessful; check fit_info['message'] for more information. [astropy.modeling.fitting]
WARNING: The fit may be unsuccessful; check fit_info['message'] for more information. [astropy.modeling.fitting]
WARNING: The fit may be unsuccessful; check fit_info['message'] for more information. [astropy.modeling.fitting]
WARNING: Sources were found, but none pass the sharpness and roundness criteria. [photutils.detection.findstars]
No star detected in GDR2/2018.0412/gdr2_cal_box_img_2018.0412.050320.1.fits
WARNING: The fit may be unsuccessful; check fit_info['message'] for more information. [astropy.modeling.fitting]
WARNING: Sources were found, but none pass the sharpness and roundness criteria. [photutils.detection.findstars]
No star detected in GDR2/2018.0412/gdr2_cal_box_img_2018.0412.053648.1.fits
WARNING: The fit may be unsuccessful; check fit_info['message'] for more information. [astropy.modeling.fitting]
No star detected in GDR2/2018.0412/gdr2_cal_box_img_2018.0412.051106.1.fits
No star detected in GDR2/2018.0412/gdr2_cal_box_img_2018.0412.051458.1.fits
WARNING: No sources were found. [photutils.detection.findstars]
No star detected in GDR2/2018.0412/gdr2_cal_box_img_2018.0412.080926.1.fits
No star detected in GDR2/2018.0412/gdr2_cal_box_img_2018.0412.080930.1.fits
No star detected in GDR2/2018.0412/gdr2_cal_box_img_2018.0412.080935.1.fits
No star detected in GDR2/2018.0412/gdr2_cal_box_img_2018.0412.080939.1.fits
No star detected in GDR2/2018.0412/gdr2_cal_box_img_2018.0412.080943.1.fits
WARNING: The fit may be unsuccessful; check fit_info['message'] for more information. [astropy.modeling.fitting]
WARNING: The fit may be unsuccessful; check fit_info['message'] for more information. [astropy.modeling.fitting]
No star detected in GDR2/2018.0412/gdr2_raw_box_img_2018.0412.050320.1.fits
No star detected in GDR2/2018.0412/gdr2_raw_box_img_2018.0412.051106.1.fits
WARNING: Sources were found, but none pass the sharpness and roundness criteria. [photutils.detection.findstars]
No star detected in GDR2/2018.0412/gdr2_raw_box_img_2018.0412.053648.1.fits
No star detected in GDR2/2018.0412/gdr2_raw_box_img_2018.0412.051458.1.fits
WARNING: No sources were found. [photutils.detection.findstars]
No star detected in GDR2/2018.0412/gdr2_raw_box_img_2018.0412.080926.1.fits
No star detected in GDR2/2018.0412/gdr2_raw_box_img_2018.0412.080930.1.fits
No star detected in GDR2/2018.0412/gdr2_raw_box_img_2018.0412.080935.1.fits
No star detected in GDR2/2018.0412/gdr2_raw_box_img_2018.0412.080939.1.fits
No star detected in GDR2/2018.0412/gdr2_raw_box_img_2018.0412.080943.1.fits

In [13]:
len(df)


Out[13]:
13050

In [14]:
%matplotlib ipympl
df.hist(column=["moffat_fwhm", 'gauss_fwhm', 'moment_fwhm'], range=(0, 4), bins=100, alpha=0.6)
df.hist(column=["moffat_alpha"], range=(0, 10), bins=100, alpha=0.6)


Out[14]:
array([[<matplotlib.axes._subplots.AxesSubplot object at 0x1c74d08048>]], dtype=object)

In [15]:
df.to_csv("2018_04_12.csv")

In [59]:
df.columns


Out[59]:
Index(['id_1', 'xcentroid_1', 'ycentroid_1', 'sharpness', 'roundness1',
       'roundness2', 'npix', 'sky', 'peak', 'flux', 'mag', 'id_2',
       'xcentroid_2', 'ycentroid_2', 'sky_centroid', 'sky_centroid_icrs',
       'source_sum', 'source_sum_err', 'background_sum', 'background_mean',
       'background_at_centroid', 'xmin', 'xmax', 'ymin', 'ymax', 'min_value',
       'max_value', 'minval_xpos', 'minval_ypos', 'maxval_xpos', 'maxval_ypos',
       'area', 'equivalent_radius', 'perimeter', 'semimajor_axis_sigma',
       'semiminor_axis_sigma', 'eccentricity', 'orientation', 'ellipticity',
       'elongation', 'covar_sigx2', 'covar_sigxy', 'covar_sigy2', 'cxx', 'cxy',
       'cyy', 'filename', 'DATE-OBS', 'RA', 'DEC', 'AZ', 'EL', 'ROT', 'TEMP',
       'FOCUS', 'EXPTIME', 'gauss_x', 'gauss_y', 'gauss_sigx', 'gauss_sigy',
       'gauss_amplitude', 'gauss_theta', 'moffat_amplitude', 'moffat_gamma',
       'moffat_alpha', 'moffat_x', 'moffat_y', 'stats_mean', 'stats_median',
       'stats_std', 'moment_fwhm', 'gauss_fwhm', 'moffat_fwhm'],
      dtype='object')

In [21]:
df.hist(column=['ROT'], range=(-180, 180.0), bins=100, alpha=0.6)


Out[21]:
array([[<matplotlib.axes._subplots.AxesSubplot object at 0x1c7e3897f0>]], dtype=object)

In [16]:
df['DATE-OBS']


Out[16]:
0        2018-04-12T02:38:53.111
1        2018-04-12T02:39:00.092
2        2018-04-12T02:39:07.104
3        2018-04-12T02:39:14.051
4        2018-04-12T02:39:25.211
5        2018-04-12T02:39:29.026
6        2018-04-12T02:39:32.938
7        2018-04-12T02:39:36.953
8        2018-04-12T02:39:40.809
9        2018-04-12T02:39:44.703
10       2018-04-12T02:39:48.601
11       2018-04-12T02:39:52.428
12       2018-04-12T02:39:56.617
13       2018-04-12T02:40:00.447
14       2018-04-12T02:40:04.328
15       2018-04-12T02:40:08.290
16       2018-04-12T02:40:12.283
17       2018-04-12T02:40:16.112
18       2018-04-12T02:40:20.053
19       2018-04-12T02:40:23.888
20       2018-04-12T02:40:27.732
21       2018-04-12T02:40:31.677
22       2018-04-12T02:40:35.519
23       2018-04-12T02:40:39.404
24       2018-04-12T02:40:43.397
25       2018-04-12T02:40:47.171
26       2018-04-12T02:40:51.035
27       2018-04-12T02:40:54.819
28       2018-04-12T02:40:58.694
29       2018-04-12T02:41:02.674
                  ...           
13020    2018-04-12T11:17:10.128
13021    2018-04-12T11:17:14.171
13022    2018-04-12T11:17:18.378
13023    2018-04-12T11:17:22.378
13024    2018-04-12T11:17:26.365
13025    2018-04-12T11:17:30.378
13026    2018-04-12T11:17:34.440
13027    2018-04-12T11:17:38.398
13028    2018-04-12T11:17:42.428
13029    2018-04-12T11:17:46.586
13030    2018-04-12T11:17:50.584
13031    2018-04-12T11:17:54.792
13032    2018-04-12T11:17:58.802
13033    2018-04-12T11:18:02.809
13034    2018-04-12T11:18:06.815
13035    2018-04-12T11:18:10.881
13036    2018-04-12T11:18:15.033
13037    2018-04-12T11:18:19.059
13038    2018-04-12T11:18:23.016
13039    2018-04-12T11:18:27.045
13040    2018-04-12T11:18:31.065
13041    2018-04-12T11:18:35.240
13042    2018-04-12T11:18:39.243
13043    2018-04-12T11:18:43.247
13044    2018-04-12T11:18:47.259
13045    2018-04-12T11:18:51.450
13046    2018-04-12T11:18:55.450
13047    2018-04-12T11:18:59.456
13048    2018-04-12T11:19:03.530
13049    2018-04-12T11:19:07.493
Name: DATE-OBS, Length: 13050, dtype: object

In [17]:
import gc

In [18]:
gc.collect()


Out[18]:
60990

In [14]:
test = fits.open("GDR2/2018.0209/gdr2_raw_box_img_2018.0209.114833.1.fits")[0].data

In [28]:
m = np.median(test, axis=1)
c = test - m[:, None]

In [29]:
%matplotlib ipympl
plt.imshow(c)
plt.show()



In [ ]: