def test_P(n=4):
    '''Projections'''
    from block import block_transpose
    mesh = UnitCubeMesh(n, n, n)

    V = VectorFunctionSpace(mesh, 'CG', 1)
    Q = VectorFunctionSpace(mesh, 'R', 0, 6)
    Zh = RMBasis(V, Q)

    P = Projector(Zh)
    # Is a projector
    f = Function(V)
    x = f.vector()
    as_backend_type(x).vec().setRandom()

    Px = P * x
    assert any(abs(alpha) > 0 for alpha in P.alphas)
    PPx = P * Px
    tol = 1E-12
    assert all(abs(alpha) < tol for alpha in P.alphas)
    assert abs((Px - PPx).norm('l2')) < tol

    y = assemble(inner(f, TestFunction(V)) * dx)
    Py = block_transpose(P) * y
    assert any(abs(beta) > 0 for beta in P.betas)
    PPy = block_transpose(P) * Py
    assert all(abs(beta) < tol for beta in P.betas)
    assert abs((Py - PPy).norm('l2')) < tol

    return True
Esempio n. 2
0
            def multTranspose(self, mat, x, y):
                '''y = A.T*x'''
                AT = block_transpose(self.A)

                y *= 0
                x_bvec = PETScVector(x)
                y_bvec = AT * x_bvec
                y.axpy(1., as_petsc(y_bvec))
Esempio n. 3
0
            def multTranspose(self, mat, x, y):
                '''y = A.T*x'''
                AT = block_transpose(self.A)

                y *= 0
                # Now x shall be comming as a nested vector
                # Convert
                x_bvec = block_vec(map(PETScVector, x.getNestSubVecs()))
                # Apply
                y_bvec = AT * x_bvec
                # Convert back
                y.axpy(1., as_petsc_nest(y_bvec))
    def assemble(self, form, arity):
        '''Assemble a biliner(2), linear(1) form'''
        reduced_integrals = self.select_integrals(form)  #! Selector
        # Signal to xii.assemble
        if not reduced_integrals: return None

        components = []
        for integral in form.integrals():
            # Delegate to friend
            if integral not in reduced_integrals:
                components.append(
                    xii.assembler.xii_assembly.assemble(Form([integral])))
                continue

            reduced_mesh = integral.ufl_domain().ufl_cargo()

            integrand = integral.integrand()
            # Split arguments in those that need to be and those that are
            # already restricted.
            terminals = set(traverse_unique_terminals(integrand))

            # FIXME: is it enough info (in general) to decide
            terminals_to_restrict = sorted(
                self.restriction_filter(terminals, reduced_mesh),
                key=lambda t: self.is_compatible(t, reduced_mesh))
            # You said this is a trace ingral!
            assert terminals_to_restrict

            # Let's pick a guy for restriction
            terminal = terminals_to_restrict.pop()
            # We have some assumption on the candidate
            assert self.is_compatible(terminal, reduced_mesh)

            data = self.reduction_matrix_data(terminal)

            integrand = ufl2uflcopy(integrand)
            # With sane inputs we can get the reduced element and setup the
            # intermediate function space where the reduction of terminal
            # lives
            V = terminal.function_space()
            TV = self.reduced_space(V, reduced_mesh)  #! Space construc

            # Setup the matrix to from space of the trace_terminal to the
            # intermediate space. FIXME: normal and trace_mesh
            #! mat construct
            df.info('\tGetting reduction op')
            rop_timer = df.Timer('rop')
            T = self.reduction_matrix(V, TV, reduced_mesh, data)
            df.info('\tDone (reduction op) %g' % rop_timer.stop())
            # T
            if is_test_function(terminal):
                replacement = df.TestFunction(TV)
                # Passing the args to get the comparison a make substitution
                integrand = replace(integrand,
                                    terminal,
                                    replacement,
                                    attributes=self.attributes)
                trace_form = Form([integral.reconstruct(integrand=integrand)])

                if arity == 2:
                    # Make attempt on the substituted form
                    A = xii.assembler.xii_assembly.assemble(trace_form)
                    components.append(block_transpose(T) * A)
                else:
                    b = xii.assembler.xii_assembly.assemble(trace_form)
                    Tb = df.Function(V).vector()  # Alloc and apply
                    T.transpmult(b, Tb)
                    components.append(Tb)

            if is_trial_function(terminal):
                assert arity == 2
                replacement = df.TrialFunction(TV)
                # Passing the args to get the comparison
                integrand = replace(integrand,
                                    terminal,
                                    replacement,
                                    attributes=self.attributes)
                trace_form = Form([integral.reconstruct(integrand=integrand)])

                A = xii.assembler.xii_assembly.assemble(trace_form)
                components.append(A * T)

            # Okay, then this guy might be a function
            if isinstance(terminal, df.Function):
                replacement = df.Function(TV)
                # Replacement is not just a placeholder
                T.mult(terminal.vector(), replacement.vector())
                # Substitute
                integrand = replace(integrand,
                                    terminal,
                                    replacement,
                                    attributes=self.attributes)
                trace_form = Form([integral.reconstruct(integrand=integrand)])
                components.append(
                    xii.assembler.xii_assembly.assemble(trace_form))

        # The whole form is then the sum of integrals
        return reduce(operator.add, components)
Esempio n. 5
0
def lagrange_mixed(lmbda, mu, f, h, mesh, Z=None):
    '''
    Solves 

        -div(sigma) = f in  Omega
            sigma.n = h on  boundary

    where sigma(u) = 2*mu*eps(u) + lambda*div(u)*I. The problem is reformulated by
    Lagrange multiplier nu to inforce orthogonality with the space of rigid
    motions. To get robustnes in lmbda solid pressure p = lambda*div u is introduced. 
    The system to be solved with MinRes is 

        P*[A C  B; *[u, = P*[L,
           C' D 0;   p,      0,
           B' 0 0]   nu]     0]

    with P a precondtioner. We run on series of meshes to show mesh independence
    of the solver.
    '''
    if not isinstance(mesh, Mesh):
        # NOTE: You can precompute the 'symbolic' basis and pass it here
        return [lagrange_mixed(lmbda, mu, f, h, mesh_) for mesh_ in mesh]
    
    # For cube
    V = VectorFunctionSpace(mesh, 'CG', 2)
    Q = FunctionSpace(mesh, 'CG', 1)

    u, v = TrialFunction(V), TestFunction(V)
    p, q = TrialFunction(Q), TestFunction(Q)

    # Strain
    epsilon = lambda u: sym(grad(u))
    # Stress
    gdim = mesh.geometry().dim()
    sigma = lambda u: 2*mu*epsilon(u) + lmbda*tr(epsilon(u))*Identity(gdim)
    a = 2*mu*inner(sym(grad(u)), sym(grad(v)))*dx

    A = assemble(a)

    c = inner(div(v), p)*dx
    C = assemble(c)

    d = -(inner(p, q)/Constant(lmbda))*dx
    D = assemble(d)

    m = inner(u, v)*dx
    M = assemble(m)

    # NOTE: Avoiding use of Q space in the assembly - dense blocks!
    X = VectorFunctionSpace(mesh, 'R', 0, dim=6)
    Zh = rigid_motions.RMBasis(V, X, Z)  # L^2 orthogonal
    B = M*Zh

    # System operator
    AA = block_mat([[A,                  C, B], 
                    [block_transpose(C), D, 0],
                    [block_transpose(B), 0, 0]])

    # Right hand side
    L = inner(f, v)*dx + inner(h, v)*ds
    b0 = assemble(L)
    b1 = assemble(inner(Constant(0), q)*dx)
    # Equivalent to assemble(inner(Constant((0, )*6), q)*dx) but cheaper
    b2 = Function(X).vector()
    bb = block_vec([b0, b1, b2])

    # Block diagonal preconditioner
    IV = assemble(a + m)
    IQ = assemble(inner(p, q)*dx)
    IX = rigid_motions.identity_matrix(X)
    BB = block_mat([[AMG(IV), 0,              0], 
                    [0,       AMG(IQ),        0],
                    [0,       0,            IX]])

    # Solve, using random initial guess
    x0 = AA.create_vec()
    [as_backend_type(xi).vec().setRandom() for xi in x0]

    AAinv = MinRes(AA, precond=BB, initial_guess=x0, maxiter=120, tolerance=1E-8,
                   show=2, relativeconv=True)

    x = AAinv*bb

    # # Functions from coefficients
    # # uh = Function(V, x[0])     # Displacement
    # # ph = Function(Q, x[1])     # Solid pressure
    # # nuh = Zh.rigid_motion(x[2])  # Function in V

    niters = len(AAinv.residuals) - 1
    assert niters < 120

    P = rigid_motions.Projector(Zh)

    P*x0[0]  # to get orthogonality

    if MPI.rank(mesh.mpi_comm()) == 0:
        print '\033[1;37;31m%s\033[0m' % ('Orthogonality %g' % max(P.alphas))
        pass

    return V.dim() + Q.dim() + 6, niters
Esempio n. 6
0
def solve_problem(ncells, eps, solver_params):
    '''Optim problem on [0, 1]^2'''
    # Made up
    f = Expression('x[0] + x[1]', degree=1)

    mesh = UnitSquareMesh(*(ncells, ) * 2)
    bmesh = BoundaryMesh(mesh, 'exterior')

    Q = FunctionSpace(mesh, 'DG', 0)
    V = FunctionSpace(mesh, 'CG', 1)
    B = FunctionSpace(mesh, 'CG', 1)
    W = [Q, V, B]

    p, u, lmbda = list(map(TrialFunction, W))
    q, v, beta = list(map(TestFunction, W))
    Tu = Trace(u, bmesh)
    Tv = Trace(v, bmesh)

    # The line integral
    dxGamma = Measure('dx', domain=bmesh)

    a = [[0] * len(W) for _ in range(len(W))]

    a[0][0] = Constant(eps) * inner(p, q) * dx
    a[0][2] = inner(q, lmbda) * dx
    # We put zero on the diagonal temporarily and then replace by
    # the fractional laplacian
    a[1][1] = 0
    a[1][2] = inner(grad(v), grad(lmbda)) * dx + inner(v, lmbda) * dx

    a[2][0] = inner(p, beta) * dx
    a[2][1] = inner(grad(u), grad(beta)) * dx + inner(u, beta) * dx

    L = [
        inner(Constant(0), q) * dx,
        inner(Constant(0), v) * dx,  # Same replacement idea here
        inner(Constant(0), beta) * dx
    ]
    # All but (1, 1) and 1 are final
    AA, bb = list(map(ii_assemble, (a, L)))

    # Now I want and operator which corresponds to (Tv, (-Delta^{0.5} T_u))_bdry
    TV = FunctionSpace(bmesh, 'CG', 1)
    T = PETScMatrix(trace_mat_no_restrict(V, TV))
    # The fractional laplacian nodal->dual
    fDelta = HsNorm(TV, s=0.5)
    # This should be it
    A11 = block_transpose(T) * fDelta * T
    # Now, while here we can also comute the rhs contribution
    # (Tv, (-Delta^{0.5}, f))
    f_vec = interpolate(f, V).vector()
    b1 = A11 * f_vec
    bb[1] = b1
    AA[1][1] = A11

    wh = ii_Function(W)
    # Direct solve
    if not solver_params:
        AAm, bbm = list(map(ii_convert, (AA, bb)))
        LUSolver('umfpack').solve(AAm, wh.vector(), bbm)
        return wh, -1

    # Magne like precond
    if False:
        # Preconditioner like in the L2 case but with L2 bdry replaced
        b00 = Constant(eps) * inner(p, q) * dx
        B00 = LumpedInvDiag(ii_assemble(b00))

        H1 = ii_assemble(inner(grad(v), grad(u)) * dx + inner(v, u) * dx)
        # From dual to nodal
        R = LumpedInvDiag(ii_assemble(inner(u, v) * dx))
        # The whole matrix to be inverted is then (second term is H2 approx)
        B11 = collapse(A11 + eps * H1 * R * H1)
        # And the inverse
        B11 = AMG(B11, parameters={'pc_hypre_boomeramg_cycle_type': 'W'})

        b22 = Constant(1. / eps) * inner(lmbda, beta) * dx
        B22 = LumpedInvDiag(ii_assemble(b22))
    # A bit like SZ
    else:
        b00 = Constant(eps) * inner(p, q) * dx
        B00 = LumpedInvDiag(ii_assemble(b00))

        # L2 \cap eps H1
        H1 = assemble(
            Constant(eps) * (inner(grad(v), grad(u)) * dx + inner(v, u) * dx))
        B11 = AMG(collapse(A11 + H1))

        # (1./eps)*L2 \cap 1./sqrt(eps)H1
        a = Constant(1./eps)*inner(beta, lmbda)*dx + \
            Constant(1./sqrt(eps))*(inner(grad(beta), grad(lmbda))*dx + inner(beta, lmbda)*dx)
        B22 = AMG(assemble(a))

    BB = block_diag_mat([B00, B11, B22])

    # Want the iterations to start from random (iterative)
    wh.block_vec().randomize()

    # Default is minres
    if '-ksp_type' not in solver_params: solver_params['-ksp_type'] = 'minres'

    opts = PETSc.Options()
    for key, value in solver_params.items():
        opts.setValue(key, None if value == 'none' else value)

    ksp = PETSc.KSP().create()
    ksp.setOperators(ii_PETScOperator(AA))
    ksp.setPC(ii_PETScPreconditioner(BB, ksp))

    ksp.setNormType(PETSc.KSP.NormType.NORM_PRECONDITIONED)
    ksp.setFromOptions()

    ksp.solve(as_petsc_nest(bb), wh.petsc_vec())

    niters = ksp.getIterationNumber()

    return wh, niters
Esempio n. 7
0
def lagrange_primal(lmbda, mu, f, h, mesh, Z=None):
    '''
    Solves 

        -div(sigma) = f in  Omega
            sigma.n = h on  boundary

    where sigma(u) = 2*mu*eps(u) + lambda*div(u)*I. The problem is reformulated by
    Lagrange multiplier p to inforce orthogonality with the space of rigid
    motions. The system to be solved with MinRes is 

        P*[A  B;*[u; = P*[L,
           B'  ]  p]      0]

    with P a precondtioner. We run on series of meshes to show mesh independence
    of the solver.
    '''
    if not isinstance(mesh, Mesh):
        # NOTE: You can precompute the 'symbolic' basis and pass it here
        return [lagrange_primal(lmbda, mu, f, h, mesh_) for mesh_ in mesh]

    # For cube
    V = VectorFunctionSpace(mesh, 'CG', 1)
    u, v = TrialFunction(V), TestFunction(V)
    # Strain
    epsilon = lambda u: sym(grad(u))
    # Stress
    gdim = mesh.geometry().dim()
    sigma = lambda u: 2 * mu * epsilon(u) + lmbda * tr(epsilon(u)) * Identity(
        gdim)
    # Energy of elastic deformation
    a = inner(sigma(u), epsilon(v)) * dx
    A = assemble(a)
    # Mass matrix for B
    m = inner(u, v) * dx
    M = assemble(m)

    # NOTE: Avoiding use of Q space in the assembly - dense blocks!
    Q = VectorFunctionSpace(mesh, 'R', 0, dim=6)
    Zh = rigid_motions.RMBasis(V, Q, Z)  # L^2 orthogonal
    B = M * Zh

    # System operator
    AA = block_mat([[A, B], [block_transpose(B), 0]])

    # Right hand side
    L = inner(f, v) * dx + inner(h, v) * ds
    b0 = assemble(L)
    # Equivalent to assemble(inner(Constant((0, )*6), q)*dx) but cheaper
    b1 = Function(Q).vector()
    bb = block_vec([b0, b1])

    # Block diagonal preconditioner
    AM = assemble(a + m)
    I = rigid_motions.identity_matrix(Q)
    BB = block_mat([[AMG(AM), 0], [0, I]])

    # Solve, using random initial guess
    x0 = AA.create_vec()
    [as_backend_type(xi).vec().setRandom() for xi in x0]

    AAinv = MinRes(AA,
                   precond=BB,
                   initial_guess=x0,
                   maxiter=100,
                   tolerance=1E-8,
                   show=2,
                   relativeconv=True)

    x = AAinv * bb

    # Functions from coefficients
    # uh = Function(V, x[0])     # Displacement
    # zh = Zh.rigid_motion(x[1])  # Function in V

    niters = len(AAinv.residuals) - 1
    assert niters < 100

    P = rigid_motions.Projector(Zh)
    P * x[0]  # to get orthogonality
    if MPI.rank(mesh.mpi_comm()) == 0:
        print '\033[1;37;31m%s\033[0m' % ('Orthogonality %g' % max(P.alphas))

    return V.dim() + 6, niters
Esempio n. 8
0
def solve_problem(ncells, eps, solver_params):
    '''Optim problem on [0, 1]^2'''
    # Made up
    f = Expression('x[0] + x[1]', degree=1)
    
    mesh = UnitSquareMesh(*(ncells, )*2)
    bmesh = BoundaryMesh(mesh, 'exterior')

    Q = FunctionSpace(mesh, 'DG', 0)
    V = FunctionSpace(mesh, 'CG', 1)
    B = FunctionSpace(mesh, 'CG', 1)
    W = [Q, V, B]

    p, u, lmbda = map(TrialFunction, W)
    q, v, beta = map(TestFunction, W)
    Tu = Trace(u, bmesh)
    Tv = Trace(v, bmesh)

    # The line integral
    dxGamma = Measure('dx', domain=bmesh)

    a = [[0]*len(W) for _ in range(len(W))]

    a[0][0] = Constant(eps)*inner(p, q)*dx
    a[0][2] = inner(q, lmbda)*dx
    # We put zero on the diagonal temporarily and then replace by
    # the fractional laplacian
    a[1][1] = 0
    a[1][2] = inner(grad(v), grad(lmbda))*dx + inner(v, lmbda)*dx

    a[2][0] = inner(p, beta)*dx
    a[2][1] = inner(grad(u), grad(beta))*dx + inner(u, beta)*dx

    L = [inner(Constant(0), q)*dx,
         inner(Constant(0), v)*dx,  # Same replacement idea here
         inner(Constant(0), beta)*dx]
    # All but (1, 1) and 1 are final
    AA, bb = map(ii_assemble, (a, L))

    # Now I want and operator which corresponds to (Tv, (-Delta^{0.5} T_u))_bdry
    TV = FunctionSpace(bmesh, 'CG', 1)
    T = PETScMatrix(trace_mat_no_restrict(V, TV))
    # The fractional laplacian nodal->dual
    fDelta = HsNorm(TV, s=0.5)
    # This should be it
    A11 = block_transpose(T)*fDelta*T
    # Now, while here we can also comute the rhs contribution
    # (Tv, (-Delta^{0.5}, f))
    f_vec = interpolate(f, V).vector()
    b1 = A11*f_vec
    bb[1] = b1
    AA[1][1] = A11

    wh = ii_Function(W)
    # Direct solve
    if not solver_params:
        AAm, bbm = map(ii_convert, (AA, bb))
        LUSolver('umfpack').solve(AAm, wh.vector(), bbm)
        return wh, -1


    # Magne like precond
    if False:
        # Preconditioner like in the L2 case but with L2 bdry replaced
        b00 = Constant(eps)*inner(p, q)*dx
        B00 = LumpedInvDiag(ii_assemble(b00))

        H1 = ii_assemble(inner(grad(v), grad(u))*dx + inner(v, u)*dx)
        # From dual to nodal
        R = LumpedInvDiag(ii_assemble(inner(u, v)*dx))
        # The whole matrix to be inverted is then (second term is H2 approx)
        B11 = collapse(A11 + eps*H1*R*H1)
        # And the inverse
        B11 = AMG(B11, parameters={'pc_hypre_boomeramg_cycle_type': 'W'})

        b22 = Constant(1./eps)*inner(lmbda, beta)*dx
        B22 = LumpedInvDiag(ii_assemble(b22))
    # A bit like SZ
    else:
        b00 = Constant(eps)*inner(p, q)*dx
        B00 = LumpedInvDiag(ii_assemble(b00))

        # L2 \cap eps H1
        H1 = assemble(Constant(eps)*(inner(grad(v), grad(u))*dx + inner(v, u)*dx))
        B11 = AMG(collapse(A11 + H1))

        # (1./eps)*L2 \cap 1./sqrt(eps)H1
        a = Constant(1./eps)*inner(beta, lmbda)*dx + \
            Constant(1./sqrt(eps))*(inner(grad(beta), grad(lmbda))*dx + inner(beta, lmbda)*dx)
        B22 = AMG(assemble(a))

    
    BB = block_diag_mat([B00, B11, B22])

    # Want the iterations to start from random (iterative)
    wh.block_vec().randomize()

    # Default is minres
    if '-ksp_type' not in solver_params: solver_params['-ksp_type'] = 'minres'
            
    opts = PETSc.Options()
    for key, value in solver_params.iteritems():
        opts.setValue(key, None if value == 'none' else value)
        
    ksp = PETSc.KSP().create()
    ksp.setOperators(ii_PETScOperator(AA))
    ksp.setPC(ii_PETScPreconditioner(BB, ksp))
    
    ksp.setNormType(PETSc.KSP.NormType.NORM_PRECONDITIONED)
    ksp.setFromOptions()
    
    ksp.solve(as_petsc_nest(bb), wh.petsc_vec())
    
    niters = ksp.getIterationNumber()

    return wh, niters
Esempio n. 9
0
    def assemble(self, form, arity):
        '''Assemble a biliner(2), linear(1) form'''
        reduced_integrals = self.select_integrals(form)   #! Selector
        # Signal to xii.assemble
        if not reduced_integrals: return None
    
        components = []
        for integral in form.integrals():
            # Delegate to friend
            if integral not in reduced_integrals:
                components.append(xii.assembler.xii_assembly.assemble(Form([integral])))
                continue

            reduced_mesh = integral.ufl_domain().ufl_cargo()

            integrand = integral.integrand()
            # Split arguments in those that need to be and those that are
            # already restricted.
            terminals = set(traverse_unique_terminals(integrand))

            # FIXME: is it enough info (in general) to decide
            terminals_to_restrict = self.restriction_filter(terminals, reduced_mesh)
            # You said this is a trace ingral!
            assert terminals_to_restrict

            # Let's pick a guy for restriction
            terminal = terminals_to_restrict.pop()
            # We have some assumption on the candidate
            assert self.is_compatible(terminal, reduced_mesh)

            data = self.reduction_matrix_data(terminal)
                
            integrand = ufl2uflcopy(integrand)
            # With sane inputs we can get the reduced element and setup the
            # intermediate function space where the reduction of terminal
            # lives
            V = terminal.function_space()
            TV = self.reduced_space(V, reduced_mesh)  #! Space construc

            # Setup the matrix to from space of the trace_terminal to the
            # intermediate space. FIXME: normal and trace_mesh
            #! mat construct
            T = self.reduction_matrix(V, TV, reduced_mesh, data)

            # T
            if is_test_function(terminal):
                replacement = df.TestFunction(TV)
                # Passing the args to get the comparison a make substitution
                integrand = replace(integrand, terminal, replacement, attributes=self.attributes)
                trace_form = Form([integral.reconstruct(integrand=integrand)])

                if arity == 2:
                    # Make attempt on the substituted form
                    A = xii.assembler.xii_assembly.assemble(trace_form)
                    components.append(block_transpose(T)*A)
                else:
                    b = xii.assembler.xii_assembly.assemble(trace_form)
                    Tb = df.Function(V).vector()  # Alloc and apply
                    T.transpmult(b, Tb)
                    components.append(Tb)

            if is_trial_function(terminal):
                assert arity == 2
                replacement = df.TrialFunction(TV)
                # Passing the args to get the comparison
                integrand = replace(integrand, terminal, replacement, attributes=self.attributes)
                trace_form = Form([integral.reconstruct(integrand=integrand)])

                A = xii.assembler.xii_assembly.assemble(trace_form)
                components.append(A*T)

            # Okay, then this guy might be a function
            if isinstance(terminal, df.Function):
                replacement = df.Function(TV)
                # Replacement is not just a placeholder
                T.mult(terminal.vector(), replacement.vector())
                # Substitute
                integrand = replace(integrand, terminal, replacement, attributes=self.attributes)
                trace_form = Form([integral.reconstruct(integrand=integrand)])
                components.append(xii.assembler.xii_assembly.assemble(trace_form))

        # The whole form is then the sum of integrals
        return reduce(operator.add, components)
Esempio n. 10
0
def energy(lmbda, mu, f, h, mesh, Z=None):
    '''
    Solves 

        -div(sigma) = f in  Omega
            sigma.n = h on  boundary

    where sigma(u) = 2*mu*eps(u) + lambda*div(u)*I. The problem is reformulated by
    considering a complemented strain energy (for which rigid motions are not
    tranparent). The system to be solved with CG as

        P*[A+E]*[u] = P'*b

    with P a precondtioner. We run on series of meshes to show mesh independence
    of the solver.
    '''
    if not isinstance(mesh, Mesh):
        # Precompute the 'symbolic' basis
        mesh0 = first(mesh)
        Z = rigid_motions.rm_basis(mesh0)
        return [energy(lmbda, mu, f, h, mesh_, Z) for mesh_ in mesh]

    # For cube
    V = VectorFunctionSpace(mesh, 'CG', 1)
    u, v = TrialFunction(V), TestFunction(V)
    # Strain
    epsilon = lambda u: sym(grad(u))
    # Stress
    gdim = mesh.geometry().dim()
    sigma = lambda u: 2 * mu * epsilon(u) + lmbda * tr(epsilon(u)) * Identity(
        gdim)
    # Energy of elastic deformation
    a = inner(sigma(u), epsilon(v)) * dx
    A = assemble(a)
    # Mass matrix for B
    m = inner(u, v) * dx
    M = assemble(m)

    # NOTE: Avoiding use of Q space in the assembly - dense blocks!
    Q = VectorFunctionSpace(mesh, 'R', 0, dim=6)
    Zh = rigid_motions.RMBasis(V, Q, Z)  # L^2 orthogonal
    B = M * Zh

    # System operator
    AA = A + B * block_transpose(B)

    # Right hand side
    L = inner(f, v) * dx + inner(h, v) * ds
    # Orthogonalize
    P = rigid_motions.Projector(Zh)
    b = assemble(L)
    b0 = block_transpose(P) * b

    # Preconditioner
    AM = assemble(a + m)
    BB = AMG(AM)

    # Solve, using random initial guess
    x0 = AA.create_vec()
    as_backend_type(x0).vec().setRandom()

    AAinv = ConjGrad(AA,
                     precond=BB,
                     initial_guess=x0,
                     maxiter=100,
                     tolerance=1E-8,
                     show=2,
                     relativeconv=True)

    x = AAinv * b0

    # Functions from coefficients
    # uh = Function(V, x)  # Displacement

    niters = len(AAinv.residuals) - 1
    assert niters < 100

    P * x  # to get orthogonality
    if MPI.rank(mesh.mpi_comm()) == 0:
        print '\033[1;37;31m%s\033[0m' % ('Orthogonality %g' % max(P.alphas))

    return V.dim(), niters