def cvar_beta_variable(rv, beta): """ cvar of Beta variable on [0,1] """ qq = rv.ppf(beta) scales, shapes = get_distribution_info(rv)[1:] qq = (qq - scales["loc"]) / scales["scale"] g1, g2 = shapes["a"], shapes["b"] cvar01 = ((1 - betainc(1 + g1, g2, qq)) * gamma_fn(1 + g1) * gamma_fn(g2) / gamma_fn(1 + g1 + g2)) / (beta_fn(g1, g2) * (1 - beta)) return cvar01 * scales["scale"] + scales["loc"]
def _gmw_k_constants(gamma, beta, k, norm='bandpass', dtype='float64'): """Laguerre polynomial constants & `coeff` term. Higher-order GMWs are coded such that constants are pre-computed and reused for any `w` input, since they remain fixed for said order. """ r = (2 * beta + 1) / gamma c = r - 1 # compute `coeff` if norm == 'bandpass': coeff = np.sqrt(np.exp(gammaln_fn(r) + gammaln_fn(k + 1) - gammaln_fn(k + r))) elif norm == 'energy': coeff = np.sqrt(2*pi * gamma * (2**r) * np.exp(gammaln_fn(k + 1) - gammaln_fn(k + r))) # compute Laguerre polynomial constants L_consts = np.zeros(k + 1, dtype=dtype) for m in range(k + 1): fact = np.exp(gammaln_fn(k + c + 1) - gammaln_fn(c + m + 1) - gammaln_fn(k - m + 1)) L_consts[m] = (-1)**m * fact / gamma_fn(m + 1) k_consts = L_consts * coeff if norm == 'bandpass': k_consts *= 2 k_consts = k_consts.astype(dtype) return k_consts
def morsefreq(gamma, beta, n_out=1): """Frequency measures for GMWs (with F. Rekibi). `n_out` controls how many parameters are computed and returned, in the following order: `wm, we, wi, cwi`, where: wm: modal / peak frequency we: energy frequency wi: instantaneous frequency at time-domain wavelet's center cwi: curvature of instantaneous frequency at time-domain wavelet's center All frequency quantities are *radian*, opposed to linear cyclic (i.e. `w` in `w = 2*pi*f`). For BETA=0, the "wavelet" becomes an analytic lowpass filter, and `wm` is not defined in the usual way. Instead, `wm` is defined as the point at which the filter has decayed to one-half of its peak power. # References [1] Higher-Order Properties of Analytic Wavelets. J. M. Lilly, S. C. Olhede. 2009. https://sci-hub.st/10.1109/TSP.2008.2007607 [2] (c) Lilly, J. M. (2021), jLab: A data analysis package for Matlab, v1.6.9, http://www.jmlilly.net/jmlsoft.html https://github.com/jonathanlilly/jLab/blob/master/jWavelet/morsefreq.m """ wm = (beta / gamma)**(1 / gamma) if n_out > 1: we = (1 / 2**(1 / gamma)) * (gamma_fn((2*beta + 2) / gamma) / gamma_fn((2*beta + 1) / gamma)) if n_out > 2: wi = (gamma_fn((beta + 2) / gamma) / gamma_fn((beta + 1) / gamma)) if n_out > 3: k2 = _morsemom(2, gamma, beta, n_out=3)[-1] k3 = _morsemom(3, gamma, beta, n_out=3)[-1] cwi = -(k3 / k2**1.5) if n_out == 1: return wm elif n_out == 2: return wm, we elif n_out == 3: return wm, we, wi return wm, we, wi, cwi
def find_radius(self): n = len(self.states) unit_ball_volume = np.sqrt( np.pi)**self.ss.dim / gamma_fn(self.ss.dim / 2.0 + 1.0) x_free_volume = self.ss.volume gamma = (2*(1.0 + 1.0/self.ss.dim) * \ (x_free_volume/unit_ball_volume))**(1.0/self.ss.dim) ball_radius = min( gamma * ((np.log(n + 1) / (n + 1))**(1.0 / self.ss.dim)), self.d_steer) return ball_radius
def make_shower_ldf(energy, theta=0, phi=0, s=1): from scipy.special import gamma as gamma_fn # critical energy in air, see EAS (4.17) and discussion # on p.154. E_critical = 84e6 # eV # shower size is proportial to energy, # see EAS (4.88) N = energy/E_critical # HACK: # for muons, the normalization is about 3 orders lower # than for photons. would be better to get a muon-specific # LDF. N *= 1e-3 eta = eta_fn(theta, N) alpha = 2-s # molliere radius, EAS p. 388 rM = 100 # m # calculate the yucky gamma function term up front: gamma_factor = gamma_fn(eta-alpha) / (gamma_fn(2-alpha)*gamma_fn(eta-2)) # unit vector pointing in the direction of the shower core: n_hat = np.array([np.cos(phi)*np.sin(theta), np.sin(phi)*np.sin(theta), np.cos(theta)]) def ldf(points): # promote the 2D vector points to 3d vector points pts = np.hstack([points, np.zeros((len(points),1))]) # vector distance from point p to line d = np.outer((n_hat.dot(pts.T)), n_hat) - pts r = np.sqrt(np.sum(d**2, axis=1)) return N / (2*np.pi*rM**2) * (r/rM)**(-alpha) * (1 + r/rM)**(-(eta-alpha)) * gamma_factor return ldf
def laguerre(x, k, c): """Generalized Laguerre polynomials. See `help(_gmw.morsewave)`. LAGUERRE is used in the computation of the generalized Morse wavelets and uses the expression given by Olhede and Walden (2002), "Generalized Morse Wavelets", Section III D. """ x = np.atleast_1d(np.asarray(x).squeeze()) assert x.ndim == 1 y = np.zeros(x.shape) for m in range(k + 1): # Log of gamma function much better ... trick from Maltab's ``beta'' fact = np.exp(gammaln_fn(k + c + 1) - gammaln_fn(c + m + 1) - gammaln_fn(k - m + 1)) y += (-1)**m * fact * x**m / gamma_fn(m + 1) return y
def gmw_l2(gamma=3., beta=60., centered_scale=False, dtype='float64'): """Generalized Morse Wavelets, first order, L2(energy)-normalized. See `help(_gmw.gmw)`. """ _check_args(gamma=gamma, beta=beta, allow_zerobeta=False) wc = morsefreq(gamma, beta) r = (2*beta + 1) / gamma rgamma = gamma_fn(r) (gamma, beta, wc, r, rgamma ) = _process_params_dtype(gamma, beta, wc, r, rgamma, dtype=dtype) fn = _gmw_l2_gpu if USE_GPU() else (_gmw_l2_par if IS_PARALLEL() else _gmw_l2) if centered_scale: return lambda w: fn(S.atleast_1d(w * wc, dtype), gamma, beta, wc, r, rgamma) else: return lambda w: fn(S.atleast_1d(w, dtype), gamma, beta, wc, r, rgamma)
def morsef(gamma, beta): # normalized first frequency-domain moment "f_{beta, gamma}" of the # first-order GMW return (1 / (2*pi * gamma)) * gamma_fn((beta + 1) / gamma)
def log_likelihood(X, beta, gamma): n = X.shape[0] s = beta * n * np.log(gamma) + (beta - 1) * np.log(X).sum() - gamma * X.sum() - n * np.log(gamma_fn(beta)) return np.exp(s)
def likelihood(X, beta, gamma): return ((gamma ** beta) ** (X.shape[0])) * np.exp(np.sum(np.log((X ** (beta - 1)) * np.exp(-gamma * X)))) / (gamma_fn(beta) ** (X.shape[0]))
def compute_A0(p0,q0): inv_A0 = (2.**(0.5*(-1. - 2.*self.p0 + self.q0))*(gamma_fn(-self.p0 + self.q0/2.) + 2**self.p0*gamma_fn(self.q0/2.)))/np.sqrt(np.pi) return 1./inv_A0
def _load_mass_function_parameters(self,mass_dict): """Load internal mass function parameters. Args: mass_function (str): Mass function name (see class description for options). mass_dict (dict): Dictionary of additional parameters. """ if self.mass_function_name=='Sheth-Tormen': # Load mass function parameters and normalization self.p_ST = 0.3 self.a_ST = 0.707 self.A_ST = (1.+2.**(-self.p_ST)*gamma_fn(0.5-self.p_ST)/np.sqrt(np.pi))**(-1.)*np.sqrt(2.*self.a_ST/np.pi) # Compute the spherical collapse threshold of Nakamura-Suto, 1997. Om_mz = self.cosmology._Omega_m() dc0 = (3./20.)*pow(12.*np.pi,2./3.); self.delta_c = dc0*(1.+0.012299*np.log10(Om_mz)); elif self.mass_function_name=='Tinker': self.delta_c = 1.686 # critical density for collapse # MASS FUNCTION PARAMETERS ## Compute model parameters from interpolation given odelta value odelta = mass_dict['tinker_overdensity'] alpha=np.asarray([0.368,0.363,0.385]) beta0=np.asarray([0.589,0.585,0.544]) gamma0=np.asarray([0.864,0.922,0.987]) phi0=np.asarray([-0.729,-0.789,-0.910]) eta0=np.asarray([-0.243,-0.261,-0.261]) odeltas=np.asarray([200,300,400]) self.alpha=interp1d(odeltas,alpha)(odelta) beta0=interp1d(odeltas,beta0)(odelta) gamma0=interp1d(odeltas,gamma0)(odelta) phi0=interp1d(odeltas,phi0)(odelta) eta0=interp1d(odeltas,eta0)(odelta) self.beta = beta0*self.a**-0.2 self.phi = phi0*self.a**0.08 self.eta = eta0*self.a**-0.27 self.gamma = gamma0*self.a**0.01 # BIAS FUNCTION PARAMETERS y = np.log10(odelta); self.fit_A = 1.0 + 0.24*y*np.exp(-np.power(4./y,4.)); self.fit_a = 0.44*y-0.88; self.fit_B = 0.183; self.fit_b = 1.5; self.fit_C = 0.019+0.107*y+0.19*np.exp(-np.power(4./y,4.)); self.fit_c = 2.4; elif self.mass_function_name=='Crocce': self.delta_c = 1.686 # critical density for collapse if self.cosmology.name=='Quijote': if self.verb: print('Using fitted parameters for the Crocce mass function from Quijote simulations ') # Optimal values for the Quijote simulations self.pA = 0.729 self.pa = 2.355 self.pb = 0.423 self.pc = 1.318 else: # Optimal values from original simulations self.pA = 0.58*self.a**0.13 self.pa = 1.37*self.a**0.15 self.pb = 0.3*self.a**0.084 self.pc = 1.036*self.a**0.024 elif self.mass_function_name=='Bhattacharya': self.delta_c = 1.686 # critical density for collapse def compute_A0(p0,q0): inv_A0 = (2.**(0.5*(-1. - 2.*self.p0 + self.q0))*(gamma_fn(-self.p0 + self.q0/2.) + 2**self.p0*gamma_fn(self.q0/2.)))/np.sqrt(np.pi) return 1./inv_A0 if self.cosmology.name=='Quijote': if self.verb: print('Using fitted parameters for the Bhattacharya mass function from Quijote simulations ') # Optimal values for the Quijote simulations self.a0 = 0.77403116 self.p0 = 0.63685683 self.q0 = 1.66263337 self.A0 = compute_A0(self.p0,self.q0) elif self.cosmology.name=='Abacus': if self.verb: print('Using fitted parameters for the Bhattacharya mass function from Abacus simulations ') # Optimal values for the Quijote simulations self.a0 = 0.86648878 self.p0 = 1.30206972 self.q0 = 1.97133804 self.A0 = 0.35087244 else: # Optimal values from original paper self.a0 = 0.788 self.p0 = 0.807 self.q0 = 1.795 self.A0 = compute_A0(self.p0,self.q0) else: raise NameError('Mass function %s not currently implemented!'%self.mass_function_name)