from dolfin import * from fenicstools import divergence_matrix from numpy import cos, pi mesh = UnitSquareMesh(10, 10) x = mesh.coordinates() x[:] = (x - 0.5) * 2 x[:] = 0.5*(cos(pi*(x-1.) / 2.) + 1.) CG = VectorFunctionSpace(mesh, 'CG', 1) u = interpolate(Expression(("sin(2*pi*x[0])", "cos(3*pi*x[1])")), CG) C = divergence_matrix(mesh) DG = FunctionSpace(mesh, 'DG', 0) cc = Function(DG) cc.vector()[:] = C * u.vector() plot(cc, title='Gauss div') plot(div(u), title="Projection") divu_dg = project(div(u), DG) plot(divu_dg - cc, title="Difference between FV and FEM")
def setup(low_memory_version, u_components, u, v, p, q, velocity_degree, bcs, scalar_components, V, Q, x_, dim, mesh, constrained_domain, velocity_update_type, **NS_namespace): """Preassemble mass and diffusion matrices. Set up and prepare all equations to be solved. Called once, before going into time loop. """ P = None Rx = None if not low_memory_version: # Constant pressure gradient matrix P = dict((ui, assemble(v*p.dx(i)*dx)) for i, ui in enumerate(u_components)) # Constant velocity divergence matrix if V == Q: Rx = P else: Rx = dict((ui, assemble(q*u.dx(i)*dx)) for i, ui in enumerate(u_components)) # Mass matrix M = assemble(inner(u, v)*dx) # Stiffness matrix (without viscosity coefficient) K = assemble(inner(grad(u), grad(v))*dx) # Pressure Laplacian. Either reuse K or assemble new if V == Q and bcs['p'] == []: Ap = K else: Bp = assemble(inner(grad(q), grad(p))*dx) [bc.apply(Bp) for bc in bcs['p']] Ap = Matrix() Bp.compressed(Ap) # Allocate coefficient matrix (needs reassembling) A = Matrix(M) # Create dictionary to be returned into global NS namespace d = dict(P=P, Rx=Rx, A=A, M=M, K=K, Ap=Ap) # Allocate coefficient matrix and work vectors for scalars. Matrix differs from velocity in boundary conditions only if len(scalar_components) > 0: d.update(Ta=Matrix(M)) if len(scalar_components) > 1: # For more than one scalar we use the same linear algebra solver for all. # For this to work we need some additional tensors. The extra matrix # is required since different scalars may have different boundary conditions Tb = Matrix(M) bb = Vector(x_[scalar_components[0]]) bx = Vector(x_[scalar_components[0]]) d.update(Tb=Tb, bb=bb, bx=bx) # Allocate for velocity update if velocity_update_type.upper() == "GRADIENT_MATRIX": from fenicstools.WeightedGradient import weighted_gradient_matrix dP = weighted_gradient_matrix(mesh, range(dim), degree=velocity_degree, constrained_domain=constrained_domain) dp = Function(V) d.update(dP=dP, dp=dp) from fenicstools import divergence_matrix C = divergence_matrix(mesh) MA = assemble(q*TrialFunction(FunctionSpace(mesh, "DG", 0))*dx) d.update(C=C, MA=MA) elif velocity_update_type.upper() == "LUMPING": ones = Function(V) ones.vector()[:] = 1. ML = M * ones.vector() ML.set_local(1. / ML.array()) d.update(ML=ML) else: Mu = Matrix(M) if len(scalar_components) > 0 else M # Copy if used by scalars [bc.apply(Mu) for bc in bcs['u0']] d.update(Mu=Mu) # Setup for solving convection u_ab = as_vector([Function(V) for i in range(len(u_components))]) a_conv = 0.5*inner(v, dot(u_ab, nabla_grad(u)))*dx # Faster version #a_conv = 0.5*inner(v, dot(U_AB, nabla_grad(u)))*dx a_scalar = a_conv d.update(u_ab=u_ab, a_conv=a_conv, a_scalar=a_scalar) return d