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)
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)