def __init__(self, parameters, options_prefix): if parameters is None: parameters = {} else: parameters = parameters.copy() if options_prefix is None: self.options_prefix = "firedrake_%d_" % next(self.count) self.parameters = parameters self.to_delete = set(parameters) else: self.options_prefix = options_prefix # Remove those options from the dict that were passed on # the commandline. self.parameters = dict( (k, v) for k, v in parameters.iteritems() if options_prefix + k not in self.commandline_options) self.to_delete = set(parameters) # Now update parameters from options, so that they're # availabe to solver setup (for, e.g., matrix-free). for k, v in PETSc.Options( self.options_prefix).getAll().iteritems(): self.parameters[k] = v self.options_object = PETSc.Options(self.options_prefix) self._setfromoptions = False super(ParametersMixin, self).__init__()
def get_patches(self, V): mesh = V._mesh mesh_dm = mesh._topology_dm # Obtain the topological entities to use to construct the stars depth = PETSc.Options().getInt(self.prefix + "construct_dim", default=-1) height = PETSc.Options().getInt(self.prefix + "construct_codim", default=-1) if (depth == -1 and height == -1) or (depth != -1 and height != -1): raise ValueError( f"Must set exactly one of {self.prefix}construct_dim or {self.prefix}construct_codim" ) # Accessing .indices causes the allocation of a global array, # so we need to cache these for efficiency V_local_ises_indices = [] for (i, W) in enumerate(V): V_local_ises_indices.append(V.dof_dset.local_ises[i].indices) # Build index sets for the patches ises = [] if depth != -1: (start, end) = mesh_dm.getDepthStratum(depth) else: (start, end) = mesh_dm.getHeightStratum(height) for seed in range(start, end): # Only build patches over owned DoFs if mesh_dm.getLabelValue("pyop2_ghost", seed) != -1: continue # Create point list from mesh DM star, _ = mesh_dm.getTransitiveClosure(seed, useCone=False) pt_array = set() for pt in star.tolist(): closure, _ = mesh_dm.getTransitiveClosure(seed, useCone=True) pt_array.update(closure.tolist()) # Get DoF indices for patch indices = [] for (i, W) in enumerate(V): section = W.dm.getDefaultSection() for p in pt_array: dof = section.getDof(p) if dof <= 0: continue off = section.getOffset(p) # Local indices within W W_indices = numpy.arange(off * W.value_size, W.value_size * (off + dof), dtype='int32') indices.extend(V_local_ises_indices[i][W_indices]) iset = PETSc.IS().createGeneral(indices, comm=COMM_SELF) ises.append(iset) return ises
def initialize(self, pc): # Get context from pc _, P = pc.getOperators() dm = pc.getDM() self.prefix = pc.getOptionsPrefix() + self._prefix # Extract function space and mesh to obtain plex and indexing functions V = get_function_space(dm) # Obtain patches from user defined funtion ises = self.get_patches(V) # Create new PC object as ASM type and set index sets for patches asmpc = PETSc.PC().create(comm=pc.comm) asmpc.incrementTabLevel(1, parent=pc) asmpc.setOptionsPrefix(self.prefix + "sub_") asmpc.setOperators(*pc.getOperators()) backend = PETSc.Options().getString(self.prefix + "backend", default="petscasm").lower() # Either use PETSc's ASM PC or use TinyASM (as simple ASM # implementation designed to be fast for small block sizes). if backend == "petscasm": asmpc.setType(asmpc.Type.ASM) # Set default solver parameters asmpc.setASMType(PETSc.PC.ASMType.BASIC) opts = PETSc.Options(asmpc.getOptionsPrefix()) if "sub_pc_type" not in opts: opts["sub_pc_type"] = "lu" if "sub_pc_factor_shift_type" not in opts: opts["sub_pc_factor_shift_type"] = "NONE" lgmap = V.dof_dset.lgmap # Translate to global numbers ises = tuple(lgmap.applyIS(iset) for iset in ises) asmpc.setASMLocalSubdomains(len(ises), ises) elif backend == "tinyasm": if not have_tinyasm: raise ValueError( "To use the TinyASM backend you need to install firedrake with TinyASM (firedrake-update --tinyasm)" ) _, P = asmpc.getOperators() lgmap = V.dof_dset.lgmap P.setLGMap(rmap=lgmap, cmap=lgmap) asmpc.setType("tinyasm") # TinyASM wants local numbers, no need to translate tinyasm.SetASMLocalSubdomains( asmpc, ises, [W.dm.getDefaultSF() for W in V], [W.value_size for W in V], sum(W.value_size * W.dof_dset.total_size for W in V)) asmpc.setUp() else: raise ValueError(f"Unknown backend type f{backend}") asmpc.setFromOptions() self.asmpc = asmpc
def configure_pmg(self, snes, pdm): odm = snes.getDM() psnes = PETSc.SNES().create(comm=snes.comm) psnes.setOptionsPrefix(snes.getOptionsPrefix() + "pfas_") psnes.setType("fas") psnes.setDM(pdm) psnes.incrementTabLevel(1, parent=snes) (f, residual) = snes.getFunction() assert residual is not None (fun, args, kargs) = residual psnes.setFunction(fun, f.duplicate(), args=args, kargs=kargs) pdm.setGlobalVector(f.duplicate()) self.dummy = f.duplicate() psnes.setSolution(f.duplicate()) # PETSc unfortunately requires us to make an ugly hack. # We would like to use GMG for the coarse solve, at least # sometimes. But PETSc will use this p-DM's getRefineLevels() # instead of the getRefineLevels() of the MeshHierarchy to # decide how many levels it should use for PCMG applied to # the p-MG's coarse problem. So we need to set an option # for the user, if they haven't already; I don't know any # other way to get PETSc to know this at the right time. opts = PETSc.Options(snes.getOptionsPrefix() + "pfas_") if "fas_coarse_pc_mg_levels" not in opts: opts["fas_coarse_pc_mg_levels"] = odm.getRefineLevel() + 1 if "fas_coarse_snes_fas_levels" not in opts: opts["fas_coarse_snes_fas_levels"] = odm.getRefineLevel() + 1 return psnes
def initialize(self, obj): if complex_mode: raise NotImplementedError("HypreAMS preconditioner not yet implemented in complex mode") Citations().register("Kolev2009") A, P = obj.getOperators() prefix = obj.getOptionsPrefix() V = get_function_space(obj.getDM()) mesh = V.mesh() family = str(V.ufl_element().family()) degree = V.ufl_element().degree() if family != 'Nedelec 1st kind H(curl)' or degree != 1: raise ValueError("Hypre AMS requires lowest order Nedelec elements! (not %s of degree %d)" % (family, degree)) P1 = FunctionSpace(mesh, "Lagrange", 1) G = Interpolator(grad(TestFunction(P1)), V).callable().handle pc = PETSc.PC().create(comm=obj.comm) pc.incrementTabLevel(1, parent=obj) pc.setOptionsPrefix(prefix + "hypre_ams_") pc.setOperators(A, P) pc.setType('hypre') pc.setHYPREType('ams') pc.setHYPREDiscreteGradient(G) zero_beta = PETSc.Options(prefix).getBool("pc_hypre_ams_zero_beta_poisson", default=False) if zero_beta: pc.setHYPRESetBetaPoissonMatrix(None) VectorP1 = VectorFunctionSpace(mesh, "Lagrange", 1) pc.setCoordinates(interpolate(SpatialCoordinate(mesh), VectorP1).dat.data_ro.copy()) pc.setUp() self.pc = pc
def __call__(self, pc): dm = pc.getDM() prefix = pc.getOptionsPrefix() sentinel = object() sweeps = PETSc.Options(prefix).getString( "pc_patch_construct_ps_sweeps", default=sentinel) if sweeps == sentinel: raise ValueError("Must set %spc_patch_construct_ps_sweeps" % prefix) patches = [] for sweep in sweeps.split(':'): axis = int(sweep[0]) dir = {'+': +1, '-': -1}[sweep[1]] ndiv = int(sweep[2:]) entities = self.sort_entities(dm, axis, dir, ndiv) for patch in entities: iset = PETSc.IS().createGeneral(patch, comm=PETSc.COMM_SELF) patches.append(iset) iterationSet = PETSc.IS().createStride(size=len(patches), first=0, step=1, comm=PETSc.COMM_SELF) return (patches, iterationSet)
def create_interpolation(self, dmc, dmf): prefix = dmc.getOptionsPrefix() mat_type = PETSc.Options(prefix).getString( "mg_levels_transfer_mat_type", default="matfree") I = self.create_transfer(get_appctx(dmc), get_appctx(dmf), mat_type, True, False) return I, None
def get_patches(self, V): mesh = V._mesh assert mesh.cell_set._extruded dm = mesh._topology_dm section = V.dm.getDefaultSection() # Obtain the codimensions to loop over from options, if present codim_list = PETSc.Options().getString(self.prefix + "codims", "0, 1") codim_list = [int(ii) for ii in codim_list.split(",")] # Build index sets for the patches ises = [] for codim in codim_list: for p in range(*dm.getHeightStratum(codim)): # Only want to build patches over owned faces if dm.getLabelValue("pyop2_ghost", p) != -1: continue dof = section.getDof(p) if dof <= 0: continue off = section.getOffset(p) indices = numpy.arange(off * V.value_size, V.value_size * (off + dof), dtype='int32') iset = PETSc.IS().createGeneral(indices, comm=COMM_SELF) ises.append(iset) return ises
def create_injection(self, dmc, dmf): prefix = dmc.getOptionsPrefix() mat_type = PETSc.Options(prefix).getString( "mg_levels_transfer_mat_type", default="matfree") I = self.create_transfer(get_appctx(dmf), get_appctx(dmc), mat_type, False, False) return PETSc.Mat().createTranspose(I)
def __call__(self, pc): dm = pc.getDM() prefix = pc.getOptionsPrefix() opts = PETSc.Options(prefix) select = partial(self.select_entity, dm=dm, exclude="pyop2_ghost") (pStart, pEnd) = dm.getChart() owned_entities = set(filter(select, range(pStart, pEnd))) overlap = 1 # FIXME: get from options all_entities = set(owned_entities) for i in range(overlap): tmp_entities = set(all_entities) for entity in tmp_entities: for s in self.star(dm, entity): for c in self.closure(dm, s): all_entities.add(c) overlap_entities = list(all_entities.difference(owned_entities)) iset = PETSc.IS().createGeneral(overlap_entities, comm=PETSc.COMM_SELF) patches = [iset] iterset = PETSc.IS().createStride(size=len(patches), first=0, step=1, comm=PETSc.COMM_SELF) #print("owned_entities: ", owned_entities) #print("all_entities: ", all_entities) #print("overlap_entities: ", overlap_entities) return (patches, iterset)
def __del__(self): # Remove stuff from the options database # It's fixed size, so if we don't it gets too big. if self._auto_prefix and hasattr(self, '_opt_prefix'): opts = PETSc.Options() for k in self.parameters.iterkeys(): del opts[self._opt_prefix + k] delattr(self, '_opt_prefix')
def _check_options(self, valid): default = object() opts = PETSc.Options(self.prefix) for key, supported in valid: value = opts.getString(key, default=default) if value is not default and value not in supported: raise ValueError( f"Unsupported value ({value}) for '{self.prefix + key}'. " f"Should be one of {supported}")
def test_petsc_options_cleared(a_L_out): a, L, out = a_L_out opts = PETSc.Options() original = {} original.update(opts.getAll()) solve(a == L, out, solver_parameters={'foo': 'bar'}) assert original == opts.getAll()
def initialize(self, pc): # Make a new DM. # Hook up a (new) coarsen routine on that DM. # Make a new PC, of type MG. # Assign the DM to that PC. odm = pc.getDM() ctx = get_appctx(odm) test, trial = ctx.J.arguments() if test.function_space() != trial.function_space(): raise NotImplementedError("test and trial spaces must be the same") prefix = pc.getOptionsPrefix() options_prefix = prefix + "pmg_" pdm = PETSc.DMShell().create(comm=pc.comm) pdm.setOptionsPrefix(options_prefix) # Get the coarse degree from PETSc options self.coarse_degree = PETSc.Options(options_prefix).getInt("mg_coarse_degree", default=1) # Construct a list with the elements we'll be using V = test.function_space() ele = V.ufl_element() elements = [ele] while True: try: ele_ = self.coarsen_element(ele) assert ele_.value_shape() == ele.value_shape() ele = ele_ except ValueError: break elements.append(ele) sf = odm.getPointSF() section = odm.getDefaultSection() attach_hooks(pdm, level=len(elements)-1, sf=sf, section=section) # Now overwrite some routines on the DM pdm.setRefine(None) pdm.setCoarsen(self.coarsen) pdm.setCreateInterpolation(self.create_interpolation) # We need this for p-FAS pdm.setCreateInjection(self.create_injection) pdm.setSNESJacobian(_SNESContext.form_jacobian) pdm.setSNESFunction(_SNESContext.form_function) pdm.setKSPComputeOperators(_SNESContext.compute_operators) set_function_space(pdm, get_function_space(odm)) parent = get_parent(odm) assert parent is not None add_hook(parent, setup=partial(push_parent, pdm, parent), teardown=partial(pop_parent, pdm, parent), call_setup=True) add_hook(parent, setup=partial(push_appctx, pdm, ctx), teardown=partial(pop_appctx, pdm, ctx), call_setup=True) self.ppc = self.configure_pmg(pc, pdm) self.ppc.setFromOptions() self.ppc.setUp()
def __init__(self, Q, free_bids=["on_boundary"]): (V, I_interp) = Q.get_space_for_inner() self.free_bids = free_bids u = fd.TrialFunction(V) v = fd.TestFunction(V) n = fd.FacetNormal(V.mesh()) def surf_grad(u): return fd.sym(fd.grad(u) - fd.outer(fd.grad(u) * n, n)) a = (fd.inner(surf_grad(u), surf_grad(v)) + fd.inner(u, v)) * fd.ds # petsc doesn't like matrices with zero rows a += 1e-10 * fd.inner(u, v) * fd.dx A = fd.assemble(a, mat_type="aij") A = A.petscmat tdim = V.mesh().topological_dimension() lsize = fd.Function(V).vector().local_size() def get_nodes_bc(bc): nodes = bc.nodes return nodes[nodes < lsize] def get_nodes_bid(bid): bc = fd.DirichletBC(V, fd.Constant(tdim * (0, )), bid) return get_nodes_bc(bc) free_nodes = np.concatenate( [get_nodes_bid(bid) for bid in self.free_bids]) free_dofs = np.concatenate( [tdim * free_nodes + i for i in range(tdim)]) free_dofs = np.unique(np.sort(free_dofs)) self.free_is = PETSc.IS().createGeneral(free_dofs) lgr, lgc = A.getLGMap() self.global_free_is_row = lgr.applyIS(self.free_is) self.global_free_is_col = lgc.applyIS(self.free_is) A = A.createSubMatrix(self.global_free_is_row, self.global_free_is_col) # A.view() A.assemble() self.A = A Aksp = PETSc.KSP().create() Aksp.setOperators(self.A) Aksp.setOptionsPrefix("A_") opts = PETSc.Options() opts["A_ksp_type"] = "cg" opts["A_pc_type"] = "hypre" opts["A_ksp_atol"] = 1e-10 opts["A_ksp_rtol"] = 1e-10 Aksp.setUp() Aksp.setFromOptions() self.Aksp = Aksp
def opts(request, prefix, global_parameters): opts = PETSc.Options() if prefix is None: prefix = "" for k, v in global_parameters.iteritems(): opts["%s%s" % (prefix, k)] = v def finalize(): for k in global_parameters.keys(): del opts["%s%s" % (prefix, k)] request.addfinalizer(finalize)
def user_construction_op(self, obj, *args, **kwargs): prefix = obj.getOptionsPrefix() sentinel = object() usercode = PETSc.Options(prefix).getString("%s_patch_construct_python_type" % self._objectname, default=sentinel) if usercode == sentinel: raise ValueError("Must set %s%s_patch_construct_python_type" % (prefix, self._objectname)) (modname, funname) = usercode.rsplit('.', 1) mod = __import__(modname) fun = getattr(mod, funname) if isinstance(fun, type): fun = fun() return fun(obj, *args, **kwargs)
def initialize(self, pc): from firedrake import TrialFunction, TestFunction, dx, assemble, inner, parameters if pc.getType() != "python": raise ValueError("Expecting PC type python") prefix = pc.getOptionsPrefix() options_prefix = prefix + "Mp_" # we assume P has things stuffed inside of it _, P = pc.getOperators() context = P.getPythonContext() test, trial = context.a.arguments() if test.function_space() != trial.function_space(): raise ValueError( "MassInvPC only makes sense if test and trial space are the same" ) V = test.function_space() mu = context.appctx.get("mu", 1.0) u = TrialFunction(V) v = TestFunction(V) # Handle vector and tensor-valued spaces. # 1/mu goes into the inner product in case it varies spatially. a = inner(1 / mu * u, v) * dx opts = PETSc.Options() mat_type = opts.getString(options_prefix + "mat_type", parameters["default_matrix_type"]) A = assemble(a, form_compiler_parameters=context.fc_params, mat_type=mat_type, options_prefix=options_prefix) A.force_evaluation() Pmat = A.petscmat Pmat.setNullSpace(P.getNullSpace()) tnullsp = P.getTransposeNullSpace() if tnullsp.handle != 0: Pmat.setTransposeNullSpace(tnullsp) ksp = PETSc.KSP().create(comm=pc.comm) ksp.incrementTabLevel(1, parent=pc) ksp.setOperators(Pmat) ksp.setOptionsPrefix(options_prefix) ksp.setFromOptions() ksp.setUp() self.ksp = ksp
def initialize(self, pc): from firedrake.assemble import allocate_matrix, create_assembly_callable _, P = pc.getOperators() if pc.getType() != "python": raise ValueError("Expecting PC type python") opc = pc context = P.getPythonContext() prefix = pc.getOptionsPrefix() options_prefix = prefix + "assembled_" # It only makes sense to preconditioner/invert a diagonal # block in general. That's all we're going to allow. if not context.on_diag: raise ValueError("Only makes sense to invert diagonal block") mat_type = PETSc.Options().getString(options_prefix + "mat_type", "aij") self.P = allocate_matrix(context.a, bcs=context.row_bcs, form_compiler_parameters=context.fc_params, mat_type=mat_type, options_prefix=options_prefix) self._assemble_P = create_assembly_callable( context.a, tensor=self.P, bcs=context.row_bcs, form_compiler_parameters=context.fc_params, mat_type=mat_type) self._assemble_P() self.P.force_evaluation() # Transfer nullspace over Pmat = self.P.petscmat Pmat.setNullSpace(P.getNullSpace()) tnullsp = P.getTransposeNullSpace() if tnullsp.handle != 0: Pmat.setTransposeNullSpace(tnullsp) # Internally, we just set up a PC object that the user can configure # however from the PETSc command line. Since PC allows the user to specify # a KSP, we can do iterative by -assembled_pc_type ksp. pc = PETSc.PC().create(comm=opc.comm) pc.incrementTabLevel(1, parent=opc) pc.setOptionsPrefix(options_prefix) pc.setOperators(Pmat, Pmat) pc.setFromOptions() pc.setUp() self.pc = pc
def GetPETScBFBTApproximateToSchurInverse(): Fass = assemble(lhs(F)) Gass = assemble(inner(u, v) * dx) # bcin.apply(Fass) # bcnoslip.apply(Fass) # bcin.apply(Gass) # bcnoslip.apply(Gass) A = Fass.M[0,0].handle BT = Fass.M[0,1].handle B = Fass.M[1,0].handle D = Fass.M[1,1].handle VM = Gass.M[0, 0].handle # Adiag = A.getDiagonal() Adiag = VM.getRowSum() invAdiag = Adiag.duplicate() Adiag.copy(invAdiag) invAdiag.reciprocal() Einv = A.duplicate() Einv.setDiagonal(invAdiag) # Einv.convert(PETSc.Mat.Type.SEQAIJ) BEBT = B.matMult(Einv.matMult(BT)) BEBT_ksp = PETSc.KSP().create() BEBT_ksp.setOperators(BEBT) opts = PETSc.Options() BEBT_ksp.setOptionsPrefix("bebt_") opts['bebt_ksp_type'] = 'richardson' opts['bebt_pc_type'] = 'hypre' opts['bebt_ksp_max_it'] = 1 opts['bebt_ksp_atol'] = 1.0e-9 opts['bebt_ksp_rtol'] = 1.0e-9 BEBT_ksp.setUp() BEBT_ksp.setFromOptions() MIDDLE = B.matMult(Einv.matMult(A.matMult(Einv.matMult(BT)))) MIDDLE.scale(-1) class SchurInvApprox(object): def mult(self, mat, x, y): y1 = y.duplicate() BEBT_ksp.solve(x, y1) y2 = y.duplicate() MIDDLE.mult(y1, y2) BEBT_ksp.solve(y2, y) schur = PETSc.Mat() schur.createPython(D.getSizes(), SchurInvApprox()) schur.setUp() return schur
def __call__(self, pc): dm = pc.getDM() prefix = pc.getOptionsPrefix() sentinel = object() opts = PETSc.Options(prefix) name = self.name assert self.name is not None self.set_options(dm, opts, name) select = partial(select_entity, dm=dm, exclude="pyop2_ghost") entities = list(filter(select, self.get_entities(opts, name, dm))) nclosure = opts.getInt("pc_patch_construction_%s_nclosures" % name, default=1) patches = [] for entity in entities: subentities = self.callback(dm, entity, nclosure) iset = PETSc.IS().createGeneral(subentities, comm=PETSc.COMM_SELF) patches.append(iset) # Now make the iteration set. iterset = [] sortorders = opts.getString("pc_patch_construction_%s_sort_order" % name, default=sentinel) if sortorders == sentinel: sortorders = "None" if sortorders == "None": piterset = PETSc.IS().createStride(size=len(patches), first=0, step=1, comm=PETSc.COMM_SELF) return (patches, piterset) coords = list(enumerate(self.coords(dm, p) for p in entities)) for sortorder in sortorders.split("|"): sortdata = [] for axis in sortorder.split(':'): ax = int(axis[0]) if len(axis) > 1: sgn = {'+': 1, '-': -1}[axis[1]] else: sgn = 1 sortdata.append((ax, sgn)) def keyfunc(z): return tuple(sgn*z[1][ax] for (ax, sgn) in sortdata) iterset += [x[0] for x in sorted(coords, key=keyfunc)] piterset = PETSc.IS().createGeneral(iterset, comm=PETSc.COMM_SELF) return (patches, piterset)
def initialize(self, obj): if complex_mode: raise NotImplementedError( "HypreAMS preconditioner not yet implemented in complex mode") Citations().register("Kolev2009") A, P = obj.getOperators() prefix = obj.getOptionsPrefix() V = get_function_space(obj.getDM()) mesh = V.mesh() family = str(V.ufl_element().family()) degree = V.ufl_element().degree() if family != 'Nedelec 1st kind H(curl)' or degree != 1: raise ValueError( "Hypre AMS requires lowest order Nedelec elements! (not %s of degree %d)" % (family, degree)) P1 = FunctionSpace(mesh, "Lagrange", 1) G = Interpolator(grad(TestFunction(P1)), V).callable().handle pc = PETSc.PC().create(comm=obj.comm) pc.incrementTabLevel(1, parent=obj) pc.setOptionsPrefix(prefix + "hypre_ams_") pc.setOperators(A, P) pc.setType('hypre') pc.setHYPREType('ams') pc.setHYPREDiscreteGradient(G) zero_beta = PETSc.Options(prefix).getBool( "pc_hypre_ams_zero_beta_poisson", default=False) if zero_beta: pc.setHYPRESetBetaPoissonMatrix(None) # Build constants basis for the Nedelec space cvecs = [] for i in range(mesh.cell_dimension()): direction = [ 1.0 if i == j else 0.0 for j in range(mesh.cell_dimension()) ] c = project(Constant(direction), V) with c.vector().dat.vec_ro as cvec: cvecs.append(cvec) pc.setHYPRESetEdgeConstantVectors(*cvecs) pc.setUp() self.pc = pc
def opts(request, prefix, global_parameters): opts = PETSc.Options() if prefix is None: prefix = "" for k, v in global_parameters.items(): opts[prefix + k] = v # Pretend these came from the commandline OptionsManager.commandline_options = frozenset(opts.getAll()) def finalize(): for k in global_parameters.keys(): del opts[prefix + k] # And remove again OptionsManager.commandline_options = frozenset(opts.getAll()) request.addfinalizer(finalize)
def update_parameters(obj, petsc_obj): """Update parameters on a petsc object :arg obj: An object with a parameters dict (mapping to petsc options). :arg petsc_obj: The PETSc object to set parameters on.""" # Skip if parameters haven't changed if hasattr(obj, '_set_parameters') and obj.parameters == obj._set_parameters: return opts = PETSc.Options(obj._opt_prefix) for k, v in obj.parameters.iteritems(): if type(v) is bool: if v: opts[k] = None else: opts[k] = v petsc_obj.setFromOptions() obj._set_parameters = obj.parameters.copy()
def solve(ctx, state): out_file = File(solution_out) if solution_out else None mass = state["mass"] hats = state["hats"] u = ctx[2]["u"] u0 = ctx[2]["u0"] solver = ctx[1] from firedrake.petsc import PETSc ksp_hats = PETSc.KSP() ksp_hats.create() ksp_hats.setOperators(hats) opts = PETSc.Options() opts['ksp_type'] = inner_ksp opts['ksp_max_it'] = max_iterations opts['pc_type'] = 'hypre' ksp_hats.setFromOptions() class SchurInv(object): def mult(self, mat, x, y): tmp1 = y.duplicate() tmp2 = y.duplicate() ksp_hats.solve(x, tmp1) mass.mult(tmp1, tmp2) ksp_hats.solve(tmp2, y) pc_schur = PETSc.Mat() pc_schur.createPython(mass.getSizes(), SchurInv()) pc_schur.setUp() pc = solver.snes.ksp.pc pc.setFieldSplitSchurPreType(PETSc.PC.SchurPreType.USER, pc_schur) for step in range(steps): casper.invoke_task(ctx, "assign", state) solver.solve() if out_file is not None: out_file.write(u.split()[0], time=step) if compute_norms: nu = norm(u) if comm.rank == 0: print(step, 'L2(u):', nu)
def get_patches(self, V): mesh = V._mesh mesh_dm = mesh.topology_dm if mesh.layers: warning("applying ASMStarPC on an extruded mesh") # Obtain the topological entities to use to construct the stars depth = PETSc.Options().getInt(self.prefix+"construct_dim", default=0) # Accessing .indices causes the allocation of a global array, # so we need to cache these for efficiency V_local_ises_indices = [] for (i, W) in enumerate(V): V_local_ises_indices.append(V.dof_dset.local_ises[i].indices) # Build index sets for the patches ises = [] (start, end) = mesh_dm.getDepthStratum(depth) for seed in range(start, end): # Only build patches over owned DoFs if mesh_dm.getLabelValue("pyop2_ghost", seed) != -1: continue # Create point list from mesh DM pt_array, _ = mesh_dm.getTransitiveClosure(seed, useCone=False) # Get DoF indices for patch indices = [] for (i, W) in enumerate(V): section = W.dm.getDefaultSection() for p in pt_array.tolist(): dof = section.getDof(p) if dof <= 0: continue off = section.getOffset(p) # Local indices within W W_indices = numpy.arange(off*W.value_size, W.value_size * (off + dof), dtype=IntType) indices.extend(V_local_ises_indices[i][W_indices]) iset = PETSc.IS().createGeneral(indices, comm=COMM_SELF) ises.append(iset) return ises
def test_options_database_cleared(): opts = PETSc.Options() expect = len(opts.getAll()) mesh = UnitIntervalMesh(1) V = FunctionSpace(mesh, "DG", 0) u = TrialFunction(V) v = TestFunction(V) A = assemble(inner(u, v) * dx) b = assemble(conj(v) * dx) u = Function(V) solvers = [] for i in range(100): solver = LinearSolver(A, solver_parameters={ "ksp_type": "preonly", "pc_type": "lu" }) solver.solve(u, b) solvers.append(solver) assert expect == len(opts.getAll())
def assembleK(self): ctx = self.ctx mat_type = PETSc.Options().getString( self.prefix + "assembled_mat_type", "aij") self.K = allocate_matrix(ctx.a, bcs=ctx.row_bcs, form_compiler_parameters=ctx.fc_params, mat_type=mat_type) self._assemble_K = create_assembly_callable( ctx.a, tensor=self.K, bcs=ctx.row_bcs, form_compiler_parameters=ctx.fc_params, mat_type=mat_type) self._assemble_K() self.mat_type = mat_type self.K.force_evaluation()
def _retrieve_options(self, pc): get_option = lambda key: PETSc.Options(self.prefix).getString( key, default="") # Get options for Schur complement decomposition self._check_options([("ksp_type", {"preonly"}), ("pc_type", {"fieldsplit"}), ("pc_fieldsplit_type", {"schur"})]) self.nested = (get_option("ksp_type") == "preonly" and get_option("pc_type") == "fieldsplit" and get_option("pc_fieldsplit_type") == "schur") # Get preconditioning options for A00 fs0, fs1 = ("fieldsplit_" + str(idx) for idx in (self.vidx, self.pidx)) self._check_options([(fs0 + "ksp_type", {"preonly", "default"}), (fs0 + "pc_type", {"jacobi"})]) self.preonly_A00 = get_option(fs0 + "_ksp_type") == "preonly" self.jacobi_A00 = get_option(fs0 + "_pc_type") == "jacobi" # Get preconditioning options for the Schur complement self._check_options([(fs1 + "ksp_type", {"preonly", "default"}), (fs1 + "pc_type", {"jacobi", "python"})]) self.preonly_S = get_option(fs1 + "_ksp_type") == "preonly" self.jacobi_S = get_option(fs1 + "_pc_type") == "jacobi" # Get user supplied operator and its options self.schur_approx = (self.retrieve_user_S_approx( pc, get_option(fs1 + "_pc_python_type")) if get_option(fs1 + "_pc_type") == "python" else None) self._check_options([(fs1 + "aux_ksp_type", {"preonly", "default"}), (fs1 + "aux_pc_type", {"jacobi"})]) self.preonly_Shat = get_option(fs1 + "_aux_ksp_type") == "preonly" self.jacobi_Shat = get_option(fs1 + "_aux_pc_type") == "jacobi" if self.jacobi_Shat or self.jacobi_A00: assert parameters["slate_compiler"]["optimise"], ( "Local systems should only get preconditioned with " "a preconditioning matrix if the Slate optimiser replaces " "inverses by solves.")
def transfer_manager(self): """This allows the transfer manager to be set from options, e.g. solver_parameters = {"ksp_type": "cg", "pc_type": "mg", "mg_transfer_manager": __name__ + ".manager"} The value for "mg_transfer_manager" can either be a specific instantiated object, or a function or class name. In the latter case it will be invoked with no arguments to instantiate the object. If "snes_type": "fas" is used, the relevant option is "fas_transfer_manager", with the same semantics. """ if self._transfer_manager is None: opts = PETSc.Options() prefix = self.options_prefix or "" if opts.hasName(prefix + "mg_transfer_manager"): managername = opts[prefix + "mg_transfer_manager"] elif opts.hasName(prefix + "fas_transfer_manager"): managername = opts[prefix + "fas_transfer_manager"] else: managername = None if managername is None: from firedrake import TransferManager transfer = TransferManager(use_averaging=True) else: (modname, objname) = managername.rsplit(".", 1) mod = __import__(modname) obj = getattr(mod, objname) if isinstance(obj, type): transfer = obj() else: transfer = obj self._transfer_manager = transfer return self._transfer_manager