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