def hat_function_collection(vertex_colors, color, element=None): """Return Expression on given element which takes values: 1 ... if vertex_colors[node] == color 0 ... at other nodes This is well defined just on Lagrange 1 element (default) and Dicontinuous Lagrange 1 element. NOTE: This expression provides a little hack as it lacks continuity across MPI partitions boundaries unless vertex_colors is compatible there. In fact, this behaviour is needed in FluxReconstructor.""" assert isinstance(vertex_colors, cpp.VertexFunctionSizet) mesh = vertex_colors.mesh() if not element: element = FiniteElement('Lagrange', mesh.ufl_cell(), 1) assert element.family() in ['Lagrange', 'Discontinuous Lagrange'] assert element.degree() == 1 ufc_element, ufc_dofmap = jit(element, mpi_comm=mesh.mpi_comm()) dolfin_element = cpp.FiniteElement(ufc_element) e = Expression(hats_cpp_code, element=element, domain=mesh) e.vertex_colors = vertex_colors e.color = color e.dolfin_element = dolfin_element return e
def create_for_cube(size, coord, order=1): """ Creates an expression for the metric matrix used for the cuboid transformation method for the stray-field calculation. *Arguments* size The size of the inner cuboid. This is used for the correct scaling of the tensor. coord The principal direction of transformation. For each shell patch this has to be chosen accordingly. order Order of transformation. Use 1 for P1 finite elements and 2 for P>1 elements. """ # Read cpp implementation from file filename = "%s/metric_matrix_cube_%d.cpp" % (os.path.dirname(__file__), order) code = open(filename, 'r').read() # Create Quadrature Element element = TensorElement("Quadrature", "tetrahedron", 2) # Initialize expression and set size and coord g = Expression(code, element=element) g.size_x = size[0] g.size_y = size[1] g.size_z = size[2] g.coord = coord return g
def _check_space_order(problem, method): mesh_generator, solution, weak_F = problem() # Translate data into FEniCS expressions. fenics_sol = Expression(smp.prining.ccode(solution['value']), degree=solution['degree'], t=0.0 ) # Create initial solution. theta0 = Expression(fenics_sol.cppcode, degree=solution['degree'], t=0.0, cell=triangle ) # Estimate the error component in space. # Leave out too rough discretizations to avoid showing spurious errors. N = [2 ** k for k in range(2, 8)] dt = 1.0e-8 Err = [] H = [] for n in N: mesh = mesh_generator(n) H.append(MPI.max(mesh.hmax())) V = FunctionSpace(mesh, 'CG', 3) # Create boundary conditions. fenics_sol.t = dt #bcs = DirichletBC(V, fenics_sol, 'on_boundary') # Create initial state. theta_approx = method(V, weak_F, theta0, 0.0, dt, bcs=[solution], tol=1.0e-12, verbose=True ) # Compute the error. fenics_sol.t = dt Err.append(errornorm(fenics_sol, theta_approx) / norm(fenics_sol, mesh=mesh) ) print('n: %d error: %e' % (n, Err[-1])) from matplotlib import pyplot as pp # Compare with order 1, 2, 3 curves. for o in [2, 3, 4]: pp.loglog([H[0], H[-1]], [Err[0], Err[0] * (H[-1] / H[0]) ** o], color='0.5' ) # Finally, the actual data. pp.loglog(H, Err, '-o') pp.xlabel('h_max') pp.ylabel('||u-u_h|| / ||u||') pp.show() return
def __init__(self, U_max, t, unit, s, K, compute_width): '''Unit and s characterize domain, t, K - time parameters, U_max is the maximal magnitude of inflow velocity.''' Expression.__init__(self) self.U_max, self.t, self.K = U_max, t, K # Channel width self.w = compute_width(unit) # Midpoint on the inflow M = [4*unit*cos(5*pi/4) + s*sin(5*pi/4) - 0.5*self.w*cos(5*pi/4), 4*unit*sin(5*pi/4) - s*cos(5*pi/4) - 0.5*self.w*sin(5*pi/4)] self.M = M
def initialise_multivector(mv, M): # initial multiindices mis = [Multiindex(mis) for mis in MultiindexSet.createCompleteOrderSet(M, 1)] # intialise fem vectors N = 15 mesh = UnitSquareMesh(N, N) V = FunctionSpace(mesh, 'CG', 1) ex = Expression('sin(2*pi*A*x[0])', A=0) for i, mi in enumerate(mis): ex.A = i+1 f = interpolate(ex, V) mv[mi] = FEniCSVector(f)
def _compute_time_errors(problem, method, mesh_sizes, Dt, plot_error=False): mesh_generator, solution, ProblemClass, cell_type = problem() # Translate data into FEniCS expressions. fenics_sol = Expression(smp.printing.ccode(solution['value']), degree=solution['degree'], t=0.0, cell=cell_type ) # Compute the problem errors = {'theta': numpy.empty((len(mesh_sizes), len(Dt)))} # Create initial state. # Deepcopy the expression into theta0. Specify the cell to allow for # more involved operations with it (e.g., grad()). theta0 = Expression(fenics_sol.cppcode, degree=solution['degree'], t=0.0, cell=cell_type ) for k, mesh_size in enumerate(mesh_sizes): mesh = mesh_generator(mesh_size) V = FunctionSpace(mesh, 'CG', 1) theta_approx = Function(V) theta0p = project(theta0, V) stepper = method(ProblemClass(V)) if plot_error: error = Function(V) for j, dt in enumerate(Dt): # TODO We are facing a little bit of a problem here, being the # fact that the time stepper only accept elements from V as u0. # In principle, though, this isn't necessary or required. We # could allow for arbitrary expressions here, but then the API # would need changing for problem.lhs(t, u). # Think about this. stepper.step(theta_approx, theta0p, 0.0, dt, tol=1.0e-12, verbose=False ) fenics_sol.t = dt # # NOTE # When using errornorm(), it is quite likely to see a good part # of the error being due to the spatial discretization. Some # analyses "get rid" of this effect by (sometimes implicitly) # projecting the exact solution onto the discrete function # space. errors['theta'][k][j] = errornorm(fenics_sol, theta_approx) if plot_error: error.assign(project(fenics_sol - theta_approx, V)) plot(error, title='error (dt=%e)' % dt) interactive() return errors, stepper.name, stepper.order
def EoM_term(self, term, output_label=True): # cast params as constant functions so that, if they are set to 0, FEniCS still understand # what is being integrated mu, M = Constant(self.physics.mu), Constant(self.physics.M) lam = Constant(self.physics.lam) mn = Constant(self.mn) D = self.physics.D Phi = self.Phi varPhi = self.varPhi # define r for use in the computation of the Laplacian r = Expression('x[0]', degree=self.fem.func_degree) if term == 1: Term = (Constant(D - 1.) / r * Phi.dx(0) + Phi.dx(0).dx(0)) * mn**2 label = r"$\nabla^2\phi$" elif term == 2: Term = mu**2 * varPhi label = r"$m^2\phi$" elif term == 3: Term = -lam * varPhi**3 label = r"$-\lambda \phi^3$" elif term == 4: Term = mn**D / M**2 * self.source.rho * varPhi label = r"$\frac{\rho}{M^2}\phi$" Term = project(Term, self.fem.dS, self.physics.D, self.fem.func_degree) if output_label: return Term, label else: return Term
def test_taylor_hood_cube(): pytest.xfail("Problem with Mixed Function Spaces") meshc = UnitCubeMesh(MPI.comm_world, 2, 2, 2) meshf = UnitCubeMesh(MPI.comm_world, 3, 4, 5) Ve = VectorElement("CG", meshc.ufl_cell(), 2) Qe = FiniteElement("CG", meshc.ufl_cell(), 1) Ze = MixedElement([Ve, Qe]) Zc = FunctionSpace(meshc, Ze) Zf = FunctionSpace(meshf, Ze) @function.expression.numba_eval def expr_eval(values, x, cell_idx): values[:, 0] = x[:, 0] * x[:, 1] values[:, 1] = x[:, 1] * x[:, 2] values[:, 2] = x[:, 2] * x[:, 0] values[:, 3] = x[:, 0] + 3.0 * x[:, 1] + x[:, 2] z = Expression(expr_eval, shape=(4,)) zc = interpolate(z, Zc) zf = interpolate(z, Zf) mat = PETScDMCollection.create_transfer_matrix(Zc, Zf) Zuc = Function(Zf) mat.mult(zc.vector(), Zuc.vector()) Zuc.vector().update_ghost_values() diff = Function(Zf) diff.assign(Zuc - zf) assert diff.vector().norm("l2") < 1.0e-12
def test_vector_p1_3d(): meshc = UnitCubeMesh(MPI.comm_world, 2, 3, 4) meshf = UnitCubeMesh(MPI.comm_world, 3, 4, 5) Vc = VectorFunctionSpace(meshc, ("CG", 1)) Vf = VectorFunctionSpace(meshf, ("CG", 1)) @function.expression.numba_eval def expr_eval(values, x, cell_idx): values[:, 0] = x[:, 0] + 2.0 * x[:, 1] values[:, 1] = 4.0 * x[:, 0] values[:, 2] = 3.0 * x[:, 2] + x[:, 0] u = Expression(expr_eval, shape=(3,)) uc = interpolate(u, Vc) uf = interpolate(u, Vf) mat = PETScDMCollection.create_transfer_matrix(Vc._cpp_object, Vf._cpp_object) Vuc = Function(Vf) mat.mult(uc.vector(), Vuc.vector()) diff = Vuc.vector() diff.axpy(-1, uf.vector()) assert diff.norm() < 1.0e-12
def test_Probes_vectorfunctionspace_2D(VF2, dirpath): u0 = interpolate(Expression(('x[0]', 'x[1]'), degree=1), VF2) x = array([[0.5, 0.5], [0.4, 0.4], [0.3, 0.3]]) p = Probes(x.flatten(), VF2) # Probe twice p(u0) p(u0) # Check both snapshots p0 = p.array(N=0) if MPI.rank(mpi_comm_world()) == 0: assert round(p0[0, 0] - 0.5, 7) == 0 assert round(p0[1, 1] - 0.4, 7) == 0 assert round(p0[2, 1] - 0.3, 7) == 0 p0 = p.array(N=1) if MPI.rank(mpi_comm_world()) == 0: assert round(p0[0, 0] - 0.5, 7) == 0 assert round(p0[1, 0] - 0.4, 7) == 0 assert round(p0[2, 1] - 0.3, 7) == 0 p0 = p.array(filename=dirpath + 'dumpvector2D') if MPI.rank(mpi_comm_world()) == 0: assert round(p0[0, 0, 0] - 0.5, 7) == 0 assert round(p0[1, 1, 1] - 0.4, 7) == 0 assert round(p0[2, 0, 1] - 0.3, 7) == 0 p1 = load(dirpath + 'dumpvector2D_all.npy') assert round(p1[0, 0, 0] - 0.5, 7) == 0 assert round(p1[1, 1, 0] - 0.4, 7) == 0 assert round(p1[2, 1, 1] - 0.3, 7) == 0
def test_save_and_checkpoint_timeseries(tempdir, encoding): if invalid_config(encoding): pytest.skip("XDMF unsupported in current configuration") mesh = UnitSquareMesh(MPI.comm_world, 16, 16) filename = os.path.join(tempdir, "u2_checkpoint.xdmf") FE = FiniteElement("CG", mesh.ufl_cell(), 2) V = FunctionSpace(mesh, FE) times = [0.5, 0.2, 0.1] u_out = [None] * len(times) u_in = [None] * len(times) with XDMFFile(mesh.mpi_comm(), filename, encoding=encoding) as file: for i, p in enumerate(times): u_out[i] = interpolate(Expression("x[0]*p", p=p, degree=1), V) file.write_checkpoint(u_out[i], "u_out", p) with XDMFFile(mesh.mpi_comm(), filename) as file: for i, p in enumerate(times): u_in[i] = file.read_checkpoint(V, "u_out", i) for i, p in enumerate(times): u_in[i].vector().axpy(-1.0, u_out[i].vector()) assert u_in[i].vector().norm(cpp.la.Norm.l2) < 1.0e-12 # test reading last with XDMFFile(mesh.mpi_comm(), filename) as file: u_in_last = file.read_checkpoint(V, "u_out", -1) u_out[-1].vector().axpy(-1.0, u_in_last.vector()) assert u_out[-1].vector().norm(cpp.la.Norm.l2) < 1.0e-12
def test_HarmonicSmoothing(): # Create some mesh and its boundary mesh = UnitSquareMesh(10, 10) boundary = BoundaryMesh(mesh, 'exterior') # Move boundary disp = Expression(("0.3*x[0]*x[1]", "0.5*(1.0-x[1])"), degree=2) ALE.move(boundary, disp) # Move mesh according to given boundary ALE.move(mesh, boundary) # Check that new boundary topology corresponds to given one boundary_new = BoundaryMesh(mesh, 'exterior') assert boundary.topology().hash() == boundary_new.topology().hash() # Check that coordinates are almost equal err = sum(sum(abs(boundary.coordinates() \ - boundary_new.coordinates()))) / mesh.num_vertices() print("Current CG solver produced error in boundary coordinates", err) assert round(err - 0.0, 5) == 0 # Check mesh quality magic_number = 0.35 rmin = MeshQuality.radius_ratio_min_max(mesh)[0] assert rmin > magic_number
def get_list_of_functions_1(block_V): shape_1 = block_V[0].ufl_element().value_shape() if len(shape_1) == 0: f = Expression("2*x[0] + 4*x[1]*x[1]", degree=2) elif len(shape_1) == 1 and shape_1[0] == 2: f = Expression(("2*x[0] + 4*x[1]*x[1]", "3*x[0] + 5*x[1]*x[1]"), degree=2) elif len(shape_1) == 1 and shape_1[0] == 3: f = Expression(("2*x[0] + 4*x[1]*x[1]", "3*x[0] + 5*x[1]*x[1]", "7*x[0] + 11*x[1]*x[1]"), degree=2) elif len(shape_1) == 2: f = Expression((("2*x[0] + 4*x[1]*x[1]", "3*x[0] + 5*x[1]*x[1]"), ("7*x[0] + 11*x[1]*x[1]", "13*x[0] + 17*x[1]*x[1]")), degree=2) return [project(f, block_V[0])]
def strong_residual_form(self, sol, units): if units == 'rescaled': resc = 1. elif units == 'physical': resc = self.mn**2 * self.mf else: message = "Invalid choice of units: valid choices are 'physical' or 'rescaled'." raise ValueError, message # cast params as constant functions so that, if they are set to 0, FEniCS still understand # what is being integrated mu, M = Constant(self.physics.mu), Constant(self.physics.M) lam = Constant(self.physics.lam) mn, mf = Constant(self.mn), Constant(self.mf) D = self.physics.D # define r for use in the computation of the Laplacian r = Expression('x[0]', degree=self.fem.func_degree) # I expand manually the Laplacian into (D-1)/r df/dr + d2f/dr2 f = sol.dx(0).dx(0) + Constant(D-1.)/r * sol.dx(0) - lam*(mf/mn)**2*sol**3 \ - 3.*d.sqrt(lam)*(mu*mf/mn**2)*sol**2 - 2.*(mu/mn)**2*sol - (mn**(D-2.)/(mf*M))*self.source.rho f *= resc F = project(f, self.fem.dS, self.physics.D, self.fem.func_degree) return F
def linear_solver(self, phi_k): # cast params as constant functions so that, if they are set to 0, FEniCS still understand # what is being integrated mu, M = Constant(self.physics.mu), Constant(self.physics.M) lam = Constant(self.physics.lam) mn, mf = Constant(self.mn), Constant(self.mf) D = self.physics.D # boundary condition Dirichlet_bc = self.get_Dirichlet_bc() # trial and test function phi = d.TrialFunction(self.fem.S) v = d.TestFunction(self.fem.S) # r^(D-1) rD = Expression('pow(x[0],D-1)', D=D, degree=self.fem.func_degree) # bilinear form a and linear form L a = - inner( grad(phi), grad(v) ) * rD * dx + ( - 3.*lam*(mf/mn)**2*phi_k**2 \ - 6.*d.sqrt(lam)*(mu*mf/mn**2)*phi_k - 2.*(mu/mn)**2 ) * phi * v * rD * dx L = ( (mn**(D-2.)/(mf*M))*self.source.rho - 2.*lam*(mf/mn)**2*phi_k**3 \ - 3.*d.sqrt(lam)*(mu*mf/mn**2)*phi_k**2 ) * v * rD * dx # define a vector with the solution sol = d.Function(self.fem.S) # solve linearised system pde = d.LinearVariationalProblem(a, L, sol, Dirichlet_bc) solver = d.LinearVariationalSolver(pde) solver.solve() return sol
def test_mixed_parallel(): mesh = UnitSquareMesh(MPI.comm_world, 5, 8) V = VectorElement("Lagrange", triangle, 4) Q = FiniteElement("Lagrange", triangle, 5) W = FunctionSpace(mesh, Q * V) F = Function(W) tree = cpp.geometry.BoundingBoxTree(mesh, mesh.geometry.dim) @function.expression.numba_eval def expr_eval(values, x, cell_idx): values[:, 0] = x[:, 0] values[:, 1] = x[:, 1] values[:, 2] = numpy.sin(x[:, 0] + x[:, 1]) F.interpolate(Expression(expr_eval, shape=(3,))) # Generate random points in this mesh partition (one per cell) x = numpy.zeros(3) for c in Cells(mesh): x[0] = random() x[1] = random() * (1 - x[0]) x[2] = (1 - x[0] - x[1]) p = Point(0.0, 0.0) for i, v in enumerate(VertexRange(c)): p += v.point() * x[i] p = p.array()[:2] val = F(p, tree) assert numpy.allclose(val[0], p[0]) assert numpy.isclose(val[1], p[1]) assert numpy.isclose(val[2], numpy.sin(p[0] + p[1]))
def test_l2projection(polynomial_order, in_expression): # Test l2 projection for scalar and vector valued expression interpolate_expression = Expression(in_expression, degree=3) xmin, xmax = 0.0, 1.0 ymin, ymax = 0.0, 1.0 property_idx = 5 mesh = RectangleMesh(Point(xmin, ymin), Point(xmax, ymax), 40, 40) if len(interpolate_expression.ufl_shape) == 0: V = FunctionSpace(mesh, "DG", polynomial_order) elif len(interpolate_expression.ufl_shape) == 1: V = VectorFunctionSpace(mesh, "DG", polynomial_order) v_exact = Function(V) v_exact.interpolate(interpolate_expression) x = RandomRectangle(Point(xmin, ymin), Point(xmax, ymax)).generate([500, 500]) s = assign_particle_values(x, interpolate_expression) # Just make a complicated particle, possibly with scalars and vectors mixed p = particles(x, [x, s, x, x, s], mesh) vh = Function(V) lstsq_rho = l2projection(p, V, property_idx) lstsq_rho.project(vh) error_sq = abs(assemble(dot(v_exact - vh, v_exact - vh) * dx)) assert error_sq < 1e-15
def test_p4_parallel_3d(): mesh = UnitCubeMesh(MPI.comm_world, 3, 5, 8) Q = FunctionSpace(mesh, ("CG", 5)) F = Function(Q) @function.expression.numba_eval def x0(values, x, cell_idx): values[:, 0] = x[:, 0] F.interpolate(Expression(x0)) # Generate random points in this mesh partition (one per cell) x = numpy.zeros(4) tree = cpp.geometry.BoundingBoxTree(mesh, mesh.geometry.dim) for c in Cells(mesh): x[0] = random() x[1] = random() * (1 - x[0]) x[2] = random() * (1 - x[0] - x[1]) x[3] = 1 - x[0] - x[1] - x[2] p = Point(0.0, 0.0, 0.0) for i, v in enumerate(VertexRange(c)): p += v.point() * x[i] p = p.array() assert numpy.isclose(F(p, tree)[0], p[0])
def initial_guess(self): r""" Obtains an initial guess for the Newton solver. This is done by solving the equation of motion for :math:`\lambda=0`, which form a linear system. All other parameters are unchanged. """ # cast params as constant functions so that, if they are set to 0, # fenics still understand what it is integrating m, M, Mp = Constant(self.fields.m), Constant(self.fields.M), Constant( self.fields.Mp) alpha = Constant(self.fields.alpha) Mn, Mf1, Mf2 = Constant(self.Mn), Constant(self.Mf1), Constant( self.Mf2) # get the boundary conditions Dirichlet_bc = self.get_Dirichlet_bc() # create a vector (phi,h) with the two trial functions for the fields u = d.TrialFunction(self.V) # ... and split it into phi and h phi, h, y, z = d.split(u) # define test functions over the function space v1, v2, v3, v4 = d.TestFunctions(self.V) # r^2 r2 = Expression('pow(x[0],2)', degree=self.fem.func_degree) # define bilinear form # Eq.1 a1 = y * v1 * r2 * dx - ( m / Mn )**2 * phi * v1 * r2 * dx \ - alpha * ( Mf2/Mf1 ) * z * v1 * r2 * dx # Eq.2 a2 = z * v2 * r2 * dx - ( M / Mn )**2 * h * v2 * r2 * dx \ - alpha * ( Mf1/Mf2 ) * y * v2 * r2 * dx a3 = -inner(grad(phi), grad(v3)) * r2 * dx - y * v3 * r2 * dx a4 = -inner(grad(h), grad(v4)) * r2 * dx - z * v4 * r2 * dx # both equations a = a1 + a2 + a3 + a4 # define linear form L = self.source.rho / Mp * Mn / Mf1 * v1 * r2 * dx # define a vector with the solution sol = d.Function(self.V) # solve linearised system pde = d.LinearVariationalProblem(a, L, sol, Dirichlet_bc) solver = d.LinearVariationalSolver(pde) solver.solve() return sol
def test_cffi_expression(V): code_h = """ void eval(double* values, const double* x, const int64_t* cell_idx, int num_points, int value_size, int gdim, int num_cells); """ code_c = """ void eval(double* values, const double* x, const int64_t* cell_idx, int num_points, int value_size, int gdim, int num_cells) { for (int i = 0; i < num_points; ++i) { values[i*value_size + 0] = x[i*gdim + 0] + x[i*gdim + 1]; } } """ module = "_expr_eval" + str(MPI.comm_world.rank) # Build the kernel ffi = cffi.FFI() ffi.set_source(module, code_c) ffi.cdef(code_h) ffi.compile() # Import the compiled kernel kernel_mod = importlib.import_module(module) ffi, lib = kernel_mod.ffi, kernel_mod.lib # Get pointer to the compiled function eval_ptr = ffi.cast("uintptr_t", ffi.addressof(lib, "eval")) # Handle C func address by hand ex1 = Expression(int(eval_ptr)) f1 = Function(V) f1.interpolate(ex1) @function.expression.numba_eval def expr_eval2(values, x, cell_idx): values[:, 0] = x[:, 0] + x[:, 1] ex2 = Expression(expr_eval2) f2 = Function(V) f2.interpolate(ex2) assert (f1.vector().get_local() == f2.vector().get_local()).all()
def main(N: int, dt: float, T: float, theta: float) -> Tuple[float, float, float, float, float]: """Run bidomain MMA.""" # Create data mesh = UnitSquareMesh(N, N) time = Constant(0.0) ac_str = "cos(t)*cos(2*pi*x[0])*cos(2*pi*x[1]) + 4*pi*pi*cos(2*pi*x[0])*cos(2*pi*x[1])*sin(t)" stimulus = Expression(ac_str, t=time, degree=5) M_i = 1. M_e = 1.0 # Set-up solver parameters = BidomainSolver.default_parameters() parameters["theta"] = theta parameters["linear_solver_type"] = "direct" parameters["use_avg_u_constraint"] = True parameters["Chi"] = 1.0 parameters["Cm"] = 1.0 solver = BidomainSolver(mesh, time, M_i, M_e, I_s=stimulus, parameters=parameters) # Define exact solution (Note: v is returned at end of time # interval(s), u is computed at somewhere in the time interval # depending on theta) v_exact = Expression("cos(2*pi*x[0])*cos(2*pi*x[1])*sin(t)", t=T, degree=3) u_exact = Expression("-cos(2*pi*x[0])*cos(2*pi*x[1])*sin(t)/2.0", t=T - (1. - theta) * dt, degree=3) # Define initial condition(s) v_, vu = solver.solution_fields() # Solve solutions = solver.solve(0, T, dt) for interval, fields in solutions: continue # Compute errors v, u = vu.split(deepcopy=True)[:2] v_error = errornorm(v_exact, v, "L2", degree_rise=2) u_error = errornorm(u_exact, u, "L2", degree_rise=2) return v_error, u_error, mesh.hmin(), dt, T
def test_mpi_dependent_jiting(): # FIXME: Not a proper unit test... from dolfin import (Expression, UnitSquareMesh, Function, TestFunction, Form, FunctionSpace, dx, CompiledSubDomain, SubSystemsManager) # Init petsc (needed to initalize petsc collectively on # all processes) SubSystemsManager.init_petsc() import mpi4py.MPI as mpi import petsc4py.PETSc as petsc # Set communicator and get process information comm = mpi.COMM_WORLD group = comm.Get_group() size = comm.Get_size() # Only consider parallel runs if size == 1: return rank = comm.Get_rank() group_comm_0 = petsc.Comm(comm.Create(group.Incl(range(1)))) group_comm_1 = petsc.Comm(comm.Create(group.Incl(range(1, 2)))) if size > 2: group_comm_2 = petsc.Comm(comm.Create(group.Incl(range(2, size)))) if rank == 0: e = Expression("4", mpi_comm=group_comm_0, degree=0) elif rank == 1: e = Expression("5", mpi_comm=group_comm_1, degree=0) assert (e) domain = CompiledSubDomain("on_boundary", mpi_comm=group_comm_1, degree=0) assert (domain) else: mesh = UnitSquareMesh(group_comm_2, 2, 2) V = FunctionSpace(mesh, "P", 1) u = Function(V) v = TestFunction(V) Form(u * v * dx)
def test_WeightedGradient(V2): expr = "+".join(["%d*x[%d]" % (i+1,i) for i in range(2)]) u = interpolate(Expression(expr, degree=3), V2) du = Function(V2) wx = weighted_gradient_matrix(V2.mesh(), tuple(range(2))) for i in range(2): du.vector()[:] = wx[i] * u.vector() assert round(du.vector().min() - (i+1), 7) == 0
def build_source(self): self.rho = Expression( 'Ms / pow( sqrt(2*pi) * sigma, D ) * exp( -0.5 * pow(x[0]/sigma,2) )', Ms=self.Ms, D=self.physics.D, sigma=self.sigma, degree=self.fem.func_degree)
def test_interpolation_mismatch_rank0(W): @function.expression.numba_eval def expr_eval(values, x, t): values[:, 0] = 1.0 f = Expression(expr_eval, shape=()) with pytest.raises(RuntimeError): interpolate(f, W)
def generate_shape_expression(self): return Expression( ParabolicInflow._shape_expression_schema, degree=2, A=self.left, B=self.right, amplitude=1.0, )
def hat_function(vertex): """Return Expression on Lagrange degree 1 element which is 1 ... at given 'vertex' 0 ... at other vertices """ assert isinstance(vertex, Vertex) mesh = vertex.mesh() element = FiniteElement('Lagrange', mesh.ufl_cell(), 1) ufc_element, ufc_dofmap = jit(element, mpi_comm=mesh.mpi_comm()) ufc_element = make_ufc_finite_element(ufc_element) dolfin_element = cpp.FiniteElement(ufc_element) e = Expression(hat_cpp_code, element=element, domain=mesh) e.vertex = vertex e.dolfin_element = dolfin_element return e
def _compute_time_errors(problem, method, mesh_sizes, Dt, plot_error=False): mesh_generator, solution, ProblemClass, _ = problem() # Translate data into FEniCS expressions. fenics_sol = Expression(sympy.printing.ccode(solution), degree=MAX_DEGREE, t=0.0) # Compute the problem errors = numpy.empty((len(mesh_sizes), len(Dt))) # Create initial state. # Deepcopy the expression into theta0. Specify the cell to allow for # more involved operations with it (e.g., grad()). theta0 = Expression(fenics_sol.cppcode, degree=MAX_DEGREE, t=0.0) for k, mesh_size in enumerate(mesh_sizes): mesh = mesh_generator(mesh_size) # Choose the function space such that the exact solution can be # represented as well as possible. V = FunctionSpace(mesh, 'CG', 4) theta_approx = Function(V) theta0p = project(theta0, V) stepper = method(ProblemClass(V)) if plot_error: error = Function(V) for j, dt in enumerate(Dt): # TODO We are facing a little bit of a problem here, being the fact # that the time stepper only accept elements from V as u0. In # principle, though, this isn't necessary or required. We could # allow for arbitrary expressions here, but then the API would need # changing for problem.lhs(t, u). Think about this. theta_approx.assign(stepper.step(theta0p, 0.0, dt)) fenics_sol.t = dt # NOTE # When using errornorm(), it is quite likely to see a good part of # the error being due to the spatial discretization. Some analyses # "get rid" of this effect by (sometimes implicitly) projecting the # exact solution onto the discrete function space. errors[k][j] = errornorm(fenics_sol, theta_approx) if plot_error: error.assign(project(fenics_sol - theta_approx, V)) plot(error, title='error (dt={:e})'.format(dt)) plt.show() return errors
def weak_residual_form(self, sol): r""" Computes the residual with respect to the weak form of the equations: .. math:: F = F_1 + F_2 + F_3 with .. math:: F_1(\hat{\pi},\hat{W},\hat{Y}) & = - \int\hat{\nabla}\hat{\pi}\hat{\nabla}v_1 \hat{r}^2 d\hat{r} - \int \hat{Y} v_1 \hat{r}^2 d\hat{r} \\ F_2(\hat{\pi},\hat{W},\hat{Y}) & = \int \hat{W} v_2 \hat{r}^2 d\hat{r} - \int \hat{Y}^n v_2 \hat{r}^2 d\hat{r} \\ F_3(\hat{\pi},\hat{W},\hat{Y}) & = \int \hat{Y} v_3 \hat{r}^2 d\hat{r} - \int \left( \frac{m}{M_n} \right)^2 \hat{\pi} v_3 \hat{r}^2 d\hat{r} + & + \epsilon \left( \frac{M_n}{\Lambda} \right)^{3n-1} \left(\frac{M_{f1}}{M_n}\right)^{n-1} \int\hat{\nabla} \hat{W} \hat{\nabla} v_3 \hat{r}^2 d\hat{r} - \int \frac{\hat{\rho}}{M_p}\frac{M_n}{M_{f1}} v_3 \hat{r}^2 d\hat{r} The weak residual is employed within :func:`solver.Solver.solve` to check convergence - also see :func:`solver.Solver.compute_errors`. *Parameters* sol the solution with respect to which the weak residual is computed. """ # cast params as constant functions so that, if they are set to 0, FEniCS still understand # what is being integrated m, Lambda, Mp = Constant(self.fields.m), Constant( self.fields.Lambda), Constant(self.fields.Mp) n = self.fields.n epsilon = Constant(self.fields.epsilon) Mn, Mf1 = Constant(self.Mn), Constant(self.Mf1) # test functions v1, v2, v3 = d.TestFunctions(self.V) # split solution into pi, w, y pi, w, y = d.split(sol) # r^2 r2 = Expression('pow(x[0],2)', degree=self.fem.func_degree) # define the weak residual form F1 = -inner(grad(pi), grad(v1)) * r2 * dx - y * v1 * r2 * dx F2 = w * v2 * r2 * dx - y**n * v2 * r2 * dx F3 = y * v3 * r2 * dx - (m/Mn)**2 * pi * v3 * r2 * dx + \ epsilon * ( Mn / Lambda )**(3*n-1) * ( Mf1 / Mn )**(n-1) * inner( grad(w), grad(v3) ) * r2 * dx \ - self.source.rho / Mp * Mn / Mf1 * v3 * r2 * dx F = F1 + F2 + F3 return F
def get_rhs_block_form_1(block_V): block_v = BlockTestFunction(block_V) (v, ) = block_split(block_v) shape_1 = block_V[0].ufl_element().value_shape() if len(shape_1) is 0: f = Expression("2*x[0] + 4*x[1]*x[1]", degree=2) block_form = [f*v*dx] elif len(shape_1) is 1 and shape_1[0] is 2: f = Expression(("2*x[0] + 4*x[1]*x[1]", "3*x[0] + 5*x[1]*x[1]"), degree=2) block_form = [inner(f, v)*dx] elif len(shape_1) is 1 and shape_1[0] is 3: f = Expression(("2*x[0] + 4*x[1]*x[1]", "3*x[0] + 5*x[1]*x[1]", "7*x[0] + 11*x[1]*x[1]"), degree=2) block_form = [inner(f, v)*dx] elif len(shape_1) is 2: f = Expression((("2*x[0] + 4*x[1]*x[1]", "3*x[0] + 5*x[1]*x[1]"), ("7*x[0] + 11*x[1]*x[1]", "13*x[0] + 17*x[1]*x[1]")), degree=2) block_form = [inner(f, v)*dx] return block_form
def test_Probe_vectorfunctionspace_2D(VF2_self): u0 = interpolate(Expression(('x[0]', 'x[1]'), degree=1), VF2_self) x = array([0.5, 0.75]) p = Probe(x, VF2_self) p(u0) p(u0) assert round(p[0][0] - 0.5, 7) == 0 assert round(p[1][1] - 0.75, 7) == 0
def _potential_gradient_normal(self, conductivity=0.0): # (1 / r)' = -1 / dst^2 # -1 * dz / dst # dz / dst^3 = dz * (dst^2)^-1.5 # drx / r * dx / dst = (drx * dx) / (r * dst) # = (x * src_x - x * x) / (r * dst) # dx = '(x[0] - src_x)' # dy = '(x[1] - src_y)' # dz = '(x[2] - src_z)' # drx = 'x[0]' # dry = 'x[1]' # drz = 'x[2]' # dot = f'({dx} * {drx} + {dy} * {dry} + {dz} * {drz})' # r2 = f'({drx} * {drx} + {dry} * {dry} + {drz} * {drz})' # dst2 = f'({dx} * {dx} + {dy} * {dy} + {dz} * {dz})' # return Expression(f''' # {0.25 / np.pi} / conductivity # * ({dot} / sqrt({dst2} * {r2}) - 1.0) # / {dst2} # ''', # degree=self.degree, # domain=self._fm.mesh, # src_x=0.0, # src_y=0.0, # src_z=0.0, # conductivity=conductivity) dx_src = f'(x[0] - src_x)' dy_src = f'(x[1] - src_y)' dz_src = f'(x[2] - src_z)' dx_snk = f'(x[0] - snk_x)' dy_snk = f'(x[1] - snk_y)' dz_snk = f'(x[2] - snk_z)' r_src2 = f'({dx_src} * {dx_src} + {dy_src} * {dy_src} + {dz_src} * {dz_src})' r_src = f'sqrt({r_src2})' r_snk2 = f'({dx_snk} * {dx_snk} + {dy_snk} * {dy_snk} + {dz_snk} * {dz_snk})' r_snk = f'sqrt({r_snk2})' r_sphere2 = '(x[0] * x[0] + x[1] * x[1] + x[2] * x[2])' r_sphere = f'sqrt({r_sphere2})' dot_src = f'({dx_src} * x[0] + {dy_src} * x[1] + {dz_src} * x[2]) / ({r_src} * {r_sphere})' dot_snk = f'({dx_snk} * x[0] + {dy_snk} * x[1] + {dz_snk} * x[2]) / ({r_snk} * {r_sphere})' return Expression(f''' {-0.25 / np.pi} / conductivity * ({dot_src} / {r_src2} - {dot_snk} / {r_snk2}) ''', degree=self.degree, domain=self._fm.mesh, conductivity=conductivity, src_x=0.0, src_y=0.0, src_z=0.0, snk_x=0.0, snk_y=0.0, snk_z=0.0)
def test_Probe_functionspace_3D(V3_self): u0 = interpolate(Expression('x[0]', degree=1), V3_self) x = array([0.25, 0.5, 0.5]) p = Probe(x, V3_self) p(u0) p(u0) assert round(p[0][0] - 0.25, 7) == 0 assert round(p[1][0] - 0.25, 7) == 0
def MHD2D(NScase,Mcase,Show="no"): PrintFuncs.PrintStr("MHD 2D Exact Solution:",5,">","\n","\n") x = symbols('x[0]') y = symbols('x[1]') u, v, p, u0, p0, Laplacian, Advection, gradPres = Fluid2D(NScase,Show,"MHD") b,d,r,b0, r0, CurlCurl, gradR = Mag2D(Mcase,Show,"MHD") NS1 = -d*(diff(d,x)-diff(b,y)) NS2 = b*(diff(d,x)-diff(b,y)) M1 = diff(u*d-v*b,y) M2 = -diff(u*d-v*b,x) NS_Couple = Expression((ccode(NS1),ccode(NS2))) M_Couple = Expression((ccode(M1),ccode(M2))) return u0, p0,b0, r0, Laplacian, Advection, gradPres,CurlCurl, gradR, NS_Couple, M_Couple
def test_GaussDivergence(mesh): dim = mesh.topology().dim() expr = ["%s*x[%s]" % (dim, i) for i in range(dim)] V = VectorFunctionSpace(mesh, 'CG', 1) u = interpolate(Expression(tuple(expr)), V) divu = gauss_divergence(u) DIVU = divu.vector().array() point_0 = all(abs(DIVU - dim * dim) < 1E-13) if MPI.rank(mpi_comm_world()) == 0: assert point_0
def apply_helix(fib, restX, setX, NTURN, A1, A2, phase): fib.problem.fields['wx'].interpolate( Expression(( "x[0]*sq", "A1*sin(x[0]*p + w)-x[1]", "A2*cos(x[0]*p + w)-x[2]", "-((A1*A2*pow(p,3))/sqrt(pow(p,4)*(pow(A1,2)*pow(A2,2)*pow(p,2) + pow(A2,2)*pow(1 + sq,2)*pow(cos(x[0]*p + w),2) + pow(A1,2)*pow(1 + sq,2)*pow(sin(x[0]*p + w),2))))", "-1 + (A2*pow(p,2)*(1 + sq)*cos(x[0]*p + w))/sqrt(pow(p,4)*(pow(A1,2)*pow(A2,2)*pow(p,2) + pow(A2,2)*pow(1 + sq,2)*pow(cos(x[0]*p + w),2) + pow(A1,2)*pow(1 + sq,2)*pow(sin(x[0]*p + w),2)))", "-((A1*pow(p,2)*(1 + sq)*sin(x[0]*p + w))/sqrt(pow(p,4)*(pow(A1,2)*pow(A2,2)*pow(p,2) + pow(A2,2)*pow(1 + sq,2)*pow(cos(x[0]*p + w),2) + pow(A1,2)*pow(1 + sq,2)*pow(sin(x[0]*p + w),2))))", "-((pow(A1,2) - pow(A2,2))*pow(p,3)*(1 + sq)*sin(2*(x[0]*p + w)))/(2.*sqrt(pow(1 + sq,2) + pow(A1,2)*pow(p,2)*pow(cos(x[0]*p + w),2) + pow(A2,2)*pow(p,2)*pow(sin(x[0]*p + w),2))*sqrt(pow(p,4)*(pow(A1,2)*pow(A2,2)*pow(p,2) + pow(A2,2)*pow(1 + sq,2)*pow(cos(x[0]*p + w),2) + pow(A1,2)*pow(1 + sq,2)*pow(sin(x[0]*p + w),2))))", "(A1*pow(p,2)*(pow(A2,2)*pow(p,2) + pow(1 + sq,2))*sin(x[0]*p + w))/(sqrt(pow(1 + sq,2) + pow(A1,2)*pow(p,2)*pow(cos(x[0]*p + w),2) + pow(A2,2)*pow(p,2)*pow(sin(x[0]*p + w),2))*sqrt(pow(p,4)*(pow(A1,2)*pow(A2,2)*pow(p,2) + pow(A2,2)*pow(1 + sq,2)*pow(cos(x[0]*p + w),2) + pow(A1,2)*pow(1 + sq,2)*pow(sin(x[0]*p + w),2))))", "(A2*pow(p,2)*(pow(A1,2)*pow(p,2) + pow(1 + sq,2))*cos(x[0]*p + w) - sqrt(pow(1 + sq,2) + pow(A1,2)*pow(p,2)*pow(cos(x[0]*p + w),2) + pow(A2,2)*pow(p,2)*pow(sin(x[0]*p + w),2))*sqrt(pow(p,4)*(pow(A2,2)*pow(1 + sq,2)*pow(cos(x[0]*p + w),2) + pow(A1,2)*(pow(A2,2)*pow(p,2) + pow(1 + sq,2)*pow(sin(x[0]*p + w),2)))))/(sqrt(pow(1 + sq,2) + pow(A1,2)*pow(p,2)*pow(cos(x[0]*p + w),2) + pow(A2,2)*pow(p,2)*pow(sin(x[0]*p + w),2))*sqrt(pow(p,4)*(pow(A2,2)*pow(1 + sq,2)*pow(cos(x[0]*p + w),2) + pow(A1,2)*(pow(A2,2)*pow(p,2) + pow(1 + sq,2)*pow(sin(x[0]*p + w),2)))))" ), sq=-(restX - setX) / restX, p=np.pi / restX * (NTURN) / 2.0, A1=A1, A2=A2, w=phase * np.pi * 2.0)) fib.problem.fields['wv'].interpolate( Expression( ("0.0", "0.0", "0.0", "0.0", " 0.0", "0.0", "0.0", "0.0", "0.0")))
def profile(mesh, degree): bot = mesh.coordinates().min(axis=0)[1] top = mesh.coordinates().max(axis=0)[1] print bot, top H = top - bot Um = 1.5 return Expression(('-4*Um*(x[1]-bot)*(x[1]-top)/H/H', '0'), bot=bot, top=top, H=H, Um=Um, degree=degree)
def generate_expression(func, freq, A, B, m, n, degree, element): func, min_val, max_val, max_grad = func if n is None: ex = Expression(func, freq=freq, A=A, B=B, m=m, degree=degree, element=element) else: ex = Expression(func, freq=freqscale, A=A, B=B, m=m, n=n, degree=degree, element=element) try: for k, v in {"freq":freq, "A":A, "B":B, "m":m, "n":n, "pi":"np.pi"}.iteritems(): v = str(v) min_val = min_val.replace(k, v) max_val = max_val.replace(k, v) max_grad = max_grad.replace(k, v) ex.min_val = eval(min_val) ex.max_val = eval(max_val) ex.max_grad = eval(max_grad) except: logger.info("no min/max info available for coefficients") return ex
def CompositeExpression(domains, expressions): e = Expression(''' class CompositeExpression : public Expression { public: std::shared_ptr<MeshFunction<std::size_t> > cell_data; std::map<std::size_t, std::shared_ptr<Expression> > expressions; CompositeExpression() : Expression(3) {} void add_expression(std::size_t domain, std::shared_ptr<Expression> expression) { expressions[domain] = expression; } void eval(Array<double>& values, const Array<double>& x, const ufc::cell& c) const { assert(cell_data); const Cell cell(*cell_data->mesh(), c.index); std::size_t domain = (*cell_data)[cell.index()]; if (expressions.find(domain) == expressions.end()) { for (std::size_t i=0; i<values.size(); ++i) values[i] = 0.0; } else { expressions.at(domain)->eval(values, x, c); } } };''') if isinstance(domains, Mesh): e.cell_data = MeshFunction('size_t', domains, 3, domains.domains()) else: e.cell_data = domains for domain in expressions: e.add_expression(domain, expressions[domain]) return e
def compute_time_errors(problem, MethodClass, mesh_sizes, Dt): mesh_generator, solution, f, mu, rho, cell_type = problem() # Translate data into FEniCS expressions. sol_u = Expression((smp.printing.ccode(solution['u']['value'][0]), smp.printing.ccode(solution['u']['value'][1]) ), degree=_truncate_degree(solution['u']['degree']), t=0.0, cell=cell_type ) sol_p = Expression(smp.printing.ccode(solution['p']['value']), degree=_truncate_degree(solution['p']['degree']), t=0.0, cell=cell_type ) fenics_rhs0 = Expression((smp.printing.ccode(f['value'][0]), smp.printing.ccode(f['value'][1]) ), degree=_truncate_degree(f['degree']), t=0.0, mu=mu, rho=rho, cell=cell_type ) # Deep-copy expression to be able to provide f0, f1 for the Dirichlet- # boundary conditions later on. fenics_rhs1 = Expression(fenics_rhs0.cppcode, degree=_truncate_degree(f['degree']), t=0.0, mu=mu, rho=rho, cell=cell_type ) # Create initial states. p0 = Expression( sol_p.cppcode, degree=_truncate_degree(solution['p']['degree']), t=0.0, cell=cell_type ) # Compute the problem errors = {'u': numpy.empty((len(mesh_sizes), len(Dt))), 'p': numpy.empty((len(mesh_sizes), len(Dt))) } for k, mesh_size in enumerate(mesh_sizes): info('') info('') with Message('Computing for mesh size %r...' % mesh_size): mesh = mesh_generator(mesh_size) mesh_area = assemble(1.0 * dx(mesh)) W = VectorFunctionSpace(mesh, 'CG', 2) P = FunctionSpace(mesh, 'CG', 1) method = MethodClass(W, P, rho, mu, theta=1.0, #theta=0.5, stabilization=None #stabilization='SUPG' ) u1 = Function(W) p1 = Function(P) err_p = Function(P) divu1 = Function(P) for j, dt in enumerate(Dt): # Prepare previous states for multistepping. u = [Expression( sol_u.cppcode, degree=_truncate_degree(solution['u']['degree']), t=0.0, cell=cell_type ), # Expression( #sol_u.cppcode, #degree=_truncate_degree(solution['u']['degree']), #t=0.5*dt, #cell=cell_type #) ] sol_u.t = dt u_bcs = [DirichletBC(W, sol_u, 'on_boundary')] sol_p.t = dt #p_bcs = [DirichletBC(P, sol_p, 'on_boundary')] p_bcs = [] fenics_rhs0.t = 0.0 fenics_rhs1.t = dt method.step(dt, u1, p1, u, p0, u_bcs=u_bcs, p_bcs=p_bcs, f0=fenics_rhs0, f1=fenics_rhs1, verbose=False, tol=1.0e-10 ) sol_u.t = dt sol_p.t = dt errors['u'][k][j] = errornorm(sol_u, u1) # The pressure is only determined up to a constant which makes # it a bit harder to define what the error is. For our # purposes, choose an alpha_0\in\R such that # # alpha0 = argmin ||e - alpha||^2 # # with e := sol_p - p. # This alpha0 is unique and explicitly given by # # alpha0 = 1/(2|Omega|) \int (e + e*) # = 1/|Omega| \int Re(e), # # i.e., the mean error in \Omega. alpha = assemble(sol_p * dx(mesh)) \ - assemble(p1 * dx(mesh)) alpha /= mesh_area # We would like to perform # p1 += alpha. # To avoid creating a temporary function every time, assume # that p1 lives in a function space where the coefficients # represent actual function values. This is true for CG # elements, for example. In that case, we can just add any # number to the vector of p1. p1.vector()[:] += alpha errors['p'][k][j] = errornorm(sol_p, p1) show_plots = False if show_plots: plot(p1, title='p1', mesh=mesh) plot(sol_p, title='sol_p', mesh=mesh) err_p.vector()[:] = p1.vector() sol_interp = interpolate(sol_p, P) err_p.vector()[:] -= sol_interp.vector() #plot(sol_p - p1, title='p1 - sol_p', mesh=mesh) plot(err_p, title='p1 - sol_p', mesh=mesh) #r = Expression('x[0]', degree=1, cell=triangle) #divu1 = 1 / r * (r * u1[0]).dx(0) + u1[1].dx(1) divu1.assign(project(u1[0].dx(0) + u1[1].dx(1), P)) plot(divu1, title='div(u1)') interactive() return errors
def supg(mesh, convection, diffusion, element_degree): """For each cell, this function return the expression ..math:: \\begin{align*} \\tau &= \\frac{h}{2\\|b\\|} \\left(\\frac{1}{\\tanh Pe} - \\frac{1}{Pe}\\right)\\\\ & = \\frac{h^2}{4\\varepsilon} \\frac{1}{Pe} \\left(\\frac{1}{\\tanh Pe} - \\frac{1}{Pe}\\right) \\end{align*} with the element diameter in the direction of the convection vector :math:`b` and the Péclet number :math:`Pe = \\frac{\\|b\\| h}{2\\varepsilon}`; see (3) in :cite:`sold2`. Note that :math:`\\tau` does not have a singularity for :math:`\\|b\\|=0` since ..math:: \\frac{1}{\\tanh Pe} - \\frac{1}{Pe} = \\frac{1}{3}Pe + O(Pe^3) for :math:`Pe\\approx 0`. This Taylor expansion (with a few more terms) is made use of in the code. """ cppcode = """#include <dolfin/mesh/Vertex.h> class SupgStab : public Expression { public: double epsilon; int p; std::shared_ptr<GenericFunction> convection; std::shared_ptr<Mesh> mesh; SupgStab(): Expression() {} void eval( Array<double>& tau, const Array<double>& x, const ufc::cell& c ) const { Array<double> v(x.size()); convection->eval(v, x, c); double conv_norm = 0.0; for (uint i = 0; i < v.size(); ++i) conv_norm += v[i]*v[i]; conv_norm = sqrt(conv_norm); Cell cell(*mesh, c.index); //// The alternative for the lazy: //const double h = cell.diameter(); // Compute the directed diameter of the cell, cf. :cite:`sold2`. // // diam(cell, s) = 2*||s|| / sum_{nodes n_i} |s.\\grad\\psi| // // where \\psi is the P_1 basis function of n_i. // const double area = cell.volume(); const unsigned int* vertices = cell.entities(0); assert(vertices); double sum = 0.0; for (int i=0; i<3; i++) { for (int j=i+1; j<3; j++) { // Get edge coords. const dolfin::Vertex v0(*mesh, vertices[i]); const dolfin::Vertex v1(*mesh, vertices[j]); const Point p0 = v0.point(); const Point p1 = v1.point(); const double e0 = p0[0] - p1[0]; const double e1 = p0[1] - p1[1]; // Note that // // \\grad\\psi = ortho_edge / edgelength / height // = ortho_edge / (2*area) // // so // // (v.\\grad\\psi) = (v.ortho_edge) / (2*area). // // Move the constant factors out of the summation. // // It would be really nice if we could just do // edge.dot((-v[1], v[0])) // but unfortunately, edges just dot with other edges. sum += fabs(e1*v[0] - e0*v[1]); } } const double h = 4 * conv_norm * area / sum; // Just a little sanity check here. assert(h <= cell.diameter()); const double Pe = 0.5*conv_norm * h/(p*epsilon); assert(Pe > 0.0); // We'd like to compute `xi = (1.0/tanh(Pe) - 1.0/Pe) / Pe`. This expression // can hardly be evaluated for small Pe, see // <https://stackoverflow.com/a/43279491/353337>. Hence, use its Taylor // expansion around 0. const double xi = Pe > 1.0e-5 ? (1.0/tanh(Pe) - 1.0/Pe) / Pe : 1.0/3.0 - Pe*Pe / 45.0 + 2.0/945.0 * Pe*Pe*Pe*Pe; // const double xi = (Pe > 1.0 ? 1.0 - 1.0/Pe : 0.0) / Pe; tau[0] = h*h / 4 / epsilon / p * xi; if (tau[0] > 1.0e3) { std::cout << "tau = " << tau[0] << std::endl; std::cout << "||b|| = " << conv_norm << std::endl; std::cout << "Pe = " << Pe << std::endl; std::cout << "h = " << h << std::endl; std::cout << "xi = " << xi << std::endl; throw 1; } return; } }; """ # TODO set degree tau = Expression(cppcode, degree=5) tau.convection = convection tau.mesh = mesh tau.epsilon = diffusion tau.p = element_degree return tau
from spuq.fem.fenics.fenics_vector import FEniCSVector from spuq.application.egsz.multi_vector import MultiVector, MultiVectorWithProjection from spuq.math_utils.multiindex import Multiindex from spuq.math_utils.multiindex_set import MultiindexSet from dolfin import UnitSquare, FunctionSpace, Function, refine, Expression, plot, interactive from math import pi import pickle mis = [Multiindex(mis) for mis in MultiindexSet.createCompleteOrderSet(3, 1)] N = len(mis) meshes = [UnitSquare(10 + 2 * i, 10 + 2 * i) for i in range(N)] functions = [Function(FunctionSpace(m, "CG", d + 1)) for d, m in enumerate(meshes)] ex = Expression('sin(A*x[0])*sin(A*x[1])', A=1) for i, f in enumerate(functions): ex.A = 2 * pi * (i + 1) f.interpolate(ex) # test FEniCSVector # ================= vectors = [FEniCSVector(f) for f in functions] with open('test-vector.pkl', 'wb') as f: pickle.dump(vectors[1], f) with open('test-vector.pkl', "rb") as f: v1 = pickle.load(f) # test MultiVector # ================ #mv1 = MultiVector()
def compute_time_errors(problem, MethodClass, mesh_sizes, Dt): mesh_generator, solution, f, mu, rho, cell_type = problem() # Compute the problem errors = { "u": numpy.empty((len(mesh_sizes), len(Dt))), "p": numpy.empty((len(mesh_sizes), len(Dt))), } for k, mesh_size in enumerate(mesh_sizes): info("") info("") with Message("Computing for mesh size {}...".format(mesh_size)): mesh = mesh_generator(mesh_size) # Define all expression with `domain`, see # <https://bitbucket.org/fenics-project/ufl/issues/96>. # # Translate data into FEniCS expressions. sol_u = Expression( (ccode(solution["u"]["value"][0]), ccode(solution["u"]["value"][1])), degree=_truncate_degree(solution["u"]["degree"]), t=0.0, domain=mesh, ) sol_p = Expression( ccode(solution["p"]["value"]), degree=_truncate_degree(solution["p"]["degree"]), t=0.0, domain=mesh, ) fenics_rhs0 = Expression( (ccode(f["value"][0]), ccode(f["value"][1])), degree=_truncate_degree(f["degree"]), t=0.0, mu=mu, rho=rho, domain=mesh, ) # Deep-copy expression to be able to provide f0, f1 for the # Dirichlet boundary conditions later on. fenics_rhs1 = Expression( fenics_rhs0.cppcode, degree=_truncate_degree(f["degree"]), t=0.0, mu=mu, rho=rho, domain=mesh, ) # Create initial states. W = VectorFunctionSpace(mesh, "CG", 2) P = FunctionSpace(mesh, "CG", 1) p0 = Expression( sol_p.cppcode, degree=_truncate_degree(solution["p"]["degree"]), t=0.0, domain=mesh, ) mesh_area = assemble(1.0 * dx(mesh)) method = MethodClass( time_step_method="backward euler", # time_step_method='crank-nicolson', # stabilization=None # stabilization='SUPG' ) u1 = Function(W) p1 = Function(P) err_p = Function(P) divu1 = Function(P) for j, dt in enumerate(Dt): # Prepare previous states for multistepping. u = { 0: Expression( sol_u.cppcode, degree=_truncate_degree(solution["u"]["degree"]), t=0.0, cell=cell_type, ) } sol_u.t = dt u_bcs = [DirichletBC(W, sol_u, "on_boundary")] sol_p.t = dt # p_bcs = [DirichletBC(P, sol_p, 'on_boundary')] p_bcs = [] fenics_rhs0.t = 0.0 fenics_rhs1.t = dt u1, p1 = method.step( Constant(dt), u, p0, W, P, u_bcs, p_bcs, Constant(rho), Constant(mu), f={0: fenics_rhs0, 1: fenics_rhs1}, verbose=False, tol=1.0e-10, ) sol_u.t = dt sol_p.t = dt errors["u"][k][j] = errornorm(sol_u, u1) # The pressure is only determined up to a constant which makes # it a bit harder to define what the error is. For our # purposes, choose an alpha_0\in\R such that # # alpha0 = argmin ||e - alpha||^2 # # with e := sol_p - p. # This alpha0 is unique and explicitly given by # # alpha0 = 1/(2|Omega|) \int (e + e*) # = 1/|Omega| \int Re(e), # # i.e., the mean error in \Omega. alpha = +assemble(sol_p * dx(mesh)) - assemble(p1 * dx(mesh)) alpha /= mesh_area # We would like to perform # p1 += alpha. # To avoid creating a temporary function every time, assume # that p1 lives in a function space where the coefficients # represent actual function values. This is true for CG # elements, for example. In that case, we can just add any # number to the vector of p1. p1.vector()[:] += alpha errors["p"][k][j] = errornorm(sol_p, p1) show_plots = False if show_plots: plot(p1, title="p1", mesh=mesh) plot(sol_p, title="sol_p", mesh=mesh) err_p.vector()[:] = p1.vector() sol_interp = interpolate(sol_p, P) err_p.vector()[:] -= sol_interp.vector() # plot(sol_p - p1, title='p1 - sol_p', mesh=mesh) plot(err_p, title="p1 - sol_p", mesh=mesh) # r = SpatialCoordinate(mesh)[0] # divu1 = 1 / r * (r * u1[0]).dx(0) + u1[1].dx(1) divu1.assign(project(u1[0].dx(0) + u1[1].dx(1), P)) plot(divu1, title="div(u1)") return errors
def teXXXst_fenics_vector(): # quad_degree = 13 # dolfin.parameters["form_compiler"]["quadrature_degree"] = quad_degree pi = 3.14159265358979323 k1, k2 = 2, 3 EV = pi * pi * (k1 * k1 + k2 * k2) N = 11 degree = 1 mesh = UnitSquare(N, N) fs = FunctionSpace(mesh, "CG", degree) ex = Expression("A*sin(k1*pi*x[0])*sin(k2*pi*x[1])", k1=k1, k2=k2, A=1.0) x = FEniCSVector(interpolate(ex, fs)) # print "x.coeff", x.coeffs.array() ex.A = EV b_ex = assemble_rhs(ex, fs) bexg = interpolate(ex, fs) # print b_ex.array() # print b_ex.array() / (2 * pi * pi * x.coeffs.array()) Afe = assemble_lhs(Expression('1'), fs) # apply discrete operator on (interpolated) x A = FEniCSOperator(Afe, x.basis) b = A * x # evaluate solution for eigenfunction rhs if False: b_num = Function(fs) solve(A, b_num.vector(), b_ex) bnv = A * b_num.vector() b3 = Function(fs, bnv / EV) np.set_printoptions(threshold='nan', suppress=True) print b.coeffs.array() print np.abs((b_ex.array() - b.coeffs.array()) / np.max(b_ex.array())) print np.max(np.abs((b_ex.array() - b.coeffs.array()) / np.max(b_ex.array()))) #print b_ex.array() / (M * interpolate(ex1, fs).vector()).array() # #assert_array_almost_equal(b.coeffs, b_ex.coeffs) b2 = Function(fs, b_ex.copy()) bg = Function(fs, b_ex.copy()) b2g = Function(fs, b_ex.copy()) G = assemble_gramian(x.basis) dolfin.solve(G, bg.vector(), b.coeffs) dolfin.solve(G, b2g.vector(), b2.vector()) # # compute eigenpairs numerically # eigensolver = evaluate_evp(FEniCSBasis(fs)) # # Extract largest (first) eigenpair # r, c, rx, cx = eigensolver.get_eigenpair(0) # print "Largest eigenvalue: ", r # # Initialize function and assign eigenvector # ef0 = Function(fs) # ef0.vector()[:] = rx if False: # export out_b = dolfin.File(__name__ + "_b.pvd", "compressed") out_b << b._fefunc out_b_ex = dolfin.File(__name__ + "_b_ex.pvd", "compressed") out_b_ex << b2 out_b_num = dolfin.File(__name__ + "_b_num.pvd", "compressed") out_b_num << b_num #dolfin.plot(x._fefunc, title="interpolant x", rescale=False, axes=True, legend=True) dolfin.plot(bg, title="b", rescale=False, axes=True, legend=True) dolfin.plot(b2g, title="b_ex (ass/G)", rescale=False, axes=True, legend=True) dolfin.plot(bexg, title="b_ex (dir)", rescale=False, axes=True, legend=True) #dolfin.plot(b_num, title="b_num", rescale=False, axes=True, legend=True) # dolfin.plot(b3, title="M*b_num", rescale=False, axes=True, legend=True) #dolfin.plot(ef0, title="ef0", rescale=False, axes=True, legend=True) print dolfin.errornorm(u=b._fefunc, uh=b2) #, norm_type, degree, mesh) dolfin.interactive()