def SchemeUpwind(u, A, omega, D, rhs, bc):
    """
    Discretization of -Tr(A(x) hess u(x)) + \| grad u(x) - omega(x) \|_D(x)^2 - rhs,
    with Dirichlet boundary conditions, using upwind finite differences for the first order part.
    The scheme is degenerate elliptic if A and D are positive definite. 
    """
    # Compute the decompositions (here offset_e = offset_f)
    nothing = (np.full((0, ), 0.), np.full((2, 0),
                                           0))  # empty coefs and offsets
    mu, offset_e = nothing if A is None else Selling.Decomposition(A)
    nu, offset_f = nothing if D is None else Selling.Decomposition(D)
    omega_f = lp.dot_VA(omega, offset_f.astype(float))

    # First and second order finite differences
    maxi = np.maximum
    mu, nu, omega_f = (bc.as_field(e) for e in (mu, nu, omega_f))

    dup = bc.DiffUpwind(u, offset_f)
    dum = bc.DiffUpwind(u, -offset_f)
    dup[...,
        bc.not_interior] = 0.  # Placeholder values to silence NaN warnings
    dum[..., bc.not_interior] = 0.

    d2u = bc.Diff2(u, offset_e)

    # Scheme in the interior
    du = maxi(0., maxi(omega_f - dup, -omega_f - dum))
    residue = -lp.dot_VV(mu, d2u) + lp.dot_VV(nu, du**2) - rhs

    # Placeholders outside domain
    return np.where(bc.interior, residue, u - bc.grid_values)
Example #2
0
def SchemeCentered(u, cst, mult, omega, diff, bc, ret_hmax=False):
    """Discretization of a linear non-divergence form second order PDE
        cst + mult u + <omega,grad u>- tr(diff hess(u)) = 0
        Second order accurate, centered yet monotone finite differences are used for <omega,grad u>
        - bc : boundary conditions. 
        - ret_hmax : return the largest grid scale for which monotony holds
    """
    # Decompose the tensor field
    coefs2, offsets = Selling.Decomposition(diff)

    # Decompose the vector field
    scals = lp.dot_VA(lp.solve_AV(diff, omega), offsets.astype(float))
    coefs1 = coefs2 * scals
    if ret_hmax: return 2. / norm(scals, ord=np.inf)

    # Compute the first and second order finite differences
    du = bc.DiffCentered(u, offsets)
    d2u = bc.Diff2(u, offsets)

    # In interior : cst + mult u + <omega,grad u>- tr(diff hess(u)) = 0
    coefs1, coefs2 = (bc.as_field(e) for e in (coefs1, coefs2))
    residue = cst + mult * u + lp.dot_VV(coefs1, du) - lp.dot_VV(coefs2, d2u)

    # On boundary : u-bc = 0
    return np.where(bc.interior, residue, u - bc.grid_values)