Esempio n. 1
0
 def __init__(self, v, t, b, Mach):
     self.mesh = Mesh(v, t, b)
     self.Mach = float(Mach)
     self.ode = Ode(self.ddt, self.J)
Esempio n. 2
0
class Euler:
    def __init__(self, v, t, b, Mach):
        self.mesh = Mesh(v, t, b)
        self.Mach = float(Mach)
        self.ode = Ode(self.ddt, self.J)

    def integrate(self, *args, **argv):
        return self.ode.integrate(*args, **argv)

    @property
    def nt(self):
        return self.mesh.nt

    @property
    def time(self):
        return self.ode.t

    @property
    def soln(self):
        return reshape(self.ode.y, [-1,4])

    @property
    def Wref(self):
        Wr = self.freeStream(1)[0]
        Wr[2] = Wr[1]
        return Wr

    def freeStream(self, nT=None):
        if nT is None: nT = self.nt
        R, gamma, rho0, T0 = 8.314 / 29E-3, 1.4, 1.225, 288.75
        u0 = self.Mach * sqrt(gamma * R * T0)
        E0 = T0 * R / (gamma - 1) + 0.5 * u0**2
        return array([rho0, rho0 * u0, 0, rho0 * E0]) + zeros([nT, 1])

    def ddt(self, W):
        assert W.size == self.nt * 4
        shp = W.shape
        W = W.reshape([-1, 4])
        m = self.mesh
        gradW = m.gradTri(W)

        xt = m.xt()
        dxt = m.dxt

        # boundary condition categories
        xeBnd = m.v[m.e[m.ieBnd,:2],:].mean(1)
        isWall = ~m.isFar(xeBnd)

        # interior flux

        #WL, WR = W[m.e[:,2],:], W[m.e[:,3],:]
        WL, WR = m.leftRightTri(W)
        WL[m.ieBnd[~isWall]] = self.freeStream(1)

        WE = 0.5*(WL+WR)
        dW = WR - WL

        #dWL = (gradW[m.e[:,2],:] * dxt[:,:,newaxis]).sum(1)
        #dWR = (gradW[m.e[:,3],:] * dxt[:,:,newaxis]).sum(1)
        gWL, gWR = m.leftRightTri(gradW)
        dWL = einsum( 'nij, ni -> nj', gWL, dxt )
        dWR = einsum( 'nij, ni -> nj', gWR, dxt )

        flux = fluxE(WE, m.n) + fluxD(WE, dW, dWL, dWR, m.n)
        
        # boundary flux
        WBnd, nBnd = WL[m.ieBnd,:], m.n[m.ieBnd,:]
        flux[m.ieBnd[isWall]] = wallBc(WBnd[isWall,:], nBnd[isWall,:])
        # accumunate flux to cells
        return (m.distributeFlux(flux) / m.a[:,newaxis]).reshape(shp)

    def J(self, W):
        if not self.__dict__.has_key('matJacDistFlux'):
            self.prepareJacMatrices()
        assert W.size == self.nt * 4
        shp = W.shape
        W = W.reshape([-1, 4])
        m = self.mesh
        # prepare values at edge
        gradW = m.gradTri(W)
        xt = m.xt(); 
        dxt = m.dxt
        WL, WR = m.leftRightTri(W)
        isFar = m.isFar(m.v[m.e[m.ieBnd,:2],:].mean(1))
        WL[m.ieBnd[isFar]] = self.freeStream(1)
        WE, dW = 0.5 * (WL + WR), WR - WL
        JE_WE = jacE(WE, m.n)

        gWL, gWR = m.leftRightTri(gradW)
        dWL = einsum( 'nij, ni -> nj', gWL, dxt )
        dWR = einsum( 'nij, ni -> nj', gWR, dxt )

        JD_WE, JD_dW, JD_dWL, JD_dWR  = jacD(WE, dW, dWL, dWR, m.n)
        # modify for wall BC
        J_WE = JE_WE + JD_WE
        ieWall = m.ieBnd[~isFar]
        J_WE[ieWall,:] = jacWall(WE[ieWall], m.n[ieWall])
        J_flux = block_diags(J_WE) * self.matJacWE \
               + block_diags(JD_dW) * self.matJacdW \
               + block_diags(JD_dWL) * self.matJacdWL \
               + block_diags(JD_dWR) * self.matJacdWR
        return self.matJacDistFlux * J_flux

    def prepareJacMatrices(self):
        m = self.mesh
        matL = accumarray(m.e[:,2], m.t.shape[0]).mat.T.tolil()
        matR = accumarray(m.e[:,3], m.t.shape[0]).mat.T.tolil()
        # WL on far bc is freestream
        isFar = m.isFar(m.v[m.e[m.ieBnd,:2],:].mean(1))
        matL[m.ieBnd[isFar],:] = 0
        # average and difference
        self.matJacWL = spkron(matL, eye(4)).tocsr()
        self.matJacWR = spkron(matR, eye(4)).tocsr()
        self.matJacWE = spkron(0.5 * (matL + matR), eye(4)).tocsr()
        self.matJacdW = spkron(matR - matL, eye(4)).tocsr()
        # distribute flux matrix
        D = block_diags(1./ m.a[:,newaxis,newaxis])
        self.matJacDistFlux = spkron(D * m.matDistFlux, eye(4)).tocsr()
        # Tri to edg gradient with boundary copy
        matTriToBnd = accumarray(m.e[m.ieBnd,2], m.t.shape[0]).mat.T
        matGradTriEdg = m.matGradTriEdg + m.bcmatGradTriEdg * matTriToBnd
        # left and right gradient in cells
        edgOfTri = invertMap(m.e[:,2:])[1].reshape([-1, 3])
        avgEdgToTri = (accumarray(edgOfTri[:,0], m.e.shape[0]).mat.T + \
                       accumarray(edgOfTri[:,1], m.e.shape[0]).mat.T + \
                       accumarray(edgOfTri[:,2], m.e.shape[0]).mat.T) / 3.
        matGradTri = spkron(avgEdgToTri, eye(2)) * matGradTriEdg
        xt = m.xt(); dxt = xt[m.e[:,3],:] - xt[m.e[:,2],:]
        matL = spkron(accumarray(m.e[:,2], m.t.shape[0]).mat.T, eye(2))
        matR = spkron(accumarray(m.e[:,3], m.t.shape[0]).mat.T, eye(2))
        matJacdWL = block_diags(dxt[:,newaxis,:]) * matL * matGradTri
        matJacdWR = block_diags(dxt[:,newaxis,:]) * matR * matGradTri
        self.matJacdWL = spkron(matJacdWL, eye(4)).tocsr()
        self.matJacdWR = spkron(matJacdWR, eye(4)).tocsr()

    def metric(self, W=None):
        if W is None: W = self.soln
        gradV = self.mesh.gradTriVrt(W / self.Wref)
        gradV /= ((gradV**2).sum(1)[:,newaxis,:])**.25
        return (gradV[:,newaxis,:,:] * gradV[:,:,newaxis,:]).sum(-1)
        # return hessian.sum(-1)

    def checkJacobian(self):
        '''
        Generate a flow with small linear variation (supress numerical diss.),
        check adjoint ddt vs Euler ddt
        '''
        xt = self.mesh.xt()
        R = 0.2 * self.mesh.diameter()
        decay = exp(-(xt**2).sum(1) / R**2)[:,newaxis]
        nT = self.mesh.t.shape[0]
        # random flow field
        variation = 0.1 * (random.rand(nT, 4) - 0.5)
        W0 = self.freeStream() + self.Wref * variation
        # random perturbation
        EPS = 0.000001
        variation = EPS * (random.rand(nT, 4) - 0.5)
        W1 = W0 + self.Wref * variation
        # compare ddt with Jacobian
        deltaFD = self.ddt(ravel(W1)) - self.ddt(ravel(W0))
        deltaJac = self.J(0.5 * (W0 + W1)) * ravel(W1 - W0)
        # difference
        print sqrt(((deltaFD - deltaJac)**2).sum()), \
              sqrt((deltaJac**2).sum()), sqrt((deltaFD**2).sum())