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)
def Gradient(u, A, bc, decomp=None): """ Approximates grad u(x), using finite differences along the axes of A. """ coefs, offsets = Selling.Decomposition(A) if decomp is None else decomp du = bc.DiffCentered(u, offsets) AGrad = lp.dot_AV(offsets.astype(float), (coefs * du)) # Approximates A * grad u return lp.solve_AV(A, AGrad) # Approximates A^{-1} (A * grad u) = grad u