Skip to content

Commit 40a0bc3

Browse files
committed
v0.7.0
Fixes or introduces a number of features that needed to be resolved before trying to move to the initial production run. These include the following changes: - Resolves #31 by introducing a new `title_quantiles` argument. Also modifies the default plotting options so now it just shows bins. - Removed the binned LOS log-likelihood, since this has now been superseeded by the sample-based version. Also added in an option to treat the foreground as an additive component, rather than just a separate number. - Modifications to some of the internals in the `seds` module to make things easier to pull out. Should resolve #28. - Cleaned up imports and similar things so the code should now be more self-contained. Next up is working on the clusters module so I can fit some isochrones!
1 parent 09e37d0 commit 40a0bc3

File tree

11 files changed

+69
-225
lines changed

11 files changed

+69
-225
lines changed

README.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,26 @@ stellar models, it is configured for two by default:
2525
and [Bayestar](https://arxiv.org/pdf/1401.1508.pdf).
2626

2727
#### Zero-points
28-
Zero-point offsets in several bands have been derived using Gaia data
29-
and can be included during runtime.
28+
Zero-point offsets in several bands have been estimated using Gaia data
29+
and can be included during runtime.
30+
**These are currently not thoroughly vetted, so use at your own risk.**
3031

3132
#### Dust Map
3233
`brutus` is able to incorporate a 3-D dust prior. The current prior is
33-
based on the "Bayestar17" dust map from
34-
[Green et al. (2018)](https://arxiv.org/abs/1801.03555).
34+
based on the "Bayestar19" dust map from
35+
[Green et al. (2019)](https://arxiv.org/abs/1905.02734).
3536

3637
#### Generating SEDs
3738
`brutus` contains built-in SED generation utilities based on the MIST
3839
stellar models, modeled off of
3940
[`minesweeper`](https://github.com/pacargile/MINESweeper).
4041
These are optimized for either generating photometry from stellar mass
41-
tracks or for a single-age stellar isochrone, and are based on
42+
tracks or for a single-age stellar isochrone based on
4243
artificial neural networks trained on bolometric correction tables.
44+
4345
An empirical correction table to the models derived using several clusters is
4446
also provided, which improves the models down to ~0.5 solar masses.
47+
**These are currently not thoroughly vetted, so use at your own risk.**
4548

4649
Please contact Phil Cargile (pcargile@cfa.harvard.edu) and Josh Speagle
4750
(jspeagle@cfa.harvard.edu) for more information on the provided data files.

brutus/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
# -*- coding: utf-8 -*-
33

44
from __future__ import (division, print_function)
5-
from six.moves import range
65

76
from .fitting import *
87
from .utils import *
98

10-
__version__ = "0.6.9"
9+
__version__ = "0.7.0"

brutus/cluster.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,5 @@
77
"""
88

99
from __future__ import (print_function, division)
10-
import six
11-
from six.moves import range
12-
13-
import sys
14-
import os
15-
import warnings
16-
import math
17-
import numpy as np
18-
import warnings
19-
20-
from .utils import get_seds, add_mag
2110

2211
__all__ = [""]

brutus/dust.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,8 @@
88
"""
99

1010
from __future__ import (print_function, division)
11-
import six
12-
from six.moves import range
1311

14-
import sys
15-
import os
16-
import warnings
17-
import math
1812
import numpy as np
19-
import warnings
2013
import h5py
2114

2215
import astropy.coordinates as coordinates
@@ -287,9 +280,6 @@ def query(self, coords):
287280
288281
"""
289282

290-
# Get number of coordinates requested.
291-
n_coords_ret = coords.shape[0]
292-
293283
# Extract the correct angular pixel(s).
294284
try:
295285
pix_idx = self._find_data_idx(coords.l.deg, coords.b.deg)

brutus/filters.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
"""
88

99
from __future__ import (print_function, division)
10-
import six
11-
from six.moves import range
1210

1311
# Define the set of filters available for the provided MIST models.
1412
# The Bayestar models are only defined for PanSTARRS `grizy` and 2MASS.

brutus/fitting.py

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,10 @@
77
"""
88

99
from __future__ import (print_function, division)
10-
from six.moves import range
1110

1211
import sys
13-
import os
1412
import warnings
15-
import math
1613
import numpy as np
17-
import warnings
1814
import h5py
1915
import time
2016
from scipy.special import xlogy, gammaln
@@ -24,8 +20,10 @@
2420
except ImportError:
2521
from scipy.misc import logsumexp
2622

27-
from .pdf import *
28-
from .utils import *
23+
from .pdf import imf_lnprior, ps1_MrLF_lnprior
24+
from .pdf import parallax_lnprior, scale_parallax_lnprior
25+
from .pdf import gal_lnprior, dust_lnprior
26+
from .utils import _function_wrapper, _inverse3, magnitude, get_seds
2927

3028
__all__ = ["loglike", "_optimize_fit", "BruteForce", "_lnpost"]
3129

@@ -608,9 +606,9 @@ def __init__(self, models, models_labels, labels_mask, pool=None):
608606

609607
def fit(self, data, data_err, data_mask, data_labels, save_file,
610608
phot_offsets=None, parallax=None, parallax_err=None,
611-
Nmc_prior=100, avlim=(0., 6.), av_gauss=None,
609+
Nmc_prior=50, avlim=(0., 6.), av_gauss=None,
612610
rvlim=(1., 8.), rv_gauss=(3.32, 0.18), binary_frac=0.5,
613-
lnprior=None, wt_thresh=1e-3, cdf_thresh=2e-4, Ndraws=2000,
611+
lnprior=None, wt_thresh=1e-3, cdf_thresh=2e-4, Ndraws=500,
614612
apply_agewt=True, apply_grad=True,
615613
lndistprior=None, lndustprior=None, dustfile='bayestar2017_v1.h5',
616614
apply_dlabels=True, data_coords=None, logl_dim_prior=True,
@@ -837,9 +835,9 @@ def fit(self, data, data_err, data_mask, data_labels, save_file,
837835
try:
838836
# Try reading in parallel-friendly way if possible.
839837
try:
840-
ft = h5py.File(dustfile, 'r', libver='latest', swmr=True)
838+
h5py.File(dustfile, 'r', libver='latest', swmr=True)
841839
except:
842-
ft = h5py.File(dustfile, 'r')
840+
h5py.File(dustfile, 'r')
843841
pass
844842
except:
845843
raise ValueError("The default dust prior is being used but "
@@ -1152,13 +1150,12 @@ def _fit(self, data, data_err, data_mask,
11521150
11531151
"""
11541152

1155-
Ndata, Nmodels = len(data), self.NMODEL
1153+
Ndata = len(data)
11561154
models = np.array(self.models)
11571155
if wt_thresh is None and cdf_thresh is None:
11581156
wt_thresh = -np.inf # default to no clipping/thresholding
11591157
if rstate is None:
11601158
rstate = np.random
1161-
mvn = rstate.multivariate_normal
11621159
if parallax is not None and parallax_err is None:
11631160
raise ValueError("Must provide both `parallax` and "
11641161
"`parallax_err`.")
@@ -1189,9 +1186,9 @@ def _fit(self, data, data_err, data_mask,
11891186
try:
11901187
# Try reading in parallel-friendly way if possible.
11911188
try:
1192-
ft = h5py.File(dustfile, 'r', libver='latest', swmr=True)
1189+
h5py.File(dustfile, 'r', libver='latest', swmr=True)
11931190
except:
1194-
ft = h5py.File(dustfile, 'r')
1191+
h5py.File(dustfile, 'r')
11951192
pass
11961193
except:
11971194
raise ValueError("The default dust prior is being used but "

brutus/los.py

Lines changed: 10 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,17 @@
77
"""
88

99
from __future__ import (print_function, division)
10-
import six
11-
from six.moves import range
1210

13-
import sys
14-
import os
1511
import warnings
16-
import math
1712
import numpy as np
18-
import warnings
1913
from scipy.stats import truncnorm
2014

2115
try:
2216
from scipy.special import logsumexp
2317
except ImportError:
2418
from scipy.misc import logsumexp
2519

26-
__all__ = ["LOS_clouds_priortransform", "LOS_clouds_loglike_bin",
27-
"LOS_clouds_loglike_samples",
20+
__all__ = ["LOS_clouds_priortransform", "LOS_clouds_loglike_samples",
2821
"kernel_tophat", "kernel_gauss", "kernel_lorentz"]
2922

3023

@@ -125,134 +118,9 @@ def LOS_clouds_priortransform(u, rlims=(0., 6.), dlims=(4., 19.),
125118
return x
126119

127120

128-
def LOS_clouds_loglike_bin(theta, cdfs, xedges, yedges, interpolate=True):
129-
"""
130-
Compute the log-likelihood for the cumulative reddening along the
131-
line of sight (LOS) parameterized by `theta`, given input binned
132-
stellar posteriors/bounds generated by `.pdf.bin_pdfs_distred`. Assumes
133-
a uniform outlier model in distance and reddening across our binned
134-
posteriors.
135-
136-
Parameters
137-
----------
138-
theta : `~numpy.ndarray` of shape `(Nparams,)`
139-
A collection of parameters that characterizes the cumulative
140-
reddening along the LOS. Contains the fraction of outliers `P_b`
141-
followed by the foreground reddening `fred` and a series of
142-
`(dist, red)` pairs for each "cloud" along the LOS.
143-
144-
cdfs : `~numpy.ndarray` of shape `(Nobj, Nxbin, Nybin)`
145-
Binned versions of the CDFs.
146-
147-
xedges : `~numpy.ndarray` of shape `(Nxbin+1,)`
148-
The edges defining the bins in distance.
149-
150-
yedges : `~numpy.ndarray` of shape `(Nybin+1,)`
151-
The edges defining the bins in reddening.
152-
153-
interpolate : bool, optional
154-
Whether to linearly interpolate between bins (defined by their central
155-
positions). Default is `True`.
156-
157-
Returns
158-
-------
159-
loglike : float
160-
The computed log-likelihood.
161-
162-
"""
163-
164-
# Grab parameters.
165-
pb = theta[0]
166-
reds, dists = np.atleast_1d(theta[1::2]), np.atleast_1d(theta[2::2])
167-
168-
# Convert to bin coordinates.
169-
dx, dy = xedges[1] - xedges[0], yedges[1] - yedges[0]
170-
Nxedges, Nyedges = len(xedges), len(yedges)
171-
Nxbin, Nybin = Nxedges - 1, Nyedges - 1
172-
x_ctrs = np.arange(0.5, Nxbin, 1.)
173-
y_ctrs = np.arange(0.5, Nybin, 1.)
174-
x = np.concatenate(([0], (dists - xedges[0]) / dx, [Nxbin]))
175-
y = (reds - yedges[0]) / dy
176-
177-
# Find (x,y) neighbors in bin space.
178-
x1 = np.array(np.floor(x - 0.5), dtype='int')
179-
x2 = np.array(np.ceil(x - 0.5), dtype='int')
180-
y1 = np.array(np.floor(y - 0.5), dtype='int')
181-
y2 = np.array(np.ceil(y - 0.5), dtype='int')
182-
183-
# Threshold values to bin edges.
184-
x1[np.where(x1 < 0)] = 0
185-
x1[np.where(x1 >= Nxbin)] = Nxbin - 1
186-
x2[np.where(x2 < 0)] = 0
187-
x2[np.where(x2 >= Nxbin)] = Nxbin - 1
188-
y1[np.where(y1 < 0)] = 0
189-
y1[np.where(y1 >= Nybin)] = Nybin - 1
190-
y2[np.where(y2 < 0)] = 0
191-
y2[np.where(y2 >= Nybin)] = Nybin - 1
192-
193-
# Threshold (x,y) to edges (and shift to deal with centers).
194-
x[np.where(x < 0.5)] = 0.5
195-
x[np.where(x > Nxbin - 0.5)] = Nxbin - 0.5
196-
y[np.where(y < 0.5)] = 0.5
197-
y[np.where(y > Nybin - 0.5)] = Nybin - 0.5
198-
199-
# Define "left" and "right" versions for xs.
200-
x1l, x1r = x1[:-1], x1[1:]
201-
x2l, x2r = x2[:-1], x2[1:]
202-
xl, xr = x[:-1], x[1:]
203-
204-
# Compute integral along LOS using the provided CDFs.
205-
if interpolate:
206-
# Interpolate between bins (left side).
207-
# Define values q(x_i, y_i).
208-
q11, q12, q21, q22 = (cdfs[:, x1l, y1], cdfs[:, x1l, y2],
209-
cdfs[:, x2l, y1], cdfs[:, x2l, y2])
210-
# Compute areas.
211-
dx1, dx2 = (xl - x_ctrs[x1l]), (x_ctrs[x2l] - xl)
212-
dy1, dy2 = (y - y_ctrs[y1]), (y_ctrs[y2] - y)
213-
# Interpolate in x.
214-
qp1, qp2 = (q11 * dx2 + q21 * dx1), (q12 * dx2 + q22 * dx1)
215-
xsel = np.where(~((dx1 > 0.) & (dx2 > 0.))) # deal with edges
216-
qp1[:, xsel], qp2[:, xsel] = q11[:, xsel], q12[:, xsel] # replace
217-
# Interpolate in y.
218-
cdf_left = qp1 * dy2 + qp2 * dy1
219-
ysel = np.where(~((dy1 > 0.) & (dy2 > 0.))) # deal with edges
220-
cdf_left[ysel] = qp1[ysel] # replace edges
221-
222-
# Interpolate between the bins (right side).
223-
# Define values q(x_i, y_i).
224-
q11, q12, q21, q22 = (cdfs[:, x1r, y1], cdfs[:, x1r, y2],
225-
cdfs[:, x2r, y1], cdfs[:, x2r, y2])
226-
# Compute areas.
227-
dx1, dx2 = (xr - x_ctrs[x1r]), (x_ctrs[x2r] - xr)
228-
dy1, dy2 = (y - y_ctrs[y1]), (y_ctrs[y2] - y)
229-
# Interpolate in x.
230-
qp1, qp2 = (q11 * dx2 + q21 * dx1), (q12 * dx2 + q22 * dx1)
231-
xsel = np.where(~((dx1 > 0.) & (dx2 > 0.))) # deal with edges
232-
qp1[:, xsel], qp2[:, xsel] = q11[:, xsel], q12[:, xsel] # replace
233-
# Interpolate in y.
234-
cdf_right = qp1 * dy2 + qp2 * dy1
235-
ysel = np.where(~((dy1 > 0.) & (dy2 > 0.))) # deal with edges
236-
cdf_right[ysel] = qp1[ysel] # replace edges
237-
else:
238-
# Just use the values from the bin we're currently in.
239-
cdf_left, cdf_right = cdfs[:, x1l, y1], cdfs[:, x1r, y1]
240-
241-
# Compute likelihood.
242-
likes = np.sum(cdf_right - cdf_left, axis=1)
243-
244-
# Add in outlier mixture model. Assume uniform in (x, y) with `pb` weight.
245-
likes = pb * (1. / (Nybin * Nxbin)) + (1. - pb) * likes
246-
247-
# Compute total log-likelihood.
248-
loglike = np.sum(np.log(likes))
249-
250-
return loglike
251-
252-
253121
def LOS_clouds_loglike_samples(theta, dsamps, rsamps, kernel='gauss',
254122
rlims=(0., 6.), template_reds=None,
255-
Ndraws=25):
123+
Ndraws=25, additive_foreground=False):
256124
"""
257125
Compute the log-likelihood for the cumulative reddening along the
258126
line of sight (LOS) parameterized by `theta`, given a set of input
@@ -293,6 +161,10 @@ def LOS_clouds_loglike_samples(theta, dsamps, rsamps, kernel='gauss',
293161
Ndraws : int, optional
294162
The number of draws to use for each star. Default is `25`.
295163
164+
additive_foreground : bool, optional
165+
Whether the foreground is treated as just another value or added
166+
to all background values. Default is `False`.
167+
296168
Returns
297169
-------
298170
loglike : float
@@ -336,6 +208,10 @@ def LOS_clouds_loglike_samples(theta, dsamps, rsamps, kernel='gauss',
336208
if template_reds is not None:
337209
reds[1:] *= template_reds[None, :, None] # reds[1:] are rescalings
338210

211+
# Adjust reddenings after the foreground if needed.
212+
if additive_foreground:
213+
reds[1:] += reds[0] # add foreground to background
214+
339215
# Define kernel parameters (mean, sigma) per LOS chunk.
340216
kparams = np.array([(r, rsmooth) for r in reds])
341217
kparams[0][1] = rsmooth0

0 commit comments

Comments
 (0)