def prepare_coefficient(coefficient, num, name, interior_facet=False): """Bridges the kernel interface and the GEM abstraction for Coefficients. :arg coefficient: UFL Coefficient :arg num: coefficient index in the original form :arg name: unique name to refer to the Coefficient in the kernel :arg interior_facet: interior facet integral? :returns: GEM expression referring to the Coefficient value """ varexp = gem.Variable(name, (None, None)) if coefficient.ufl_element().family() == 'Real': size = numpy.prod(coefficient.ufl_shape, dtype=int) data = gem.view(varexp, slice(num, num + 1), slice(size)) return gem.reshape(data, (), coefficient.ufl_shape) element = create_element(coefficient.ufl_element()) size = numpy.prod(element.index_shape, dtype=int) def expression(data): result, = prune( [gem.reshape(gem.view(data, slice(size)), element.index_shape)]) return result if not interior_facet: data = gem.view(varexp, slice(num, num + 1), slice(size)) return expression(gem.reshape(data, (), (size, ))) else: data_p = gem.view(varexp, slice(num, num + 1), slice(size)) data_m = gem.view(varexp, slice(num, num + 1), slice(size, 2 * size)) return (expression(gem.reshape(data_p, (), (size, ))), expression(gem.reshape(data_m, (), (size, ))))
def prepare_coefficient(coefficient, num, name, interior_facet=False): """Bridges the kernel interface and the GEM abstraction for Coefficients. :arg coefficient: UFL Coefficient :arg num: coefficient index in the original form :arg name: unique name to refer to the Coefficient in the kernel :arg interior_facet: interior facet integral? :returns: GEM expression referring to the Coefficient value """ varexp = gem.Variable(name, (None, None)) if coefficient.ufl_element().family() == 'Real': size = numpy.prod(coefficient.ufl_shape, dtype=int) data = gem.view(varexp, slice(num, num + 1), slice(size)) return gem.reshape(data, (), coefficient.ufl_shape) element = create_element(coefficient.ufl_element()) size = numpy.prod(element.index_shape, dtype=int) def expression(data): result, = prune([gem.reshape(gem.view(data, slice(size)), element.index_shape)]) return result if not interior_facet: data = gem.view(varexp, slice(num, num + 1), slice(size)) return expression(gem.reshape(data, (), (size,))) else: data_p = gem.view(varexp, slice(num, num + 1), slice(size)) data_m = gem.view(varexp, slice(num, num + 1), slice(size, 2 * size)) return (expression(gem.reshape(data_p, (), (size,))), expression(gem.reshape(data_m, (), (size,))))
def test_view_view(matrix): expression = gem.view(gem.view(matrix, slice(3, 8), slice(5, 12)), slice(4), slice(3, 6)) assert expression.shape == (4, 3) actual = [convert(expression, multiindex) for multiindex in numpy.ndindex(expression.shape)] assert list(product(range(3, 7), range(8, 11))) == actual
def prepare_coefficient(coefficient, name, interior_facet=False): """Bridges the kernel interface and the GEM abstraction for Coefficients. :arg coefficient: UFL Coefficient :arg name: unique name to refer to the Coefficient in the kernel :arg interior_facet: interior facet integral? :returns: (funarg, expression) funarg - :class:`coffee.Decl` function argument expression - GEM expression referring to the Coefficient values """ assert isinstance(interior_facet, bool) if coefficient.ufl_element().family() == 'Real': # Constant funarg = coffee.Decl(SCALAR_TYPE, coffee.Symbol(name), pointers=[("restrict", )], qualifiers=["const"]) expression = gem.reshape(gem.Variable(name, (None, )), coefficient.ufl_shape) return funarg, expression finat_element = create_element(coefficient.ufl_element()) if isinstance(finat_element, TensorFiniteElement): scalar_shape = finat_element.base_element.index_shape tensor_shape = finat_element.index_shape[len(scalar_shape):] else: scalar_shape = finat_element.index_shape tensor_shape = () scalar_size = numpy.prod(scalar_shape, dtype=int) tensor_size = numpy.prod(tensor_shape, dtype=int) funarg = coffee.Decl(SCALAR_TYPE, coffee.Symbol(name), pointers=[("const", "restrict"), ("restrict", )], qualifiers=["const"]) if not interior_facet: expression = gem.reshape( gem.Variable(name, (scalar_size, tensor_size)), scalar_shape, tensor_shape) else: varexp = gem.Variable(name, (2 * scalar_size, tensor_size)) plus = gem.view(varexp, slice(scalar_size), slice(tensor_size)) minus = gem.view(varexp, slice(scalar_size, 2 * scalar_size), slice(tensor_size)) expression = (gem.reshape(plus, scalar_shape, tensor_shape), gem.reshape(minus, scalar_shape, tensor_shape)) return funarg, expression
def test_view_reshape(vector): expression = gem.view(gem.reshape(vector, (3, 4)), slice(2), slice(1, 3)) assert expression.shape == (2, 2) actual = [convert(expression, multiindex) for multiindex in numpy.ndindex(expression.shape)] assert [(1,), (2,), (5,), (6,)] == actual
def test_reshape_shape(vector): expression = gem.reshape(gem.view(vector, slice(5, 11)), (3, 2)) assert expression.shape == (3, 2) actual = [convert(expression, multiindex) for multiindex in numpy.ndindex(expression.shape)] assert [(i,) for i in range(5, 11)] == actual
def prepare_arguments(arguments, multiindices, scalar_type, interior_facet=False, diagonal=False): """Bridges the kernel interface and the GEM abstraction for Arguments. Vector Arguments are rearranged here for interior facet integrals. :arg arguments: UFL Arguments :arg multiindices: Argument multiindices :arg interior_facet: interior facet integral? :arg diagonal: Are we assembling the diagonal of a rank-2 element tensor? :returns: (funarg, expression) funarg - :class:`loopy.GlobalArg` function argument expressions - GEM expressions referring to the argument tensor """ assert isinstance(interior_facet, bool) if len(arguments) == 0: # No arguments funarg = lp.GlobalArg("A", dtype=scalar_type, shape=(1,)) expression = gem.Indexed(gem.Variable("A", (1,)), (0,)) return funarg, [expression] elements = tuple(create_element(arg.ufl_element()) for arg in arguments) shapes = tuple(element.index_shape for element in elements) if diagonal: if len(arguments) != 2: raise ValueError("Diagonal only for 2-forms") try: element, = set(elements) except ValueError: raise ValueError("Diagonal only for diagonal blocks (test and trial spaces the same)") elements = (element, ) shapes = tuple(element.index_shape for element in elements) multiindices = multiindices[:1] def expression(restricted): return gem.Indexed(gem.reshape(restricted, *shapes), tuple(chain(*multiindices))) u_shape = numpy.array([numpy.prod(shape, dtype=int) for shape in shapes]) if interior_facet: c_shape = tuple(2 * u_shape) slicez = [[slice(r * s, (r + 1) * s) for r, s in zip(restrictions, u_shape)] for restrictions in product((0, 1), repeat=len(arguments))] else: c_shape = tuple(u_shape) slicez = [[slice(s) for s in u_shape]] funarg = lp.GlobalArg("A", dtype=scalar_type, shape=c_shape) varexp = gem.Variable("A", c_shape) expressions = [expression(gem.view(varexp, *slices)) for slices in slicez] return funarg, prune(expressions)
def _slate2gem_block(expr, self): child, = map(self, expr.children) child_shapes = expr.children[0].shapes offsets = tuple( sum(shape[:idx]) for shape, (idx, *_) in zip(child_shapes.values(), expr._indices)) return view( child, *(slice(idx, idx + extent) for idx, extent in zip(offsets, expr.shape)))
def test_pickle_gem(protocol): f = gem.VariableIndex(gem.Indexed(gem.Variable('facet', (2,)), (1,))) q = gem.Index() r = gem.Index() _1 = gem.Indexed(gem.Literal(numpy.random.rand(3, 6, 8)), (f, q, r)) _2 = gem.Indexed(gem.view(gem.Variable('w', (None, None)), slice(8), slice(1)), (r, 0)) expr = gem.ComponentTensor(gem.IndexSum(gem.Product(_1, _2), (r,)), (q,)) unpickled = pickle.loads(pickle.dumps(expr, protocol)) assert repr(expr) == repr(unpickled)
def prepare_arguments(arguments, multiindices, scalar_type, interior_facet=False): """Bridges the kernel interface and the GEM abstraction for Arguments. Vector Arguments are rearranged here for interior facet integrals. :arg arguments: UFL Arguments :arg multiindices: Argument multiindices :arg interior_facet: interior facet integral? :returns: (funarg, prepare, expressions) funarg - :class:`coffee.Decl` function argument prepare - list of COFFEE nodes to be prepended to the kernel body expressions - GEM expressions referring to the argument tensor """ funarg = coffee.Decl(scalar_type, coffee.Symbol("A"), pointers=[()]) varexp = gem.Variable("A", (None, )) if len(arguments) == 0: # No arguments zero = coffee.FlatBlock("memset({name}, 0, sizeof(*{name}));\n".format( name=funarg.sym.gencode())) return funarg, [zero], [gem.reshape(varexp, ())] elements = tuple(create_element(arg.ufl_element()) for arg in arguments) shapes = [element.index_shape for element in elements] indices = tuple(chain(*multiindices)) def expression(restricted): return gem.Indexed(gem.reshape(restricted, *shapes), indices) u_shape = numpy.array( [numpy.prod(element.index_shape, dtype=int) for element in elements]) if interior_facet: c_shape = tuple(2 * u_shape) slicez = [[ slice(r * s, (r + 1) * s) for r, s in zip(restrictions, u_shape) ] for restrictions in product((0, 1), repeat=len(arguments))] else: c_shape = tuple(u_shape) slicez = [[slice(s) for s in u_shape]] expressions = [ expression(gem.view(gem.reshape(varexp, c_shape), *slices)) for slices in slicez ] zero = coffee.FlatBlock( str.format("memset({name}, 0, {size} * sizeof(*{name}));\n", name=funarg.sym.gencode(), size=numpy.product(c_shape, dtype=int))) return funarg, [zero], prune(expressions)
def prepare_coefficient(coefficient, name, interior_facet=False): """Bridges the kernel interface and the GEM abstraction for Coefficients. :arg coefficient: UFL Coefficient :arg name: unique name to refer to the Coefficient in the kernel :arg interior_facet: interior facet integral? :returns: (funarg, expression) funarg - :class:`coffee.Decl` function argument expression - GEM expression referring to the Coefficient values """ assert isinstance(interior_facet, bool) if coefficient.ufl_element().family() == 'Real': # Constant funarg = coffee.Decl(SCALAR_TYPE, coffee.Symbol(name), pointers=[("restrict",)], qualifiers=["const"]) expression = gem.reshape(gem.Variable(name, (None,)), coefficient.ufl_shape) return funarg, expression finat_element = create_element(coefficient.ufl_element()) shape = finat_element.index_shape size = numpy.prod(shape, dtype=int) funarg = coffee.Decl(SCALAR_TYPE, coffee.Symbol(name), pointers=[("restrict",)], qualifiers=["const"]) if not interior_facet: expression = gem.reshape(gem.Variable(name, (size,)), shape) else: varexp = gem.Variable(name, (2 * size,)) plus = gem.view(varexp, slice(size)) minus = gem.view(varexp, slice(size, 2 * size)) expression = (gem.reshape(plus, shape), gem.reshape(minus, shape)) return funarg, expression
def test_pickle_gem(protocol): f = gem.VariableIndex(gem.Indexed(gem.Variable('facet', (2, )), (1, ))) q = gem.Index() r = gem.Index() _1 = gem.Indexed(gem.Literal(numpy.random.rand(3, 6, 8)), (f, q, r)) _2 = gem.Indexed( gem.view(gem.Variable('w', (None, None)), slice(8), slice(1)), (r, 0)) expr = gem.ComponentTensor(gem.IndexSum(gem.Product(_1, _2), (r, )), (q, )) unpickled = pickle.loads(pickle.dumps(expr, protocol)) assert repr(expr) == repr(unpickled)
def prepare_coefficient(coefficient, name, scalar_type, interior_facet=False): """Bridges the kernel interface and the GEM abstraction for Coefficients. :arg coefficient: UFL Coefficient :arg name: unique name to refer to the Coefficient in the kernel :arg interior_facet: interior facet integral? :returns: (funarg, expression) funarg - :class:`loopy.GlobalArg` function argument expression - GEM expression referring to the Coefficient values """ assert isinstance(interior_facet, bool) if coefficient.ufl_element().family() == 'Real': # Constant funarg = lp.GlobalArg(name, dtype=scalar_type, shape=(coefficient.ufl_element().value_size(), )) expression = gem.reshape(gem.Variable(name, (None, )), coefficient.ufl_shape) return funarg, expression finat_element = create_element(coefficient.ufl_element()) shape = finat_element.index_shape size = numpy.prod(shape, dtype=int) if not interior_facet: expression = gem.reshape(gem.Variable(name, (size, )), shape) else: varexp = gem.Variable(name, (2 * size, )) plus = gem.view(varexp, slice(size)) minus = gem.view(varexp, slice(size, 2 * size)) expression = (gem.reshape(plus, shape), gem.reshape(minus, shape)) size = size * 2 funarg = lp.GlobalArg(name, dtype=scalar_type, shape=(size, )) return funarg, expression
def prepare_arguments(arguments, multiindices, interior_facet=False): """Bridges the kernel interface and the GEM abstraction for Arguments. Vector Arguments are rearranged here for interior facet integrals. :arg arguments: UFL Arguments :arg multiindices: Argument multiindices :arg interior_facet: interior facet integral? :returns: (funarg, prepare, expressions) funarg - :class:`coffee.Decl` function argument prepare - list of COFFEE nodes to be prepended to the kernel body expressions - GEM expressions referring to the argument tensor """ funarg = coffee.Decl(SCALAR_TYPE, coffee.Symbol("A"), pointers=[()]) varexp = gem.Variable("A", (None,)) if len(arguments) == 0: # No arguments zero = coffee.FlatBlock( "memset({name}, 0, sizeof(*{name}));\n".format(name=funarg.sym.gencode()) ) return funarg, [zero], [gem.reshape(varexp, ())] elements = tuple(create_element(arg.ufl_element()) for arg in arguments) shapes = [element.index_shape for element in elements] indices = tuple(chain(*multiindices)) def expression(restricted): return gem.Indexed(gem.reshape(restricted, *shapes), indices) u_shape = numpy.array([numpy.prod(element.index_shape, dtype=int) for element in elements]) if interior_facet: c_shape = tuple(2 * u_shape) slicez = [[slice(r * s, (r + 1) * s) for r, s in zip(restrictions, u_shape)] for restrictions in product((0, 1), repeat=len(arguments))] else: c_shape = tuple(u_shape) slicez = [[slice(s) for s in u_shape]] expressions = [expression(gem.view(gem.reshape(varexp, c_shape), *slices)) for slices in slicez] zero = coffee.FlatBlock( str.format("memset({name}, 0, {size} * sizeof(*{name}));\n", name=funarg.sym.gencode(), size=numpy.product(c_shape, dtype=int)) ) return funarg, [zero], prune(expressions)
def prepare_arguments(arguments, multiindices, scalar_type, interior_facet=False): """Bridges the kernel interface and the GEM abstraction for Arguments. Vector Arguments are rearranged here for interior facet integrals. :arg arguments: UFL Arguments :arg multiindices: Argument multiindices :arg interior_facet: interior facet integral? :returns: (funarg, expression) funarg - :class:`coffee.Decl` function argument expressions - GEM expressions referring to the argument tensor """ assert isinstance(interior_facet, bool) if len(arguments) == 0: # No arguments funarg = coffee.Decl(scalar_type, coffee.Symbol("A", rank=(1, ))) expression = gem.Indexed(gem.Variable("A", (1, )), (0, )) return funarg, [expression] elements = tuple(create_element(arg.ufl_element()) for arg in arguments) shapes = tuple(element.index_shape for element in elements) def expression(restricted): return gem.Indexed(gem.reshape(restricted, *shapes), tuple(chain(*multiindices))) u_shape = numpy.array([numpy.prod(shape, dtype=int) for shape in shapes]) if interior_facet: c_shape = tuple(2 * u_shape) slicez = [[ slice(r * s, (r + 1) * s) for r, s in zip(restrictions, u_shape) ] for restrictions in product((0, 1), repeat=len(arguments))] else: c_shape = tuple(u_shape) slicez = [[slice(s) for s in u_shape]] funarg = coffee.Decl(scalar_type, coffee.Symbol("A", rank=c_shape)) varexp = gem.Variable("A", c_shape) expressions = [expression(gem.view(varexp, *slices)) for slices in slicez] return funarg, prune(expressions)
def prepare_arguments(arguments, multiindices, interior_facet=False): """Bridges the kernel interface and the GEM abstraction for Arguments. Vector Arguments are rearranged here for interior facet integrals. :arg arguments: UFL Arguments :arg multiindices: Argument multiindices :arg interior_facet: interior facet integral? :returns: (funarg, expression) funarg - :class:`coffee.Decl` function argument expressions - GEM expressions referring to the argument tensor """ assert isinstance(interior_facet, bool) if len(arguments) == 0: # No arguments funarg = coffee.Decl(SCALAR_TYPE, coffee.Symbol("A", rank=(1,))) expression = gem.Indexed(gem.Variable("A", (1,)), (0,)) return funarg, [expression] elements = tuple(create_element(arg.ufl_element()) for arg in arguments) shapes = tuple(element.index_shape for element in elements) def expression(restricted): return gem.Indexed(gem.reshape(restricted, *shapes), tuple(chain(*multiindices))) u_shape = numpy.array([numpy.prod(shape, dtype=int) for shape in shapes]) if interior_facet: c_shape = tuple(2 * u_shape) slicez = [[slice(r * s, (r + 1) * s) for r, s in zip(restrictions, u_shape)] for restrictions in product((0, 1), repeat=len(arguments))] else: c_shape = tuple(u_shape) slicez = [[slice(s) for s in u_shape]] funarg = coffee.Decl(SCALAR_TYPE, coffee.Symbol("A", rank=c_shape)) varexp = gem.Variable("A", c_shape) expressions = [expression(gem.view(varexp, *slices)) for slices in slicez] return funarg, prune(expressions)
def expression(data): result, = prune([gem.reshape(gem.view(data, slice(size)), element.index_shape)]) return result
def expression(data): result, = prune( [gem.reshape(gem.view(data, slice(size)), element.index_shape)]) return result
def expressions(data): return prune([transpose(gem.reshape(gem.view(data, slice_), shape), rank) for slice_, shape, rank in zip(slices, transposed_shapes, tensor_ranks)])
def prepare_coefficients(coefficients, num, name, interior_facet=False): """Bridges the kernel interface and the GEM abstraction for Coefficients. :arg coefficients: split UFL Coefficients :arg num: coefficient index in the original form :arg name: unique name to refer to the Coefficient in the kernel :arg interior_facet: interior facet integral? :returns: GEM expression referring to the Coefficient value """ varexp = gem.Variable(name, (None, None)) if len(coefficients) == 1 and coefficients[0].ufl_element().family() == 'Real': coefficient, = coefficients size = numpy.prod(coefficient.ufl_shape, dtype=int) data = gem.view(varexp, slice(num, num + 1), slice(size)) expression = gem.reshape(data, (), coefficient.ufl_shape) return [expression] elements = [create_element(coeff.ufl_element()) for coeff in coefficients] space_dimensions = [numpy.prod(element.index_shape, dtype=int) for element in elements] ends = list(numpy.cumsum(space_dimensions)) starts = [0] + ends[:-1] slices = [slice(start, end) for start, end in zip(starts, ends)] transposed_shapes = [] tensor_ranks = [] for element in elements: if isinstance(element, TensorFiniteElement): scalar_shape = element.base_element.index_shape tensor_shape = element.index_shape[len(scalar_shape):] else: scalar_shape = element.index_shape tensor_shape = () transposed_shapes.append(tensor_shape + scalar_shape) tensor_ranks.append(len(tensor_shape)) def transpose(expr, rank): assert not expr.free_indices assert 0 <= rank < len(expr.shape) if rank == 0: return expr else: indices = tuple(gem.Index(extent=extent) for extent in expr.shape) transposed_indices = indices[rank:] + indices[:rank] return gem.ComponentTensor(gem.Indexed(expr, indices), transposed_indices) def expressions(data): return prune([transpose(gem.reshape(gem.view(data, slice_), shape), rank) for slice_, shape, rank in zip(slices, transposed_shapes, tensor_ranks)]) size = sum(space_dimensions) if not interior_facet: data = gem.view(varexp, slice(num, num + 1), slice(size)) return expressions(gem.reshape(data, (), (size,))) else: data_p = gem.view(varexp, slice(num, num + 1), slice(size)) data_m = gem.view(varexp, slice(num, num + 1), slice(size, 2 * size)) return list(zip(expressions(gem.reshape(data_p, (), (size,))), expressions(gem.reshape(data_m, (), (size,)))))