/
strehlcube.py
131 lines (113 loc) · 5.21 KB
/
strehlcube.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
from pyraf import iraf
import math
import os
import re
import shutil
import time
import tempfile
import pyfits
import numpy as np
import matplotlib
matplotlib.use('agg') # cannot import pyplot within pyraf without this
from matplotlib import pyplot as plt
# why won't logging work in PyRAF :(
from aotools.util import debug, info, warn, error, write_table, parse_ranges
from aotools.strehl import (Frame, generate_pupil, generate_circular_mask,
generate_psf_full, compute_psf_scale, generate_scaled_psf, first_min_from_core, avgrow,
avgrow_median_subtract, curve_of_growth, profile_from_growthcurve,
daofind_brightest
)
from aotools.cubetoframes import split_frames
def strehlcube(cubefile, rangespec, primary, secondary, dimension, f_number,
pixel_scale, lambda_mean, growth_step, fwhmpsf, threshold, quiet):
start_time = time.time()
info("Started at:", start_time)
if not os.path.exists(cubefile):
raise RuntimeError("No file named {0}".format(cubefile))
cubefile_base = os.path.splitext(os.path.basename(cubefile))[0]
# I: compute ideal psf
scale_to_physical, plate_scale_px, min_radius_real = compute_psf_scale(
dimension,
primary,
secondary,
f_number,
lambda_mean,
pixel_scale
)
scaled_psf, scaled_psf_ctr, max_aperture_radius = generate_scaled_psf(
dimension,
primary,
secondary,
scale_to_physical
)
# wrap psf in a frame
psf = Frame(scaled_psf, scaled_psf_ctr)
# precompute CoG and profile to be rescaled later
curve_of_growth(psf, max_aperture_radius, step=growth_step, quiet=quiet)
profile_from_growthcurve(psf)
# II: analyze images
# values and functions to rescale our PSF Frame computed values
# to physical counts
max_extent_px = 2.5 / plate_scale_px # After 2.5" we're almost certainly measuring noise
debug("after 2.5'' or", max_extent_px, "px we're almost certainly measuring noise")
def max_flux(frame):
"""Frame max integrated flux (for a radius less than 2.5'')"""
return np.max(frame.fluxes[frame.radii <= max_extent_px])
def scale_psf_fluxes(frame, psf):
"""
Returns a profile and curve of growth values for the ideal PSF
scaled such that the total integrated flux is equivalent to the
maximum flux in the frame passed as the first argument.
"""
scale_factor = (max_flux(frame) / max_flux(psf))
return psf.profile * scale_factor, psf.fluxes * scale_factor
tmp_target_dir = tempfile.mkdtemp()
ranges = parse_ranges(rangespec)
debug("splitting ranges", ranges)
fits_frames = split_frames(cubefile, ranges, tmp_target_dir)
debug("working in", tmp_target_dir, "with frames", fits_frames)
# set up array to hold each frame's analysis data
radii_count = psf.radii.shape[0]
frame_count = len(fits_frames)
shape = (frame_count, 5, radii_count)
analysis_frames = np.zeros(shape)
# [cog x count, prof x count, ideal x count, idealprof x count, strehl x count] x frames
strehl_rows = []
for fits_frame in fits_frames:
bright = daofind_brightest(fits_frame, fwhmpsf, threshold)
center_col, center_row = bright['XCENTER'], bright['YCENTER']
# this is slightly dumb... parse the frame # out of the filename
frame_num = int(re.findall(r'\d+', os.path.basename(fits_frame))[0])
debug("frame #", frame_num, "has brightest at", center_col, center_row)
frame = Frame(pyfits.getdata(fits_frame), (float(center_col), float(center_row)))
debug("loaded frame from", fits_frame)
# subtract median row to handle light/charge leakage biasing measurements
exclude_from, exclude_to = frame.ybounds(r=int(max_extent_px)) # exclude region of max_extent_px around center of frame
avgrow_median_subtract(frame, exclude_from, exclude_to)
debug("median subtracted frame")
curve_of_growth(frame, max_aperture_radius, step=growth_step, quiet=quiet)
debug("curve of growth generated")
profile_from_growthcurve(frame)
debug("profile generated")
# scale psf.fluxes and psf.profile to a max value determined from frame
ideal_profile, ideal_fluxes = scale_psf_fluxes(frame, psf)
strehls_for_all_radii = frame.fluxes / ideal_fluxes
strehl_rows.append((frame_num, strehls_for_all_radii))
outfile = "{0}_{1}_strehlseries.txt".format(cubefile_base, rangespec)
debug("writing strehl series to", outfile)
with open(outfile, 'w') as f:
f.write("# columns 2 and up are the pixel radii at which we computed the Strehl ratio")
f.write("# frameidx\t")
f.write('\t'.join(map(str, psf.radii)))
f.write('\n')
for idx, ratios in strehl_rows:
f.write(str(idx))
f.write('\t')
f.write('\t'.join(map(str, ratios)))
f.write('\n')
debug("removing exploded cube from", tmp_target_dir)
shutil.rmtree(tmp_target_dir)
info("Completed at:", time.time())
info("Total time:", time.time() - start_time)
parfile = iraf.osfn("aotools$strehlcube.par")
t = iraf.IrafTaskFactory(taskname="strehlcube", value=parfile, function=strehlcube)