Skip to content

Commit fdf045f

Browse files
committed
Updating the make_report module to print best duration/depth, fixing requirements for remote systems like Travis, adding extra metadata to FITS output
1 parent 6f5214d commit fdf045f

File tree

5 files changed

+95
-42
lines changed

5 files changed

+95
-42
lines changed

.travis.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ before_install:
1414
# Install packages
1515
install:
1616
- conda install --yes python=$TRAVIS_PYTHON_VERSION atlas numpy scipy matplotlib dateutil pip pandas=0.13.0
17-
- pip install -r python/requirements.txt
18-
- pip install openpyxl==1.8.6
17+
- pip install -r python/requirements.txt --allow-external pil --allow-unverified pil
1918

2019
# Run test
2120
script:

python/clean_signal.py

+31-25
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ class NonIntegerClustersError(Exception):
2222

2323
def clean_signal(time, flux, dtime, dflux, dfluxerr, out):
2424
'''
25-
Remove possible eclipsing binary signals from a light curve. This works best
26-
on deep, strongly periodic signals, so it is unlikely to clean transit signals
27-
(though it sometimes will). This should help BLS pulse find less prominent
28-
signals in the same data.
25+
Remove possible eclipsing binary signals from a light curve. This works
26+
best on deep, strongly periodic signals, so it is unlikely to clean
27+
transit signals (though it sometimes will). This should help BLS pulse
28+
find less prominent signals in the same data.
2929
3030
:param time: Raw time vector (no detrending or binning)
3131
:type time: np.ndarray
@@ -42,15 +42,17 @@ def clean_signal(time, flux, dtime, dflux, dfluxerr, out):
4242
'''
4343
# We restrict the "standard deviation" of the cluster to be 5% of the
4444
# size of the space.
45-
size = max(np.nanmax(np.absolute(out['depth_dip'])), np.nanmax(out['depth_blip']))
45+
size = max(np.nanmax(np.absolute(out['depth_dip'])),
46+
np.nanmax(out['depth_blip']))
4647
mean_flux_err = 0.05 * size
4748

48-
# Construct an array of all the useful quantities. We will only be finding
49-
# clusters in the first two dimensions! The other dimensions are for bookkeeping.
49+
# Construct an array of all the useful quantities. We will only be
50+
# finding clusters in the first two dimensions! The other dimensions are
51+
# for bookkeeping.
5052
ndx = np.where((out['srsq_dip'] > 0.) & (out['srsq_blip'] > 0.))
5153
X = np.column_stack((out['depth_dip'][ndx], out['depth_blip'][ndx],
52-
out['duration_dip'][ndx], out['duration_blip'][ndx], out['midtime_dip'][ndx],
53-
out['midtime_blip'][ndx]))
54+
out['duration_dip'][ndx], out['duration_blip'][ndx],
55+
out['midtime_dip'][ndx], out['midtime_blip'][ndx]))
5456

5557
metric = lambda x, y: np.sqrt((x[0] - y[0])**2. / mean_flux_err**2. +
5658
(x[1] - y[1])**2. / mean_flux_err**2.)
@@ -95,18 +97,19 @@ def clean_signal(time, flux, dtime, dflux, dfluxerr, out):
9597
class_member_mask & core_samples_mask, err_flux=mean_flux_err)
9698
except NoClustersError:
9799
# We didn't find any clusters at all. This is a good place to stop.
98-
logger.info('DBSCAN did not resolve any clusters in the depth_dip/period '
99-
'space; stopping algorithm.')
100+
logger.info('DBSCAN did not resolve any clusters in the '
101+
'depth_dip/period space; stopping algorithm.')
100102
raise RuntimeError
101103
except NonIntegerClustersError:
102104
# Something weird is going on. Try one more time with a step of 2,
103105
# then quit, marking this system for further consideration.
104106
try:
105-
best_period, best_duration, best_phase = __do_period_search(X, time,
106-
class_member_mask & core_samples_mask, err_flux=mean_flux_err, step=2)
107+
best_period, best_duration, best_phase = __do_period_search(X,
108+
time, class_member_mask & core_samples_mask,
109+
err_flux=mean_flux_err, step=2)
107110
except (NoClustersError, NonIntegerClustersError):
108-
logger.warning('DBSCAN found multiple clusters that do not look like '
109-
'integer multiples; investigate!')
111+
logger.warning('DBSCAN found multiple clusters that do not look '
112+
'like integer multiples; investigate!')
110113
raise RuntimeError
111114

112115
def boxcar(time, duration, depth, P, phase):
@@ -119,7 +122,8 @@ def boxcar(time, duration, depth, P, phase):
119122

120123
return flux
121124

122-
p0 = np.array([best_duration, depth, best_period, best_phase], dtype='float64')
125+
p0 = np.array([best_duration, depth, best_period, best_phase],
126+
dtype='float64')
123127
logger.info('Best guess boxcar parameters:\n\t' + str(p0))
124128

125129
ndx = np.where(np.isfinite(dflux))
@@ -128,6 +132,7 @@ def boxcar(time, duration, depth, P, phase):
128132
logger.info('Best fit boxcar parameters:\n\t' + str(pbest))
129133

130134
best_duration = pbest[0]
135+
best_depth = pbest[1]
131136
best_period = pbest[2]
132137
best_phase = pbest[3]
133138

@@ -136,7 +141,8 @@ def boxcar(time, duration, depth, P, phase):
136141
(pftime < best_phase + 2. * best_duration))
137142
flux[ndx] = np.nan
138143

139-
return dict(period=best_period, duration=best_duration, phase=best_phase)
144+
return dict(period=best_period, duration=best_duration, depth=best_depth,
145+
phase=best_phase)
140146

141147

142148
def __do_period_search(X, time, mask, step=1, err_midtime=0.1, err_flux=0.01,
@@ -150,9 +156,9 @@ def __do_period_search(X, time, mask, step=1, err_midtime=0.1, err_flux=0.01,
150156
metric = lambda x, y: np.sqrt((x[0] - y[0])**2. / err_flux**2. + \
151157
(x[1] - y[1])**2. / err_midtime**2.)
152158

153-
# Search for clusters a second time, this time to identify the period. We expect
154-
# a cluster around the mean value and less significant ones around integer
155-
# multiples of that value.
159+
# Search for clusters a second time, this time to identify the period.
160+
# We expect a cluster around the mean value and less significant ones
161+
# around integer multiples of that value.
156162
try:
157163
db = DBSCAN(eps=1., min_samples=10, metric=metric).fit(Y[:,0:2])
158164
except ValueError:
@@ -167,9 +173,9 @@ def __do_period_search(X, time, mask, step=1, err_midtime=0.1, err_flux=0.01,
167173
n_clusters_ = len(unique_labels) - (1 if -1 in labels else 0)
168174

169175
if n_clusters_ == 1:
170-
# This is the best-case scenario. The best choice for the period is just
171-
# the mean of the consecutive differences. The phase and duration follow
172-
# easily.
176+
# This is the best-case scenario. The best choice for the period is
177+
# just the mean of the consecutive differences. The phase and
178+
# duration follow easily.
173179
class_member_mask = (labels != -1)
174180

175181
best_period = np.mean(Y[class_member_mask & core_samples_mask][:,1])
@@ -197,8 +203,8 @@ def __do_period_search(X, time, mask, step=1, err_midtime=0.1, err_flux=0.01,
197203
candidate_periods.append([np.mean(Y[class_member_mask &
198204
core_samples_mask][:,1]), kk])
199205

200-
# Check for integer multiples in the candidate periods list. The modulus
201-
# by the minimum one should be sufficient.
206+
# Check for integer multiples in the candidate periods list. The
207+
# modulus by the minimum one should be sufficient.
202208
candidate_periods = np.array(candidate_periods)
203209
min_period = np.amin(candidate_periods[:,0])
204210
mods = np.mod(candidate_periods[:,0], min_period)

python/fits_output.py

+54-12
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,24 @@ def __init__(self):
1414
'''
1515
Initialize the object.
1616
'''
17+
self.prihdr = None
1718
self.prihdu = None
1819
self.cfghdu = None
1920
self.ext_list = []
2021

2122

22-
def make_header(self, kic_id):
23+
def make_header(self, kic_cadence_id):
2324
'''
2425
Create the FITS header. Currently, only the KIC ID of the relevant star
2526
is saved in this header, but other fields will be added later.
2627
2728
:param kic_id: KIC ID of this star
2829
:type kic_id: str
2930
'''
30-
prihdr = pyfits.Header()
31-
prihdr['KIC_ID'] = kic_id
32-
self.prihdu = pyfits.PrimaryHDU(header=prihdr)
31+
self.prihdr = pyfits.Header()
32+
kic_id, cadence = kic_cadence_id.split('_')
33+
self.prihdr['KIC_ID'] = kic_id
34+
self.prihdr['CADENCE'] = 'long' if cadence == 'llc' else 'short'
3335

3436

3537
def push_bls_output(self, bls_out):
@@ -67,17 +69,39 @@ def push_detrended_lightcurve(self, time, flux, fluxerr, clean_out=None):
6769
:param clean_out: Unprocessed output from ``clean_signal``
6870
:type clean_out: dict
6971
'''
72+
hdr = pyfits.Header()
73+
7074
if clean_out is not None:
71-
hdr = pyfits.Header()
7275
keys = clean_out.keys()
7376
vals = clean_out.values()
7477

7578
for k, v in zip(keys, vals):
7679
hdr[k] = v
77-
else:
78-
hdr = None
7980

80-
columns = [pyfits.Column(name='Time', array=time, format='D'),
81+
try:
82+
hdr.comments['period'] = 'period of strongest signal [days]'
83+
except KeyError:
84+
pass
85+
86+
try:
87+
hdr.comments['phase'] = 'phase of strongest periodic ' \
88+
'signal [XXXXX]'
89+
except KeyError:
90+
pass
91+
92+
try:
93+
hdr.comments['duration'] = 'duration of strongest ' \
94+
'periodic signal [days]'
95+
except KeyError:
96+
pass
97+
98+
try:
99+
hdr.comments['depth'] = 'depth of strongest periodic signal'
100+
except KeyError:
101+
pass
102+
103+
columns = [pyfits.Column(name='Time', array=time, format='D',
104+
unit='BJD - 2454833'),
81105
pyfits.Column(name='Flux', array=flux, format='D'),
82106
pyfits.Column(name='Flux error', array=fluxerr, format='D')]
83107
cols = pyfits.ColDefs(columns)
@@ -100,7 +124,11 @@ def push_config(self, config):
100124
columns = [pyfits.Column(name='Parameter', array=keys, format='A20'),
101125
pyfits.Column(name='Value', array=vals, format='A20')]
102126
cols = pyfits.ColDefs(columns)
103-
self.cfghdu = pyfits.TableHDU.from_columns(cols)
127+
128+
hdr = pyfits.Header()
129+
hdr['EXTNAME'] = 'INPUT_PARAMS'
130+
131+
self.cfghdu = pyfits.TableHDU.from_columns(cols, header=hdr)
104132

105133

106134
def write_file(self, fname, clobber=False):
@@ -109,13 +137,27 @@ def write_file(self, fname, clobber=False):
109137
110138
:param fname: The name of the file to save
111139
:type fname: str
112-
:param clobber: Whether to clobber an existing output file; passed directly to pyfits
140+
:param clobber: Whether to clobber an existing output file; passed
141+
directly to pyfits
113142
:type clobber: bool
114143
'''
115-
if self.prihdu is not None:
116-
hdus = [self.prihdu]
144+
hdus = []
145+
146+
if self.prihdr is not None:
147+
self.prihdr['N_EXTEN'] = (len(self.ext_list) + 1,
148+
'(n_passes * 2) + 1')
149+
self.prihdu = pyfits.PrimaryHDU(header=self.prihdr)
150+
hdus.append(self.prihdu)
117151

118152
if len(self.ext_list) > 0:
153+
j = len(self.ext_list) / 2
154+
155+
for i in xrange(0,len(self.ext_list),2):
156+
self.ext_list[i].header['EXTNAME'] = 'BLIP-DIP_Pass_%02d' % j
157+
self.ext_list[i+1].header['EXTNAME'] = 'TIME-FLUX_Pass_%02d' % j
158+
159+
j -= 1
160+
119161
hdus.extend(self.ext_list)
120162

121163
if self.cfghdu is not None:

python/postprocessing/make_report.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ def __init_parser():
9292
period = lchdr['period']
9393
phase = lchdr['phase']
9494
duration = lchdr['duration']
95+
depth = lchdr['depth']
9596

9697
pftime = np.mod(time, period)
9798
signal_mask = ((pftime > phase - 0.5 * duration) &
@@ -116,7 +117,11 @@ def __init_parser():
116117
plt.xlabel(r'Time (days)')
117118
plt.ylabel(r'Flux')
118119
plt.figtext(0.05, 0.02,
119-
r'P = %.4f, phi = %.2f' % (period, phase / period))
120+
r'P = %.4f, phi = %.2f, W = %.2f, delta = %.2g' % (period,
121+
phase / period, duration, depth))
122+
123+
plt.tight_layout()
124+
plt.subplots_adjust(bottom=0.15)
120125
except KeyError:
121126
plt.subplot(111)
122127
plt.scatter(time, flux, color=color1, edgecolor=edgecolor,
@@ -127,7 +132,7 @@ def __init_parser():
127132
plt.ylabel(r'Flux')
128133
plt.title(r'KIC' + kic_id + r', pass #%d' % count)
129134

130-
plt.tight_layout()
135+
plt.tight_layout()
131136

132137
imgdata = cStringIO.StringIO()
133138
fig.savefig(imgdata, format='png')

python/requirements.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
numpy
22
scipy
3-
pandas
3+
openpyxl==1.8.6
4+
pandas==0.13.0
45
matplotlib
56
cython
67
pyfits

0 commit comments

Comments
 (0)