def test_save_and_read_function_timeseries(tempdir): filename = os.path.join(tempdir, "function.h5") mesh = UnitSquareMesh(MPI.comm_world, 10, 10) Q = FunctionSpace(mesh, ("CG", 3)) F0 = Function(Q) F1 = Function(Q) E = Expression("t*x[0]", t=0.0, degree=1) F0.interpolate(E) # Save to HDF5 File hdf5_file = HDF5File(mesh.mpi_comm(), filename, "w") for t in range(10): E.t = t F0.interpolate(E) hdf5_file.write(F0, "/function", t) hdf5_file.close() # Read back from file hdf5_file = HDF5File(mesh.mpi_comm(), filename, "r") for t in range(10): E.t = t F1.interpolate(E) vec_name = "/function/vector_%d" % t F0 = hdf5_file.read_function(Q, vec_name) # timestamp = hdf5_file.attributes(vec_name)["timestamp"] # assert timestamp == t F0.vector().axpy(-1.0, F1.vector()) assert F0.vector().norm(cpp.la.Norm.l2) < 1.0e-12 hdf5_file.close()
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 _check_spatial_order(problem, method): mesh_generator, solution, weak_F = problem() # Translate data into FEniCS expressions. fenics_sol = Expression(sympy.printing.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', 5) # 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])) # Plot order curves for comparison. for order in [2, 3, 4]: plt.loglog([H[0], H[-1]], [Err[0], Err[0] * (H[-1] / H[0])**order], color='0.5') # Finally, the actual data. plt.loglog(H, Err, '-o') plt.xlabel('h_max') plt.ylabel('||u-u_h|| / ||u||') plt.show() return
def test_interpolation_rank0(V): @function.expression.numba_eval def expr_eval(values, x, t): values[:, 0] = 1.0 * t f = Expression(expr_eval, shape=()) f.t = 1.0 w = interpolate(f, V) with w.vector().localForm() as x: assert (x[:] == 1.0).all() f.t = 2.0 w = interpolate(f, V) with w.vector().localForm() as x: assert (x[:] == 2.0).all()
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 _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 test_unsteady_stokes(): nx, ny = 15, 15 k = 1 nu = Constant(1.0e-0) dt = Constant(2.5e-2) num_steps = 20 theta0 = 1.0 # Initial theta value theta1 = 0.5 # Theta after 1 step theta = Constant(theta0) mesh = UnitSquareMesh(nx, ny) # The 'unsteady version' of the benchmark in the 2012 paper by Labeur&Wells u_exact = Expression( ( "sin(t) * x[0]*x[0]*(1.0 - x[0])*(1.0 - x[0])*(2.0*x[1] \ -6.0*x[1]*x[1] + 4.0*x[1]*x[1]*x[1])", "-sin(t)* x[1]*x[1]*(1.0 - x[1])*(1.0 - x[1])*(2.0*x[0] \ - 6.0*x[0]*x[0] + 4.0*x[0]*x[0]*x[0])", ), t=0, degree=7, domain=mesh, ) p_exact = Expression("sin(t) * x[0]*(1.0 - x[0])", t=0, degree=7, domain=mesh) du_exact = Expression( ( "cos(t) * x[0]*x[0]*(1.0 - x[0])*(1.0 - x[0])*(2.0*x[1] \ - 6.0*x[1]*x[1] + 4.0*x[1]*x[1]*x[1])", "-cos(t)* x[1]*x[1]*(1.0 - x[1])*(1.0 - x[1])*(2.0*x[0] \ -6.0*x[0]*x[0] + 4.0*x[0]*x[0]*x[0])", ), t=0, degree=7, domain=mesh, ) ux_exact = Expression( ( "x[0]*x[0]*(1.0 - x[0])*(1.0 - x[0])*(2.0*x[1] \ - 6.0*x[1]*x[1] + 4.0*x[1]*x[1]*x[1])", "-x[1]*x[1]*(1.0 - x[1])*(1.0 - x[1])*(2.0*x[0] \ - 6.0*x[0]*x[0] + 4.0*x[0]*x[0]*x[0])", ), degree=7, domain=mesh, ) px_exact = Expression("x[0]*(1.0 - x[0])", degree=7, domain=mesh) sin_ext = Expression("sin(t)", t=0, degree=7, domain=mesh) f = du_exact + sin_ext * div(px_exact * Identity(2) - 2 * sym(grad(ux_exact))) Vhigh = VectorFunctionSpace(mesh, "DG", 7) Phigh = FunctionSpace(mesh, "DG", 7) # New syntax: V = VectorElement("DG", mesh.ufl_cell(), k) Q = FiniteElement("DG", mesh.ufl_cell(), k - 1) Vbar = VectorElement("DGT", mesh.ufl_cell(), k) Qbar = FiniteElement("DGT", mesh.ufl_cell(), k) mixedL = FunctionSpace(mesh, MixedElement([V, Q])) mixedG = FunctionSpace(mesh, MixedElement([Vbar, Qbar])) V2 = FunctionSpace(mesh, V) Uh = Function(mixedL) Uhbar = Function(mixedG) U0 = Function(mixedL) Uhbar0 = Function(mixedG) u0, p0 = split(U0) ubar0, pbar0 = split(Uhbar0) ustar = Function(V2) # Then the boundary conditions bc0 = DirichletBC(mixedG.sub(0), Constant((0, 0)), Gamma) bc1 = DirichletBC(mixedG.sub(1), Constant(0), Corner, "pointwise") bcs = [bc0, bc1] alpha = Constant(6 * k * k) forms_stokes = FormsStokes(mesh, mixedL, mixedG, alpha).forms_unsteady(ustar, dt, nu, f) ssc = StokesStaticCondensation( mesh, forms_stokes["A_S"], forms_stokes["G_S"], forms_stokes["G_ST"], forms_stokes["B_S"], forms_stokes["Q_S"], forms_stokes["S_S"], ) t = 0.0 step = 0 for step in range(num_steps): step += 1 t += float(dt) if comm.Get_rank() == 0: print("Step " + str(step) + " Time " + str(t)) # Set time level in exact solution u_exact.t = t p_exact.t = t du_exact.t = t - (1 - float(theta)) * float(dt) sin_ext.t = t - (1 - float(theta)) * float(dt) ssc.assemble_global_lhs() ssc.assemble_global_rhs() for bc in bcs: ssc.apply_boundary(bc) ssc.solve_problem(Uhbar, Uh, "none", "default") assign(U0, Uh) assign(ustar, U0.sub(0)) assign(Uhbar0, Uhbar) if step == 1: theta.assign(theta1) udiv_e = sqrt(assemble(div(Uh.sub(0)) * div(Uh.sub(0)) * dx)) u_ex_h = interpolate(u_exact, Vhigh) p_ex_h = interpolate(p_exact, Phigh) u_error = sqrt(assemble(dot(Uh.sub(0) - u_ex_h, Uh.sub(0) - u_ex_h) * dx)) p_error = sqrt(assemble(dot(Uh.sub(1) - p_ex_h, Uh.sub(1) - p_ex_h) * dx)) assert udiv_e < 1e-12 assert u_error < 1.5e-4 assert p_error < 1e-2
v = TestFunction(V) f = Constant(beta - 2 - 2 * alpha) F = u * v * dx + dt * dot(grad(u), grad(v)) * dx - (u_n + dt * f) * v * dx a, L = lhs(F), rhs(F) # Time-stepping u = Function(V) t = 0 vtkfile = File('heat/solution_3D.pvd') for n in range(num_steps): # Update current time t += dt u_D.t = t # Compute solution solve(a == L, u, bc) # Plot solution # plot(u) # axi.triplot(u) vtkfile << u # Compute error at vertices # u_e = interpolate(u_D, V) # error = np.abs(u_e.vector().array() - u.vector().array()).max() # print('t = %.2f: error = %.3g' % (t, error)) # Update previous solution
pde_projection = PDEStaticCondensation(mesh, p, forms_pde['N_a'], forms_pde['G_a'], forms_pde['L_a'], forms_pde['H_a'], forms_pde['B_a'], forms_pde['Q_a'], forms_pde['R_a'], forms_pde['S_a'], [], 1) ap = advect_rk3(p, V, uh, 'open') # Initialize the initial condition at mesh by an l2 projection lstsq_rho = l2projection(p, Q_Rho, 1) lstsq_rho.project(phih0) outfile << phih0 for step in range(num_steps): u_expr.t = step * float(dt) u_expre_neg.t = step * float(dt) uh.assign(u_expr) # Compute area at old configuration old_area = assemble(phih0*dx) # Pre-assemble rhs pde_projection.assemble_state_rhs() # Advect the particles ap.do_step(float(dt)) # Move mesh umesh.assign(u_expre_neg)
def _test_time_stepping_1_sparse(callback_type, integrator_type): # Create mesh and define function space mesh = IntervalMesh(132, 0, 2*pi) V = FunctionSpace(mesh, "Lagrange", 1) # Define Dirichlet boundary (x = 0 or x = 2*pi) def boundary(x): return x[0] < 0 + DOLFIN_EPS or x[0] > 2*pi - 10*DOLFIN_EPS # Define time step dt = 0.01 T = 1. # Define exact solution exact_solution_expression = Expression("sin(x[0]+t)", t=0, element=V.ufl_element()) # ... and interpolate it at the final time exact_solution_expression.t = T exact_solution = project(exact_solution_expression, V) # Define exact solution dot exact_solution_dot_expression = Expression("cos(x[0]+t)", t=0, element=V.ufl_element()) # ... and interpolate it at the final time exact_solution_dot_expression.t = T exact_solution_dot = project(exact_solution_dot_expression, V) # Define variational problem du = TrialFunction(V) du_dot = TrialFunction(V) v = TestFunction(V) u = Function(V) u_dot = Function(V) g = Expression("sin(x[0]+t) + cos(x[0]+t)", t=0., element=V.ufl_element()) r_u = inner(grad(u), grad(v))*dx j_u = derivative(r_u, u, du) r_u_dot = inner(u_dot, v)*dx j_u_dot = derivative(r_u_dot, u_dot, du_dot) r = r_u_dot + r_u - g*v*dx x = inner(du, v)*dx def bc(t): exact_solution_expression.t = t return [DirichletBC(V, exact_solution_expression, boundary)] # Assemble inner product matrix X = assemble(x) # Define callback function depending on callback type assert callback_type in ("form callbacks", "tensor callbacks") if callback_type == "form callbacks": def callback(arg): return arg elif callback_type == "tensor callbacks": def callback(arg): return assemble(arg) # Define problem wrapper class SparseProblemWrapper(TimeDependentProblem1Wrapper): # Residual and jacobian functions def residual_eval(self, t, solution, solution_dot): g.t = t return callback(r) def jacobian_eval(self, t, solution, solution_dot, solution_dot_coefficient): return callback(Constant(solution_dot_coefficient)*j_u_dot + j_u) # Define boundary condition def bc_eval(self, t): return bc(t) # Define initial condition def ic_eval(self): exact_solution_expression.t = 0. return project(exact_solution_expression, V) # Define custom monitor to plot the solution def monitor(self, t, solution, solution_dot): if matplotlib.get_backend() != "agg": plt.subplot(1, 2, 1).clear() plot(solution, title="u at t = " + str(t)) plt.subplot(1, 2, 2).clear() plot(solution_dot, title="u_dot at t = " + str(t)) plt.show(block=False) plt.pause(DOLFIN_EPS) else: print("||u|| at t = " + str(t) + ": " + str(solution.vector().norm("l2"))) print("||u_dot|| at t = " + str(t) + ": " + str(solution_dot.vector().norm("l2"))) # Solve the time dependent problem sparse_problem_wrapper = SparseProblemWrapper() (sparse_solution, sparse_solution_dot) = (u, u_dot) sparse_solver = SparseTimeStepping(sparse_problem_wrapper, sparse_solution, sparse_solution_dot) sparse_solver.set_parameters({ "initial_time": 0.0, "time_step_size": dt, "final_time": T, "exact_final_time": "stepover", "integrator_type": integrator_type, "problem_type": "linear", "linear_solver": "mumps", "monitor": sparse_problem_wrapper.monitor, "report": True }) all_sparse_solutions_time, all_sparse_solutions, all_sparse_solutions_dot = sparse_solver.solve() assert len(all_sparse_solutions_time) == int(T/dt + 1) assert len(all_sparse_solutions) == int(T/dt + 1) assert len(all_sparse_solutions_dot) == int(T/dt + 1) # Compute the error sparse_error = Function(V) sparse_error.vector().add_local(+ sparse_solution.vector().get_local()) sparse_error.vector().add_local(- exact_solution.vector().get_local()) sparse_error.vector().apply("") sparse_error_norm = sparse_error.vector().inner(X*sparse_error.vector()) sparse_error_dot = Function(V) sparse_error_dot.vector().add_local(+ sparse_solution_dot.vector().get_local()) sparse_error_dot.vector().add_local(- exact_solution_dot.vector().get_local()) sparse_error_dot.vector().apply("") sparse_error_dot_norm = sparse_error_dot.vector().inner(X*sparse_error_dot.vector()) print("SparseTimeStepping error (" + callback_type + ", " + integrator_type + "):", sparse_error_norm, sparse_error_dot_norm) assert isclose(sparse_error_norm, 0., atol=1.e-4) assert isclose(sparse_error_dot_norm, 0., atol=1.e-4) return ((sparse_error_norm, sparse_error_dot_norm), V, dt, T, u, u_dot, g, r, j_u, j_u_dot, X, exact_solution_expression, exact_solution, exact_solution_dot)
def compute_time_errors(problem, method, mesh_sizes, Dt): mesh_generator, solution, f, mu, rho, cell_type = problem() # Translate data into FEniCS expressions. u = solution['u'] sol_u = Expression((ccode(u['value'][0]), ccode(u['value'][1])), degree=_truncate_degree(u['degree']), t=0.0) p = solution['p'] sol_p = Expression(ccode(p['value']), degree=_truncate_degree(p['degree']), t=0.0) # Deep-copy expression to be able to provide f0, f1 for the Dirichlet- # boundary conditions later on. fenics_rhs0 = Expression((ccode(f['value'][0]), ccode(f['value'][1])), degree=_truncate_degree(f['degree']), t=0.0, mu=mu, rho=rho) fenics_rhs1 = Expression(fenics_rhs0.cppcode, element=fenics_rhs0.ufl_element(), **fenics_rhs0.user_parameters) # Create initial states. p = 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): print() print() print('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) 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_1 = Expression(sol_u.cppcode, degree=_truncate_degree(solution['u']['degree']), t=-dt, cell=cell_type) u_1 = project(u_1, W) u0 = Expression( sol_u.cppcode, degree=_truncate_degree(solution['u']['degree']), t=0.0, # t=0.5*dt, cell=cell_type) u0 = project(u0, W) sol_u.t = dt u_bcs = [DirichletBC(W, sol_u, 'on_boundary')] sol_p.t = dt p0 = project(p, P) p_bcs = [] fenics_rhs0.t = 0.0 fenics_rhs1.t = dt u1, p1 = method.step(Constant(dt), { -1: u_1, 0: u0 }, p0, u_bcs=u_bcs, p_bcs=p_bcs, rho=Constant(rho), mu=Constant(mu), f={ 0: fenics_rhs0, 1: fenics_rhs1 }, verbose=False, tol=1.0e-10) # plot(sol_u, mesh=mesh, title='u_sol') # plot(sol_p, mesh=mesh, title='p_sol') # plot(u1, title='u') # plot(p1, title='p') # from dolfin import div # plot(div(u1), title='div(u)') # plot(p1 - sol_p, title='p_h - p') # interactive() 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 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 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
p.increment(Udiv.cpp_object(), ustar.cpp_object(), np.array([1, 2], dtype=np.uintp), theta_p, step) if step == 2: theta_L.assign(theta_next) # Probably can be combined into one file? xdmf_u.write(Uh.sub(0), t) xdmf_p.write(Uh.sub(1), t) del t1 timer.stop() # Compute errors u_exact.t = t p_exact.t = t u_error = sqrt(assemble(dot(Uh.sub(0) - u_exact, Uh.sub(0) - u_exact) * dx)) p_error = sqrt(assemble(dot(Uh.sub(1) - p_exact, Uh.sub(1) - p_exact) * dx)) udiv = sqrt(assemble(div(Uh.sub(0)) * div(Uh.sub(0)) * dx)) momentum = assemble((dot(Uh.sub(0), ex) + dot(Uh.sub(0), ey)) * dx) if comm.Get_rank() == 0: print("Velocity error " + str(u_error)) print("Pressure error " + str(p_error)) print("Momentum " + str(momentum)) print("Divergence " + str(udiv)) print("Elapsed time " + str(timer.elapsed()[0]))
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
from dolfin import Expression ccode = '(t-x[0])*(((t-x[0]) < 0) ? 0 : 1)*(((t-x[0]) > tmax) ? 0 : 1)' foo = Expression(ccode, tmax=20, t=0.0) for t in (0.1, 0.2, 0.3): foo.t = t print[foo(x) for x in (-1, -2, -3)]