ext_mesh = EmbeddedMesh(facet_f, 1) EV = FunctionSpace(ext_mesh, 'CG', 1) # The auxiliary problem would be speced at aux_mesh = SubMesh(mesh, cell_f, 1) facet_f = MeshFunction('size_t', aux_mesh, 1, 0) DomainBoundary().mark(facet_f, 1) left.mark(facet_f, 2) right.mark(facet_f, 2) # Extending from gamma_mesh = StraightLineMesh(np.array([0.5, 0]), np.array([0.5, 1]), 3*ny) V = FunctionSpace(gamma_mesh, 'CG', 1) E = harmonic_extension_operator(V, EV, auxiliary_facet_f=facet_f) v = interpolate(Constant(1), V).vector() q = Function(EV, E*v) File('foo.pvd') << q from xii.linalg.convert import collapse E_ = collapse(E) q = Function(EV, E_*v) File('foo_.pvd') << q
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
def setup_preconditioner(W, which, eps=None): ''' Mirror the structure of preconditioner proposed in Robust preconditioners for PDE-constrained optimization with limited observations; Mardal and Nielsen and Nordaas, BIT 2017 or Schoeberl and Zulehner's Symmetric indefinite preconditioners for saddle point problems with applications to PDE constrained optimization problems ''' from block.algebraic.petsc import AMG from block.algebraic.petsc import LumpedInvDiag from xii.linalg.convert import collapse print 'WHICH is', which (Q, V, B) = W p, u, lmbda = map(TrialFunction, W) q, v, beta = map(TestFunction, W) bmesh = BoundaryMesh(Q.mesh(), 'exterior') Tu = Trace(u, bmesh) Tv = Trace(v, bmesh) # The line integral dxGamma = Measure('dx', domain=bmesh) # Nielsen if which == 0: b00 = Constant(eps)*inner(p, q)*dx B00 = LumpedInvDiag(ii_assemble(b00)) M_bdry = ii_convert(ii_assemble(inner(Tu, Tv)*dxGamma)) # H2 norm with H1 elements A = ii_assemble(inner(grad(v), grad(u))*dx + inner(v, u)*dx) # From dual to nodal M = LumpedInvDiag(ii_assemble(inner(u, v)*dx)) # The whole matrix to be inverted is then (second term is H2 approx) B11 = collapse(M_bdry + eps*A*M*A) # 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)) # SZ else: print 'X' # eps*L2 b00 = Constant(eps)*inner(p, q)*dx B00 = LumpedInvDiag(ii_assemble(b00)) # L2 \cap eps H1 a = inner(u, v)*ds + Constant(eps)*(inner(grad(v), grad(u))*dx + inner(v, u)*dx) B11 = AMG(assemble(a)) # (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)) return block_diag_mat([B00, B11, B22])
def setup_preconditioner(W, which, eps=None): ''' Mirror the structure of preconditioner proposed in Robust preconditioners for PDE-constrained optimization with limited observations; Mardal and Nielsen and Nordaas, BIT 2017 or Schoeberl and Zulehner's Symmetric indefinite preconditioners for saddle point problems with applications to PDE constrained optimization problems ''' from block.algebraic.petsc import AMG from block.algebraic.petsc import LumpedInvDiag from xii.linalg.convert import collapse print('WHICH is', which) (Q, V, B) = W p, u, lmbda = list(map(TrialFunction, W)) q, v, beta = list(map(TestFunction, W)) bmesh = BoundaryMesh(Q.mesh(), 'exterior') Tu = Trace(u, bmesh) Tv = Trace(v, bmesh) # The line integral dxGamma = Measure('dx', domain=bmesh) # Nielsen if which == 0: b00 = Constant(eps) * inner(p, q) * dx B00 = LumpedInvDiag(ii_assemble(b00)) M_bdry = ii_convert(ii_assemble(inner(Tu, Tv) * dxGamma)) # H2 norm with H1 elements A = ii_assemble(inner(grad(v), grad(u)) * dx + inner(v, u) * dx) # From dual to nodal M = LumpedInvDiag(ii_assemble(inner(u, v) * dx)) # The whole matrix to be inverted is then (second term is H2 approx) B11 = collapse(M_bdry + eps * A * M * A) # 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)) # SZ else: print('X') # eps*L2 b00 = Constant(eps) * inner(p, q) * dx B00 = LumpedInvDiag(ii_assemble(b00)) # L2 \cap eps H1 a = inner(u, v) * ds + Constant(eps) * (inner(grad(v), grad(u)) * dx + inner(v, u) * dx) B11 = AMG(assemble(a)) # (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)) return block_diag_mat([B00, B11, B22])
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