def _finalize_kernels_and_update(self): """Prepares the kernel AST by transforming all outpute/input references to Slate tensors with eigen references and updates any orientation information. """ kernel_list = [] transformer = Transformer() oriented = self.oriented cxt_kernels = self.context_kernels splitkernels = [ splitkernel for cxt_k in cxt_kernels for splitkernel in cxt_k.tsfc_kernels ] for splitkernel in splitkernels: oriented = oriented or splitkernel.kinfo.oriented # TODO: Extend multiple domains support assert splitkernel.kinfo.subdomain_id == "otherwise" kast = transformer.visit(splitkernel.kinfo.kernel._ast) kernel_list.append(kast) self.oriented = oriented self.finalized_ast = kernel_list self._is_finalized = True
def construct_ast(self, name, args, statements): """Constructs the full kernel AST of a given SLATE expression. The :class:`Transformer` is used to perform the conversion from standard C into the Eigen C++ template library syntax. :arg name: a string denoting the name of the macro kernel. :arg args: a list of arguments for the macro_kernel. :arg statements: a `coffee.base.Block` of instructions, which contains declarations of temporaries, function calls to all subkernels and any auxilliary information needed to evaulate the SLATE expression. E.g. facet integral loops and action loops. Returns: the full kernel AST to be converted into a PyOP2 kernel, as well as any orientation information. """ # all kernel body statements must be wrapped up as a coffee.base.Block assert isinstance(statements, ast.Block) macro_kernel = ast.FunDecl("void", name, args, statements, pred=["static", "inline"]) kernel_list = [] transformer = Transformer() oriented = False # Assume self.kernel_exprs is populated at this point for kernel_items in self.kernel_exprs.values(): for ks in kernel_items: oriented = oriented or ks.kinfo.oriented # TODO: Extend multiple domains support assert ks.kinfo.subdomain_id == "otherwise" kast = transformer.visit(ks.kinfo.kernel._ast) kernel_list.append(kast) kernel_list.append(macro_kernel) return ast.Node(kernel_list), oriented
def construct_ast(self, name, args, statements): """Constructs the full kernel AST of a given SLATE expression. The :class:`Transformer` is used to perform the conversion from standard C into the Eigen C++ template library syntax. :arg name: a string denoting the name of the macro kernel. :arg args: a list of arguments for the macro_kernel. :arg statements: a `coffee.base.Block` of instructions, which contains declarations of temporaries, function calls to all subkernels and any auxilliary information needed to evaulate the SLATE expression. E.g. facet integral loops and action loops. Returns: the full kernel AST to be converted into a PyOP2 kernel, as well as any orientation information. """ # all kernel body statements must be wrapped up as a coffee.base.Block assert isinstance(statements, ast.Block) macro_kernel = ast.FunDecl("void", name, args, statements, pred=["static", "inline"]) kernel_list = [] transformer = Transformer() oriented = False # Assume self.kernel_exprs is populated at this point for kernel_items in self.kernel_exprs.values(): for ks in kernel_items: oriented = oriented or ks.kinfo.oriented # TODO: Extend multiple domains support assert ks.kinfo.subdomain_id == "otherwise" kast = transformer.visit(ks.kinfo.kernel._ast) kernel_list.append(kast) kernel_list.append(macro_kernel) return ast.Node(kernel_list), oriented
def _setup(self): """A setup method to initialize all the local assembly kernels generated by TSFC and creates templated function calls conforming to the Eigen-C++ template library standard. This function also collects any information regarding orientations and extra include directories. """ transformer = Transformer() include_dirs = [] templated_subkernels = [] assembly_calls = OrderedDict([(it, []) for it in self.supported_integral_types]) coords = None oriented = False for cxt_kernel in self.context_kernels: local_coefficients = cxt_kernel.coefficients it_type = cxt_kernel.original_integral_type exp = cxt_kernel.tensor if it_type not in self.supported_integral_types: raise ValueError("Integral type '%s' not recognized" % it_type) # Explicit checking of coordinates coordinates = cxt_kernel.tensor.ufl_domain().coordinates if coords is not None: assert coordinates == coords, "Mismatching coordinates!" else: coords = coordinates for split_kernel in cxt_kernel.tsfc_kernels: indices = split_kernel.indices kinfo = split_kernel.kinfo # TODO: Implement subdomains for Slate tensors if kinfo.subdomain_id != "otherwise": raise NotImplementedError("Subdomains not implemented.") args = [ c for i in kinfo.coefficient_map for c in self.coefficient(local_coefficients[i]) ] if kinfo.oriented: args.insert(0, self.cell_orientations_sym) if kinfo.integral_type in [ "interior_facet", "exterior_facet", "interior_facet_vert", "exterior_facet_vert" ]: args.append(ast.FlatBlock("&%s" % self.it_sym)) # Assembly calls within the macro kernel tensor = eigen_tensor(exp, self.temps[exp], indices) call = ast.FunCall(kinfo.kernel.name, tensor, self.coord_sym, *args) assembly_calls[it_type].append(call) # Subkernels for local assembly (Eigen templated functions) kast = transformer.visit(kinfo.kernel._ast) templated_subkernels.append(kast) include_dirs.extend(kinfo.kernel._include_dirs) oriented = oriented or kinfo.oriented self.assembly_calls = assembly_calls self.templated_subkernels = templated_subkernels self.include_dirs = list(set(include_dirs)) self.oriented = oriented
def _setup(self): """A setup method to initialize all the local assembly kernels generated by TSFC and creates templated function calls conforming to the Eigen-C++ template library standard. This function also collects any information regarding orientations and extra include directories. """ transformer = Transformer() include_dirs = [] templated_subkernels = [] assembly_calls = OrderedDict([(it, []) for it in self.supported_integral_types]) subdomain_calls = OrderedDict([(sd, []) for sd in self.supported_subdomain_types]) coords = None oriented = False needs_cell_sizes = False # Maps integral type to subdomain key subdomain_map = {"exterior_facet": "subdomains_exterior_facet", "exterior_facet_vert": "subdomains_exterior_facet", "interior_facet": "subdomains_interior_facet", "interior_facet_vert": "subdomains_interior_facet"} for cxt_kernel in self.context_kernels: local_coefficients = cxt_kernel.coefficients it_type = cxt_kernel.original_integral_type exp = cxt_kernel.tensor if it_type not in self.supported_integral_types: raise ValueError("Integral type '%s' not recognized" % it_type) # Explicit checking of coordinates coordinates = cxt_kernel.tensor.ufl_domain().coordinates if coords is not None: assert coordinates == coords, "Mismatching coordinates!" else: coords = coordinates for split_kernel in cxt_kernel.tsfc_kernels: indices = split_kernel.indices kinfo = split_kernel.kinfo kint_type = kinfo.integral_type needs_cell_sizes = needs_cell_sizes or kinfo.needs_cell_sizes args = [c for i in kinfo.coefficient_map for c in self.coefficient(local_coefficients[i])] if kinfo.oriented: args.insert(0, self.cell_orientations_sym) if kint_type in ["interior_facet", "exterior_facet", "interior_facet_vert", "exterior_facet_vert"]: args.append(ast.FlatBlock("&%s" % self.it_sym)) if kinfo.needs_cell_sizes: args.append(self.cell_size_sym) # Assembly calls within the macro kernel tensor = eigen_tensor(exp, self.temps[exp], indices) call = ast.FunCall(kinfo.kernel.name, tensor, self.coord_sym, *args) # Subdomains only implemented for exterior facet integrals if kinfo.subdomain_id != "otherwise": if kint_type not in subdomain_map: msg = "Subdomains for integral type '%s' not implemented" % kint_type raise NotImplementedError(msg) sd_id = kinfo.subdomain_id sd_key = subdomain_map[kint_type] subdomain_calls[sd_key].append((sd_id, call)) else: assembly_calls[it_type].append(call) # Subkernels for local assembly (Eigen templated functions) from coffee.base import Node assert isinstance(kinfo.kernel._code, Node) kast = transformer.visit(kinfo.kernel._code) templated_subkernels.append(kast) include_dirs.extend(kinfo.kernel._include_dirs) oriented = oriented or kinfo.oriented # Add subdomain call to assembly dict assembly_calls.update(subdomain_calls) self.assembly_calls = assembly_calls self.templated_subkernels = templated_subkernels self.include_dirs = list(set(include_dirs)) self.oriented = oriented self.needs_cell_sizes = needs_cell_sizes
def _setup(self): """A setup method to initialize all the local assembly kernels generated by TSFC and creates templated function calls conforming to the Eigen-C++ template library standard. This function also collects any information regarding orientations and extra include directories. """ transformer = Transformer() include_dirs = [] templated_subkernels = [] assembly_calls = OrderedDict([(it, []) for it in self.supported_integral_types]) subdomain_calls = OrderedDict([(sd, []) for sd in self.supported_subdomain_types]) coords = None oriented = False needs_cell_sizes = False # Maps integral type to subdomain key subdomain_map = {"exterior_facet": "subdomains_exterior_facet", "exterior_facet_vert": "subdomains_exterior_facet", "interior_facet": "subdomains_interior_facet", "interior_facet_vert": "subdomains_interior_facet"} for cxt_kernel in self.context_kernels: local_coefficients = cxt_kernel.coefficients it_type = cxt_kernel.original_integral_type exp = cxt_kernel.tensor if it_type not in self.supported_integral_types: raise ValueError("Integral type '%s' not recognized" % it_type) # Explicit checking of coordinates coordinates = cxt_kernel.tensor.ufl_domain().coordinates if coords is not None: assert coordinates == coords, "Mismatching coordinates!" else: coords = coordinates for split_kernel in cxt_kernel.tsfc_kernels: indices = split_kernel.indices kinfo = split_kernel.kinfo kint_type = kinfo.integral_type needs_cell_sizes = needs_cell_sizes or kinfo.needs_cell_sizes args = [c for i in kinfo.coefficient_map for c in self.coefficient(local_coefficients[i])] if kinfo.oriented: args.insert(0, self.cell_orientations_sym) if kint_type in ["interior_facet", "exterior_facet", "interior_facet_vert", "exterior_facet_vert"]: args.append(ast.FlatBlock("&%s" % self.it_sym)) if kinfo.needs_cell_sizes: args.append(self.cell_size_sym) # Assembly calls within the macro kernel tensor = eigen_tensor(exp, self.temps[exp], indices) call = ast.FunCall(kinfo.kernel.name, tensor, self.coord_sym, *args) # Subdomains only implemented for exterior facet integrals if kinfo.subdomain_id != "otherwise": if kint_type not in subdomain_map: msg = "Subdomains for integral type '%s' not implemented" % kint_type raise NotImplementedError(msg) sd_id = kinfo.subdomain_id sd_key = subdomain_map[kint_type] subdomain_calls[sd_key].append((sd_id, call)) else: assembly_calls[it_type].append(call) # Subkernels for local assembly (Eigen templated functions) from coffee.base import Node assert isinstance(kinfo.kernel._code, Node) kast = transformer.visit(kinfo.kernel._code) templated_subkernels.append(kast) include_dirs.extend(kinfo.kernel._include_dirs) oriented = oriented or kinfo.oriented # Add subdomain call to assembly dict assembly_calls.update(subdomain_calls) self.assembly_calls = assembly_calls self.templated_subkernels = templated_subkernels self.include_dirs = list(set(include_dirs)) self.oriented = oriented self.needs_cell_sizes = needs_cell_sizes