Пример #1
0
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