예제 #1
0
    def _invert_quantile(self):
        cdf = PchipInterpolator(self.quantile_eval, self.quantile_grid)
        self.cdf_grid = np.linspace(self.quantile_eval[0],
                                    self.quantile_eval[-1], 1000)
        self.pdf_grid = self.cdf_grid

        pdf_eval = gaussian_filter1d(cdf.derivative()(self.pdf_grid),
                                     sigma=self.smooth_sigma)
        self.pdf_eval = pdf_eval / simps(pdf_eval, self.cdf_grid)
        self.cdf_eval = cumtrapz(self.pdf_eval, self.pdf_grid, initial=0)
예제 #2
0
def GQ(model_param, num_rsteps = 1e5, num_Qsteps = 1000):
        time_ini = time.time()
        print 'Calculating f(Q) function... '

        ra, rs_s, al_s, be_s, ga_s, rho, rs, alpha, beta, gamma = model_param
        G = 4.302 * 1e-6 # (kpc/m_sun) (km/s)^2
        rhos = 4*np.pi*G*rho

        DM_param = [rhos, rs, alpha, beta, gamma]

        rhos_s = 1.0
        al_s, be_s, ga_s = al_s*1.0, be_s*1.0, ga_s*1.0

        nsteps = 1e5
        r200   = getR200(DM_param)
        rmax   = r200*1000000
        rtrunc = r200*1 #Dark matter density cut off radius
        Plim = 0  

        #---------------we want drho/dP over large range of rarr, so use rmax----------------
        t0 = time.time()
        rarr0 = np.linspace(1e-8, rmax*1, num_rsteps*.5)
        rarr1 = np.logspace(-5, np.log10(rmax)-0, num_rsteps*.5)
        rarr2 = np.logspace(-8, np.log10(rmax)-6, num_rsteps*.5)
        rarr = np.unique( np.hstack((rarr0, rarr1, rarr2)) )
        rarr = rarr[np.argsort(rarr)]
        Parr = -1*(OMgenphi(rarr, rtrunc, rhos, rs, alpha, beta, gamma)) 
        #print 'calculate potential time: ', time.time()-t0 

        # -------- interpolate between rhoQ(r) and Phi(r) -------------------------
        rhoQ = rho_Q(rarr, ra, rs_s, al_s, be_s, ga_s)

        rhoQ_sorted = rhoQ[np.argsort(Parr)]
        Parr_sorted = Parr[np.argsort(Parr)]
        Parr_sorted, Pindx = np.unique(Parr_sorted, return_index=True)
        rhoQ_sorted = rhoQ_sorted[Pindx]

        t0 = time.time()
        frhoQ  = PchipInterpolator(Parr_sorted, rhoQ_sorted, extrapolate=False)
        dfrhoQ = frhoQ.derivative()
        #print "interpolate rhoQ and relative potential time:  ",  time.time()-t0

        #-------- calculate G(Q) -------------------------------------------------------
        def G_integrand(u, Q):
            phi = Q-u*u
            return -2 * dfrhoQ(phi) 


        t0 = time.time()
        rarr0 = np.logspace(-8, np.log10(r200)+1, int(num_Qsteps*.35))
        Qarr0 = -1*(OMgenphi(rarr0 , rtrunc, rhos, rs, alpha, beta, gamma) - Plim )
        Qarr1 = np.linspace(0, max(Parr_sorted)*1, int(num_Qsteps*.65))
        Qarr = np.hstack((Qarr1, Qarr0))
        Qarr = np.unique(Qarr)
        Qarr = Qarr[np.argsort(Qarr)]

        Garr = [integrate.quad(G_integrand, Q**.5, 0, args=(Q,), full_output=1, 
                epsabs=0, epsrel=1.49e-05)[0] for Q in Qarr]

        Garr = np.nan_to_num( np.array(Garr) )
        #print 'G(Q) integrate time: ', time.time()-t0

        #------------ interpolate Qarr and Garr to get f(Q) ----------------------
        Garr = Garr/(np.pi*np.pi* 2**1.5)
        GQ = PchipInterpolator(Qarr, Garr, extrapolate=False)
        fQ = GQ.derivative() 
        fQarr = fQ(Qarr)
        
        print '    Finish calculating f(Q). Time used (sec): ', time.time()-time_ini

        #-------------------check if f(Q) is negative --> unphysical--------------
        numQ = 20000
        Qtest = np.linspace(0, max(Qarr)*1, numQ)
        fQtest = fQ(Qtest)
        num_neg_fQ = sum(fQtest<0)
        neg_Q_fraction = num_neg_fQ / (numQ*1.)
        if neg_Q_fraction >= 0.0001: #len(neg_fQ) > len(Qarr)*.01:
                print 'This model could be unphysical! please double check'
                print 'model_param = ', model_param
        #--------------------end check ----------------------------------

        return Qarr, fQ, rtrunc
예제 #3
0
def constructMagneticField(Rp=2,
                           Zp=0,
                           a=0.5,
                           nR=150,
                           ntheta=151,
                           rG_R0=None,
                           G_R0=None,
                           rpsi=None,
                           psi=None,
                           Delta=None,
                           rDelta=None,
                           kappa=None,
                           rkappa=None,
                           delta=None,
                           rdelta=None,
                           retdict=False):
    """
    Construct the numeric magnetic field.
    """
    raMax = 1.05
    r = np.linspace(0, a * 1.05, nR + 1)[1:]
    theta = np.linspace(0, 2 * np.pi, ntheta + 1)[:-1]

    mgR, mgT = np.meshgrid(r, theta)

    iG_R0, ipsi, iDelta, ikappa, idelta = (None, ) * 5

    if G_R0 is None:
        raise Exception(
            'The toroidal magnetic field function must be specified.')
    else:
        iG_R0 = PchipInterpolator(rG_R0, G_R0, extrapolate=True)

    if psi is None: raise Exception('The poloidal flux must be specified.')
    else: ipsi = PchipInterpolator(rpsi, psi, extrapolate=True)

    if Delta is None:
        iDelta = PchipInterpolator([0, raMax], [0, 0], extrapolate=True)
    else:
        iDelta = PchipInterpolator(rDelta, Delta, extrapolate=True)

    if kappa is None:
        ikappa = PchipInterpolator([0, raMax], [1, 1], extrapolate=True)
    else:
        ikappa = PchipInterpolator(rkappa, kappa, extrapolate=True)

    if delta is None:
        idelta = PchipInterpolator([0, raMax], [0, 0], extrapolate=True)
    else:
        idelta = PchipInterpolator(rdelta, delta, extrapolate=True)

    R = lambda r, theta: Rp + iDelta(r) + r * np.cos(theta + idelta(r) * np.
                                                     sin(theta))
    Z = lambda r, theta: Zp + r * ikappa(r) * np.sin(theta)

    psiPrime = ipsi.derivative()

    # Derivatives of shape parameters
    iDeltap = iDelta.derivative()
    ideltap = idelta.derivative()
    ikappap = ikappa.derivative()

    dRdr = lambda r, theta: iDeltap(r) + np.cos(theta + idelta(r) * np.sin(
        theta)) - r * ideltap(r) * np.sin(theta + idelta(r) * np.sin(theta))
    dZdr = lambda r, theta: ikappa(r) * (1 + r * ikappap(r) / ikappa(r)
                                         ) * np.sin(theta)

    dRdt = lambda r, theta: -r * (1 + idelta(r) * np.cos(theta)) * np.sin(
        theta + idelta(r) * np.sin(theta))
    dZdt = lambda r, theta: r * ikappa(r) * np.cos(theta)

    # Magnitude squared of the minor radius gradient
    def gradr2(r, theta):
        ct = np.cos(theta)
        st = np.sin(theta)
        sdt = np.sin(theta + idelta(r) * st)
        cdt = 1 + idelta(r) * ct

        Jt1 = ikappa(r) * np.cos(idelta(r) * st)
        Jt2 = ikappa(r) * iDeltap(r) * ct
        Jt3 = st * np.sin(theta + idelta(r) * st)
        Jt4 = r * ikappap(r) + ct * (idelta(r) * ikappa(r) + r * idelta(r) *
                                     ikappap(r) - r * ikappa(r) * ideltap(r))
        JOverRr = Jt1 + Jt2 + Jt3 * Jt4

        try:
            print('J/rR = {:.12f}'.format(JOverRr))
        except:
            pass
        return (ikappa(r)**2 * ct**2 + cdt**2 * sdt**2) / (JOverRr**2)

    Bphi = lambda r, theta: iG_R0(r) * Rp / R(r, theta)
    Br = lambda r, theta: -psiPrime(r) * np.sqrt(gradr2(r, theta)) / (
        2 * np.pi * R(r, theta)) * dZdr(r, theta) / np.sqrt(
            dRdr(r, theta)**2 + dZdr(r, theta)**2)
    Bz = lambda r, theta: psiPrime(r) * np.sqrt(gradr2(r, theta)) / (
        2 * np.pi * R(r, theta)) * dRdr(r, theta) / np.sqrt(
            dRdr(r, theta)**2 + dZdr(r, theta)**2)

    #B    = lambda r, theta : np.sqrt(Bphi(r,theta)**2 + Br(r,theta)**2 + Bz(r,theta)**2)

    if retdict:
        return {
            'Rp': Rp,
            'Zp': Zp,
            'psi': ipsi(r),
            'theta': theta,
            'R': R(mgR, mgT),
            'Z': Z(mgR, mgT),
            'Br': Br(mgR, mgT),
            'Bz': Bz(mgR, mgT),
            'Bphi': Bphi(mgR, mgT)
        }
    else:
        return Rp, Zp, ipsi(r), theta, R(mgR,
                                         mgT), Z(mgR, mgT), Br(mgR, mgT), Bz(
                                             mgR, mgT), Bphi(mgR, mgT)
예제 #4
0
class BinSmooth:
    """A binned data smoother.

    This class implements the method outlined in [1]. It proceeds by fitting a
    cubic spline to the empirical distribution function of the binned data.

    Attributes
    ----------
    min_x_: float
        The minimum value of the empirical distribution function
    tail_: float
        The maximum value of the estimated CDF
    mean_est_: float
        The estimated mean of the estimated distribution
    cdf_cs_: func
        The estimated CDF function
    inv_cdf_cs_: func
        The estimated inverse CDF function

    References
    ----------
    .. [1] P. von Hippel, D. Hunter, M. Drown "Better Estimates from Binned
           Income Data: Interpolated CDFs and Mean-Matching", 2017.

    Examples
    --------

    >>> from binsmooth import BinSmooth

    >>>  bin_edges = np.array([0, 18200, 37000, 87000, 180000])
    >>> counts = np.array([0, 7527, 13797, 75481, 50646, 803])

    >>>  bs = BinSmooth()

    >>> bs.fit(bin_edges, counts)

    >>> print(bs.inv_cdf(0.5))
    70120.071...
    """

    def fit(self, x, y, m=None, includes_tail=False):
        """Fit the cubic spline to the data.

        Parameters
        ----------
        x: ndarray
            The bin edges
        y: ndarray
            The values for each bin
        m: float
            The mean of the distribution
        includes_tail: bool
            If True then it is assumed that the last value in x is the upper
            bound of the distribution, otherwise the upper bound is estimated

        Returns
        -------
        self : object
            Fitted estimator.
        """
        if includes_tail and len(x) != len(y):
            raise ValueError(
                "Length of x and y must match when tail is included"
            )

        if not includes_tail and len(x) != len(y) - 1:
            raise ValueError(
                "Length of x must be N-1 when tail is not included"
            )

        if y[0] != 0:
            raise ValueError("y must begin with 0")

        if m is None:
            # Adhoc mean estimate if none supplied
            if includes_tail:
                bin_edges = x
            else:
                bin_edges = np.concatenate([x[:-1] / 2, [x[-1], x[-1] * 2]])

            m = np.average(bin_edges, weights=y / np.sum(y),)

            warnings.warn("No mean provided, results may be innacurate.")

        x = x.astype(float)
        y = y.astype(float)

        self.min_x_ = x[0]

        y_ecdf = np.cumsum(y)
        y_ecdf_normed = y_ecdf / np.max(y_ecdf)

        if includes_tail is False:
            # Temporarily set the tail value
            tail_0 = x[-1] * 2
            x_wtail = np.concatenate([x, [tail_0]])

            # Search for a tail
            self.tail_ = minimize(
                evaluate_tail,
                tail_0,
                args=(x_wtail.copy(), y_ecdf_normed, m),
                bounds=[(180000, None)],
                method="Powell",
                options=dict(maxiter=16),
            ).x[0]

            x_wtail[-1] = self.tail_
        else:
            if x[-2] >= x[-1]:
                raise ValueError(
                    "Tail value must be greater than the last bin edge"
                )

            self.tail_ = x[-1]
            x_wtail = x

        # Estimate the CDF by fitting a spline
        self.cdf_cs_ = PchipInterpolator(x_wtail, y_ecdf_normed)

        self.mean_est_ = estimate_mean(x_wtail[0], x_wtail[-1], self.cdf_cs_)

        # Approximate inverse CDF by sampling the CDF
        x_cs = cumdensityspace(
            self.min_x_, self.tail_, self.cdf_cs_, interp_num=1000
        )
        y_cs = self.cdf_cs_(x_cs)
        self.inv_cdf_cs_ = PchipInterpolator(y_cs, x_cs)

        return self

    def pdf(self, x):
        """Estimated PDF.

        Parameters
        ----------
        x: ndarray
            Values to calculate the PDF of.

        Returns
        -------
        pdf : ndarray
            Estimated PDF values
        """
        return self.cdf_cs_.derivative()(np.clip(x, self.min_x_, self.tail_))

    def cdf(self, x):
        """Estimated CDF.

        Parameters
        ----------
        x: ndarray
            Values to calculate the CDF of.

        Returns
        -------
        cdf : ndarray
            Estimated CDF values
        """
        return self.cdf_cs_(np.clip(x, self.min_x_, self.tail_))

    def inv_cdf(self, percentile):
        """Estimated inverse CDF.

        Parameters
        ----------
        percentile: ndarray
            Values to calculate the inverse CDF of

        Returns
        -------
        inverse_cdf : ndarray
            Estimated inverse CDF values
        """
        return self.inv_cdf_cs_(np.clip(percentile, 0, 1))