def __init__(self, poly_set, dual, order, formdegree=None, mapping="affine"): ref_el = poly_set.get_reference_element() super(CiarletElement, self).__init__(ref_el, dual, order, formdegree, mapping) # build generalized Vandermonde matrix old_coeffs = poly_set.get_coeffs() dualmat = dual.to_riesz(poly_set) shp = dualmat.shape if len(shp) > 2: num_cols = numpy.prod(shp[1:]) A = numpy.reshape(dualmat, (dualmat.shape[0], num_cols)) B = numpy.reshape(old_coeffs, (old_coeffs.shape[0], num_cols)) else: A = dualmat B = old_coeffs V = numpy.dot(A, numpy.transpose(B)) self.V = V Vinv = numpy.linalg.inv(V) new_coeffs_flat = numpy.dot(numpy.transpose(Vinv), B) new_shp = tuple([new_coeffs_flat.shape[0]] + list(shp[1:])) new_coeffs = numpy.reshape(new_coeffs_flat, new_shp) self.poly_set = PolynomialSet(ref_el, poly_set.get_degree(), poly_set.get_embedded_degree(), poly_set.get_expansion_set(), new_coeffs, poly_set.get_dmats())
def __init__(self, poly_set, dual, order, formdegree=None, mapping="affine", ref_el=None): ref_el = ref_el or poly_set.get_reference_element() super(CiarletElement, self).__init__(ref_el, dual, order, formdegree, mapping) # build generalized Vandermonde matrix old_coeffs = poly_set.get_coeffs() dualmat = dual.to_riesz(poly_set) shp = dualmat.shape if len(shp) > 2: num_cols = numpy.prod(shp[1:]) A = numpy.reshape(dualmat, (dualmat.shape[0], num_cols)) B = numpy.reshape(old_coeffs, (old_coeffs.shape[0], num_cols)) else: A = dualmat B = old_coeffs V = numpy.dot(A, numpy.transpose(B)) self.V = V Vinv = numpy.linalg.inv(V) new_coeffs_flat = numpy.dot(numpy.transpose(Vinv), B) new_shp = tuple([new_coeffs_flat.shape[0]] + list(shp[1:])) new_coeffs = numpy.reshape(new_coeffs_flat, new_shp) self.poly_set = PolynomialSet(ref_el, poly_set.get_degree(), poly_set.get_embedded_degree(), poly_set.get_expansion_set(), new_coeffs, poly_set.get_dmats())
def __init__(self, *elements): # Test elements are nodal if not all(e.is_nodal() for e in elements): raise ValueError("Not all elements given for construction " "of NodalEnrichedElement are nodal") # Extract common data ref_el = elements[0].get_reference_element() expansion_set = elements[0].get_nodal_basis().get_expansion_set() degree = min(e.get_nodal_basis().get_degree() for e in elements) embedded_degree = max(e.get_nodal_basis().get_embedded_degree() for e in elements) order = max(e.get_order() for e in elements) mapping = elements[0].mapping()[0] formdegree = None if any(e.get_formdegree() is None for e in elements) \ else max(e.get_formdegree() for e in elements) value_shape = elements[0].value_shape() # Sanity check assert all(e.get_nodal_basis().get_reference_element() == ref_el for e in elements) assert all( type(e.get_nodal_basis().get_expansion_set()) == type( expansion_set) for e in elements) assert all(e_mapping == mapping for e in elements for e_mapping in e.mapping()) assert all(e.value_shape() == value_shape for e in elements) # Merge polynomial sets coeffs = _merge_coeffs([e.get_coeffs() for e in elements]) dmats = _merge_dmats([e.dmats() for e in elements]) poly_set = PolynomialSet(ref_el, degree, embedded_degree, expansion_set, coeffs, dmats) # Renumber dof numbers offsets = np.cumsum([0] + [e.space_dimension() for e in elements[:-1]]) entity_ids = _merge_entity_ids((e.entity_dofs() for e in elements), offsets) # Merge dual bases nodes = [node for e in elements for node in e.dual_basis()] dual_set = DualSet(nodes, ref_el, entity_ids) # CiarletElement constructor adjusts poly_set coefficients s.t. # dual_set is really dual to poly_set super(NodalEnrichedElement, self).__init__(poly_set, dual_set, order, formdegree=formdegree, mapping=mapping)
class CiarletElement(FiniteElement): """Class implementing Ciarlet's abstraction of a finite element being a domain, function space, and set of nodes. Elements derived from this class are nodal finite elements, with a nodal basis generated from polynomials encoded in a `PolynomialSet`. """ def __init__(self, poly_set, dual, order, formdegree=None, mapping="affine", ref_el=None): ref_el = ref_el or poly_set.get_reference_element() super(CiarletElement, self).__init__(ref_el, dual, order, formdegree, mapping) # build generalized Vandermonde matrix old_coeffs = poly_set.get_coeffs() dualmat = dual.to_riesz(poly_set) shp = dualmat.shape if len(shp) > 2: num_cols = numpy.prod(shp[1:]) A = numpy.reshape(dualmat, (dualmat.shape[0], num_cols)) B = numpy.reshape(old_coeffs, (old_coeffs.shape[0], num_cols)) else: A = dualmat B = old_coeffs V = numpy.dot(A, numpy.transpose(B)) self.V = V Vinv = numpy.linalg.inv(V) new_coeffs_flat = numpy.dot(numpy.transpose(Vinv), B) new_shp = tuple([new_coeffs_flat.shape[0]] + list(shp[1:])) new_coeffs = numpy.reshape(new_coeffs_flat, new_shp) self.poly_set = PolynomialSet(ref_el, poly_set.get_degree(), poly_set.get_embedded_degree(), poly_set.get_expansion_set(), new_coeffs, poly_set.get_dmats()) def degree(self): "Return the degree of the (embedding) polynomial space." return self.poly_set.get_embedded_degree() def get_nodal_basis(self): """Return the nodal basis, encoded as a PolynomialSet object, for the finite element.""" return self.poly_set def get_coeffs(self): """Return the expansion coefficients for the basis of the finite element.""" return self.poly_set.get_coeffs() def tabulate(self, order, points, entity=None): """Return tabulated values of derivatives up to given order of basis functions at given points. :arg order: The maximum order of derivative. :arg points: An iterable of points. :arg entity: Optional (dimension, entity number) pair indicating which topological entity of the reference element to tabulate on. If ``None``, default cell-wise tabulation is performed. """ if entity is None: entity = (self.ref_el.get_spatial_dimension(), 0) entity_dim, entity_id = entity transform = self.ref_el.get_entity_transform(entity_dim, entity_id) return self.poly_set.tabulate(list(map(transform, points)), order) def value_shape(self): "Return the value shape of the finite element functions." return self.poly_set.get_shape() def dmats(self): """Return dmats: expansion coefficients for basis function derivatives.""" return self.get_nodal_basis().get_dmats() def get_num_members(self, arg): "Return number of members of the expansion set." return self.get_nodal_basis().get_expansion_set().get_num_members(arg) @staticmethod def is_nodal(): """True if primal and dual bases are orthogonal. If false, dual basis is not implemented or is undefined. All implementations/subclasses are nodal including this one. """ return True
class CiarletElement(FiniteElement): """Class implementing Ciarlet's abstraction of a finite element being a domain, function space, and set of nodes. Elements derived from this class are nodal finite elements, with a nodal basis generated from polynomials encoded in a `PolynomialSet`. """ def __init__(self, poly_set, dual, order, formdegree=None, mapping="affine"): ref_el = poly_set.get_reference_element() super(CiarletElement, self).__init__(ref_el, dual, order, formdegree, mapping) # build generalized Vandermonde matrix old_coeffs = poly_set.get_coeffs() dualmat = dual.to_riesz(poly_set) shp = dualmat.shape if len(shp) > 2: num_cols = numpy.prod(shp[1:]) A = numpy.reshape(dualmat, (dualmat.shape[0], num_cols)) B = numpy.reshape(old_coeffs, (old_coeffs.shape[0], num_cols)) else: A = dualmat B = old_coeffs V = numpy.dot(A, numpy.transpose(B)) self.V = V Vinv = numpy.linalg.inv(V) new_coeffs_flat = numpy.dot(numpy.transpose(Vinv), B) new_shp = tuple([new_coeffs_flat.shape[0]] + list(shp[1:])) new_coeffs = numpy.reshape(new_coeffs_flat, new_shp) self.poly_set = PolynomialSet(ref_el, poly_set.get_degree(), poly_set.get_embedded_degree(), poly_set.get_expansion_set(), new_coeffs, poly_set.get_dmats()) def degree(self): "Return the degree of the (embedding) polynomial space." return self.poly_set.get_embedded_degree() def get_nodal_basis(self): """Return the nodal basis, encoded as a PolynomialSet object, for the finite element.""" return self.poly_set def get_coeffs(self): """Return the expansion coefficients for the basis of the finite element.""" return self.poly_set.get_coeffs() def tabulate(self, order, points, entity=None): """Return tabulated values of derivatives up to given order of basis functions at given points. :arg order: The maximum order of derivative. :arg points: An iterable of points. :arg entity: Optional (dimension, entity number) pair indicating which topological entity of the reference element to tabulate on. If ``None``, default cell-wise tabulation is performed. """ if entity is None: entity = (self.ref_el.get_spatial_dimension(), 0) entity_dim, entity_id = entity transform = self.ref_el.get_entity_transform(entity_dim, entity_id) return self.poly_set.tabulate(list(map(transform, points)), order) def value_shape(self): "Return the value shape of the finite element functions." return self.poly_set.get_shape() def dmats(self): """Return dmats: expansion coefficients for basis function derivatives.""" return self.get_nodal_basis().get_dmats() def get_num_members(self, arg): "Return number of members of the expansion set." return self.get_nodal_basis().get_expansion_set().get_num_members(arg) @staticmethod def is_nodal(): """True if primal and dual bases are orthogonal. If false, dual basis is not implemented or is undefined. All implementations/subclasses are nodal including this one. """ return True