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 pick_mode(mode): "Return one of the specialized optimisation modules from a mode string." try: from firedrake_citations import Citations cites = { "vanilla": ("Homolya2017", ), "coffee": ( "Luporini2016", "Homolya2017", ), "spectral": ("Luporini2016", "Homolya2017", "Homolya2017a"), "tensor": ( "Kirby2006", "Homolya2017", ) } for c in cites[mode]: Citations().register(c) except ImportError: pass if mode == "vanilla": import tsfc.vanilla as m elif mode == "coffee": import tsfc.coffee_mode as m elif mode == "spectral": import tsfc.spectral as m elif mode == "tensor": import tsfc.tensor as m else: raise ValueError("Unknown mode: {}".format(mode)) return m
def update_citations(params): """Update citations list for known COFFEE users.""" # Firedrake try: from firedrake_citations import Citations rewrite = params.get('rewrite', 0) nozeros = params.get('dead_ops_elimination', False) align_pad = params.get('align_pad', False) vectorize = params.get('vectorize', False) split = params.get('split', False) if rewrite == 1 or align_pad or vectorize or split: Citations().register('Luporini2015') if rewrite > 1 or nozeros: Citations().register('Luporini2016') except ImportError: pass
def __init__(self, meshes, coarse_to_fine_cells, fine_to_coarse_cells): from firedrake_citations import Citations Citations().register("Mitchell2016") self.meshes = tuple(meshes) self.coarse_to_fine_cells = tuple(coarse_to_fine_cells) self.fine_to_coarse_cells = tuple(fine_to_coarse_cells) for level, m in enumerate(self): set_level(m, self, level) self._shared_data_cache = defaultdict(dict)
def generate_loopy_kernel(slate_expr, tsfc_parameters=None): cpu_time = time.time() if len(slate_expr.ufl_domains()) > 1: raise NotImplementedError("Multiple domains not implemented.") Citations().register("Gibson2018") # Create a loopy builder for the Slate expression, # e.g. contains the loopy kernels coming from TSFC gem_expr, var2terminal = slate_to_gem(slate_expr) scalar_type = tsfc_parameters["scalar_type"] slate_loopy, output_arg = gem_to_loopy(gem_expr, var2terminal, scalar_type) builder = LocalLoopyKernelBuilder(expression=slate_expr, tsfc_parameters=tsfc_parameters) loopy_merged = merge_loopy(slate_loopy, output_arg, builder, var2terminal) loopy_merged = loopy.register_function_id_to_in_knl_callable_mapper( loopy_merged, inv_fn_lookup) loopy_merged = loopy.register_function_id_to_in_knl_callable_mapper( loopy_merged, solve_fn_lookup) # WORKAROUND: Generate code directly from the loopy kernel here, # then attach code as a c-string to the op2kernel code = loopy.generate_code_v2(loopy_merged).device_code() code = code.replace(f'void {loopy_merged.name}', f'static void {loopy_merged.name}') loopykernel = op2.Kernel(code, loopy_merged.name, include_dirs=BLASLAPACK_INCLUDE.split(), ldargs=BLASLAPACK_LIB.split()) kinfo = KernelInfo( kernel=loopykernel, integral_type= "cell", # slate can only do things as contributions to the cell integrals oriented=builder.bag.needs_cell_orientations, subdomain_id="otherwise", domain_number=0, coefficient_map=tuple(range(len(slate_expr.coefficients()))), needs_cell_facets=builder.bag.needs_cell_facets, pass_layer_arg=builder.bag.needs_mesh_layers, needs_cell_sizes=builder.bag.needs_cell_sizes) # Cache the resulting kernel # Slate kernels are never split, so indicate that with None in the index slot. idx = tuple([None] * slate_expr.rank) logger.info(GREEN % "compile_slate_expression finished in %g seconds.", time.time() - cpu_time) return (SplitKernel(idx, kinfo), )
def __init__(self, meshes, coarse_to_fine_cells, fine_to_coarse_cells, refinements_per_level=1): from firedrake_citations import Citations Citations().register("Mitchell2016") self._meshes = tuple(meshes) self.meshes = tuple(meshes[::refinements_per_level]) self.coarse_to_fine_cells = coarse_to_fine_cells self.fine_to_coarse_cells = fine_to_coarse_cells self.refinements_per_level = refinements_per_level for level, m in enumerate(meshes): set_level(m, self, Fraction(level, refinements_per_level)) for level, m in enumerate(self): set_level(m, self, level) self._shared_data_cache = defaultdict(dict)
def __init__(self): """Create a PC context suitable for PETSc. Matrix free preconditioners should inherit from this class and implement: - :meth:`initialize` - :meth:`update` - :meth:`apply` - :meth:`applyTranspose` """ Citations().register("Kirby2017") self.initialized = False super(PCBase, self).__init__()
def generate_loopy_kernel(slate_expr, tsfc_parameters=None): cpu_time = time.time() if len(slate_expr.ufl_domains()) > 1: raise NotImplementedError("Multiple domains not implemented.") Citations().register("Gibson2018") # Create a loopy builder for the Slate expression, # e.g. contains the loopy kernels coming from TSFC gem_expr, var2terminal = slate_to_gem(slate_expr) scalar_type = tsfc_parameters["scalar_type"] slate_loopy, output_arg = gem_to_loopy(gem_expr, var2terminal, scalar_type) builder = LocalLoopyKernelBuilder(expression=slate_expr, tsfc_parameters=tsfc_parameters) name = "slate_wrapper" loopy_merged = merge_loopy(slate_loopy, output_arg, builder, var2terminal, name) loopy_merged = loopy.register_callable(loopy_merged, INVCallable.name, INVCallable()) loopy_merged = loopy.register_callable(loopy_merged, SolveCallable.name, SolveCallable()) loopykernel = op2.Kernel(loopy_merged, name, include_dirs=BLASLAPACK_INCLUDE.split(), ldargs=BLASLAPACK_LIB.split()) kinfo = KernelInfo( kernel=loopykernel, integral_type= "cell", # slate can only do things as contributions to the cell integrals oriented=builder.bag.needs_cell_orientations, subdomain_id="otherwise", domain_number=0, coefficient_map=tuple(range(len(slate_expr.coefficients()))), needs_cell_facets=builder.bag.needs_cell_facets, pass_layer_arg=builder.bag.needs_mesh_layers, needs_cell_sizes=builder.bag.needs_cell_sizes) # Cache the resulting kernel # Slate kernels are never split, so indicate that with None in the index slot. idx = tuple([None] * slate_expr.rank) logger.info(GREEN % "compile_slate_expression finished in %g seconds.", time.time() - cpu_time) return (SplitKernel(idx, kinfo), )
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 generate_kernel(slate_expr, tsfc_parameters=None): cpu_time = time.time() # TODO: Get PyOP2 to write into mixed dats if slate_expr.is_mixed: raise NotImplementedError("Compiling mixed slate expressions") if len(slate_expr.ufl_domains()) > 1: raise NotImplementedError("Multiple domains not implemented.") Citations().register("Gibson2018") # Create a builder for the Slate expression builder = LocalKernelBuilder(expression=slate_expr, tsfc_parameters=tsfc_parameters) # Keep track of declared temporaries declared_temps = {} statements = [] # Declare terminal tensor temporaries terminal_declarations = terminal_temporaries(builder, declared_temps) statements.extend(terminal_declarations) # Generate assembly calls for tensor assembly subkernel_calls = tensor_assembly_calls(builder) statements.extend(subkernel_calls) # Create coefficient temporaries if necessary if builder.coefficient_vecs: coefficient_temps = coefficient_temporaries(builder, declared_temps) statements.extend(coefficient_temps) # Create auxiliary temporaries/expressions (if necessary) statements.extend(auxiliary_expressions(builder, declared_temps)) # Generate the kernel information with complete AST kinfo = generate_kernel_ast(builder, statements, declared_temps) # Cache the resulting kernel idx = tuple([0] * slate_expr.rank) logger.info(GREEN % "compile_slate_expression finished in %g seconds.", time.time() - cpu_time) return (SplitKernel(idx, kinfo), )
import gem from gem.utils import cached_property from finat.finiteelementbase import FiniteElementBase from finat.point_set import PointSet from finat.sympy2gem import sympy2gem try: from firedrake_citations import Citations Citations().add( "Geevers2018new", """ @article{Geevers2018new, title={New higher-order mass-lumped tetrahedral elements for wave propagation modelling}, author={Geevers, Sjoerd and Mulder, Wim A and van der Vegt, Jaap JW}, journal={SIAM journal on scientific computing}, volume={40}, number={5}, pages={A2830--A2857}, year={2018}, publisher={SIAM}, doi={https://doi.org/10.1137/18M1175549}, } """) Citations().add( "Chin1999higher", """ @article{chin1999higher, title={Higher-order triangular and tetrahedral finite elements with mass lumping for solving the wave equation}, author={Chin-Joe-Kong, MJS and Mulder, Wim A and Van Veldhuizen, M}, journal={Journal of Engineering Mathematics}, volume={35}, number={4}, pages={405--426},
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if Citations is not None: Citations().register("Kirby2018zany") Citations().register("Kirby2019zany")
import gem from abc import ABCMeta, abstractmethod try: from firedrake_citations import Citations Citations().add( "Kirby2018zany", """ @Article{Kirby2018zany, author = {Robert C. Kirby}, title = {A general approach to transforming finite elements}, journal = {SMAI Journal of Computational Mathematics}, year = 2018, volume = 4, pages = {197-224}, doi = {10.5802/smai-jcm.33}, archiveprefix ={arXiv}, eprint = {1706.09017}, primaryclass = {math.NA} } """) Citations().add( "Kirby2019zany", """ @Article{Kirby:2019, author = {Robert C. Kirby and Lawrence Mitchell}, title = {Code generation for generally mapped finite elements}, journal = {ACM Transactions on Mathematical Software}, year = 2019, volume = 45, number = 41, pages = {41:1--41:23},
# # To get around this, since the default __del__ on Expr is just # "pass", we just remove the method from the definition of Expr. import ufl try: del ufl.core.expr.Expr.__del__ except AttributeError: pass del ufl from ufl import * # Set up the cache directories before importing PyOP2. firedrake_configuration.setup_cache_dirs() from firedrake_citations import Citations # noqa: F401 # Always get the firedrake paper. Citations().register("Rathgeber2016") from pyop2 import op2 # noqa: F401 from pyop2.mpi import COMM_WORLD, COMM_SELF # noqa: F401 from firedrake.assemble import * from firedrake.bcs import * from firedrake.checkpointing import * from firedrake.constant import * from firedrake.exceptions import * from firedrake.expression import * from firedrake.function import * from firedrake.functionspace import * from firedrake.interpolation import * from firedrake.output import * from firedrake.linear_solver import * from firedrake.matrix_free.preconditioners import *
def __init__(self, cell, degree): super(KongMulderVeldhuizen, self).__init__(FIAT.KongMulderVeldhuizen(cell, degree)) if Citations is not None: Citations().register("Chin1999higher") Citations().register("Geevers2018new")
def compile_expression(slate_expr, tsfc_parameters=None): """Takes a Slate expression `slate_expr` and returns the appropriate :class:`firedrake.op2.Kernel` object representing the Slate expression. :arg slate_expr: a :class:'TensorBase' expression. :arg tsfc_parameters: an optional `dict` of form compiler parameters to be passed to TSFC during the compilation of ufl forms. Returns: A `tuple` containing a `SplitKernel(idx, kinfo)` """ if not isinstance(slate_expr, slate.TensorBase): raise ValueError("Expecting a `TensorBase` object, not %s" % type(slate_expr)) # If the expression has already been symbolically compiled, then # simply reuse the produced kernel. if slate_expr._metakernel_cache is not None: return slate_expr._metakernel_cache # TODO: Get PyOP2 to write into mixed dats if slate_expr.is_mixed: raise NotImplementedError("Compiling mixed slate expressions") if len(slate_expr.ufl_domains()) > 1: raise NotImplementedError("Multiple domains not implemented.") Citations().register("Gibson2018") # Create a builder for the Slate expression builder = LocalKernelBuilder(expression=slate_expr, tsfc_parameters=tsfc_parameters) # Keep track of declared temporaries declared_temps = {} statements = [] # Declare terminal tensor temporaries terminal_declarations = terminal_temporaries(builder, declared_temps) statements.extend(terminal_declarations) # Generate assembly calls for tensor assembly subkernel_calls = tensor_assembly_calls(builder) statements.extend(subkernel_calls) # Create coefficient temporaries if necessary if builder.coefficient_vecs: coefficient_temps = coefficient_temporaries(builder, declared_temps) statements.extend(coefficient_temps) # Create auxiliary temporaries/expressions (if necessary) statements.extend(auxiliary_expressions(builder, declared_temps)) # Generate the kernel information with complete AST kinfo = generate_kernel_ast(builder, statements, declared_temps) # Cache the resulting kernel idx = tuple([0] * slate_expr.rank) kernel = (SplitKernel(idx, kinfo), ) slate_expr._metakernel_cache = kernel return kernel
from tsfc.driver import compile_form, compile_expression_at_points # noqa: F401 from tsfc.parameters import default_parameters # noqa: F401 try: from firedrake_citations import Citations Citations().add("Kirby2006", """ @Article{Kirby2006, author = {Kirby, Robert C. and Logg, Anders}, title = {A Compiler for Variational Forms}, journal = {ACM Trans. Math. Softw.}, year = 2006, volume = 32, number = 3, pages = {417--444}, month = sep, numpages = 28, doi = {10.1145/1163641.1163644}, acmid = 1163644, }""") del Citations except ImportError: pass
def __init__(self, m, refinement_levels, refinements_per_level=1, reorder=None): """Build a hierarchy of meshes by uniformly refining a coarse mesh. :arg m: the coarse :func:`~.Mesh` to refine :arg refinement_levels: the number of levels of refinement :arg refinements_per_level: Optional number of refinements per level in the resulting hierarchy. Note that the intermediate meshes are still kept, but iteration over the mesh hierarchy skips them. :arg reorder: optional flag indicating whether to reorder the refined meshes. """ from firedrake_citations import Citations Citations().register("Mitchell2016") if m.ufl_cell().cellname() not in ["triangle", "interval"]: raise NotImplementedError( "Only supported on intervals and triangles") if refinements_per_level < 1: raise ValueError( "Must provide positive number of refinements per level") m._plex.setRefinementUniform(True) dm_hierarchy = [] cdm = m._plex self.comm = m.comm fpoint_ises = [] if m.comm.size > 1 and m._grown_halos: raise RuntimeError( "Cannot refine parallel overlapped meshes (make sure the MeshHierarchy is built immediately after the Mesh)" ) for i in range(refinement_levels * refinements_per_level): rdm = cdm.refine() fpoint_ises.append(cdm.createCoarsePointIS()) # Remove interior facet label (re-construct from # complement of exterior facets). Necessary because the # refinement just marks points "underneath" the refined # facet with the appropriate label. This works for # exterior, but not marked interior facets rdm.removeLabel("interior_facets") # Remove vertex (and edge) points from labels on exterior # facets. Interior facets will be relabeled in Mesh # construction below. impl.filter_exterior_facet_labels(rdm) rdm.removeLabel("pyop2_core") rdm.removeLabel("pyop2_owned") rdm.removeLabel("pyop2_ghost") dm_hierarchy.append(rdm) cdm = rdm # Fix up coords if refining embedded circle or sphere if hasattr(m, '_radius'): # FIXME, really we need some CAD-like representation # of the boundary we're trying to conform to. This # doesn't DTRT really for cubed sphere meshes (the # refined meshes are no longer gnonomic). coords = cdm.getCoordinatesLocal().array.reshape( -1, m.geometric_dimension()) scale = m._radius / np.linalg.norm(coords, axis=1).reshape( -1, 1) coords *= scale hierarchy = [m] + [ mesh.Mesh(dm, dim=m.ufl_cell().geometric_dimension(), distribute=False, reorder=reorder) for i, dm in enumerate(dm_hierarchy) ] for m in hierarchy: m._non_overlapped_lgmap = impl.create_lgmap(m._plex) m._non_overlapped_nent = [] for d in range(m._plex.getDimension() + 1): m._non_overlapped_nent.append(m._plex.getDepthStratum(d)) m.init() m._overlapped_lgmap = impl.create_lgmap(m._plex) # On coarse mesh n, a map of consistent cell orientations and # vertex permutations for the fine cells on each coarse cell. self._cells_vperm = [] for mc, mf, fpointis in zip(hierarchy[:-1], hierarchy[1:], fpoint_ises): mc._fpointIS = fpointis c2f = impl.coarse_to_fine_cells(mc, mf) P1c = functionspace.FunctionSpace(mc, 'CG', 1) P1f = functionspace.FunctionSpace(mf, 'CG', 1) self._cells_vperm.append(impl.compute_orientations(P1c, P1f, c2f)) self._hierarchy = tuple(hierarchy[::refinements_per_level]) self._unskipped_hierarchy = tuple(hierarchy) for level, m in enumerate(self): set_level(m, self, level) # Attach fractional levels to skipped parts # This allows us to do magic under the hood so that multigrid # on skipping hierarchies still works! for level, m in enumerate(hierarchy): if level % refinements_per_level == 0: continue set_level(m, self, Fraction(level, refinements_per_level)) self.refinements_per_level = refinements_per_level