| 
7 | 7 | """  | 
8 | 8 | 
 
  | 
9 | 9 | from __future__ import (print_function, division)  | 
10 |  | -import six  | 
11 |  | -from six.moves import range  | 
12 | 10 | 
 
  | 
13 |  | -import sys  | 
14 |  | -import os  | 
15 | 11 | import warnings  | 
16 |  | -import math  | 
17 | 12 | import numpy as np  | 
18 |  | -import warnings  | 
19 | 13 | from scipy.stats import truncnorm  | 
20 | 14 | 
 
  | 
21 | 15 | try:  | 
22 | 16 |     from scipy.special import logsumexp  | 
23 | 17 | except ImportError:  | 
24 | 18 |     from scipy.misc import logsumexp  | 
25 | 19 | 
 
  | 
26 |  | -__all__ = ["LOS_clouds_priortransform", "LOS_clouds_loglike_bin",  | 
27 |  | -           "LOS_clouds_loglike_samples",  | 
 | 20 | +__all__ = ["LOS_clouds_priortransform", "LOS_clouds_loglike_samples",  | 
28 | 21 |            "kernel_tophat", "kernel_gauss", "kernel_lorentz"]  | 
29 | 22 | 
 
  | 
30 | 23 | 
 
  | 
@@ -125,134 +118,9 @@ def LOS_clouds_priortransform(u, rlims=(0., 6.), dlims=(4., 19.),  | 
125 | 118 |     return x  | 
126 | 119 | 
 
  | 
127 | 120 | 
 
  | 
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 |  | - | 
253 | 121 | def LOS_clouds_loglike_samples(theta, dsamps, rsamps, kernel='gauss',  | 
254 | 122 |                                rlims=(0., 6.), template_reds=None,  | 
255 |  | -                               Ndraws=25):  | 
 | 123 | +                               Ndraws=25, additive_foreground=False):  | 
256 | 124 |     """  | 
257 | 125 |     Compute the log-likelihood for the cumulative reddening along the  | 
258 | 126 |     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',  | 
293 | 161 |     Ndraws : int, optional  | 
294 | 162 |         The number of draws to use for each star. Default is `25`.  | 
295 | 163 | 
  | 
 | 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 | +
  | 
296 | 168 |     Returns  | 
297 | 169 |     -------  | 
298 | 170 |     loglike : float  | 
@@ -336,6 +208,10 @@ def LOS_clouds_loglike_samples(theta, dsamps, rsamps, kernel='gauss',  | 
336 | 208 |     if template_reds is not None:  | 
337 | 209 |         reds[1:] *= template_reds[None, :, None]  # reds[1:] are rescalings  | 
338 | 210 | 
 
  | 
 | 211 | +    # Adjust reddenings after the foreground if needed.  | 
 | 212 | +    if additive_foreground:  | 
 | 213 | +        reds[1:] += reds[0]  # add foreground to background  | 
 | 214 | + | 
339 | 215 |     # Define kernel parameters (mean, sigma) per LOS chunk.  | 
340 | 216 |     kparams = np.array([(r, rsmooth) for r in reds])  | 
341 | 217 |     kparams[0][1] = rsmooth0  | 
 | 
0 commit comments