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)
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
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)
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))