Пример #1
0
    def __missing__(self, key):
        assert len(key) == 4
        form, bcs, solver_type, preconditioner_type = key
        prec = PETScPreconditioner(preconditioner_type)
        sol = PETScKrylovSolver(solver_type, prec)
        sol.prec = prec
        #sol = KrylovSolver(solver_type, preconditioner_type)

        #sol.parameters["preconditioner"]["structure"] = "same"
        sol.parameters["error_on_nonconvergence"] = False
        sol.parameters["monitor_convergence"] = False
        sol.parameters["report"] = False
        self[key] = sol
        return self[key]
Пример #2
0
def create_solver(solver, preconditioner="default"):
    """Create solver from arguments. Should be flexible to handle
    
    - strings specifying the solver and preconditioner types
    - PETScKrylovSolver/PETScPreconditioner objects
    - petsc4py.PETSC.KSP/petsc4py.PETSC.pc objects
    
    or any combination of the above
    """
    # Create solver
    if isinstance(solver, str):
        try:
            linear_solvers = set(dict(linear_solver_methods()).keys())
            krylov_solvers = set(dict(krylov_solver_methods()).keys())
        except:
            linear_solvers = set(linear_solver_methods())
            krylov_solvers = set(krylov_solver_methods())
        direct_solvers = linear_solvers - krylov_solvers

        if solver in direct_solvers:
            s = LinearSolver(solver)
            return s
        elif solver in krylov_solvers:
            s = PETScKrylovSolver(solver)
        else:
            s = PETScKrylovSolver()
            s.ksp().setType(solver)
            if s.ksp().getNormType() == petsc4py.PETSc.KSP.NormType.NONE:
                s.ksp().setNormType(petsc4py.PETSc.KSP.NormType.PRECONDITIONED)
            #raise RuntimeError("Don't know how to handle solver %s" %solver)
    elif isinstance(solver, PETScKrylovSolver):
        s = solver
    elif isinstance(solver, petsc4py.PETSc.KSP):
        s = PETScKrylovSolver(solver)
    else:
        raise ValueError("Unable to create solver from argument of type %s" %
                         type(solver))

    assert isinstance(s, PETScKrylovSolver)
    if preconditioner == "default":
        return s

    # Create preconditioner
    if preconditioner in [None, "none", "None"]:
        pc = PETScPreconditioner("none")
        pc.set(s)
        return s
    elif isinstance(preconditioner, str):
        if preconditioner in krylov_solver_preconditioners():
            pc = PETScPreconditioner(preconditioner)
            pc.set(s)
            return s
        elif preconditioner in ["additive_schwarz", "bjacobi", "jacobi"]:
            if preconditioner == "additive_schwarz":
                pc_type = "asm"
            else:
                pc_type = preconditioner
            ksp = s.ksp()
            pc = ksp.pc
            pc.setType(pc_type)
            return s
    elif isinstance(preconditioner, PETScPreconditioner):
        pc = preconditioner
        pc.set(s)
        return s
    elif isinstance(preconditioner, petsc4py.PETSc.PC):
        ksp = s.ksp()
        ksp.setPC(preconditioner)
        return s
    else:
        raise ValueError(
            "Unable to create preconditioner from argument of type %s" %
            type(solver))

    raise RuntimeError(
        "Should not reach this code. The solver/preconditioner (%s/%s) failed to return a valid solver."
        % (str(solver), str(preconditioner)))
Пример #3
0
def stokes_solve(
    up_out,
    mu,
    u_bcs, p_bcs,
    f,
    dx=dx,
    verbose=True,
    tol=1.0e-10,
    maxiter=1000
    ):
    # Some initial sanity checks.
    assert mu > 0.0

    WP = up_out.function_space()

    # Translate the boundary conditions into the product space.
    new_bcs = []
    for k, bcs in enumerate([u_bcs, p_bcs]):
        for bc in bcs:
            space = bc.function_space()
            C = space.component()
            if len(C) == 0:
                new_bcs.append(DirichletBC(WP.sub(k),
                                           bc.value(),
                                           bc.domain_args[0]))
            elif len(C) == 1:
                new_bcs.append(DirichletBC(WP.sub(k).sub(int(C[0])),
                                           bc.value(),
                                           bc.domain_args[0]))
            else:
                raise RuntimeError('Illegal number of subspace components.')

    # TODO define p*=-1 and reverse sign in the end to get symmetric system?

    # Define variational problem
    (u, p) = TrialFunctions(WP)
    (v, q) = TestFunctions(WP)

    r = Expression('x[0]', degree=1, domain=WP.mesh())

    print("mu = %e" % mu)

    # build system
    a = mu * inner(r * grad(u), grad(v)) * 2 * pi * dx \
        - ((r * v[0]).dx(0) + (r * v[1]).dx(1)) * p * 2 * pi * dx \
        + ((r * u[0]).dx(0) + (r * u[1]).dx(1)) * q * 2 * pi * dx
      #- div(r*v)*p* 2*pi*dx \
      #+ q*div(r*u)* 2*pi*dx
    L = inner(f, v) * 2 * pi * r * dx

    A, b = assemble_system(a, L, new_bcs)

    mode = 'lu'

    if mode == 'lu':
        solve(A, up_out.vector(), b, 'lu')

    elif mode == 'gmres':
        # For preconditioners for the Stokes system, see
        #
        #     Fast iterative solvers for discrete Stokes equations;
        #     J. Peters, V. Reichelt, A. Reusken.
        #
        prec = mu * inner(r * grad(u), grad(v)) * 2 * pi * dx \
            - p * q * 2 * pi * r * dx
        P, btmp = assemble_system(prec, L, new_bcs)
        solver = KrylovSolver('tfqmr', 'amg')
        #solver = KrylovSolver('gmres', 'amg')
        solver.set_operators(A, P)

        solver.parameters['monitor_convergence'] = verbose
        solver.parameters['report'] = verbose
        solver.parameters['absolute_tolerance'] = 0.0
        solver.parameters['relative_tolerance'] = tol
        solver.parameters['maximum_iterations'] = maxiter

        # Solve
        solver.solve(up_out.vector(), b)
    elif mode == 'fieldsplit':
        raise NotImplementedError('Fieldsplit solver not yet implemented.')
        # For an assortment of preconditioners, see
        #
        #     Performance and analysis of saddle point preconditioners
        #     for the discrete steady-state Navier-Stokes equations;
        #     H.C. Elman, D.J. Silvester, A.J. Wathen;
        #     Numer. Math. (2002) 90: 665-688;
        #     <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.145.3554>.
        #
        # Set up field split.
        W = SubSpace(WP, 0)
        P = SubSpace(WP, 1)
        u_dofs = W.dofmap().dofs()
        p_dofs = P.dofmap().dofs()
        prec = PETScPreconditioner()
        prec.set_fieldsplit([u_dofs, p_dofs], ['u', 'p'])

        PETScOptions.set('pc_type', 'fieldsplit')
        PETScOptions.set('pc_fieldsplit_type', 'additive')
        PETScOptions.set('fieldsplit_u_pc_type', 'lu')
        PETScOptions.set('fieldsplit_p_pc_type', 'jacobi')

        # Create Krylov solver with custom preconditioner.
        solver = PETScKrylovSolver('gmres', prec)
        solver.set_operator(A)

    return
Пример #4
0
def compute_pressure(
    P,
    p0,
    mu,
    ui,
    u,
    my_dx,
    p_bcs=None,
    rotational_form=False,
    tol=1.0e-10,
    verbose=True,
):
    """Solve the pressure Poisson equation

    .. math::

        \\begin{align}
          -\\frac{1}{r} \\div(r \\nabla (p_1-p_0)) =
              -\\frac{1}{r} \\div(r u),\\\\
          \\text{(with boundary conditions)},
        \\end{align}

    for :math:`\\nabla p = u`.

    The pressure correction is based on the update formula

    .. math::
        \\frac{\\rho}{dt} (u_{n+1}-u^*)
            + \\begin{pmatrix}
                \\text{d}\\phi/\\text{d}r\\\\
                \\text{d}\\phi/\\text{d}z\\\\
                \\frac{1}{r} \\text{d}\\phi/\\text{d}\\theta
              \\end{pmatrix}
                = 0

    with :math:`\\phi = p_{n+1} - p^*` and

    .. math::

         \\frac{1}{r} \\frac{\\text{d}}{\\text{d}r} (r u_r^{(n+1)})
       + \\frac{\\text{d}}{\\text{d}z}  (u_z^{(n+1)})
       + \\frac{1}{r} \\frac{\\text{d}}{\\text{d}\\theta} (u_{\\theta}^{(n+1)})
           = 0

    With the assumption that u does not change in the direction
    :math:`\\theta`, one derives

    .. math::

       - \\frac{1}{r}   \\div(r \\nabla \\phi) =
           \\frac{1}{r} \\frac{\\rho}{dt}   \\div(r (u_{n+1} - u^*))\\\\
       - \\frac{1}{r} \\langle n, r \\nabla \\phi\\rangle =
           \\frac{1}{r} \\frac{\\rho}{dt} \\langle n, r (u_{n+1} - u^*)\\rangle

    In its weak form, this is

    .. math::

      \\int r \\langle\\nabla\\phi, \\nabla q\\rangle \\,2 \\pi =
           - \\frac{\\rho}{dt} \\int \\div(r u^*) q \\, 2 \\pi
           - \\frac{\\rho}{dt} \\int_{\\Gamma}
                 \\langle n,  r (u_{n+1}-u^*)\\rangle q \\, 2\\pi.

    (The terms :math:`1/r` cancel with the volume elements :math:`2\\pi r`.)
    If the Dirichlet boundary conditions are applied to both :math:`u^*` and
    :math:`u_n` (the latter in the velocity correction step), the boundary
    integral vanishes.

    If no Dirichlet conditions are given (which is the default case), the
    system has no unique solution; one eigenvalue is 0. This however, does not
    hurt CG convergence if the system is consistent, cf. :cite:`vdV03`. And
    indeed it is consistent if and only if

    .. math::
        \\int_\\Gamma r \\langle n, u\\rangle = 0.

    This condition makes clear that for incompressible Navier-Stokes, one
    either needs to make sure that inflow and outflow always add up to 0, or
    one has to specify pressure boundary conditions.

    Note that, when using a multigrid preconditioner as is done here, the
    coarse solver must be chosen such that it preserves the nullspace of the
    problem.
    """
    W = ui.function_space()
    r = SpatialCoordinate(W.mesh())[0]

    p = TrialFunction(P)
    q = TestFunction(P)
    a2 = dot(r * grad(p), grad(q)) * 2 * pi * my_dx
    # The boundary conditions
    #     n.(p1-p0) = 0
    # are implicitly included.
    #
    # L2 = -div(r*u) * q * 2*pi*my_dx
    div_u = 1 / r * (r * u[0]).dx(0) + u[1].dx(1)
    L2 = -div_u * q * 2 * pi * r * my_dx
    if p0:
        L2 += r * dot(grad(p0), grad(q)) * 2 * pi * my_dx

    # In the Cartesian variant of the rotational form, one makes use of the
    # fact that
    #
    #     curl(curl(u)) = grad(div(u)) - div(grad(u)).
    #
    # The same equation holds true in cylindrical form. Hence, to get the
    # rotational form of the splitting scheme, we need to
    #
    # rotational form
    if rotational_form:
        # If there is no dependence of the angular coordinate, what is
        # div(grad(div(u))) in Cartesian coordinates becomes
        #
        #     1/r div(r * grad(1/r div(r*u)))
        #
        # in cylindrical coordinates (div and grad are in cylindrical
        # coordinates). Unfortunately, we cannot write it down that
        # compactly since u_phi is in the game.
        # When using P2 elements, this value will be 0 anyways.
        div_ui = 1 / r * (r * ui[0]).dx(0) + ui[1].dx(1)
        grad_div_ui = as_vector((div_ui.dx(0), div_ui.dx(1)))
        L2 -= r * mu * dot(grad_div_ui, grad(q)) * 2 * pi * my_dx
        # div_grad_div_ui = 1/r * (r * grad_div_ui[0]).dx(0) \
        #     + (grad_div_ui[1]).dx(1)
        # L2 += mu * div_grad_div_ui * q * 2*pi*r*dx
        # n = FacetNormal(Q.mesh())
        # L2 -= mu * (n[0] * grad_div_ui[0] + n[1] * grad_div_ui[1]) \
        #     * q * 2*pi*r*ds

    p1 = Function(P)
    if p_bcs:
        solve(
            a2 == L2,
            p1,
            bcs=p_bcs,
            solver_parameters={
                "linear_solver": "iterative",
                "symmetric": True,
                "preconditioner": "hypre_amg",
                "krylov_solver": {
                    "relative_tolerance": tol,
                    "absolute_tolerance": 0.0,
                    "maximum_iterations": 100,
                    "monitor_convergence": verbose,
                },
            },
        )
    else:
        # If we're dealing with a pure Neumann problem here (which is the
        # default case), this doesn't hurt CG if the system is consistent,
        # cf. :cite:`vdV03`. And indeed it is consistent if and only if
        #
        #   \int_\Gamma r n.u = 0.
        #
        # This makes clear that for incompressible Navier-Stokes, one
        # either needs to make sure that inflow and outflow always add up
        # to 0, or one has to specify pressure boundary conditions.
        #
        # If the right-hand side is very small, round-off errors may impair
        # the consistency of the system. Make sure the system we are
        # solving remains consistent.
        A = assemble(a2)
        b = assemble(L2)
        # Assert that the system is indeed consistent.
        e = Function(P)
        e.interpolate(Constant(1.0))
        evec = e.vector()
        evec /= norm(evec)
        alpha = b.inner(evec)
        normB = norm(b)
        # Assume that in every component of the vector, a round-off error
        # of the magnitude DOLFIN_EPS is present. This leads to the
        # criterion
        #    |<b,e>| / (||b||*||e||) < DOLFIN_EPS
        # as a check whether to consider the system consistent up to
        # round-off error.
        #
        # TODO think about condition here
        # if abs(alpha) > normB * DOLFIN_EPS:
        if abs(alpha) > normB * 1.0e-12:
            # divu = 1 / r * (r * u[0]).dx(0) + u[1].dx(1)
            adivu = assemble(((r * u[0]).dx(0) + u[1].dx(1)) * 2 * pi * my_dx)
            info("\\int 1/r * div(r*u) * 2*pi*r  =  {:e}".format(adivu))
            n = FacetNormal(P.mesh())
            boundary_integral = assemble((n[0] * u[0] + n[1] * u[1]) * 2 * pi * r * ds)
            info("\\int_Gamma n.u * 2*pi*r = {:e}".format(boundary_integral))
            message = (
                "System not consistent! "
                "<b,e> = {:g}, ||b|| = {:g}, <b,e>/||b|| = {:e}.".format(
                    alpha, normB, alpha / normB
                )
            )
            info(message)
            # # Plot the stuff, and project it to a finer mesh with linear
            # # elements for the purpose.
            # plot(divu, title='div(u_tentative)')
            # # Vp = FunctionSpace(Q.mesh(), 'CG', 2)
            # # Wp = MixedFunctionSpace([Vp, Vp])
            # # up = project(u, Wp)
            # fine_mesh = Q.mesh()
            # for k in range(1):
            #     fine_mesh = refine(fine_mesh)
            # V = FunctionSpace(fine_mesh, 'CG', 1)
            # W = V * V
            # # uplot = Function(W)
            # # uplot.interpolate(u)
            # uplot = project(u, W)
            # plot(uplot[0], title='u_tentative[0]')
            # plot(uplot[1], title='u_tentative[1]')
            # # plot(u, title='u_tentative')
            # interactive()
            # exit()
            raise RuntimeError(message)
        # Project out the roundoff error.
        b -= alpha * evec

        #
        # In principle, the ILU preconditioner isn't advised here since it
        # might destroy the semidefiniteness needed for CG.
        #
        # The system is consistent, but the matrix has an eigenvalue 0.
        # This does not harm the convergence of CG, but when
        # preconditioning one has to make sure that the preconditioner
        # preserves the kernel. ILU might destroy this (and the
        # semidefiniteness). With AMG, the coarse grid solves cannot be LU
        # then, so try Jacobi here.
        # <http://lists.mcs.anl.gov/pipermail/petsc-users/2012-February/012139.html>
        #
        prec = PETScPreconditioner("hypre_amg")
        from dolfin import PETScOptions

        PETScOptions.set("pc_hypre_boomeramg_relax_type_coarse", "jacobi")
        solver = PETScKrylovSolver("cg", prec)
        solver.parameters["absolute_tolerance"] = 0.0
        solver.parameters["relative_tolerance"] = tol
        solver.parameters["maximum_iterations"] = 100
        solver.parameters["monitor_convergence"] = verbose
        # Create solver and solve system
        A_petsc = as_backend_type(A)
        b_petsc = as_backend_type(b)
        p1_petsc = as_backend_type(p1.vector())
        solver.set_operator(A_petsc)
        solver.solve(p1_petsc, b_petsc)
    return p1
Пример #5
0
def solve(W, P,
          mu,
          u_bcs, p_bcs,
          f,
          verbose=True,
          tol=1.0e-10
          ):
    # Some initial sanity checks.
    assert mu > 0.0

    WP = MixedFunctionSpace([W, P])

    # Translate the boundary conditions into the product space.
    # This conditional loop is able to deal with conditions of the kind
    #
    #     DirichletBC(W.sub(1), 0.0, right_boundary)
    #
    new_bcs = []
    for k, bcs in enumerate([u_bcs, p_bcs]):
        for bc in bcs:
            space = bc.function_space()
            C = space.component()
            if len(C) == 0:
                new_bcs.append(DirichletBC(WP.sub(k),
                                           bc.value(),
                                           bc.domain_args[0]))
            elif len(C) == 1:
                new_bcs.append(DirichletBC(WP.sub(k).sub(int(C[0])),
                                           bc.value(),
                                           bc.domain_args[0]))
            else:
                raise RuntimeError('Illegal number of subspace components.')

    # Define variational problem
    (u, p) = TrialFunctions(WP)
    (v, q) = TestFunctions(WP)

    # Build system.
    # The sign of the div(u)-term is somewhat arbitrary since the right-hand
    # side is 0 here. We can either make the system symmetric or positive-
    # definite.
    # On a second note, we have
    #
    #    \int grad(p).v = - \int p * div(v) + \int_\Gamma p n.v.
    #
    # Since, we have either p=0 or n.v=0 on the boundary, we could as well
    # replace the term dot(grad(p), v) by -p*div(v).
    #
    a = mu * inner(grad(u), grad(v))*dx \
      - p * div(v) * dx \
      - q * div(u) * dx
    #a = mu * inner(grad(u), grad(v))*dx + dot(grad(p), v) * dx \
    #  - div(u) * q * dx
    L = dot(f, v)*dx
    A, b = assemble_system(a, L, new_bcs)

    if has_petsc():
        # For an assortment of preconditioners, see
        #
        #     Performance and analysis of saddle point preconditioners
        #     for the discrete steady-state Navier-Stokes equations;
        #     H.C. Elman, D.J. Silvester, A.J. Wathen;
        #     Numer. Math. (2002) 90: 665-688;
        #     <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.145.3554>.
        #
        # Set up field split.
        W = SubSpace(WP, 0)
        P = SubSpace(WP, 1)
        u_dofs = W.dofmap().dofs()
        p_dofs = P.dofmap().dofs()
        prec = PETScPreconditioner()
        prec.set_fieldsplit([u_dofs, p_dofs], ['u', 'p'])

        PETScOptions.set('pc_type', 'fieldsplit')
        PETScOptions.set('pc_fieldsplit_type', 'additive')
        PETScOptions.set('fieldsplit_u_pc_type', 'lu')
        PETScOptions.set('fieldsplit_p_pc_type', 'jacobi')

        ## <http://scicomp.stackexchange.com/questions/7288/which-preconditioners-and-solver-in-petsc-for-indefinite-symmetric-systems-sho>
        #PETScOptions.set('pc_type', 'fieldsplit')
        ##PETScOptions.set('pc_fieldsplit_type', 'schur')
        ##PETScOptions.set('pc_fieldsplit_schur_fact_type', 'upper')
        #PETScOptions.set('pc_fieldsplit_detect_saddle_point')
        ##PETScOptions.set('fieldsplit_u_pc_type', 'lsc')
        ##PETScOptions.set('fieldsplit_u_ksp_type', 'preonly')

        #PETScOptions.set('pc_type', 'fieldsplit')
        #PETScOptions.set('fieldsplit_u_pc_type', 'hypre')
        #PETScOptions.set('fieldsplit_u_ksp_type', 'preonly')
        #PETScOptions.set('fieldsplit_p_pc_type', 'jacobi')
        #PETScOptions.set('fieldsplit_p_ksp_type', 'preonly')

        ## From PETSc/src/ksp/ksp/examples/tutorials/ex42-fsschur.opts:
        #PETScOptions.set('pc_type', 'fieldsplit')
        #PETScOptions.set('pc_fieldsplit_type', 'SCHUR')
        #PETScOptions.set('pc_fieldsplit_schur_fact_type', 'UPPER')
        #PETScOptions.set('fieldsplit_p_ksp_type', 'preonly')
        #PETScOptions.set('fieldsplit_u_pc_type', 'bjacobi')

        ## From
        ##
        ##     Composable Linear Solvers for Multiphysics;
        ##     J. Brown, M. Knepley, D.A. May, L.C. McInnes, B. Smith;
        ##     <http://www.computer.org/csdl/proceedings/ispdc/2012/4805/00/4805a055-abs.html>;
        ##     <http://www.mcs.anl.gov/uploads/cels/papers/P2017-0112.pdf>.
        ##
        #PETScOptions.set('pc_type', 'fieldsplit')
        #PETScOptions.set('pc_fieldsplit_type', 'schur')
        #PETScOptions.set('pc_fieldsplit_schur_factorization_type', 'upper')
        ##
        #PETScOptions.set('fieldsplit_u_ksp_type', 'cg')
        #PETScOptions.set('fieldsplit_u_ksp_rtol', 1.0e-6)
        #PETScOptions.set('fieldsplit_u_pc_type', 'bjacobi')
        #PETScOptions.set('fieldsplit_u_sub_pc_type', 'cholesky')
        ##
        #PETScOptions.set('fieldsplit_p_ksp_type', 'fgmres')
        #PETScOptions.set('fieldsplit_p_ksp_constant_null_space')
        #PETScOptions.set('fieldsplit_p_pc_type', 'lsc')
        ##
        #PETScOptions.set('fieldsplit_p_lsc_ksp_type', 'cg')
        #PETScOptions.set('fieldsplit_p_lsc_ksp_rtol', 1.0e-2)
        #PETScOptions.set('fieldsplit_p_lsc_ksp_constant_null_space')
        ##PETScOptions.set('fieldsplit_p_lsc_ksp_converged_reason')
        #PETScOptions.set('fieldsplit_p_lsc_pc_type', 'bjacobi')
        #PETScOptions.set('fieldsplit_p_lsc_sub_pc_type', 'icc')

        # Create Krylov solver with custom preconditioner.
        solver = PETScKrylovSolver('gmres', prec)
        solver.set_operator(A)
    else:
        # Use the preconditioner as recommended in
        # <http://fenicsproject.org/documentation/dolfin/dev/python/demo/pde/stokes-iterative/python/documentation.html>,
        #
        #     prec = inner(grad(u), grad(v))*dx - p*q*dx
        #
        # although it doesn't seem to be too efficient.
        # The sign on the last term doesn't matter.
        prec = mu * inner(grad(u), grad(v))*dx \
             - p*q*dx
        M, _ = assemble_system(prec, L, new_bcs)
        #solver = KrylovSolver('tfqmr', 'amg')
        solver = KrylovSolver('gmres', 'amg')
        solver.set_operators(A, M)

    solver.parameters['monitor_convergence'] = verbose
    solver.parameters['report'] = verbose
    solver.parameters['absolute_tolerance'] = 0.0
    solver.parameters['relative_tolerance'] = tol
    solver.parameters['maximum_iterations'] = 500

    # Solve
    up = Function(WP)
    solver.solve(up.vector(), b)

    # Get sub-functions
    u, p = up.split()

    return u, p
Пример #6
0
def _compute_pressure(p0,
                      alpha,
                      rho,
                      dt,
                      mu,
                      div_ui,
                      p_bcs=None,
                      p_function_space=None,
                      rotational_form=False,
                      tol=1.0e-10,
                      verbose=True):
    '''Solve the pressure Poisson equation

        - \\Delta phi = -div(u),
        boundary conditions,

    for p with

        \\nabla p = u.
    '''
    #
    # The following is based on the update formula
    #
    #     rho/dt (u_{n+1}-u*) + \nabla phi = 0
    #
    # with
    #
    #     phi = (p_{n+1} - p*) + chi*mu*div(u*)
    #
    # and div(u_{n+1})=0. One derives
    #
    #   - \nabla^2 phi = rho/dt div(u_{n+1} - u*),
    #   - n.\nabla phi = rho/dt  n.(u_{n+1} - u*),
    #
    # In its weak form, this is
    #
    #     \int \grad(phi).\grad(q)
    #   = - rho/dt \int div(u*) q - rho/dt \int_Gamma n.(u_{n+1}-u*) q.
    #
    # If Dirichlet boundary conditions are applied to both u* and u_{n+1} (the
    # latter in the final step), the boundary integral vanishes.
    #
    # Assume that on the boundary
    #   L2 -= inner(n, rho/k (u_bcs - ui)) * q * ds
    # is zero. This requires the boundary conditions to be set for ui as well
    # as u_final.
    # This creates some problems if the boundary conditions are supposed to
    # remain 'free' for the velocity, i.e., no Dirichlet conditions in normal
    # direction. In that case, one needs to specify Dirichlet pressure
    # conditions.
    #
    if p0:
        P = p0.function_space()
    else:
        P = p_function_space

    p1 = Function(P)
    p = TrialFunction(P)
    q = TestFunction(P)

    a2 = dot(grad(p), grad(q)) * dx
    L2 = -alpha * rho / dt * div_ui * q * dx

    L2 += dot(grad(p0), grad(q)) * dx

    if rotational_form:
        L2 -= mu * dot(grad(div_ui), grad(q)) * dx

    if p_bcs:
        solve(a2 == L2,
              p1,
              bcs=p_bcs,
              solver_parameters={
                  'linear_solver': 'iterative',
                  'symmetric': True,
                  'preconditioner': 'hypre_amg',
                  'krylov_solver': {
                      'relative_tolerance': tol,
                      'absolute_tolerance': 0.0,
                      'maximum_iterations': 100,
                      'monitor_convergence': verbose,
                      'error_on_nonconvergence': True
                  }
              })
    else:
        # If we're dealing with a pure Neumann problem here (which is the
        # default case), this doesn't hurt CG if the system is consistent, cf.
        #
        #    Iterative Krylov methods for large linear systems,
        #    Henk A. van der Vorst.
        #
        # And indeed, it is consistent: Note that
        #
        #    <1, rhs> = \sum_i 1 * \int div(u) v_i
        #             = 1 * \int div(u) \sum_i v_i
        #             = \int div(u).
        #
        # With the divergence theorem, we have
        #
        #    \int div(u) = \int_\Gamma n.u.
        #
        # The latter term is 0 if and only if inflow and outflow are exactly
        # the same at any given point in time. This corresponds with the
        # incompressibility of the liquid.
        #
        # Another lesson from this:
        # If the mesh has penetration boundaries, you either have to specify
        # the normal component of the velocity such that \int(n.u) = 0, or
        # specify Dirichlet conditions for the pressure somewhere.
        #
        A = assemble(a2)
        b = assemble(L2)

        # If the right hand side is flawed (e.g., by round-off errors), then it
        # may have a component b1 in the direction of the null space,
        # orthogonal to the image of the operator:
        #
        #     b = b0 + b1.
        #
        # When starting with initial guess x0=0, the minimal achievable
        # relative tolerance is then
        #
        #    min_rel_tol = ||b1|| / ||b||.
        #
        # If ||b|| is very small, which is the case when ui is almost
        # divergence-free, then min_rel_to may be larger than the prescribed
        # relative tolerance tol. This happens, for example, when the time
        # steps is very small.
        # Sanitation of right-hand side is easy with
        #
        #     e = Function(P)
        #     e.interpolate(Constant(1.0))
        #     evec = e.vector()
        #     evec /= norm(evec)
        #     print(b.inner(evec))
        #     b -= b.inner(evec) * evec
        #
        # However it's hard to decide when the right-hand side is inconsistent
        # because of round-off errors in previous steps, or because the system
        # is actually inconsistent (insufficient boundary conditions or
        # something like that). Hence, don't do anything and rather try to
        # fight the cause for round-off.

        # In principle, the ILU preconditioner isn't advised here since it
        # might destroy the semidefiniteness needed for CG.
        #
        # The system is consistent, but the matrix has an eigenvalue 0. This
        # does not harm the convergence of CG, but with preconditioning one has
        # to make sure that the preconditioner preserves the kernel. ILU might
        # destroy this (and the semidefiniteness). With AMG, the coarse grid
        # solves cannot be LU then, so try Jacobi here.
        # <http://lists.mcs.anl.gov/pipermail/petsc-users/2012-February/012139.html>
        #

        # TODO clear everything; possible in FEniCS 2017.1
        # <https://fenicsproject.org/qa/12916/clear-petscoptions>
        # PETScOptions.clear()

        prec = PETScPreconditioner('hypre_amg')
        PETScOptions.set('pc_hypre_boomeramg_relax_type_coarse', 'jacobi')
        solver = PETScKrylovSolver('cg', prec)
        solver.parameters['absolute_tolerance'] = 0.0
        solver.parameters['relative_tolerance'] = tol
        solver.parameters['maximum_iterations'] = 1000
        solver.parameters['monitor_convergence'] = verbose
        solver.parameters['error_on_nonconvergence'] = True

        # Create solver and solve system
        A_petsc = as_backend_type(A)
        b_petsc = as_backend_type(b)
        p1_petsc = as_backend_type(p1.vector())
        solver.set_operator(A_petsc)

        solver.solve(p1_petsc, b_petsc)
    return p1