Skip to content
Snippets Groups Projects
reference_implementation.py 3.79 KiB
Newer Older
  • Learn to ignore specific revisions
  • import numpy as np
    import numpy.linalg as la  # noqa: F401
    import pyopencl as cl  # noqa: F401
    import pyopencl.array  # noqa
    import pyopencl.tools  # noqa
    import pyopencl.clrandom  # noqa
    import loopy as lp  # noqa
    
    
    
    # FIXME: add new file ideal_gas.py that has flux, pressure, etc. (any
    # computation that depends on EOS
    
    def pressure(state):
        # FIXME: for ideal gas stuff, make nvars, ndim, gamma, etc module level
        # constants
        # FIXME: also split out velocity, rho, energy into separate routines
        gamma = 1.4
        ndim = state.size - 2
    
        rho = state[0]
        energy = state[ndim+1]
    
        ke = 0.0
        for i in range(ndim):
            ke += (state[i+1]/rho)**2
        ke = 0.5*rho*ke
    
        return (gamma - 1)*(energy - ke)
    
    
    def flux(state):
        nvars = state.size
        ndim = nvars - 2
        result = np.empty((nvars, ndim))
    
        rho = state[0]
        u = state[1:ndim+1]/rho
        energy = state[ndim+1]
        p = pressure(state)
    
        for i in range(ndim):
            result[:,i] = u[i]*state
            result[i+1,i] += p
            result[ndim+1,i] += u[i]*p
    
        return result
    
    
    def pointwise_fluxes(states):
        nvars, npoints = states.shape
        ndim = 3
        result = np.empty((nvars, ndim, npoints))
    
        for k in range(npoints):
            result[:,:,k] = flux(states[:,k])
    
        return result
    
    
    def split_char_fluxes(states, wavespeeds, frozen_metrics, frozen_jacobian, R_inv):
        nvars, npoints = states.shape
        ndim = frozen_metrics.size
    
        fluxes = pointwise_fluxes(states)
    
        char_fluxes_pos = np.empty((nvars, npoints))
        char_fluxes_neg = np.empty((nvars, npoints))
        for k in range(npoints):
            generalized_fluxes = np.zeros(nvars)
            for i in range(ndim):
                generalized_fluxes += frozen_metrics[i]*fluxes[:,i,k]
    
            generalized_states = states[:,k]/frozen_jacobian
    
            combination_pos = np.empty((nvars, nvars))
            combination_neg = np.empty((nvars, nvars))
            for i in range(nvars):
                char_fluxes_pos[i,k] = 0.5*np.dot(R_inv[i,:],
                        (generalized_fluxes + wavespeeds[i]*generalized_states))
                char_fluxes_neg[i,k] = 0.5*np.dot(R_inv[i,:],
                        (generalized_fluxes - wavespeeds[i]*generalized_states))
    
        return char_fluxes_pos, char_fluxes_neg
    
    
    
    def oscillation(fluxes):
        sum1 = np.empty((fluxes.shape[0], 3))
        sum2 = np.empty((fluxes.shape[0], 3))
    
        sum1[:,0] = fluxes[:,0] - 4*fluxes[:,1] + 3*fluxes[:,2]
        sum1[:,1] = -fluxes[:,1] + fluxes[:,3]
        sum1[:,2] = -3*fluxes[:,2] + 4*fluxes[:,3] - fluxes[:,4]
    
        for i in range(3):
            sum2[:,i] = fluxes[:,i] - 2*fluxes[:,i+1] + fluxes[:,i+2]
    
        result = (1.0/4)*(sum1**2) + (13.0/12)*(sum2**2)
    
        return result
    
    
    
    def weno_weights(oscillation, frozen_metric):
        linear = np.array([0.1, 0.6, 0.3])
        eps = 1e-6*frozen_metric
    
        raw_weights = np.empty((5,3))
        for i in range(5):
            for j in range(3):
                raw_weights[i,j] = linear[j]/(oscillation[i,j] + eps)**2
    
        weight_sum = raw_weights.sum(axis=1)
        weights = np.empty((5,3))
        for i in range(5):
            for j in range(3):
                weights[i,j] = raw_weights[i,j]/weight_sum[i]
    
        return weights
    
    
    
    def flux_differences(f):
        w = np.array([-1, 3, -3, 1])
        res = np.empty((5, 3))
        for j in range(res.shape[1]):
            res[:,j] = f[:,j:j+4]@w
        return res
    
    
    def combination_weighting(w):
        return np.array(
                [20*w[:,0] - 1, -10*(w[:,0] + w[:,1]) + 5, np.ones(w.shape[0])]
                ).T
    
    
    def combine_fluxes(w, f):
        cw = combination_weighting(w)
        return np.sum(np.multiply(cw, f), axis=1)
    
    
    
    def dissipation_part(R, char_fluxes, w, sign):
        flux_diff = flux_differences(char_fluxes)[:,::sign]
    
        flux_comb = combine_fluxes(w, flux_diff)
    
    
        return -sign*R@flux_comb/60
    
    
    
    def weno_flux(consistent, dissipation_pos, dissipation_neg):
        return consistent + dissipation_pos + dissipation_neg