Ejemplo n.º 1
0
def test_form_splitter_matrices(shape):
    mesh = UnitSquareMesh(dolfin.MPI.comm_self, 3, 3)
    Vu = FunctionSpace(mesh, 'DG', 2)
    Vp = FunctionSpace(mesh, 'DG', 1)

    def define_eq(u, v, p, q):
        "A simple Stokes-like coupled weak form"
        eq = Constant(2) * dot(u, v) * dx
        eq += dot(grad(p), v) * dx
        eq -= dot(Constant([1, 1]), v) * dx
        eq += dot(grad(q), u) * dx
        eq -= dot(Constant(0.3), q) * dx
        return eq

    if shape == (2, 2):
        eu = MixedElement([Vu.ufl_element(), Vu.ufl_element()])
        ew = MixedElement([eu, Vp.ufl_element()])
        W = FunctionSpace(mesh, ew)

        u, p = TrialFunctions(W)
        v, q = TestFunctions(W)
        u = as_vector([u[0], u[1]])
        v = as_vector([v[0], v[1]])

    elif shape == (3, 3):
        ew = MixedElement(
            [Vu.ufl_element(),
             Vu.ufl_element(),
             Vp.ufl_element()])
        W = FunctionSpace(mesh, ew)

        u0, u1, p = TrialFunctions(W)
        v0, v1, q = TestFunctions(W)
        u = as_vector([u0, u1])
        v = as_vector([v0, v1])
        eq = define_eq(u, v, p, q)

    # Define coupled problem
    eq = define_eq(u, v, p, q)

    # Split the weak form into a saddle point block matrix system
    mat, vec = split_form_into_matrix(eq, W, W)

    # Check shape and that appropriate elements are none
    assert mat.shape == shape
    assert mat[-1, -1] is None
    for i in range(shape[0] - 1):
        for j in range(shape[1] - 1):
            if i != j:
                assert mat[i, j] is None

    # Check that the split matrices are identical with the
    # coupled matrix when reassembled into a single matrix
    compare_split_matrices(eq, mat, vec, W, W)
Ejemplo n.º 2
0
def compute_babuska_infsup(c, m, W, bc=None, inverse=False):
    """
    For a given form c : V x V \rightarrow \R and an inner product m
    defining V and a element space function space W, compute the
    Babuska inf-sup constant.

    The boolean 'inverse' is for ... It defaults to False.
    """

    u = TrialFunctions(W)
    v = TestFunctions(W)

    if len(u) == 1:
        u, v = u[0], v[0]

    lhs = c(v, u)
    rhs = m(v, u)

    if inverse:
        lhs, rhs = rhs, lhs

    # Compute eigenvalues
    params = ascot_parameters["babuska"]
    num = ascot_parameters["number_of_eigenvalues"]
    eigenvalues = EigenProblem(lhs, rhs, params, bc).solve(num)
    return InfSupConstant(W.mesh().hmax(), eigenvalues)
Ejemplo n.º 3
0
    def _init_form(self, **kwargs):
        M_i = self.parameters['M_i']
        M_e = self.parameters['M_e']
        I_a = self.parameters['I_a']  # externally applied current
        dt = self.parameters['dt']
        theta = self.parameters['theta']

        use_constraint = self.parameters['use_average_u_constraint']
        if use_constraint:
            v, u, l = TrialFunctions(self.solution_space)
            w, q, lbd = TestFunctions(self.solution_space)
        else:
            v, u = TrialFunctions(self.solution_space)
            w, q = TestFunctions(self.solution_space)

        dx = self.geometry.dx
        v_ = self.prev_current
        k = Constant(1 / dt)
        t = float(self.time)

        # bidomain equation
        Vmid = theta * v + (1 - theta) * v_
        theta_parabolic = (inner(M_i*grad(Vmid), grad(w))*dx\
                                            + inner(M_i*grad(u), grad(w))*dx)
        theta_elliptic = (inner(M_i*grad(Vmid), grad(q))*dx\
                                    + inner((M_i + M_e)*grad(u), grad(q))*dx)
        self._form = k * (v - v_) * w * dx + theta_parabolic + theta_elliptic

        if use_constraint:
            self._form += (lbd * u + l * q) * dx

        # external current
        self._form += I_a * q * dx

        # stimulus
        if 'STIMULUS' in self.geometry.markers.keys():
            stim_marker = self.geometry.markers['STIMULUS']
            I_s = Stimulus(self.geometry.markers,
                           stim_marker,
                           amplitude=self.parameters["I_s"]['amplitude'],
                           period=self.parameters["I_s"]['amplitude'],
                           duration=self.parameters["I_s"]['duration'],
                           t=self.time,
                           degree=1)
            self._form += I_s * w * dx
Ejemplo n.º 4
0
 def solve(self):
     """
     Solve Stokes problem with current mesh
     """
     (u, p) = TrialFunctions(self.VQ)
     (v, q) = TestFunctions(self.VQ)
     a = inner(grad(u), grad(v))*dx - div(u)*q*dx - div(v)*p*dx
     l = inner(self.f, v)*dx
     solve(a==l, self.w, bcs=self.bcs)
     self.u, self.p = self.w.split()
Ejemplo n.º 5
0
def compute_brezzi_coercivity(xxx_todo_changeme1, m, W, bc=None):
    """
    For given forms a: V x V \rightarrow \R and b: V x Q \rightarrow
    \R and an inner product m defining V and a function space W =
    V_h x Q_h, compute the Brezzi coercivity constant.
    """
    (a, b) = xxx_todo_changeme1
    (u, p) = TrialFunctions(W)
    (v, q) = TestFunctions(W)
    lhs = a(v, u) + b(v, p) + b(u, q)
    rhs = m(v, u)

    # Compute eigenvalues
    params = ascot_parameters["brezzi_coercivity"]
    num = ascot_parameters["number_of_eigenvalues"]
    eigenvalues = EigenProblem(lhs, rhs, params, bc).solve(num)
    return InfSupConstant(W.mesh().hmax(), eigenvalues)
Ejemplo n.º 6
0
def compute_brezzi_infsup(b, xxx_todo_changeme, W, bc=None):
    """
    For a given form b: V x Q \rightarrow \R and inner products m and
    n defining V and Q respectively and a function space W = V_h x
    Q_h, compute the Brezzi inf-sup constant.
    """
    (m, n) = xxx_todo_changeme
    (u, p) = TrialFunctions(W)
    (v, q) = TestFunctions(W)
    lhs = m(v, u) + b(v, p) + b(u, q)
    rhs = -n(q, p)

    # Get parameters
    params = ascot_parameters["brezzi_infsup"]
    num = ascot_parameters["number_of_eigenvalues"]

    # Compute eigenvalues
    eigenvalues = EigenProblem(lhs, rhs, params, bc).solve(num)
    return InfSupConstant(W.mesh().hmax(), eigenvalues, operator=sqrt)
Ejemplo n.º 7
0
    def assemble_matrices(self):
        nedelec = FiniteElement( "Nedelec 1st kind H(curl)",
                                 self.mesh.ufl_cell(), self.nedelec_order)
        lagrange = FiniteElement( "Lagrange", self.mesh.ufl_cell(),
                                  self.lagrange_order)
        self._finite_element = nedelec*lagrange
        self._combined_space = FunctionSpace(self.mesh, nedelec*lagrange)
        # define the test and trial functions from the combined space

        (N_i, L_i) = TestFunctions(self._combined_space)
        (N_j, L_j) = TrialFunctions(self._combined_space)

        # construct matrices for each domain
        if not isinstance(self.materials, collections.Iterable):
            material = self.materials
            u_r = material.em.u_r
            e_r = material.em.e_r
            DX  = material.domain
            (A_ij, B_ij) = em_weak_form(N_i, N_j, L_i, L_j, u_r, e_r,
                                            self._k_o_squared,DX)

        else:
            counter = 0 # a work around for summing forms
            for material in self.materials:
                u_r = material.em.u_r
                e_r = material.em.e_r
                DX  = material.domain
                if counter == 0:
                    (A_ij, B_ij) = em_weak_form(N_i, N_j, L_i, L_j, u_r, e_r,
                                            self._k_o_squared, DX)
                    counter += 1
                else:
                    (a_ij, b_ij) = em_weak_form(N_i, N_j, L_i, L_j, u_r, e_r,
                                            self._k_o_squared, DX)
                    A_ij += a_ij
                    B_ij += b_ij

        # assemble the matrices
        assemble(A_ij, tensor=self._A)
        assemble(B_ij, tensor=self._B)
Ejemplo n.º 8
0
    def solve(self):
        """
        Solves the stokes equation with the current multimesh
        """
        (u, p) = TrialFunctions(self.VQ)
        (v, q) = TestFunctions(self.VQ)
        n = FacetNormal(self.multimesh)
        h = 2.0 * Circumradius(self.multimesh)
        alpha = Constant(6.0)

        tensor_jump = lambda u: outer(u("+"), n("+")) + outer(u("-"), n("-"))

        a_s = inner(grad(u), grad(v)) * dX
        a_IP = - inner(avg(grad(u)), tensor_jump(v))*dI\
               - inner(avg(grad(v)), tensor_jump(u))*dI\
               + alpha/avg(h) * inner(jump(u), jump(v))*dI
        a_O = inner(jump(grad(u)), jump(grad(v))) * dO

        b_s = -div(u) * q * dX - div(v) * p * dX
        b_IP = jump(u, n) * avg(q) * dI + jump(v, n) * avg(p) * dI
        l_s = inner(self.f, v) * dX

        s_C = h*h*inner(-div(grad(u)) + grad(p), -div(grad(v)) - grad(q))*dC\
              + h("+")*h("+")*inner(-div(grad(u("+"))) + grad(p("+")),
                                    -div(grad(v("+"))) + grad(q("+")))*dO
        l_C = h*h*inner(self.f, -div(grad(v)) - grad(q))*dC\
              + h("+")*h("+")*inner(self.f("+"),
                                    -div(grad(v("+"))) - grad(q("+")))*dO

        a = a_s + a_IP + a_O + b_s + b_IP + s_C
        l = l_s + l_C

        A = assemble_multimesh(a)
        L = assemble_multimesh(l)
        [bc.apply(A, L) for bc in self.bcs]
        self.VQ.lock_inactive_dofs(A, L)
        solve(A, self.w.vector(), L, "mumps")
        self.splitMMF()
Ejemplo n.º 9
0
def stokes_solve(up_out, mu, u_bcs, p_bcs, f, my_dx=dx):
    # Some initial sanity checks.
    assert mu > 0.0

    WP = up_out.function_space()

    # Translate the boundary conditions into the product space.
    new_bcs = helpers.dbcs_to_productspace(WP, [u_bcs, p_bcs])

    # 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)

    mesh = WP.mesh()
    r = SpatialCoordinate(mesh)[0]

    # build system
    f = F(u, p, v, q, f, r, mu, my_dx)
    a = lhs(f)
    L = rhs(f)
    A, b = assemble_system(a, L, new_bcs)

    mode = "lu"

    assert mode == "lu"
    solve(A, up_out.vector(), b, "lu")

    # TODO Krylov solver for Stokes
    # assert 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 * my_dx \
    #     - p * q * 2 * pi * r * my_dx
    # P, _ = assemble_system(prec, L, new_bcs)
    # solver = KrylovSolver('tfqmr', 'hypre_amg')
    # # solver = KrylovSolver('gmres', 'hypre_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':
    #     # 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
Ejemplo n.º 10
0
def xtest_mg_solver_stokes():

    mesh0 = UnitCubeMesh(2, 2, 2)
    mesh1 = UnitCubeMesh(4, 4, 4)
    mesh2 = UnitCubeMesh(8, 8, 8)

    Ve = VectorElement("CG", mesh0.ufl_cell(), 2)
    Qe = FiniteElement("CG", mesh0.ufl_cell(), 1)
    Ze = MixedElement([Ve, Qe])

    Z0 = FunctionSpace(mesh0, Ze)
    Z1 = FunctionSpace(mesh1, Ze)
    Z2 = FunctionSpace(mesh2, Ze)
    W = Z2

    # Boundaries
    def right(x, on_boundary):
        return x[0] > (1.0 - DOLFIN_EPS)

    def left(x, on_boundary):
        return x[0] < DOLFIN_EPS

    def top_bottom(x, on_boundary):
        return x[1] > 1.0 - DOLFIN_EPS or x[1] < DOLFIN_EPS

    # No-slip boundary condition for velocity
    noslip = Constant((0.0, 0.0, 0.0))
    bc0 = DirichletBC(W.sub(0), noslip, top_bottom)

    # Inflow boundary condition for velocity
    inflow = Expression(("-sin(x[1]*pi)", "0.0", "0.0"), degree=2)
    bc1 = DirichletBC(W.sub(0), inflow, right)

    # Collect boundary conditions
    bcs = [bc0, bc1]

    # Define variational problem
    (u, p) = TrialFunctions(W)
    (v, q) = TestFunctions(W)
    f = Constant((0.0, 0.0, 0.0))
    a = inner(grad(u), grad(v)) * dx + div(v) * p * dx + q * div(u) * dx
    L = inner(f, v) * dx

    # Form for use in constructing preconditioner matrix
    b = inner(grad(u), grad(v)) * dx + p * q * dx

    # Assemble system
    A, bb = assemble_system(a, L, bcs)

    # Assemble preconditioner system
    P, btmp = assemble_system(b, L, bcs)

    spaces = [Z0, Z1, Z2]
    dm_collection = PETScDMCollection(spaces)

    solver = PETScKrylovSolver()
    solver.set_operators(A, P)

    PETScOptions.set("ksp_type", "gcr")
    PETScOptions.set("pc_type", "mg")
    PETScOptions.set("pc_mg_levels", 3)
    PETScOptions.set("pc_mg_galerkin")
    PETScOptions.set("ksp_monitor_true_residual")

    PETScOptions.set("ksp_atol", 1.0e-10)
    PETScOptions.set("ksp_rtol", 1.0e-10)
    solver.set_from_options()

    from petsc4py import PETSc

    ksp = solver.ksp()

    ksp.setDM(dm_collection.dm())
    ksp.setDMActive(False)

    x = PETScVector()
    solver.solve(x, bb)

    # Check multigrid solution against LU solver
    solver = LUSolver(A)  # noqa
    x_lu = PETScVector()
    solver.solve(x_lu, bb)
    assert round((x - x_lu).norm("l2"), 10) == 0

    # Clear all PETSc options
    opts = PETSc.Options()
    for key in opts.getAll():
        opts.delValue(key)
Ejemplo n.º 11
0
# The first argument to
# :py:class:`DirichletBC <dolfin.cpp.fem.DirichletBC>`
# specifies the :py:class:`FunctionSpace
# <dolfin.cpp.function.FunctionSpace>`. Since we have a
# mixed function space, we write
# ``W.sub(0)`` for the velocity component of the space, and
# ``W.sub(1)`` for the pressure component of the space.
# The second argument specifies the value on the Dirichlet
# boundary. The last two arguments specify the marking of the subdomains:
# ``sub_domains`` contains the subdomain markers, and the final argument is the subdomain index.
#
# The bilinear and linear forms corresponding to the weak mixed
# formulation of the Stokes equations are defined as follows::

# Define variational problem
(u, p) = TrialFunctions(W)
(v, q) = TestFunctions(W)
f = Function(W.sub(0).collapse())
a = (inner(grad(u), grad(v)) - inner(p, div(v)) + inner(div(u), q)) * dx
L = inner(f, v) * dx

# We also need to create a :py:class:`Function
# <dolfin.cpp.function.Function>` to store the solution(s). The (full)
# solution will be stored in ``w``, which we initialize using the mixed
# function space ``W``. The actual
# computation is performed by calling solve with the arguments ``a``,
# ``L``, ``w`` and ``bcs``. The separate components ``u`` and ``p`` of
# the solution can be extracted by calling the :py:meth:`split
# <dolfin.functions.function.Function.split>` function. Here we use an
# optional argument True in the split function to specify that we want a
# deep copy. If no argument is given we will get a shallow copy. We want
Ejemplo n.º 12
0
def solverNeilan(P, opt):
    '''
    This function implements the method presented in
    Neilan:Convergence Analysis of a Finite Element
    Method for Second Order Non-Variational Problems
    Main characteristics:
    - no stabilization
    - method relies on a discontinuous Hessian approximation
    - no action on test function of solution u_h
    - no normalization of system
    '''

    (trial_u, trial_H) = TrialFunctions(P.mixedSpace)
    (test_u, test_H) = TestFunctions(P.mixedSpace)

    # Define bilinear form
    jump_outer = inner(grad(trial_u), test_H * P.nE) * ds
    jump_inner = inner(avg(grad(trial_u)),
                       test_H('+') * P.nE('+') + test_H('-') * P.nE('-')) * dS

    a_h = -inner(P.a, trial_H) * test_u * dx \
        + inner(trial_H, test_H) * dx \
        + inner(grad(trial_u), div(test_H)) * dx \
        - jump_inner - jump_outer

    if P.hasDrift:
        a_h += -inner(P.b, grad(trial_u)) * test_u * dx

    if P.hasPotential:
        a_h += -P.c * trial_u * test_u * dx

    # Define linear form
    f_h = -P.f * test_u * dx

    # Adjust system matrix and load vector in case of time-dependent problem
    if P.isTimeDependant:
        a_h += 1. / P.dt * trial_u * test_u * dx
        f_h += 1. / P.dt * P.u_np1 * test_u * dx

    # Set boundary conditions
    print('Setting boundary conditions')
    if isinstance(P.g, list):
        bc_V = []
        for fun, dom in P.g:
            bc_V.append(DirichletBC(P.mixedSpace.sub(0), fun, dom))
    else:
        if isinstance(P.g, Function):
            bc_V = DirichletBC(P.mixedSpace.sub(0), P.g, 'on_boundary')
        else:
            g = project(P.g, P.V)
            bc_V = DirichletBC(P.mixedSpace.sub(0), g, 'on_boundary')

    if opt['time_check']:
        t1 = time()

    S, rhs = assemble_system(a_h, f_h, bc_V)
    try:
        solve(S, P.x.vector(), rhs)

    except RuntimeError:
        try:
            solve(S, P.x.vector(), rhs, 'gmres', 'hypre_amg')
        except RuntimeError:
            import ipdb
            ipdb.set_trace()

    N_iter = 1

    if opt['time_check']:
        print("Solve linear equation system ... %.2fs" % (time() - t1))
        sys.stdout.flush()

    return N_iter
Ejemplo n.º 13
0
def cmscr1dnewton(img: np.array, alpha0: float, alpha1: float, alpha2: float,
                  alpha3: float, beta: float) \
                  -> (np.array, np.array, float, float, bool):
    """Same as cmscr1d but doesn't use FEniCS Newton method.

    Args:
        img (np.array): A 1D image sequence of shape (m, n), where m is the
                        number of time steps and n is the number of pixels.
        alpha0 (float): The spatial regularisation parameter for v.
        alpha1 (float): The temporal regularisation parameter for v.
        alpha2 (float): The spatial regularisation parameter for k.
        alpha3 (float): The temporal regularisation parameter for k.
        beta (float): The parameter for convective regularisation.

    Returns:
        v: A velocity array of shape (m, n).
        k: A source array of shape (m, n).
        res (float): The residual.
        fun (float): The function value.
        converged (bool): True if Newton's method converged.

    """
    # Create mesh.
    [m, n] = img.shape
    mesh = UnitSquareMesh(m - 1, n - 1)

    # Define function space and functions.
    W = VectorFunctionSpace(mesh, 'CG', 1, dim=2)
    w = Function(W)
    v, k = split(w)
    w1, w2 = TestFunctions(W)

    # Convert image to function.
    V = FunctionSpace(mesh, 'CG', 1)
    f = Function(V)
    f.vector()[:] = dh.img2funvec(img)

    # Define derivatives of data.
    ft = Function(V)
    ftv = np.diff(img, axis=0) * (m - 1)
    ftv = np.concatenate((ftv, ftv[-1, :].reshape(1, n)), axis=0)
    ft.vector()[:] = dh.img2funvec(ftv)

    fx = Function(V)
    fxv = np.gradient(img, 1 / (n - 1), axis=1)
    fx.vector()[:] = dh.img2funvec(fxv)

    # Define weak formulation.
    F = - (ft + fx*v + f*v.dx(1) - k) * (fx*w1 + f*w1.dx(1))*dx \
        - alpha0*v.dx(1)*w1.dx(1)*dx - alpha1*v.dx(0)*w1.dx(0)*dx \
        - beta*k.dx(1)*(k.dx(0) + k.dx(1)*v)*w1*dx \
        + (ft + fx*v + f*v.dx(1) - k)*w2*dx \
        - alpha2*k.dx(1)*w2.dx(1)*dx - alpha3*k.dx(0)*w2.dx(0)*dx \
        - beta*(k.dx(0)*w2.dx(0) + k.dx(1)*v*w2.dx(0)
                + k.dx(0)*v*w2.dx(1) + k.dx(1)*v*v*w2.dx(1))*dx

    # Define derivative.
    dv, dk = TrialFunctions(W)
    J = - (fx*dv + f*dv.dx(1) - dk)*(fx*w1 + f*w1.dx(1))*dx \
        - alpha0*dv.dx(1)*w1.dx(1)*dx - alpha1*dv.dx(0)*w1.dx(0)*dx \
        - beta*(k.dx(1)*(dk.dx(0) + dk.dx(1)*v) + k.dx(1)**2*dv
                + dk.dx(1)*(k.dx(0) + k.dx(1)*v))*w1*dx \
        + (fx*dv + f*dv.dx(1) - dk)*w2*dx \
        - alpha2*dk.dx(1)*w2.dx(1)*dx - alpha3*dk.dx(0)*w2.dx(0)*dx \
        - beta*(dv*k.dx(1) + dk.dx(0) + v*dk.dx(1))*w2.dx(0)*dx \
        - beta*(dv*k.dx(0) + 2*v*dv*k.dx(1) + v*dk.dx(0)
                + v*v*dk.dx(1))*w2.dx(1)*dx

    # Alternatively, use automatic differentiation.
    # J = derivative(F, w)

    # Define algorithm parameters.
    tol = 1e-10
    maxiter = 100

    # Define increment.
    dw = Function(W)

    # Run Newton iteration.
    niter = 0
    eps = 1
    res = 1
    while res > tol and niter < maxiter:
        niter += 1

        # Solve for increment.
        solve(J == -F, dw)

        # Update solution.
        w.assign(w + dw)

        # Compute norm of increment.
        eps = dw.vector().norm('l2')

        # Compute norm of residual.
        a = assemble(F)
        res = a.norm('l2')

        # Print statistics.
        print("Iteration {0} eps={1} res={2}".format(niter, eps, res))

    # Split solution.
    v, k = w.split(deepcopy=True)

    # Evaluate and print residual and functional value.
    res = abs(ft + fx * v + f * v.dx(1) - k)
    fun = 0.5 * (res**2 + alpha0 * v.dx(1)**2 + alpha1 * v.dx(0)**2 +
                 alpha2 * k.dx(1)**2 + alpha3 * k.dx(0)**2 + beta *
                 (k.dx(0) + k.dx(1) * v)**2)
    print('Res={0}, Func={1}'.format(assemble(res * dx), assemble(fun * dx)))

    # Convert back to array.
    vel = dh.funvec2img(v.vector().get_local(), m, n)
    k = dh.funvec2img(k.vector().get_local(), m, n)
    return vel, k, assemble(res * dx), assemble(fun * dx), res > tol
Ejemplo n.º 14
0
def build_system(V, dx, Mu, Sigma, omega, f_list, f_degree, convections, bcs):
    """Build FEM system for

    .. math::
         \\div\\left(\\frac{1}{\\mu r} \\nabla(r\\phi)\\right)
         + \\left\\langle u, \\frac{1}{r} \\nabla(r\\phi)\\right\\rangle
         + \\text{i} \\sigma \\omega \\phi
            = f

    by multiplying with :math:`2\\pi r v` and integrating over the domain and
    the preconditioner given by :cite:`KL2012`.
    """
    r = SpatialCoordinate(V.mesh())[0]

    subdomain_indices = Mu.keys()

    ee = V.ufl_element() * V.ufl_element()
    W = FunctionSpace(V.mesh(), ee)

    # Bilinear form.
    ur, ui = TrialFunctions(W)
    vr, vi = TestFunctions(W)

    # build right-hand sides
    b_list = []
    for f in f_list:
        L = +Constant(0.0) * vr * dx(0) + Constant(0.0) * vi * dx(0)
        for i, fval in f.items():
            L += +fval[0] * vr * 2 * pi * r * dx(
                i, degree=f_degree) + fval[1] * vi * 2 * pi * r * dx(
                    i, degree=f_degree)
        b_list.append(assemble(L))

    # div(1/(mu r) grad(r phi)) + i sigma omega phi
    #
    # Split up diffusive and reactive terms to be able to assemble them with
    # different FFC parameters.
    #
    # Make omega a constant function to avoid rebuilding the equation system
    # when omega changes.
    om = Constant(omega)
    a1 = Constant(0.0) * ur * vr * dx(0)
    a2 = Constant(0.0) * ur * vr * dx(0)
    for i in subdomain_indices:
        # The term 1/r looks like it might cause problems. The dubious term is
        #
        #  1/r d/dr (r u_r) = u_r + 1/r du_r/dr,
        #
        # so we have to make sure that 1/r du_r/dr is bounded for all trial
        # functions u. This is guaranteed when taking Dirichlet boundary
        # conditions at r=0.
        sigma = Constant(Sigma[i])
        a1 += +1.0 / (Mu[i] * r) * dot(grad(r * ur), grad(
            r * vr)) * 2 * pi * dx(i) + 1.0 / (Mu[i] * r) * dot(
                grad(r * ui), grad(r * vi)) * 2 * pi * dx(i)
        a2 += -om * sigma * ui * vr * 2 * pi * r * dx(
            i) + om * sigma * ur * vi * 2 * pi * r * dx(i)
        # Don't do anything at the interior boundary. Taking the Poisson
        # problem as an example, the weak formulation is
        #
        #     \int \Delta(u) v = -\int grad(u).grad(v) + \int_ n.grad(u) v.
        #
        # If we have 'artificial' boundaries through the domain, we would
        # like to make sure that along those boundaries, the equation is
        # exactly what it would be without the them. The important case to
        # look at are the trial and test functions which are nonzero on
        # the boundary. It is clear that the integral along the interface
        # boundary has to be omitted.

    # Add the convective component for the workpiece,
    #   a += <u, 1/r grad(r phi)> *2*pi*r*dx
    for i, conv in convections.items():
        a1 += +dot(conv, grad(r * ur)) * vr * 2 * pi * dx(i) + dot(
            conv, grad(r * ui)) * vi * 2 * pi * dx(i)

    force_m_matrix = False
    if force_m_matrix:
        A1 = assemble(a1)
        A2 = assemble(
            a2,
            form_compiler_parameters={
                "quadrature_rule": "vertex",
                "quadrature_degree": 1,
            },
        )
        A = A1 + A2
    else:
        # Assembling the thing into one single object makes it possible to
        # extract .data() for conversion to SciPy's sparse types later.
        A = assemble(a1 + a2)

    # Compute the preconditioner as described in
    #
    #     A robust preconditioned MINRES-solver for time-periodic eddy-current
    #     problems;
    #     M. Kolmbauer, U. Langer;
    #     <http://www.numa.uni-linz.ac.at/Publications/List/2012/2012-02.pdf>.
    #
    # For the real-imag system
    #
    #     ( K  M )
    #     (-M  K ),
    #
    # Kolmbauer and Langer suggest the preconditioner
    #
    #     ( K+M        )
    #     (     -(K+M) ).
    #
    # The diagonal blocks can, for example, be solved with standard AMG
    # methods.
    p1 = Constant(0.0) * ur * vr * dx(0)
    p2 = Constant(0.0) * ur * vr * dx(0)
    # Diffusive terms.
    for i in subdomain_indices:
        p1 += +1.0 / (Mu[i] * r) * dot(grad(r * ur), grad(
            r * vr)) * 2 * pi * dx(i) - 1.0 / (Mu[i] * r) * dot(
                grad(r * ui), grad(r * vi)) * 2 * pi * dx(i)
        p2 += +om * Constant(Sigma[i]) * ur * vr * 2 * pi * r * dx(
            i) - om * Constant(Sigma[i]) * ui * vi * 2 * pi * r * dx(i)
    P = assemble(p1 + p2)

    # build mass matrix
    # mm = sum([(ur * vr + ui * vi) * 2*pi*r * dx(i)
    #           for i in subdomain_indices
    #           ])
    mm = Constant(0.0) * ur * vr * dx(0)
    for i in subdomain_indices:
        mm += +ur * vr * 2 * pi * r * dx(i) + ui * vi * 2 * pi * r * dx(i)
    M = assemble(mm)

    # Apply boundary conditions.
    if bcs:
        bcs.apply(A)
        bcs.apply(P)
        bcs.apply(M)
        for b in b_list:
            bcs.apply(b)

    # helpers.show_matrix(A)
    # print(helpers.get_eigenvalues(A))
    # helpers.show_matrix(M)
    # helpers.show_matrix(P)

    return A, P, b_list, M, W
Ejemplo n.º 15
0
def forward(mu_expression,
            lmbda_expression,
            rho,
            Lx=10,
            Ly=10,
            t_end=1,
            omega_p=5,
            amplitude=5000,
            center=0,
            target=False):
    Lpml = Lx / 10
    #c_p = cp(mu.vector(), lmbda.vector(), rho)
    max_velocity = 200  #c_p.max()

    stable_hx = stable_dx(max_velocity, omega_p)
    nx = int(Lx / stable_hx) + 1
    #nx = max(nx, 60)
    ny = int(Ly * nx / Lx) + 1
    mesh = mesh_generator(Lx, Ly, Lpml, nx, ny)
    used_hx = Lx / nx
    dt = stable_dt(used_hx, max_velocity)
    cfl_ct = cfl_constant(max_velocity, dt, used_hx)
    print(used_hx, stable_hx)
    print(cfl_ct)
    #time.sleep(10)
    PE = FunctionSpace(mesh, "DG", 0)
    mu = interpolate(mu_expression, PE)
    lmbda = interpolate(lmbda_expression, PE)

    m = 2
    R = 10e-8
    t = 0.0
    gamma = 0.50
    beta = 0.25

    ff = MeshFunction("size_t", mesh, mesh.geometry().dim() - 1)
    Dirichlet(Lx, Ly, Lpml).mark(ff, 1)

    # Create function spaces
    VE = VectorElement("CG", mesh.ufl_cell(), 1, dim=2)
    TE = TensorElement("DG", mesh.ufl_cell(), 0, shape=(2, 2), symmetry=True)

    W = FunctionSpace(mesh, MixedElement([VE, TE]))
    F = FunctionSpace(mesh, "CG", 2)
    V = W.sub(0).collapse()
    M = W.sub(1).collapse()

    alpha_0 = Alpha_0(m, stable_hx, R, Lpml)
    alpha_1 = Alpha_1(alpha_0, Lx, Lpml, degree=2)
    alpha_2 = Alpha_2(alpha_0, Ly, Lpml, degree=2)

    beta_0 = Beta_0(m, max_velocity, R, Lpml)
    beta_1 = Beta_1(beta_0, Lx, Lpml, degree=2)
    beta_2 = Beta_2(beta_0, Ly, Lpml, degree=2)

    alpha_1 = interpolate(alpha_1, F)
    alpha_2 = interpolate(alpha_2, F)
    beta_1 = interpolate(beta_1, F)
    beta_2 = interpolate(beta_2, F)

    a_ = alpha_1 * alpha_2
    b_ = alpha_1 * beta_2 + alpha_2 * beta_1
    c_ = beta_1 * beta_2

    Lambda_e = as_tensor([[alpha_2, 0], [0, alpha_1]])
    Lambda_p = as_tensor([[beta_2, 0], [0, beta_1]])

    a_ = alpha_1 * alpha_2
    b_ = alpha_1 * beta_2 + alpha_2 * beta_1
    c_ = beta_1 * beta_2

    Lambda_e = as_tensor([[alpha_2, 0], [0, alpha_1]])
    Lambda_p = as_tensor([[beta_2, 0], [0, beta_1]])

    # Set up boundary condition
    bc = DirichletBC(W.sub(0), Constant(("0.0", "0.0")), ff, 1)

    # Create measure for the source term
    dx = Measure("dx", domain=mesh)
    ds = Measure("ds", domain=mesh, subdomain_data=ff)

    # Set up initial values
    u0 = Function(V)
    u0.set_allow_extrapolation(True)
    v0 = Function(V)
    a0 = Function(V)
    U0 = Function(M)
    V0 = Function(M)
    A0 = Function(M)

    # Test and trial functions
    (u, S) = TrialFunctions(W)
    (w, T) = TestFunctions(W)

    g = ModifiedRickerPulse(0, omega_p, amplitude, center)

    F = rho * inner(a_ * N_ddot(u, u0, a0, v0, dt, beta) \
        + b_ * N_dot(u, u0, v0, a0, dt, beta, gamma) + c_ * u, w) * dx \
        + inner(N_dot(S, U0, V0, A0, dt, beta, gamma).T * Lambda_e + S.T * Lambda_p, grad(w)) * dx \
        - inner(g, w) * ds \
        + inner(compliance(a_ * N_ddot(S, U0, A0, V0, dt, beta) + b_ * N_dot(S, U0, V0, A0, dt, beta, gamma) + c_ * S, u, mu, lmbda), T) * dx \
        - 0.5 * inner(grad(u) * Lambda_p + Lambda_p * grad(u).T + grad(N_dot(u, u0, v0, a0, dt, beta, gamma)) * Lambda_e \
        + Lambda_e * grad(N_dot(u, u0, v0, a0, dt, beta, gamma)).T, T) * dx \

    a, L = lhs(F), rhs(F)

    # Assemble rhs (once)
    A = assemble(a)

    # Create GMRES Krylov solver
    solver = KrylovSolver(A, "gmres")

    # Create solution function
    S = Function(W)

    if target:
        xdmffile_u = XDMFFile("inversion_temporal_file/target/u.xdmf")
        pvd = File("inversion_temporal_file/target/u.pvd")
        xdmffile_u.write(u0, t)
        timeseries_u = TimeSeries(
            "inversion_temporal_file/target/u_timeseries")
    else:
        xdmffile_u = XDMFFile("inversion_temporal_file/obs/u.xdmf")
        xdmffile_u.write(u0, t)
        timeseries_u = TimeSeries("inversion_temporal_file/obs/u_timeseries")

    rec_counter = 0

    while t < t_end - 0.5 * dt:
        t += float(dt)

        if rec_counter % 10 == 0:
            print(
                '\n\rtime: {:.3f} (Progress: {:.2f}%)'.format(
                    t, 100 * t / t_end), )

        g.t = t

        # Assemble rhs and apply boundary condition
        b = assemble(L)
        bc.apply(A, b)

        # Compute solution
        solver.solve(S.vector(), b)
        (u, U) = S.split(True)

        # Update previous time step
        update(u, u0, v0, a0, beta, gamma, dt)
        update(U, U0, V0, A0, beta, gamma, dt)

        xdmffile_u.write(u, t)
        pvd << (u, t)
        timeseries_u.store(u.vector(), t)

        energy = inner(u, u) * dx
        E = assemble(energy)
        print("E = ", E)
        print(u.vector().max())
Ejemplo n.º 16
0
 def __trial_functions(self):
     u, p = TrialFunctions(self.mixedL)
     ubar, pbar = TrialFunctions(self.mixedG)
     return (u, p, ubar, pbar)
Ejemplo n.º 17
0
def of2dmcs(img1: np.array, img2: np.array, alpha0: float, alpha1: float,
            beta0: float, beta1: float) -> (np.array, np.array):
    """Computes the L2-H1 optical flow for a 2D two-channel image sequence and
    source for the second channel (optical flow 2d multi-channel with source).

    Takes a two-dimensional image sequence and returns a minimiser of the
    Horn-Schunck functional with source and with spatio-temporal
    regularisation for both velocity and source.

    Args:
        img1 (np.array): A 2D image sequence of shape (t, m, n), where t is the
                         number of time steps and (n, n) is the number of
                         pixels.
        img2 (np.array): A 2D image sequence of shape (t, m, n), where t is the
                         number of time steps and (n, n) is the number of
                         pixels.
        alpha0 (float):  The spatial regularisation parameter.
        alpha1 (float):  The temporal regularisation parameter.

    Returns:
        v (np.array): A velocity array of shape (t, m, n, 2).
        k (np.array): A source array of shape (t, m, n).

    """
    # Create mesh.
    [t, m, n] = img1.shape
    mesh = UnitCubeMesh(t-2, m-1, n-1)

    # Define function space and functions.
    V = FunctionSpace(mesh, 'CG', 1)
    W = VectorFunctionSpace(mesh, 'CG', 1, dim=3)
    v1, v2, k = TrialFunctions(W)
    w1, w2, w3 = TestFunctions(W)

    # Convert image to function.
    f1, f2 = Function(V), Function(V)
    f1.vector()[:] = dh.imgseq2funvec(img1[0:-1])
    f2.vector()[:] = dh.imgseq2funvec(img2[0:-1])

    # Define function to compute temporal derivative.
    def time_deriv(img: np.array) -> Function:
        # Evaluate function at vertices.
        mc = mesh.coordinates().reshape((-1, 3))
        hx, hy, hz = 1./(t-2), 1./(m-1), 1./(n-1)
        x = np.array(mc[:, 0]/hx, dtype=int)
        y = np.array(mc[:, 1]/hy, dtype=int)
        z = np.array(mc[:, 2]/hz, dtype=int)

        # Map pixel values to vertices.
        d2v = dof_to_vertex_map(V)

        # Compute derivative wrt. time.
        imgt = img[1:] - img[0:-1]
        ftv = imgt[x, y, z]

        # Create function.
        ft = Function(V)
        ft.vector()[:] = ftv[d2v]
        return ft

    # Compute temporal derivatives.
    f1t = time_deriv(img1)
    f2t = time_deriv(img2)

    # Define derivatives of data.
    f1x, f1y = f1.dx(1), f1.dx(2)
    f2x, f2y = f2.dx(1), f2.dx(2)

    # Define weak formulation.
    A = f1x*(f1x*v1 + f1y*v2)*w1*dx + f2x*(f2x*v1 + f2y*v2 - k)*w1*dx \
        + f1y*(f1x*v1 + f1y*v2)*w2*dx + f2y*(f2x*v1 + f2y*v2 - k)*w2*dx \
        - (f2x*v1 + f2y*v2 - k)*w3*dx \
        + alpha0*v1.dx(1)*w1.dx(1)*dx + alpha0*v1.dx(2)*w1.dx(2)*dx \
        + alpha1*v1.dx(0)*w1.dx(0)*dx \
        + alpha0*v2.dx(1)*w2.dx(1)*dx + alpha0*v2.dx(2)*w2.dx(2)*dx \
        + alpha1*v2.dx(0)*w2.dx(0)*dx \
        + beta0*k.dx(1)*w3.dx(1)*dx + beta0*k.dx(2)*w3.dx(2)*dx \
        + beta1*k.dx(0)*w3.dx(0)*dx
    b = - f1x*f1t*w1*dx - f2x*f2t*w1*dx \
        - f1y*f1t*w2*dx - f2y*f2t*w2*dx \
        + f2t*w3*dx

    # Compute solution.
    v = Function(W)
    solve(A == b, v, [], solver_parameters={"linear_solver": "cg"})

    # Split solution into functions.
    v1, v2, k = v.split(deepcopy=True)

    # Convert back to arrays.
    v1 = dh.funvec2imgseq(v1.vector().get_local(), t-1, m, n)
    v2 = dh.funvec2imgseq(v2.vector().get_local(), t-1, m, n)
    k = dh.funvec2imgseq(k.vector().get_local(), t-1, m, n)
    return (np.stack((v1, v2), axis=3), k)
Ejemplo n.º 18
0
class InitialConditions(UserExpression):
    def eval(self, values, x):
        values[0] = 0.0
        values[1] = 0.0

    def value_shape(self):
        return (2, )


# Define mesh, function space and test functions
mesh = RectangleMesh(Point(0.0, 0.0), Point(1.0, 1.0), 49, 49)
P1 = FiniteElement("Lagrange", mesh.ufl_cell(), 1)
ME = FunctionSpace(mesh, P1 * P1)
q1, q2 = TestFunctions(ME)
U1, U2 = TrialFunctions(ME)

# Define and interpolate initial condition
W = Function(ME)
W.interpolate(InitialConditions())
u, v = split(W)

domainSource = Expression(
    "0.1*t*exp(-((x[0]-0.7)*(x[0]-0.7) + (x[1]-0.5)*(x[1]-0.5))/0.01)",
    t=0,
    degree=1)

# Define the right hand side for each of the PDEs
F1 = (-inner(grad(U1), grad(q1)) + U2 * q1 + domainSource * q1) * dx
F2 = (-inner(grad(U2), grad(q2)) - U1 * q2) * dx
Ejemplo n.º 19
0
    bc = DirichletBC(W.sub(0), Constant(("0.0", "0.0")), ff, 1)

    # Create measure for the source term
    ds = Measure("ds", domain=mesh, subdomain_data=ff)

    # Set up initial values
    u0 = Function(V)
    u0.set_allow_extrapolation(True)
    v0 = Function(V)
    a0 = Function(V)
    U0 = Function(M)
    V0 = Function(M)
    A0 = Function(M)

    # Test and trial functions
    (u, S) = TrialFunctions(W)
    (w, T) = TestFunctions(W)

    pulses = [
        ModifiedRickerPulse(t,
                            omega_p_list[i],
                            amplitude_list[i],
                            center=sources_positions[i])
        for i in range(len(omega_p_list))
    ]

    g = sum(pulses)

    F = rho * inner(a_ * N_ddot(u, u0, a0, v0, dt, beta) \
        + b_ * N_dot(u, u0, v0, a0, dt, beta, gamma) + c_ * u, w) * dx \
        + inner(N_dot(S, U0, V0, A0, dt, beta, gamma).T * Lambda_e + S.T * Lambda_p, grad(w)) * dx \
Ejemplo n.º 20
0
def solve(WP, bcs, mu, f, verbose=True, tol=1.0e-13, max_iter=500):
    # Some initial sanity checks.
    assert mu > 0.0

    # 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 = inner(f, v) * dx
    A, b = assemble_system(a, L, bcs)

    # 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, bcs)
    # solver = KrylovSolver('tfqmr', 'hypre_amg')
    solver = KrylovSolver('gmres', 'hypre_amg')
    solver.set_operators(A, M)

    # 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.
    # <https://fenicsproject.org/qa/12856/fieldsplit-petscpreconditioner_set_fieldsplit-arguments>
    # PETScOptions.set('ksp_view')
    # PETScOptions.set('ksp_monitor_true_residual')
    # PETScOptions.set('pc_type', 'fieldsplit')
    # PETScOptions.set('pc_fieldsplit_type', 'additive')
    # PETScOptions.set('pc_fieldsplit_detect_saddle_point')
    # PETScOptions.set('fieldsplit_0_ksp_type', 'preonly')
    # PETScOptions.set('fieldsplit_0_pc_type', 'lu')
    # PETScOptions.set('fieldsplit_1_ksp_type', 'preonly')
    # PETScOptions.set('fieldsplit_1_pc_type', 'jacobi')

    # solver = PETScKrylovSolver('gmres')
    # solver.set_operator(A)
    # solver.set_from_options()

    # 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')

    solver.parameters['monitor_convergence'] = verbose
    solver.parameters['report'] = verbose
    solver.parameters['absolute_tolerance'] = 0.0
    solver.parameters['relative_tolerance'] = tol
    solver.parameters['maximum_iterations'] = max_iter
    solver.parameters['error_on_nonconvergence'] = True

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

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

    return u, p