예제 #1
0
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"]
예제 #2
0
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
예제 #3
0
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
예제 #4
0
 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
예제 #5
0
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
예제 #6
0
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
예제 #7
0
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)
예제 #8
0
 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)
예제 #9
0
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)
예제 #10
0
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]))
예제 #11
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
예제 #12
0
    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)