def affine_mesh(cell, ufl_id=None): "Create a Mesh over a given cell type with an affine geometric parameterization." from ufl.finiteelement import VectorElement cell = as_cell(cell) gdim = cell.geometric_dimension() degree = 1 coordinate_element = VectorElement("Lagrange", cell, degree, dim=gdim) return Mesh(coordinate_element, ufl_id=ufl_id)
def affine_mesh(cell, ufl_id=None): "Create a Mesh over a given cell type with an affine geometric parameterization." from ufl.finiteelement import VectorElement cell = as_cell(cell) gdim = cell.geometric_dimension() degree = 1 coordinate_element = VectorElement("Lagrange", cell, degree, dim=gdim) return Mesh(coordinate_element, ufl_id=ufl_id)
def __init__(self, family, cell=None, degree=None, dim=None, form_degree=None, quad_scheme=None): """ Create vector element (repeated mixed element) *Arguments* family (string) The finite element family (or an existing FiniteElement) cell The geometric cell, ignored if family is a FiniteElement degree (int) The polynomial degree, ignored if family is a FiniteElement dim (int) The value dimension of the element (optional) form_degree (int) The form degree (FEEC notation, used when field is viewed as k-form), ignored if family is a FiniteElement quad_scheme The quadrature scheme (optional), ignored if family is a FiniteElement """ if isinstance(family, FiniteElementBase): sub_element = family cell = sub_element.cell() else: if cell is not None: cell = as_cell(cell) # Create sub element sub_element = FiniteElement(family, cell, degree, form_degree=form_degree, quad_scheme=quad_scheme) # Set default size if not specified if dim is None: if cell is None: error("Cannot infer vector dimension without a cell.") dim = cell.geometric_dimension() # Create list of sub elements for mixed element constructor sub_elements = [sub_element]*dim # Compute value shapes value_shape = (dim,) + sub_element.value_shape() reference_value_shape = (dim,) + sub_element.reference_value_shape() # Initialize element data MixedElement.__init__(self, sub_elements, value_shape=value_shape, reference_value_shape=reference_value_shape) # FIXME: Storing this here is strange, isn't that handled by # subclass? self._family = sub_element.family() self._degree = sub_element.degree() self._sub_element = sub_element # Cache repr string self._repr = "VectorElement(%s, dim=%d)" % ( repr(sub_element), len(self._sub_elements))
def __init__(self, family, cell=None, degree=None, dim=None, form_degree=None, quad_scheme=None): """ Create vector element (repeated mixed element) *Arguments* family (string) The finite element family (or an existing FiniteElement) cell The geometric cell, ignored if family is a FiniteElement degree (int) The polynomial degree, ignored if family is a FiniteElement dim (int) The value dimension of the element (optional) form_degree (int) The form degree (FEEC notation, used when field is viewed as k-form), ignored if family is a FiniteElement quad_scheme The quadrature scheme (optional), ignored if family is a FiniteElement """ if isinstance(family, FiniteElementBase): sub_element = family cell = sub_element.cell() else: if cell is not None: cell = as_cell(cell) # Create sub element sub_element = FiniteElement(family, cell, degree, form_degree=form_degree, quad_scheme=quad_scheme) # Set default size if not specified if dim is None: if cell is None: error("Cannot infer vector dimension without a cell.") dim = cell.geometric_dimension() # Create list of sub elements for mixed element constructor sub_elements = [sub_element] * dim # Compute value shapes value_shape = (dim,) + sub_element.value_shape() reference_value_shape = (dim,) + sub_element.reference_value_shape() # Initialize element data MixedElement.__init__(self, sub_elements, value_shape=value_shape, reference_value_shape=reference_value_shape) # FIXME: Storing this here is strange, isn't that handled by # subclass? self._family = sub_element.family() self._degree = sub_element.degree() self._sub_element = sub_element # Cache repr string self._repr = "VectorElement(%s, dim=%d)" % ( repr(sub_element), len(self._sub_elements))
def as_domain(domain): """Convert any valid object to an AbstractDomain type.""" if isinstance(domain, AbstractDomain): # Modern .ufl files and dolfin behaviour return domain elif hasattr(domain, "ufl_domain"): # If we get a dolfin.Mesh, it can provide us a corresponding # ufl.Mesh. This would be unnecessary if dolfin.Mesh could # subclass ufl.Mesh. return domain.ufl_domain() else: # Legacy .ufl files # TODO: Make this conversion in the relevant constructors # closer to the user interface? # TODO: Make this configurable to be an error from the dolfin side? cell = as_cell(domain) return default_domain(cell)
def as_domain(domain): """Convert any valid object to an AbstractDomain type.""" if isinstance(domain, AbstractDomain): # Modern .ufl files and dolfin behaviour return domain elif hasattr(domain, "ufl_domain"): # If we get a dolfin.Mesh, it can provide us a corresponding # ufl.Mesh. This would be unnecessary if dolfin.Mesh could # subclass ufl.Mesh. return domain.ufl_domain() else: # Legacy .ufl files # TODO: Make this conversion in the relevant constructors # closer to the user interface? # TODO: Make this configurable to be an error from the dolfin side? cell = as_cell(domain) return default_domain(cell)
def __init__(self, *elements, **kwargs): "Create TensorProductElement from a given list of elements." if not elements: error("Cannot create TensorProductElement from empty list.") keywords = list(kwargs.keys()) if keywords and keywords != ["cell"]: raise ValueError( "TensorProductElement got an unexpected keyword argument '%s'" % keywords[0]) cell = kwargs.get("cell") family = "TensorProductElement" if cell is None: # Define cell as the product of each elements cell cell = TensorProductCell(*[e.cell() for e in elements]) else: cell = as_cell(cell) # Define polynomial degree as a tuple of sub-degrees degree = tuple(e.degree() for e in elements) # No quadrature scheme defined quad_scheme = None # match FIAT implementation value_shape = tuple(chain(*[e.value_shape() for e in elements])) reference_value_shape = tuple( chain(*[e.reference_value_shape() for e in elements])) if len(value_shape) > 1: error("Product of vector-valued elements not supported") if len(reference_value_shape) > 1: error("Product of vector-valued elements not supported") FiniteElementBase.__init__(self, family, cell, degree, quad_scheme, value_shape, reference_value_shape) self._sub_elements = elements self._cell = cell self._repr = "TensorProductElement(%s, cell=%s)" % (", ".join( repr(e) for e in elements), repr(cell))
def __init__(self, *elements, **kwargs): "Create TensorProductElement from a given list of elements." if not elements: error("Cannot create TensorProductElement from empty list.") keywords = list(kwargs.keys()) if keywords and keywords != ["cell"]: raise ValueError("TensorProductElement got an unexpected keyword argument '%s'" % keywords[0]) cell = kwargs.get("cell") family = "TensorProductElement" if cell is None: # Define cell as the product of each elements cell cell = TensorProductCell(*[e.cell() for e in elements]) else: cell = as_cell(cell) # Define polynomial degree as a tuple of sub-degrees degree = tuple(e.degree() for e in elements) # No quadrature scheme defined quad_scheme = None # match FIAT implementation value_shape = tuple(chain(*[e.value_shape() for e in elements])) reference_value_shape = tuple(chain(*[e.reference_value_shape() for e in elements])) if len(value_shape) > 1: error("Product of vector-valued elements not supported") if len(reference_value_shape) > 1: error("Product of vector-valued elements not supported") FiniteElementBase.__init__(self, family, cell, degree, quad_scheme, value_shape, reference_value_shape) self._sub_elements = elements self._cell = cell self._repr = "TensorProductElement(%s, cell=%s)" % ( ", ".join(repr(e) for e in elements), repr(cell))
def __init__(self, family, cell, degree, quad_scheme, value_shape, reference_value_shape): "Initialize basic finite element data." if not isinstance(family, str): error("Invalid family type.") if not (degree is None or isinstance(degree, (int, tuple))): error("Invalid degree type.") if not isinstance(value_shape, tuple): error("Invalid value_shape type.") if not isinstance(reference_value_shape, tuple): error("Invalid reference_value_shape type.") if cell is not None: cell = as_cell(cell) if not isinstance(cell, AbstractCell): error("Invalid cell type.") self._family = family self._cell = cell self._degree = degree self._value_shape = value_shape self._reference_value_shape = reference_value_shape self._quad_scheme = quad_scheme
def __init__(self, family, cell, degree, quad_scheme, value_shape, reference_value_shape): "Initialize basic finite element data." if not isinstance(family, str): error("Invalid family type.") if not (degree is None or isinstance(degree, (int, tuple))): error("Invalid degree type.") if not isinstance(value_shape, tuple): error("Invalid value_shape type.") if not isinstance(reference_value_shape, tuple): error("Invalid reference_value_shape type.") if cell is not None: cell = as_cell(cell) if not isinstance(cell, AbstractCell): error("Invalid cell type.") self._family = family self._cell = cell self._degree = degree self._value_shape = value_shape self._reference_value_shape = reference_value_shape self._quad_scheme = quad_scheme
def __init__(self, family, cell=None, degree=None, shape=None, symmetry=None, quad_scheme=None): """Create tensor element (repeated mixed element with optional symmetries). :arg family: The family string, or an existing FiniteElement. :arg cell: The geometric cell (ignored if family is a FiniteElement). :arg degree: The polynomial degree (ignored if family is a FiniteElement). :arg shape: The shape of the element (defaults to a square tensor given by the geometric dimension of the cell). :arg symmetry: Optional symmetries. :arg quad_scheme: Optional quadrature scheme (ignored if family is a FiniteElement).""" if isinstance(family, FiniteElementBase): sub_element = family cell = sub_element.cell() else: if cell is not None: cell = as_cell(cell) # Create scalar sub element sub_element = FiniteElement(family, cell, degree, quad_scheme=quad_scheme) # Set default shape if not specified if shape is None: if cell is None: error("Cannot infer tensor shape without a cell.") dim = cell.geometric_dimension() shape = (dim, dim) if symmetry is None: symmetry = EmptyDict elif symmetry is True: # Construct default symmetry dict for matrix elements if not (len(shape) == 2 and shape[0] == shape[1]): error("Cannot set automatic symmetry for non-square tensor.") symmetry = dict(((i, j), (j, i)) for i in range(shape[0]) for j in range(shape[1]) if i > j) else: if not isinstance(symmetry, dict): error("Expecting symmetry to be None (unset), True, or dict.") # Validate indices in symmetry dict for i, j in symmetry.items(): if len(i) != len(j): error("Non-matching length of symmetry index tuples.") for k in range(len(i)): if not (i[k] >= 0 and j[k] >= 0 and i[k] < shape[k] and j[k] < shape[k]): error("Symmetry dimensions out of bounds.") # Compute all index combinations for given shape indices = compute_indices(shape) # Compute mapping from indices to sub element number, # accounting for symmetry sub_elements = [] sub_element_mapping = {} for index in indices: if index in symmetry: continue sub_element_mapping[index] = len(sub_elements) sub_elements += [sub_element] # Update mapping for symmetry for index in indices: if index in symmetry: sub_element_mapping[index] = sub_element_mapping[ symmetry[index]] flattened_sub_element_mapping = [ sub_element_mapping[index] for i, index in enumerate(indices) ] # Compute value shape value_shape = shape # Compute reference value shape based on symmetries if symmetry: # Flatten and subtract symmetries reference_value_shape = (product(shape) - len(symmetry), ) self._mapping = "symmetries" else: # Do not flatten if there are no symmetries reference_value_shape = shape self._mapping = "identity" value_shape = value_shape + sub_element.value_shape() reference_value_shape = reference_value_shape + sub_element.reference_value_shape( ) # Initialize element data MixedElement.__init__(self, sub_elements, value_shape=value_shape, reference_value_shape=reference_value_shape) self._family = sub_element.family() self._degree = sub_element.degree() self._sub_element = sub_element self._shape = shape self._symmetry = symmetry self._sub_element_mapping = sub_element_mapping self._flattened_sub_element_mapping = flattened_sub_element_mapping # Cache repr string self._repr = "TensorElement(%s, shape=%s, symmetry=%s)" % ( repr(sub_element), repr(self._shape), repr(self._symmetry))
def __init__(self, family, cell=None, degree=None, form_degree=None, quad_scheme=None, variant=None): """Create finite element. *Arguments* family (string) The finite element family cell The geometric cell degree (int) The polynomial degree (optional) form_degree (int) The form degree (FEEC notation, used when field is viewed as k-form) quad_scheme The quadrature scheme (optional) variant Hint for the local basis function variant (optional) """ # Note: Unfortunately, dolfin sometimes passes None for # cell. Until this is fixed, allow it: if cell is not None: cell = as_cell(cell) family, short_name, degree, value_shape, reference_value_shape, sobolev_space, mapping = canonical_element_description(family, cell, degree, form_degree) # TODO: Move these to base? Might be better to instead # simplify base though. self._sobolev_space = sobolev_space self._mapping = mapping self._short_name = short_name self._variant = variant # Finite elements on quadrilaterals and hexahedrons have an IrreducibleInt as degree if cell is not None: if cell.cellname() in ["quadrilateral", "hexahedron"]: from ufl.algorithms.estimate_degrees import IrreducibleInt degree = IrreducibleInt(degree) # Type check variant if variant is not None and not isinstance(variant, str): raise ValueError("Illegal variant: must be string or None") # Initialize element data FiniteElementBase.__init__(self, family, cell, degree, quad_scheme, value_shape, reference_value_shape) # Cache repr string qs = self.quadrature_scheme() if qs is None: quad_str = "" else: quad_str = ", quad_scheme=%s" % repr(qs) v = self.variant() if v is None: var_str = "" else: var_str = ", variant=%s" % repr(v) self._repr = as_native_str("FiniteElement(%s, %s, %s%s%s)" % ( repr(self.family()), repr(self.cell()), repr(self.degree()), quad_str, var_str)) assert '"' not in self._repr
def __new__(cls, family, cell=None, degree=None, form_degree=None, quad_scheme=None, variant=None): """Intercepts construction to expand CG, DG, RTCE and RTCF spaces on TensorProductCells.""" if cell is not None: cell = as_cell(cell) if isinstance(cell, TensorProductCell): # Delay import to avoid circular dependency at module load time from ufl.finiteelement.tensorproductelement import TensorProductElement from ufl.finiteelement.enrichedelement import EnrichedElement from ufl.finiteelement.hdivcurl import HDivElement as HDiv, HCurlElement as HCurl family, short_name, degree, value_shape, reference_value_shape, sobolev_space, mapping = \ canonical_element_description(family, cell, degree, form_degree) if family in ["RTCF", "RTCE"]: cell_h, cell_v = cell.sub_cells() if cell_h.cellname() != "interval": error( "%s is available on TensorProductCell(interval, interval) only." % family) if cell_v.cellname() != "interval": error( "%s is available on TensorProductCell(interval, interval) only." % family) C_elt = FiniteElement("CG", "interval", degree, variant=variant) D_elt = FiniteElement("DG", "interval", degree - 1, variant=variant) CxD_elt = TensorProductElement(C_elt, D_elt, cell=cell) DxC_elt = TensorProductElement(D_elt, C_elt, cell=cell) if family == "RTCF": return EnrichedElement(HDiv(CxD_elt), HDiv(DxC_elt)) if family == "RTCE": return EnrichedElement(HCurl(CxD_elt), HCurl(DxC_elt)) elif family == "NCF": cell_h, cell_v = cell.sub_cells() if cell_h.cellname() != "quadrilateral": error( "%s is available on TensorProductCell(quadrilateral, interval) only." % family) if cell_v.cellname() != "interval": error( "%s is available on TensorProductCell(quadrilateral, interval) only." % family) Qc_elt = FiniteElement("RTCF", "quadrilateral", degree, variant=variant) Qd_elt = FiniteElement("DQ", "quadrilateral", degree - 1, variant=variant) Id_elt = FiniteElement("DG", "interval", degree - 1, variant=variant) Ic_elt = FiniteElement("CG", "interval", degree, variant=variant) return EnrichedElement( HDiv(TensorProductElement(Qc_elt, Id_elt, cell=cell)), HDiv(TensorProductElement(Qd_elt, Ic_elt, cell=cell))) elif family == "NCE": cell_h, cell_v = cell.sub_cells() if cell_h.cellname() != "quadrilateral": error( "%s is available on TensorProductCell(quadrilateral, interval) only." % family) if cell_v.cellname() != "interval": error( "%s is available on TensorProductCell(quadrilateral, interval) only." % family) Qc_elt = FiniteElement("Q", "quadrilateral", degree, variant=variant) Qd_elt = FiniteElement("RTCE", "quadrilateral", degree, variant=variant) Id_elt = FiniteElement("DG", "interval", degree - 1, variant=variant) Ic_elt = FiniteElement("CG", "interval", degree, variant=variant) return EnrichedElement( HCurl(TensorProductElement(Qc_elt, Id_elt, cell=cell)), HCurl(TensorProductElement(Qd_elt, Ic_elt, cell=cell))) elif family == "Q": return TensorProductElement(*[ FiniteElement("CG", c, degree, variant=variant) for c in cell.sub_cells() ], cell=cell) elif family == "DQ": def dq_family(cell): return "DG" if cell.cellname() in simplices else "DQ" return TensorProductElement(*[ FiniteElement(dq_family(c), c, degree, variant=variant) for c in cell.sub_cells() ], cell=cell) return super(FiniteElement, cls).__new__(cls)
def __init__(self, family, cell=None, degree=None, form_degree=None, quad_scheme=None, variant=None): """Create finite element. *Arguments* family (string) The finite element family cell The geometric cell degree (int) The polynomial degree (optional) form_degree (int) The form degree (FEEC notation, used when field is viewed as k-form) quad_scheme The quadrature scheme (optional) variant Hint for the local basis function variant (optional) """ # Note: Unfortunately, dolfin sometimes passes None for # cell. Until this is fixed, allow it: if cell is not None: cell = as_cell(cell) family, short_name, degree, value_shape, reference_value_shape, sobolev_space, mapping = canonical_element_description( family, cell, degree, form_degree) # TODO: Move these to base? Might be better to instead # simplify base though. self._sobolev_space = sobolev_space self._mapping = mapping self._short_name = short_name self._variant = variant # Finite elements on quadrilaterals have an IrreducibleInt as degree if cell is not None: if cell.cellname() == "quadrilateral": from ufl.algorithms.estimate_degrees import IrreducibleInt degree = IrreducibleInt(degree) # Type check variant if variant is not None and not isinstance(variant, str): raise ValueError("Illegal variant: must be string or None") # Initialize element data FiniteElementBase.__init__(self, family, cell, degree, quad_scheme, value_shape, reference_value_shape) # Cache repr string qs = self.quadrature_scheme() if qs is None: quad_str = "" else: quad_str = ", quad_scheme=%s" % repr(qs) v = self.variant() if v is None: var_str = "" else: var_str = ", variant=%s" % repr(qs) self._repr = as_native_str("FiniteElement(%s, %s, %s%s%s)" % (repr(self.family()), repr(self.cell()), repr(self.degree()), quad_str, var_str)) assert '"' not in self._repr
def __new__(cls, family, cell=None, degree=None, form_degree=None, quad_scheme=None, variant=None): """Intercepts construction to expand CG, DG, RTCE and RTCF spaces on TensorProductCells.""" if cell is not None: cell = as_cell(cell) if isinstance(cell, TensorProductCell): # Delay import to avoid circular dependency at module load time from ufl.finiteelement.tensorproductelement import TensorProductElement from ufl.finiteelement.enrichedelement import EnrichedElement from ufl.finiteelement.hdivcurl import HDivElement as HDiv, HCurlElement as HCurl family, short_name, degree, value_shape, reference_value_shape, sobolev_space, mapping = \ canonical_element_description(family, cell, degree, form_degree) if family in ["RTCF", "RTCE"]: cell_h, cell_v = cell.sub_cells() if cell_h.cellname() != "interval": error("%s is available on TensorProductCell(interval, interval) only." % family) if cell_v.cellname() != "interval": error("%s is available on TensorProductCell(interval, interval) only." % family) C_elt = FiniteElement("CG", "interval", degree, variant=variant) D_elt = FiniteElement("DG", "interval", degree - 1, variant=variant) CxD_elt = TensorProductElement(C_elt, D_elt, cell=cell) DxC_elt = TensorProductElement(D_elt, C_elt, cell=cell) if family == "RTCF": return EnrichedElement(HDiv(CxD_elt), HDiv(DxC_elt)) if family == "RTCE": return EnrichedElement(HCurl(CxD_elt), HCurl(DxC_elt)) elif family == "NCF": cell_h, cell_v = cell.sub_cells() if cell_h.cellname() != "quadrilateral": error("%s is available on TensorProductCell(quadrilateral, interval) only." % family) if cell_v.cellname() != "interval": error("%s is available on TensorProductCell(quadrilateral, interval) only." % family) Qc_elt = FiniteElement("RTCF", "quadrilateral", degree, variant=variant) Qd_elt = FiniteElement("DQ", "quadrilateral", degree - 1, variant=variant) Id_elt = FiniteElement("DG", "interval", degree - 1, variant=variant) Ic_elt = FiniteElement("CG", "interval", degree, variant=variant) return EnrichedElement(HDiv(TensorProductElement(Qc_elt, Id_elt, cell=cell)), HDiv(TensorProductElement(Qd_elt, Ic_elt, cell=cell))) elif family == "NCE": cell_h, cell_v = cell.sub_cells() if cell_h.cellname() != "quadrilateral": error("%s is available on TensorProductCell(quadrilateral, interval) only." % family) if cell_v.cellname() != "interval": error("%s is available on TensorProductCell(quadrilateral, interval) only." % family) Qc_elt = FiniteElement("Q", "quadrilateral", degree, variant=variant) Qd_elt = FiniteElement("RTCE", "quadrilateral", degree, variant=variant) Id_elt = FiniteElement("DG", "interval", degree - 1, variant=variant) Ic_elt = FiniteElement("CG", "interval", degree, variant=variant) return EnrichedElement(HCurl(TensorProductElement(Qc_elt, Id_elt, cell=cell)), HCurl(TensorProductElement(Qd_elt, Ic_elt, cell=cell))) elif family == "Q": return TensorProductElement(*[FiniteElement("CG", c, degree, variant=variant) for c in cell.sub_cells()], cell=cell) elif family == "DQ": def dq_family(cell): return "DG" if cell.cellname() in simplices else "DQ" return TensorProductElement(*[FiniteElement(dq_family(c), c, degree, variant=variant) for c in cell.sub_cells()], cell=cell) return super(FiniteElement, cls).__new__(cls)
def __init__(self, family, cell=None, degree=None, shape=None, symmetry=None, quad_scheme=None): """Create tensor element (repeated mixed element with optional symmetries). :arg family: The family string, or an existing FiniteElement. :arg cell: The geometric cell (ignored if family is a FiniteElement). :arg degree: The polynomial degree (ignored if family is a FiniteElement). :arg shape: The shape of the element (defaults to a square tensor given by the geometric dimension of the cell). :arg symmetry: Optional symmetries. :arg quad_scheme: Optional quadrature scheme (ignored if family is a FiniteElement).""" if isinstance(family, FiniteElementBase): sub_element = family cell = sub_element.cell() else: if cell is not None: cell = as_cell(cell) # Create scalar sub element sub_element = FiniteElement(family, cell, degree, quad_scheme=quad_scheme) if sub_element.value_shape() != (): error("Expecting only scalar valued subelement for TensorElement.") # Set default shape if not specified if shape is None: if cell is None: error("Cannot infer tensor shape without a cell.") dim = cell.geometric_dimension() shape = (dim, dim) if symmetry is None: symmetry = EmptyDict elif symmetry is True: # Construct default symmetry dict for matrix elements if not (len(shape) == 2 and shape[0] == shape[1]): error("Cannot set automatic symmetry for non-square tensor.") symmetry = dict(((i, j), (j, i)) for i in range(shape[0]) for j in range(shape[1]) if i > j) else: if not isinstance(symmetry, dict): error("Expecting symmetry to be None (unset), True, or dict.") # Validate indices in symmetry dict for i, j in symmetry.items(): if len(i) != len(j): error("Non-matching length of symmetry index tuples.") for k in range(len(i)): if not (i[k] >= 0 and j[k] >= 0 and i[k] < shape[k] and j[k] < shape[k]): error("Symmetry dimensions out of bounds.") # Compute all index combinations for given shape indices = compute_indices(shape) # Compute mapping from indices to sub element number, # accounting for symmetry sub_elements = [] sub_element_mapping = {} for index in indices: if index in symmetry: continue sub_element_mapping[index] = len(sub_elements) sub_elements += [sub_element] # Update mapping for symmetry for index in indices: if index in symmetry: sub_element_mapping[index] = sub_element_mapping[symmetry[index]] flattened_sub_element_mapping = [sub_element_mapping[index] for i, index in enumerate(indices)] # Compute value shape value_shape = shape # Compute reference value shape based on symmetries if symmetry: # Flatten and subtract symmetries reference_value_shape = (product(shape)-len(symmetry),) self._mapping = "symmetries" else: # Do not flatten if there are no symmetries reference_value_shape = shape self._mapping = "identity" # Initialize element data MixedElement.__init__(self, sub_elements, value_shape=value_shape, reference_value_shape=reference_value_shape) self._family = sub_element.family() self._degree = sub_element.degree() self._sub_element = sub_element self._shape = shape self._symmetry = symmetry self._sub_element_mapping = sub_element_mapping self._flattened_sub_element_mapping = flattened_sub_element_mapping # Cache repr string self._repr = "TensorElement(%s, shape=%s, symmetry=%s)" % ( repr(sub_element), repr(self._shape), repr(self._symmetry))
def __init__(self, family, cell=None, degree=None, dim=None, form_degree=None, quad_scheme=None, variant=None): """ Create vector element (repeated mixed element) *Arguments* family (string) The finite element family (or an existing FiniteElement) cell The geometric cell, ignored if family is a FiniteElement degree (int) The polynomial degree, ignored if family is a FiniteElement dim (int) The value dimension of the element (optional) form_degree (int) The form degree (FEEC notation, used when field is viewed as k-form), ignored if family is a FiniteElement quad_scheme The quadrature scheme (optional), ignored if family is a FiniteElement variant Hint for the local basis function variant (optional) """ if isinstance(family, FiniteElementBase): sub_element = family cell = sub_element.cell() variant = sub_element.variant() else: if cell is not None: cell = as_cell(cell) # Create sub element sub_element = FiniteElement(family, cell, degree, form_degree=form_degree, quad_scheme=quad_scheme, variant=variant) # Set default size if not specified if dim is None: if cell is None: error("Cannot infer vector dimension without a cell.") dim = cell.geometric_dimension() self._mapping = sub_element.mapping() # Create list of sub elements for mixed element constructor sub_elements = [sub_element] * dim # Compute value shapes value_shape = (dim,) + sub_element.value_shape() reference_value_shape = (dim,) + sub_element.reference_value_shape() # Initialize element data MixedElement.__init__(self, sub_elements, value_shape=value_shape, reference_value_shape=reference_value_shape) FiniteElementBase.__init__(self, sub_element.family(), cell, sub_element.degree(), quad_scheme, value_shape, reference_value_shape) self._sub_element = sub_element if variant is None: var_str = "" else: var_str = ", variant='" + variant + "'" # Cache repr string self._repr = "VectorElement(%s, dim=%d%s)" % ( repr(sub_element), len(self._sub_elements), var_str)