def ldiv(a, b):
    """ Equivalent to matlab's a\b"""
    if a.shape[0] == a.shape[1] and a.shape[0] == b.shape[0]:
        lu, piv, x, info = dgesv(a, b, False, False)
        return x
    else:
        return lstsq(a, b, rcond=None)[0]
Exemple #2
0
def run_dgesv(N,l):

	a = randn(N,N).astype('float64')
	b = randn(N,N).astype('float64')

	start = time.time();
	for i in range(0,l):
		dgesv(a,b,1,1)
	end = time.time()
	
	timediff = (end -start) 

	mflops = ( 2.0/3.0 *N*N*N + 2.0*N*N*N) *l / timediff
	mflops *= 1e-6

	size = "%dx%d" % (N,N)
	print("%14s :\t%20f MFlops\t%20f sec" % (size,mflops,timediff))
Exemple #3
0
def compute_inv_cov(npop, npk, kaiser, pk, nbar):
    """ Computes the covariance matrix of the auto and cross-power spectra for a given
        k and mu value, as well as its inverse.

    Parameters
    ----------
    npop: int
        The number of different galaxy populations to consider. Used to compute all combinations
        necessary for the power spectra.
    npk: int
        The number of different auto and cross power spectra.
        Equivalent to npop*(npop+1)/2, but passed in to avoid recomputing for each k/mu value.
    kaiser: np.ndarray
        The kaiser factors for each galaxy population at a fixed mu and redshift. Has length npop.
    pk: float
        The power spectrum value at the given k, mu and redshift values.
    nbar: np.ndarray
        The number density in units of Mpc^3/h^3 for each of the npop samples at the current redshift.

    Returns
    -------
    covariance: np.ndarray
        The covariance matrix between the various auto and cross-power spectra at a given k, mu and redshift.
        Includes shot noise and has size (npk, npk).
    cov_inv: np.ndarray
        The inverse of the covariance matrix between the various auto and cross-power spectra at a given k,
        mu and redshift. Includes shot noise and has size (npk, npk).
    """

    covariance = np.empty((npk, npk))

    # Loop over power spectra of different samples P_12
    for ps1, pair1 in enumerate(combinations_with_replacement(range(npop), 2)):
        n1, n2 = pair1
        # Loop over power spectra of different samples P_34
        for ps2, pair2 in enumerate(
                combinations_with_replacement(range(npop), 2)):
            n3, n4 = pair2
            # Cov(P_12,P_34)
            pk13, pk24 = kaiser[n1] * kaiser[n3] * pk, kaiser[n2] * kaiser[
                n4] * pk
            pk14, pk23 = kaiser[n1] * kaiser[n4] * pk, kaiser[n2] * kaiser[
                n3] * pk
            if n1 == n3:
                pk13 += 1.0 / nbar[n1]
            if n1 == n4:
                pk14 += 1.0 / nbar[n1]
            if n2 == n3:
                pk23 += 1.0 / nbar[n2]
            if n2 == n4:
                pk24 += 1.0 / nbar[n2]
            covariance[ps1, ps2] = pk13 * pk24 + pk14 * pk23

    identity = np.eye(npk)
    cov_inv = dgesv(covariance, identity)[2]

    return covariance, cov_inv
Exemple #4
0
def solver(vlmdata):
    """
    Solve linear system for vortex strengths

    Args:
        :vlmdata: (object) data structure for VLM input and output
    """

    logger.info("Solving linear system...")
    vlmdata.matrix_lu, vlmdata.array_pivots, vlmdata.panelwise['gamma'], _ \
            = lapack.dgesv(vlmdata.matrix_downwash, vlmdata.array_rhs)
Exemple #5
0
def _build_and_solve_system(y, d, smoothing, kernel, epsilon, powers):
    """Build and solve the RBF interpolation system of equations.

    Parameters
    ----------
    y : (P, N) float ndarray
        Data point coordinates.
    d : (P, S) float ndarray
        Data values at `y`.
    smoothing : (P,) float ndarray
        Smoothing parameter for each data point.
    kernel : str
        Name of the RBF.
    epsilon : float
        Shape parameter.
    powers : (R, N) int ndarray
        The exponents for each monomial in the polynomial.

    Returns
    -------
    coeffs : (P + R, S) float ndarray
        Coefficients for each RBF and monomial.
    shift : (N,) float ndarray
        Domain shift used to create the polynomial matrix.
    scale : (N,) float ndarray
        Domain scaling used to create the polynomial matrix.

    """
    lhs, rhs, shift, scale = _build_system(y, d, smoothing, kernel, epsilon,
                                           powers)
    _, _, coeffs, info = dgesv(lhs, rhs, overwrite_a=True, overwrite_b=True)
    if info < 0:
        raise ValueError(f"The {-info}-th argument had an illegal value.")
    elif info > 0:
        msg = "Singular matrix."
        nmonos = powers.shape[0]
        if nmonos > 0:
            pmat = _polynomial_matrix((y - shift) / scale, powers)
            rank = np.linalg.matrix_rank(pmat)
            if rank < nmonos:
                msg = ("Singular matrix. The matrix of monomials evaluated at "
                       "the data point coordinates does not have full column "
                       f"rank ({rank}/{nmonos}).")

        raise LinAlgError(msg)

    return shift, scale, coeffs
Exemple #6
0
def compute_cov_inv(data):

    if (data.cov is None):

        data.cov_det = None
        data.cov_inv = None

    else:

        # Compute the log determinant of the covariance matrix
        cov_copy, pivots, info = lapack.dgetrf(data.cov)
        abs_element = np.fabs(np.diagonal(cov_copy))
        data.cov_det = np.sum(np.log(abs_element))

        # Invert the covariance matrix
        identity = np.eye(len(data.x))
        cov_lu, pivots, cov_inv, info = lapack.dgesv(data.cov, identity)
        data.cov_inv = cov_inv

    return data
Exemple #7
0
    def diagonalize_q_matrix(self):
        # type: () -> None
        """
        calculate Q matrix and eigenvalues and eigenvectors if necessary
        c.f. Felsenstein - Inferring Phylogenies (chapter 13)
        The naming of the variables follows the naming in Felsenstein.
        """

        # if self.necessary:
        self.freq_log = np.log(self.frequencies)

        self.create_q_c()

        # calculate root
        self.d_mat = np.sqrt(self.d_mat)

        self.b_mat = np.asfortranarray(self.b_mat)
        d_b_d = np.empty((self._size, self._size), dtype=np.float64, order="F")

        # get symmetric matrix
        # use SciPys BLAS wrappers
        c = sp_la.blas.dgemm(alpha=1.0, a=self.d_mat, b=self.b_mat)
        sp_la.blas.dgemm(alpha=1.0, a=c, b=self.d_mat, c=d_b_d, overwrite_c=1)

        # get eigenvalues and eigenvectors
        self.q_eigenvalues, u_mat = np_la.eigh(d_b_d)

        # calculate actual eigenvectors of Q-Matrix
        # use SciPys BLAS wrappers
        u_mat = np.asfortranarray(u_mat)
        sp_la.blas.dgemm(alpha=1.0,
                         a=self.d_mat,
                         b=u_mat,
                         c=self.q_eigenvectors,
                         overwrite_c=1)

        self.q_eigenvectors_inv = sp_la_lp.dgesv(self.q_eigenvectors,
                                                 self._eye)[2]

        self.q_eigenvectors_inv = np.asfortranarray(self.q_eigenvectors_inv)
        self.necessary = False
Exemple #8
0
            ExtraCatch = Fish(
                cosmo,
                cosmo.kmax,
                0.5,
                data,
                iz,
                recon[iz],
                derPalpha_BAO_only,
                True,
                pardict.as_bool("GoFast"),
            )
            Catch[-2:, -2:] += ExtraCatch[-2:, -2:]
            # print(Catch)

            # Invert the Fisher matrix to get the parameter covariance matrix
            cov = dgesv(Catch, identity)[2]

            # Renormalise the covariance from fsigma8, alpha_perp, alpha_par to fsigma8, Da, H
            means = [cosmo.f[iz] * cosmo.sigma8[iz], cosmo.da[iz], cosmo.h[iz]]
            cov_renorm = CovRenorm(cov, means)

            # Print the parameter means and errors
            errs = 100.0 * np.sqrt(np.diag(cov_renorm)[-3:]) / means
            print(
                " {0:.2f}     {1:.4f}    {2:.3f}       {3:.2f}         {4:.1f}       {5:.2f}        {6:.1f}       {7:.2f}"
                .format(
                    cosmo.z[iz],
                    cosmo.volume[iz] / 1e9,
                    means[0],
                    errs[0],
                    means[1],
Exemple #9
0
def HydrostaticShape(radius, rho, omega, gm, r_ref, rp=None, mp=None):
    """
    Calculate the shape of hydrostatic relief in a rotating planet or moon,
    along with the total gravitation potential. For the case of a moon in
    synchronous rotation, optionally include the tidal potential.

    Usage
    -----
    hlm, clm_hydro, mass = HydrostaticFlatteningLith(radius, density,
        omega, gm, r_ref, [rp, mp])

    Returns
    -------
    hlm : array of SHCoeffs class instances, size(n+1)
        Array of SHCoeffs class instances of the spherical harmonic
        coefficients of the hydrostatic relief at each interface.
    clm_hydro : SHCoeffs class instance containing the gravitational potential
        resulting from all hydrostatic interfaces.
    mass : float
        Total mass of the planet, assuming a spherical shape and the provided
        1D density profile.

    Parameters
    ----------
    radius : ndarray, float, size(n+1)
        Radius of each density interface, where index 0 corresponds to the
        center of the planet and n corresponds to the surface.
    density : ndarray, float, size(n+1)
        Density of layer i between radius[i] and radius[i+1]. The density
        at index 0 is from the center of the planet to radius[1], whereas the
        the density at index n should be zero.
    omega : float
        Angular rotation rate of the planet.
    gm : float
        GM of the planet.
    r_ref : float
        Refernce radius for output potential coefficients.
    rp : float, optional, default = None
        If specified, include the tidal potential acting on a synchronously
        rotating moon, where rp is the average distance between the planet
        and satellite.
    mp : float, optional, default = None
        The mass of the host planet, at a distance rp from the satellite.
    """
    tides = False
    if rp is not None:
        if mp is None:
            raise ValueError('When including tides, both rp and mp must be ' +
                             'specified.')
        tides = True
    if mp is not None:
        if rp is None:
            raise ValueError('When including tides, both rp and mp must be ' +
                             'specified.')
        tides = True

    if len(radius) != len(rho):
        raise ('Length of radius and density must be the same.' +
               'len(radius) = {:d}. len(density) = {:d}.'.format(
                   len(radius), len(rho)))

    n = len(radius) - 1  # index of surface
    lmax = 4

    g = pyshtools.constant.G.value

    hlm = [pyshtools.SHCoeffs.from_zeros(lmax) for i in range(n + 1)]
    clm_hydro = pyshtools.SHCoeffs.from_zeros(lmax)

    for i in range(n + 1):
        hlm[i].coeffs[0, 0, 0] = radius[i]

    # First determine the spherical harmonic coefficients of (Y20 Ylm)
    # and for tides, (Y22 Ylm). We are only concerned with the coefficient
    # that corresponds to lm, so for each lm, store only the lm component in
    # the array cp20 and cp22.

    sh20 = np.zeros((2, lmax + 1, lmax + 1))
    sh22 = np.zeros((2, lmax + 1, lmax + 1))
    sh = np.zeros((2, lmax + 1, lmax + 1))
    cp20 = np.zeros((2, lmax + 1, lmax + 1))
    cp22 = np.zeros((2, lmax + 1, lmax + 1))

    sh20[0, 2, 0] = 1.  # Y20
    sh22[0, 2, 2] = 1.  # Y22

    for l in range(2, lmax + 1):
        for m in range(0, l + 1):
            sh[0, l, m] = 1.
            coeffs = pyshtools.expand.SHMultiply(sh20, sh)
            cp20[0, l, m] = coeffs[0, l, m]
            if m != 0:
                cp20[1, l, m] = cp20[0, l, m]
            if l == 2 and m == 0:
                p402020 = coeffs[0, 4, 0]
            if l == 2 and m == 1:
                p412021 = coeffs[0, 4, 1]
            if l == 2 and m == 2:
                p422022 = coeffs[0, 4, 2]

            coeffs = pyshtools.expand.SHMultiply(sh22, sh)
            cp22[0, l, m] = coeffs[0, l, m]
            sh[0, l, m] = 0.

            if m > 0:
                sh[1, l, m] = 1.
                coeffs = pyshtools.expand.SHMultiply(sh22, sh)
                cp22[1, l, m] = coeffs[1, l, m]
                sh[1, l, m] = 0.

    # Calculate delta_rho

    drho = np.zeros(n + 1)
    mass = np.zeros(n + 1)

    for i in range(1, n + 1):
        drho[i] = rho[i - 1] - rho[i]

    # Calculate matrix A and invert for relief.

    a = np.zeros((n + 1, n + 1))
    atides = np.zeros((2, n + 1))
    b4 = np.zeros((2, 3, n + 1))

    # Calculate cumulate mass function
    for i in range(1, n + 1):
        if i == 1:
            mass[1] = 4. * np.pi * radius[1]**3 * rho[0] / 3.
        else:
            mass[i] = mass[i-1] + 4. * np.pi * \
                    (radius[i]**3 - radius[i-1]**3) * rho[i-1] / 3.

    mass_model = mass[n]

    for l in range(2, lmax + 1, 2):
        for m in range(0, lmax + 1):
            for i in range(1, n + 1):  # zero index not computed
                for j in range(1, n + 1):
                    if i == j:  # cp20 for sin and cosine terms are equal
                        a[i, j] = 4. * np.pi * g * drho[i] * radius[i] / \
                            (2. * l + 1.) - g * mass[i] / radius[i]**2 + \
                            (2./3.) * radius[i] * omega**2 * \
                            (1. - cp20[0, l, m] / np.sqrt(5.0))
                    elif j < i:
                        a[i, j] = 4. * np.pi * g * drho[j] * \
                            radius[j]**(l+2) / (2. * l + 1.) / \
                            radius[i]**(l+1)
                    else:
                        a[i, j] = 4. * np.pi * g * drho[j] * \
                            radius[i]**l / (2. * l + 1.) / \
                            radius[j]**(l-1)

                if tides is True:
                    atides[0, i] = g * mp * radius[i] / rp**3 * (
                        -np.sqrt(5.) / 5. * cp20[0, l, m] +
                        np.sqrt(12. / 5.) * cp22[0, l, m] / 2.)
                    atides[1, i] = g * mp * radius[i] / rp**3 * (
                        -np.sqrt(5.) / 5. * cp20[1, l, m] +
                        np.sqrt(12. / 5.) * cp22[1, l, m] / 2.)

            # --- do cosine term ---

            b = np.zeros(n + 1)
            if l == 2 and m == 0:
                for i in range(1, n + 1):
                    b[i] = (omega * radius[i])**2 / (3. * np.sqrt(5.))
                    if tides:
                        b[i] += g * mp * radius[i]**2 / rp**3 * \
                            np.sqrt(5.) / 10.
            if l == 2 and m == 2 and tides:
                for i in range(1, n + 1):
                    b[i] = - g * mp * radius[i]**2 / rp**3 * \
                        np.sqrt(12./5.) / 4.

            # Add contributions from degree 2 relief to degree 4.
            if l == 4 and m <= 2:
                b[1:n + 1] = b4[0, m, 1:n + 1]

            # solve the linear equation A h = b
            atemp = a.copy()
            if tides:
                for i in range(1, n + 1):
                    atemp[i, i] += atides[0, i]

            btemp = b.copy()

            # note that the zero index is not used
            lu, piv, x, info = lapack.dgesv(atemp[1:, 1:], btemp[1:])
            if info != 0:
                raise ("lapack.dgesv did not exit properly: {:d}", info)
            for i in range(1, n + 1):
                hlm[i].coeffs[0, l, m] = x[i - 1]

            # calculate b4 contribution
            if l == 2:
                for i in range(1, n + 1):
                    if m == 0:
                        b4[0, m, i] = 2. / 3. / np.sqrt(5.) * \
                            omega**2 * radius[i] * \
                            hlm[i].coeffs[0, l, m] * p402020
                    elif m == 1:
                        b4[0, m, i] = 2. / 3. / np.sqrt(5.) * \
                            omega**2 * radius[i] * \
                            hlm[i].coeffs[0, l, m] * p412021
                    elif m == 2:
                        b4[0, m, i] = 2. / 3. / np.sqrt(5.) * \
                            omega**2 * radius[i] * \
                            hlm[i].coeffs[0, l, m] * p422022

            # --- do sine term ---

            b = np.zeros(n + 1)
            if m != 0:
                # Add contributions from degree 2 relief to degree 4.
                if l == 4 and m <= 2:
                    b[1:n + 1] = b4[1, m, 1:n + 1]

                # solve the linear equation A h = b
                atemp = a.copy()
                if tides:
                    for i in range(1, n + 1):
                        atemp[i, i] += atides[1, i]

                btemp = b.copy()

                # note that the zero index is not used
                lu, piv, x, info = lapack.dgesv(atemp[1:, 1:], btemp[1:])
                if info != 0:
                    raise ("lapack.dgesv did not exit properly: {:d}", info)
                for i in range(1, n + 1):
                    hlm[i].coeffs[1, l, m] = x[i - 1]

                # calculate b4 contribution
                if l == 2:
                    for i in range(1, n + 1):
                        if m == 1:
                            b4[1, m, i] = 2. / 3. / np.sqrt(5.) * \
                                omega**2 * radius[i] * \
                                hlm[i].coeffs[1, l, m] * p412021
                        elif m == 2:
                            b4[1, m, i] = 2. / 3. / np.sqrt(5.) * \
                                omega**2 * radius[i] * \
                                hlm[i].coeffs[1, l, m] * p422022

    # Calculate potential at r_ref resulting from all interfaces

    coeffs = np.zeros((2, lmax + 1, lmax + 1))
    for i in range(1, n + 1):
        for l in range(2, lmax + 1):
            coeffs[:, l, :l+1] += hlm[i].coeffs[:, l, :l+1] * 4. * \
                np.pi * drho[i] * radius[i]**2 * (radius[i] / r_ref)**l * \
                g / gm / (2. * l + 1.)

    clm_hydro = pyshtools.SHGravCoeffs.from_array(coeffs,
                                                  gm=gm,
                                                  r0=r_ref,
                                                  omega=omega)

    return hlm, clm_hydro, mass_model
Exemple #10
0
def HydrostaticShape(radius,
                     rho,
                     omega,
                     gm,
                     r_ref,
                     finiteamplitude=False,
                     rp=None,
                     mp=None,
                     nmax=7,
                     kmax=4):
    """
    Calculate the shape of hydrostatic relief in a rotating planet or moon,
    along with the total gravitation potential. For the case of a moon in
    synchronous rotation, optionally include the tidal potential.

    Usage
    -----
    hlm, clm_hydro, mass = HydrostaticFlatteningLith(radius, density,
        omega, gm, r_ref, [finiteamplitude, rp, mp, nmax])

    Returns
    -------
    hlm : array of SHCoeffs class instances, size(n+1)
        Array of SHCoeffs class instances of the spherical harmonic
        coefficients of the hydrostatic relief at each interface.
    clm_hydro : SHCoeffs class instance containing the gravitational potential
        resulting from all hydrostatic interfaces.
    mass : float
        Total mass of the planet, assuming a spherical shape and the provided
        1D density profile.

    Parameters
    ----------
    radius : ndarray, float, size(n+1)
        Radius of each density interface, where index 0 corresponds to the
        center of the planet and n corresponds to the surface.
    density : ndarray, float, size(n+1)
        Density of layer i between radius[i] and radius[i+1]. The density
        at index 0 is from the center of the planet to radius[1], whereas the
        the density at index n should be zero.
    omega : float
        Angular rotation rate of the planet.
    gm : float
        GM of the planet.
    r_ref : float
        Refernce radius for output potential coefficients.
    finiteamplitude : bool, optional, default = False
        If True, compute finite amplitude terms when calculating the
        gravitational potentials.
    rp : float, optional, default = None
        If specified, include the tidal potential acting on a synchronously
        rotating moon, where rp is the average distance between the planet
        and satellite.
    mp : float, optional, default = None
        The mass of the host planet, at a distance rp from the satellite.
    nmax : int, optional, default = 7
        The order of the approximation when computing the gravitational
        potential.
    kmax : int, optionalm, defaut = 4
        Number of iterations to perform when calculating the finite-amplitude
        correction.

    """
    tides = False
    if rp is not None:
        if mp is None:
            raise ValueError('When including tides, both rp and mp must be ' +
                             'specified.')
        tides = True
    if mp is not None:
        if rp is None:
            raise ValueError('When including tides, both rp and mp must be ' +
                             'specified.')
        tides = True

    if len(radius) != len(rho):
        raise ('Length of radius and density must be the same.' +
               'len(radius) = {:d}. len(density) = {:d}.'.format(
                   len(radius), len(rho)))

    n = len(radius) - 1  # index of surface
    lmax = 4
    lmaxgrid = 7 * lmax  # increase grid size to avoid aliasing

    g = float(pyshtools.constant.grav_constant)

    hlm = [pyshtools.SHCoeffs.from_zeros(lmax) for i in range(n + 1)]
    clm_hydro = pyshtools.SHCoeffs.from_zeros(lmax)

    for i in range(n + 1):
        hlm[i].coeffs[0, 0, 0] = radius[i]

    if finiteamplitude:
        dcminus = np.zeros((n + 1, 2, lmax + 1, lmax + 1))
        dcplus = np.zeros((n + 1, 2, lmax + 1, lmax + 1))
    else:
        kmax = 1

    # First determine the spherical harmonic coefficients of (Y20 Ylm)
    # and for tides, (Y22 Ylm). We are only concerned with the coefficient
    # that corresponds to lm, so for each lm, store only the lm component in
    # the array cp20 and cp22.

    sh20 = np.zeros((2, lmax + 1, lmax + 1))
    sh22 = np.zeros((2, lmax + 1, lmax + 1))
    sh = np.zeros((2, lmax + 1, lmax + 1))
    cp20 = np.zeros((2, lmax + 1, lmax + 1))
    cp22 = np.zeros((2, lmax + 1, lmax + 1))

    sh20[0, 2, 0] = 1.  # Y20
    sh22[0, 2, 2] = 1.  # Y22

    for l in range(2, lmax + 1):
        for m in range(0, l + 1):
            sh[0, l, m] = 1.
            coeffs = pyshtools.expand.SHMultiply(sh20, sh)
            cp20[0, l, m] = coeffs[0, l, m]
            if m != 0:
                cp20[1, l, m] = cp20[0, l, m]
            if l == 2 and m == 0:
                p402020 = coeffs[0, 4, 0]
            if l == 2 and m == 1:
                p412021 = coeffs[0, 4, 1]
            if l == 2 and m == 2:
                p422022 = coeffs[0, 4, 2]

            coeffs = pyshtools.expand.SHMultiply(sh22, sh)
            cp22[0, l, m] = coeffs[0, l, m]
            sh[0, l, m] = 0.

            if m > 0:
                sh[1, l, m] = 1.
                coeffs = pyshtools.expand.SHMultiply(sh22, sh)
                cp22[1, l, m] = coeffs[1, l, m]
                sh[1, l, m] = 0.

    # Calculate delta_rho

    drho = np.zeros(n + 1)
    mass = np.zeros(n + 1)

    for i in range(1, n + 1):
        drho[i] = rho[i - 1] - rho[i]

    # Calculate matrix A and invert for relief.

    a = np.zeros((n + 1, n + 1))
    atides = np.zeros((2, n + 1))
    b4 = np.zeros((2, 3, n + 1))
    mass_sheet = np.zeros((2, lmax + 1, lmax + 1))

    for k in range(kmax):

        # calculate mass, taking into account the flattening of each interface
        for i in range(1, n + 1):
            if i == 1:
                mass[1] = 4. * np.pi * radius[1]**3 * rho[0] / 3. + \
                    4. * np.pi * rho[0] * radius[1] * \
                    hlm[1].coeffs[0, 2, 0]**2 + 8. * np.pi * np.sqrt(5.) / \
                    21. * rho[0] * hlm[1].coeffs[0, 2, 0]**3
            else:
                mass[i] = mass[i-1] + 4. * np.pi * \
                    (radius[i]**3 - radius[i-1]**3) * rho[i-1] / 3. + \
                    4. * np.pi * rho[i-1] * (radius[i] *
                                             hlm[i].coeffs[0, 2, 0]**2 -
                                             radius[i-1] *
                                             hlm[i-1].coeffs[0, 2, 0]**2) + \
                    8. * np.pi * np.sqrt(5.) / 21. * rho[i-1] * \
                    (hlm[i].coeffs[0, 2, 0]**3 - hlm[i-1].coeffs[0, 2, 0]**3)

        mass_model = mass[n]

        # calculate finite amplitude corrections
        if finiteamplitude and k > 0:
            for i in range(1, n + 1):
                grid = hlm[i].expand(grid='DH1', lmax=lmaxgrid, lmax_calc=lmax)
                clm, r = pyshtools.gravmag.CilmPlusDH(grid.data,
                                                      nmax,
                                                      gm / g,
                                                      drho[i],
                                                      lmax=lmax)
                dcplus[i, :, :, :] = clm[:, :, :]
                clm, r = pyshtools.gravmag.CilmMinusDH(grid.data,
                                                       nmax,
                                                       gm / g,
                                                       drho[i],
                                                       lmax=lmax)
                dcminus[i, :, :, :] = clm[:, :, :]
                for l in range(1, lmax + 1):
                    mass_sheet[:, l, :l+1] = 4. * np.pi * g * drho[i] * \
                        radius[i]**2 * hlm[i].coeffs[:, l, :l+1] / gm / \
                        (2. * l + 1.)
                    dcplus[i, :, l, :l + 1] -= mass_sheet[:, l, :l + 1]
                    dcminus[i, :, l, :l + 1] -= mass_sheet[:, l, :l + 1]

        for l in range(2, lmax + 1, 2):
            for m in range(0, lmax + 1):
                for i in range(1, n + 1):  # zero index not computed
                    for j in range(1, n + 1):
                        if i == j:  # cp20 for sin and cosine terms are equal
                            a[i, j] = 4. * np.pi * g * drho[i] * radius[i] / \
                                (2. * l + 1.) - g * mass[i] / radius[i]**2 + \
                                (2./3.) * radius[i] * omega**2 * \
                                (1. - cp20[0, l, m] / np.sqrt(5.0))
                        elif j < i:
                            a[i, j] = 4. * np.pi * g * drho[j] * \
                                radius[j]**(l+2) / (2. * l + 1.) / \
                                radius[i]**(l+1)
                        else:
                            a[i, j] = 4. * np.pi * g * drho[j] * \
                                radius[i]**l / (2. * l + 1.) / \
                                radius[j]**(l-1)

                    if tides is True:
                        atides[0, i] = g * mp * radius[i] / rp**3 * (
                            -np.sqrt(5.) / 5. * cp20[0, l, m] +
                            np.sqrt(12. / 5.) * cp22[0, l, m] / 2.)
                        atides[1, i] = g * mp * radius[i] / rp**3 * (
                            -np.sqrt(5.) / 5. * cp20[1, l, m] +
                            np.sqrt(12. / 5.) * cp22[1, l, m] / 2.)

                b = np.zeros(n + 1)
                if l == 2 and m == 0:
                    for i in range(1, n + 1):
                        b[i] = (omega * radius[i])**2 / (3. * np.sqrt(5.))
                        if tides:
                            b[i] += g * mp * radius[i]**2 / rp**3 * \
                                np.sqrt(5.) / 10.
                if l == 2 and m == 2 and tides:
                    for i in range(1, n + 1):
                        b[i] = - g * mp * radius[i]**2 / rp**3 * \
                            np.sqrt(12./5.) / 4.

                # --- do cosine term ---

                # Add contributions from degree 2 relief to degree 4.
                if l == 4 and m <= 2:
                    b[1:n + 1] = b4[0, m, 1:n + 1]

                # calculate delta
                if k > 0:
                    d = np.zeros(n + 1)
                    for i in range(1, n + 1):
                        for j in range(1, n + 1):
                            if j <= i:
                                d[i] -= dcplus[j, 0, l, m] * gm * \
                                    radius[j]**l / radius[i]**(l+1)
                            else:
                                d[i] -= dcminus[j, 0, l, m] * gm * \
                                    radius[i]**l / radius[j]**(l+1)

                # solve the linear equation A h = b
                atemp = a.copy()
                if tides:
                    for i in range(1, n + 1):
                        atemp[i, i] += atides[0, i]

                btemp = b.copy()
                if k > 0:
                    btemp += d

                # note that the zero index is not used
                lu, piv, x, info = lapack.dgesv(atemp[1:, 1:], btemp[1:])
                if info != 0:
                    raise ("lapack.dgesv did not exit properly: {:d}", info)
                for i in range(1, n + 1):
                    hlm[i].coeffs[0, l, m] = x[i - 1]

                # calculate b4 contribution
                if l == 2:
                    for i in range(1, n + 1):
                        if m == 0:
                            b4[0, m, i] = 2. / 3. / np.sqrt(5.) * \
                                omega**2 * radius[i] * \
                                hlm[i].coeffs[0, l, m] * p402020
                        elif m == 1:
                            b4[0, m, i] = 2. / 3. / np.sqrt(5.) * \
                                omega**2 * radius[i] * \
                                hlm[i].coeffs[0, l, m] * p412021
                        elif m == 2:
                            b4[0, m, i] = 2. / 3. / np.sqrt(5.) * \
                                omega**2 * radius[i] * \
                                hlm[i].coeffs[0, l, m] * p422022

                # --- do sine term ---

                b = np.zeros(n + 1)
                if m != 0:
                    # Add contributions from degree 2 relief to degree 4.
                    if l == 4 and m <= 2:
                        b[1:n + 1] = b4[1, m, 1:n + 1]

                    # calculate delta
                    if k > 0:
                        d = np.zeros(n + 1)
                        for i in range(1, n + 1):
                            for j in range(1, n + 1):
                                if j <= i:
                                    d[i] -= dcplus[j, 1, l, m] * gm * \
                                        radius[j]**l / radius[i]**(l+1)
                                else:
                                    d[i] -= dcminus[j, 1, l, m] * gm * \
                                        radius[i]**l / radius[j]**(l+1)

                    # solve the linear equation A h = b
                    atemp = a.copy()
                    if tides:
                        for i in range(1, n + 1):
                            atemp[i, i] += atides[1, i]

                    btemp = b.copy()
                    if k > 0:
                        btemp += d

                    # note that the zero index is not used
                    lu, piv, x, info = lapack.dgesv(atemp[1:, 1:], btemp[1:])
                    if info != 0:
                        raise ("lapack.dgesv did not exit properly: {:d}",
                               info)
                    for i in range(1, n + 1):
                        hlm[i].coeffs[1, l, m] = x[i - 1]

                    # calculate b4 contribution
                    if l == 2:
                        for i in range(1, n + 1):
                            if m == 1:
                                b4[1, m, i] = 2. / 3. / np.sqrt(5.) * \
                                    omega**2 * radius[i] * \
                                    hlm[i].coeffs[1, l, m] * p412021
                            elif m == 2:
                                b4[1, m, i] = 2. / 3. / np.sqrt(5.) * \
                                    omega**2 * radius[i] * \
                                    hlm[i].coeffs[1, l, m] * p422022

    # Calculate potential at r_ref resulting from all interfaces below and
    # including ilith

    coeffs = np.zeros((2, lmax + 1, lmax + 1))
    for i in range(1, n + 1):
        if finiteamplitude is True:
            grid = hlm[i].expand(grid='DH1', lmax=lmaxgrid, lmax_calc=lmax)
            clm, r = pyshtools.gravmag.CilmPlusDH(grid.data,
                                                  nmax,
                                                  gm / g,
                                                  drho[i],
                                                  lmax=lmax)
            for l in range(2, lmax + 1):
                coeffs[:,
                       l, :l + 1] += clm[:, l, :l + 1] * (radius[i] / r_ref)**l
        else:
            for l in range(2, lmax + 1):
                coeffs[:, l, :l+1] += hlm[i].coeffs[:, l, :l+1] * 4. * \
                    np.pi * drho[i] * radius[i]**2 * (radius[i] / r_ref)**l * \
                    g / gm / (2. * l + 1.)

    clm_hydro = pyshtools.SHCoeffs.from_array(coeffs,
                                              normalization='4pi',
                                              csphase=1)
    clm_hydro.r_ref = r_ref
    clm_hydro.gm = gm

    return hlm, clm_hydro, mass_model
Exemple #11
0
def HydrostaticShapeLith(radius, rho, ilith, potential, topo, rho_surface,
                         r_sigma, omega, lmax, rp=None, mp=None, nmax=7):
    """
    Calculate the shape of hydrostatic relief in a rotating planet or moon with
    a non-hydrostatic lithosphere, along with the total gravitation potential
    of the hydrostatic interfaces. For the case of a moon in synchronous
    rotation, optionally include the tidal potential.

    Returns
    -------
    hlm : array of SHCoeffs class instances, size(n+1)
        Array of SHCoeffs class instances of the spherical harmonic
        coefficients of the hydrostatic relief at each interface.
    clm_hydro : SHCoeffs class instance containing the gravitational potential
        resulting from all hydrostatic interfaces.
    mass : float
        Total mass of the planet, assuming a spherical shape and the provided
        1D density profile.

    Parameters
    ----------
    radius : ndarray, float, size(n+1)
        Radius of each density interface, where index 0 corresponds to the
        center of the planet and n corresponds to the surface.
    density : ndarray, float, size(n+1)
        Density of layer i between radius[i] and radius[i+1]. The density
        at index 0 is from the center of the planet to radius[1], whereas the
        the density at index n should be zero.
    ilith : int
        Index of the interface that corresponds to the base of the lithosphere.
    potential : SHGravCoeffs class instance
        Observed gravitational potential coefficients.
    topo : SHCoeffs class instance
        Observed shape of the planet.
    rho_surface : float
        Effective density of the surface relief.
    r_sigma : float
        Radius of the mass sheet source in the lithosphere.
    omega : float
        Angular rotation rate of the planet.
    lmax : int
        Maximum spherical harmonic degree to compute for the hydrostatic
        relief at each interface.
    rp : float, optional, default = None
        If specified, include the tidal potential acting on a synchronously
        rotating moon, where rp is the average distance between the planet
        and satellite.
    mp : float, optional, default = None
        The mass of the host planet, at a distance rp from the satellite.
    nmax : int, optional, default = 7
        The order of the approximation when computing the gravitational
        potential of the surface.
    """
    tides = False
    if rp is not None:
        if mp is None:
            raise ValueError('When including tides, both rp and mp must be ' +
                             'specified.')
        tides = True
    if mp is not None:
        if rp is None:
            raise ValueError('When including tides, both rp and mp must be ' +
                             'specified.')
        tides = True

    if len(radius) != len(rho):
        raise('Length of radius and density must be the same.' +
              'len(radius) = {:d}. len(density) = {:d}.'
              .format(len(radius), len(rho)))

    n = len(radius) - 1  # index of surface
    lmaxgrid = 3*lmax  # increase grid size to avoid aliasing

    g = pysh.constants.G.value
    gm = potential.gm
    r_ref = potential.r0

    hlm = [pysh.SHCoeffs.from_zeros(lmax) for i in range(ilith+1)]
    clm_hydro = pysh.SHCoeffs.from_zeros(lmax)

    for i in range(ilith+1):
        hlm[i].coeffs[0, 0, 0] = radius[i]

    # First determine the spherical harmonic coefficients of (Y20 Ylm)
    # and for tides, (Y22 Ylm). We are only concerned with the coefficient
    # that corresponds to lm, so for each lm, store only the lm component in
    # the array cp20 and cp22.

    sh20 = np.zeros((2, lmax+1, lmax+1))
    sh22 = np.zeros((2, lmax+1, lmax+1))
    sh = np.zeros((2, lmax+1, lmax+1))
    cp20 = np.zeros((2, lmax+1, lmax+1))
    cp22 = np.zeros((2, lmax+1, lmax+1))

    sh20[0, 2, 0] = 1.  # Y20
    sh22[0, 2, 2] = 1.  # Y22

    for l in range(1, lmax+1):
        for m in range(0, l+1):
            sh[0, l, m] = 1.
            coeffs = pysh.expand.SHMultiply(sh20, sh)
            cp20[0, l, m] = coeffs[0, l, m]
            if m != 0:
                cp20[1, l, m] = cp20[0, l, m]
            if l == 2 and m == 0:
                p402020 = coeffs[0, 4, 0]
            if l == 2 and m == 1:
                p412021 = coeffs[0, 4, 1]
            if l == 2 and m == 2:
                p422022 = coeffs[0, 4, 2]

            coeffs = pysh.expand.SHMultiply(sh22, sh)
            cp22[0, l, m] = coeffs[0, l, m]
            sh[0, l, m] = 0.

            if m > 0:
                sh[1, l, m] = 1.
                coeffs = pysh.expand.SHMultiply(sh22, sh)
                cp22[1, l, m] = coeffs[1, l, m]
                sh[1, l, m] = 0.

    # Calculate delta_rho

    drho = np.zeros(n+1)
    mass = np.zeros(n+1)

    for i in range(1, n):
        drho[i] = rho[i-1] - rho[i]
    drho[n] = rho_surface  # Effective density of the surface layer

    a = np.zeros((ilith+2, ilith+2))
    atides = np.zeros((2, ilith+1))
    b4 = np.zeros((2, 3, ilith+1))

    # Calculate cumulate mass function

    for i in range(1, n+1):
        if i == 1:
            mass[1] = 4. * np.pi * radius[1]**3 * rho[0] / 3.
        else:
            mass[i] = mass[i-1] + 4. * np.pi * \
                (radius[i]**3 - radius[i-1]**3) * rho[i-1] / 3.

    mass_model = mass[n]

    # Calculate potential coefficients of the surface relief

    grid = topo.expand(grid='DH2', lmax=lmaxgrid, lmax_calc=lmax, extend=False)
    cplus, r_surface = pysh.gravmag.CilmPlusDH(grid.data, nmax, gm/g,
                                               rho_surface, lmax=lmax)
    cminus, r_surface = pysh.gravmag.CilmMinusDH(grid.data, nmax, gm/g,
                                                 rho_surface, lmax=lmax)

    # Calculate matrix A and invert for relief.

    for l in range(1, lmax+1):
        for m in range(0, lmax+1):
            for i in range(1, ilith+1):  # zero index not computed
                for j in range(1, ilith+1):
                    if i == j:  # cp20 for sin and cosine terms are equal
                        a[i, j] = 4. * np.pi * g * drho[i] * radius[i] / \
                            (2. * l + 1.) - g * mass[i] / radius[i]**2 + \
                            (2./3.) * radius[i] * omega**2 * \
                            (1. - cp20[0, l, m] / np.sqrt(5.0))
                    elif j < i:
                        a[i, j] = 4. * np.pi * g * drho[j] / (2. * l + 1.) \
                            * radius[j] * (radius[j] / radius[i])**(l+1)
                    else:
                        a[i, j] = 4. * np.pi * g * drho[j] / (2. * l + 1.) \
                            * radius[i] * (radius[i] / radius[j])**(l-1)

                a[i, ilith+1] = 4. * np.pi * g / (2. * l + 1.) \
                    * radius[i] * (radius[i] / r_sigma)**(l-1)

                if tides is True:
                    atides[0, i] = g * mp * radius[i] / rp**3 * (
                        - np.sqrt(5.) / 5. * cp20[0, l, m] +
                        np.sqrt(12./5.) * cp22[0, l, m] / 2.)
                    atides[1, i] = g * mp * radius[i] / rp**3 * (
                        - np.sqrt(5.) / 5. * cp20[1, l, m] +
                        np.sqrt(12./5.) * cp22[1, l, m] / 2.)

            for j in range(1, ilith+1):
                a[ilith+1, j] = 4. * np.pi * g * drho[j] / (2. * l + 1.) \
                    * radius[j] * (radius[j] / r_ref)**(l+1)

            a[ilith+1, ilith+1] = 4. * np.pi * g / (2. * l + 1.)\
                * r_sigma * (r_sigma / r_ref)**(l+1)

            # --- do cosine term ---

            b = np.zeros(ilith+2)
            if l == 2 and m == 0:
                for i in range(1, ilith+1):
                    b[i] = (omega * radius[i])**2 / (3. * np.sqrt(5.))
                    if tides:
                        b[i] += g * mp * radius[i]**2 / rp**3 * \
                            np.sqrt(5.) / 10.
            if l == 2 and m == 2 and tides:
                for i in range(1, ilith+1):
                    b[i] = - g * mp * radius[i]**2 / rp**3 * \
                        np.sqrt(12./5.) / 4.

            # Add contributions from degree 2 relief to degree 4.
            if l == 4 and m <= 2:
                b[1:ilith+1] = b4[0, m, 1:ilith+1]

            for i in range(1, ilith+1):
                b[i] -= gm * cminus[0, l, m] * (radius[i] / r_surface)**l \
                    / r_surface
            b[ilith+1] = gm * potential.coeffs[0, l, m] / r_ref - \
                gm * cplus[0, l, m] * (r_surface / r_ref)**l / r_ref

            # solve the linear equation A h = b
            atemp = a.copy()
            if tides:
                for i in range(1, ilith+1):
                    atemp[i, i] += atides[0, i]

            btemp = b.copy()

            # note that the zero index is not used
            lu, piv, x, info = lapack.dgesv(atemp[1:, 1:], btemp[1:])
            if info != 0:
                raise("lapack.dgesv did not exit properly: {:d}", info)
            for i in range(1, ilith+1):
                hlm[i].coeffs[0, l, m] = x[i-1]

            # calculate b4 contribution
            if l == 2:
                for i in range(1, ilith+1):
                    if m == 0:
                        b4[0, m, i] = 2. / 3. / np.sqrt(5.) * \
                            omega**2 * radius[i] * \
                            hlm[i].coeffs[0, l, m] * p402020
                    elif m == 1:
                        b4[0, m, i] = 2. / 3. / np.sqrt(5.) * \
                            omega**2 * radius[i] * \
                            hlm[i].coeffs[0, l, m] * p412021
                    elif m == 2:
                        b4[0, m, i] = 2. / 3. / np.sqrt(5.) * \
                            omega**2 * radius[i] * \
                            hlm[i].coeffs[0, l, m] * p422022

            # --- do sine term ---

            b = np.zeros(ilith+2)
            if m != 0:
                # Add contributions from degree 2 relief to degree 4.
                if l == 4 and m <= 2:
                    b[1:ilith+1] = b4[1, m, 1:ilith+1]

                for i in range(1, ilith+1):
                    b[i] -= gm * cminus[1, l, m] * (radius[i] / r_surface)**l \
                            / r_surface
                    b[ilith+1] = gm * potential.coeffs[1, l, m] / r_ref - \
                        gm * cplus[1, l, m] * (r_surface / r_ref)**l / r_ref

                # solve the linear equation A h = b
                atemp = a.copy()
                if tides:
                    for i in range(1, ilith+1):
                        atemp[i, i] += atides[1, i]

                btemp = b.copy()

                # note that the zero index is not used
                lu, piv, x, info = lapack.dgesv(atemp[1:, 1:], btemp[1:])
                if info != 0:
                    raise("lapack.dgesv did not exit properly: {:d}", info)
                for i in range(1, ilith+1):
                    hlm[i].coeffs[1, l, m] = x[i-1]

                # calculate b4 contribution
                if l == 2:
                    for i in range(1, ilith+1):
                        if m == 1:
                            b4[1, m, i] = 2. / 3. / np.sqrt(5.) * \
                                omega**2 * radius[i] * \
                                hlm[i].coeffs[1, l, m] * p412021
                        elif m == 2:
                            b4[1, m, i] = 2. / 3. / np.sqrt(5.) * \
                                omega**2 * radius[i] * \
                                hlm[i].coeffs[1, l, m] * p422022

    # Calculate potential at r_ref resulting from all interfaces below and
    # including ilith

    coeffs = np.zeros((2, lmax+1, lmax+1))
    for i in range(1, ilith+1):
        for l in range(1, lmax+1):
            coeffs[:, l, :l+1] += hlm[i].coeffs[:, l, :l+1] * 4. * \
                np.pi * drho[i] * radius[i]**2 * (radius[i] / r_ref)**l * \
                g / gm / (2. * l + 1.)

    clm_hydro = pysh.SHGravCoeffs.from_array(coeffs, gm=gm, r0=r_ref,
                                             omega=omega)

    return hlm, clm_hydro, mass_model