def __init__(self, *elements): "Create TensorProductElement from a given list of elements." self._sub_elements = list(elements) ufl_assert( len(self._sub_elements) > 0, "Cannot create TensorProductElement from empty list.") self._repr = "TensorProductElement(*%r)" % self._sub_elements family = "TensorProductElement" # Define cell as the product of each subcell cell = ProductCell(*[e.cell() for e in self._sub_elements]) domain = as_domain( cell) # FIXME: figure out what this is supposed to mean :) # Define polynomial degree as the maximal of each subelement degree = max(e.degree() for e in self._sub_elements) # No quadrature scheme defined quad_scheme = None # For now, check that all subelements have the same value # shape, and use this. # TODO: Not sure if this makes sense, what kind of product is used to build the basis? value_shape = self._sub_elements[0].value_shape() ufl_assert( all(e.value_shape() == value_shape for e in self._sub_elements), "All subelements in must have same value shape") super(TensorProductElement, self).__init__(family, domain, degree, quad_scheme, value_shape)
def __init__(self, *elements): "Create TensorProductElement from a given list of elements." self._sub_elements = list(elements) ufl_assert(len(self._sub_elements) > 0, "Cannot create TensorProductElement from empty list.") self._repr = "TensorProductElement(*%r)" % self._sub_elements family = "TensorProductElement" # Define cell as the product of each subcell cell = ProductCell(*[e.cell() for e in self._sub_elements]) domain = as_domain(cell) # FIXME: figure out what this is supposed to mean :) # Define polynomial degree as the maximal of each subelement degree = max(e.degree() for e in self._sub_elements) # No quadrature scheme defined quad_scheme = None # For now, check that all subelements have the same value # shape, and use this. # TODO: Not sure if this makes sense, what kind of product is used to build the basis? value_shape = self._sub_elements[0].value_shape() ufl_assert(all(e.value_shape() == value_shape for e in self._sub_elements), "All subelements in must have same value shape") super(TensorProductElement, self).__init__(family, domain, degree, quad_scheme, value_shape)
def __init__(self, family, domain, degree, dim=None, quad_scheme=None, form_degree=None): """ Create vector element (repeated mixed element) *Arguments* family (string) The finite element family domain The geometric domain degree (int) The polynomial degree dim (int) The value dimension of the element (optional) quad_scheme The quadrature scheme (optional) form_degree (int) The form degree (FEEC notation, used when field is viewed as k-form) """ if domain is not None: domain = as_domain(domain) # Set default size if not specified if dim is None: ufl_assert(domain is not None, "Cannot infer vector dimension without a domain.") dim = domain.geometric_dimension() # Create mixed element from list of finite elements sub_element = FiniteElement(family, domain, degree, quad_scheme, form_degree) sub_elements = [sub_element]*dim # Get common family name (checked in FiniteElement.__init__) family = sub_element.family() # Compute value shape shape = (dim,) value_shape = shape + sub_element.value_shape() # Initialize element data super(VectorElement, self).__init__(sub_elements, value_shape=value_shape) self._family = family self._degree = degree self._sub_element = sub_element # Cache repr string self._repr = "VectorElement(%r, %r, %r, %d, %r)" % \ (self._family, self._domain, self._degree, len(self._sub_elements), quad_scheme)
def build_element_mapping(element_mapping, common_cell, arguments, coefficients): """Complete an element mapping for all elements used by arguments and coefficients, using a well defined common cell.""" # Build a new dict to avoid modifying the dict passed from non-ufl code new_element_mapping = {} # Check that the given initial mapping has no invalid entries as values for v in element_mapping.itervalues(): ufl_assert( v.cell() is not None, "Found incomplete element with undefined cell in element mapping.") ufl_assert( v.family() is not None, "Found incomplete element with undefined family in element mapping." ) common_domain = as_domain(common_cell) # FIXME: handle better somehow? # Reconstruct all elements we need to map for f in chain(arguments, coefficients): e = f.element() # Prefer the given mapping: new_e = element_mapping.get(e) if new_e is None: if e.cell() is None: # Otherwise complete with domain by reconstructing if cell is missing new_e = e.reconstruct(domain=common_domain) else: # Or just use the original element new_e = e new_element_mapping[e] = new_e # Check that the new mapping has no invalid entries as values for v in new_element_mapping.itervalues(): ufl_assert( v.cell() is not None, "Found incomplete element with undefined cell in new element mapping." ) ufl_assert( v.family() is not None, "Found incomplete element with undefined family in new element mapping." ) return new_element_mapping
def __init__(self, family, domain, degree, quad_scheme, value_shape): "Initialize basic finite element data" ufl_assert(isinstance(family, str), "Invalid family type.") ufl_assert(isinstance(degree, int) or degree is None, "Invalid degree type.") ufl_assert(isinstance(value_shape, tuple), "Invalid value_shape type.") if domain is None: self._domain = None self._cell = None else: self._domain = as_domain(domain) self._cell = self._domain.cell() ufl_assert(isinstance(self._domain, DomainDescription), "Invalid domain type.") ufl_assert(isinstance(self._cell, Cell), "Invalid cell type.") self._family = family self._degree = degree self._value_shape = value_shape self._quad_scheme = quad_scheme
def __init__(self, family, domain, degree, quad_scheme, value_shape): "Initialize basic finite element data" ufl_assert(isinstance(family, str), "Invalid family type.") ufl_assert( isinstance(degree, int) or degree is None, "Invalid degree type.") ufl_assert(isinstance(value_shape, tuple), "Invalid value_shape type.") if domain is None: self._domain = None self._cell = None else: self._domain = as_domain(domain) self._cell = self._domain.cell() ufl_assert(isinstance(self._domain, DomainDescription), "Invalid domain type.") ufl_assert(isinstance(self._cell, Cell), "Invalid cell type.") self._family = family self._degree = degree self._value_shape = value_shape self._quad_scheme = quad_scheme
def build_element_mapping(element_mapping, common_cell, arguments, coefficients): """Complete an element mapping for all elements used by arguments and coefficients, using a well defined common cell.""" # Build a new dict to avoid modifying the dict passed from non-ufl code new_element_mapping = {} # Check that the given initial mapping has no invalid entries as values for v in element_mapping.itervalues(): ufl_assert(v.cell() is not None, "Found incomplete element with undefined cell in element mapping.") ufl_assert(v.family() is not None, "Found incomplete element with undefined family in element mapping.") common_domain = as_domain(common_cell) # FIXME: handle better somehow? # Reconstruct all elements we need to map for f in chain(arguments, coefficients): e = f.element() # Prefer the given mapping: new_e = element_mapping.get(e) if new_e is None: if e.cell() is None: # Otherwise complete with domain by reconstructing if cell is missing new_e = e.reconstruct(domain=common_domain) else: # Or just use the original element new_e = e new_element_mapping[e] = new_e # Check that the new mapping has no invalid entries as values for v in new_element_mapping.itervalues(): ufl_assert(v.cell() is not None, "Found incomplete element with undefined cell in new element mapping.") ufl_assert(v.family() is not None, "Found incomplete element with undefined family in new element mapping.") return new_element_mapping
def __rmul__(self, integrand): # Let other types implement multiplication with Measure # if they want to (to support the dolfin-adjoint TimeMeasure) if not isinstance(integrand, Expr): return NotImplemented # Allow only scalar integrands if not is_true_ufl_scalar(integrand): error("Trying to integrate expression of rank %d with free indices %r." \ % (integrand.rank(), integrand.free_indices())) # Is the measure in a state where multiplication is not allowed? if self._domain_description == Measure.DOMAIN_ID_UNDEFINED: error("Missing domain id. You need to select a subdomain, " +\ "e.g. M = f*dx(0) for subdomain 0.") #else: # TODO: Do it this way instead, and move all logic below into preprocess: # # Return a one-integral form: # from ufl.form import Form # return Form( [Integral(integrand, self.domain_type(), self.domain_id(), self.metadata(), self.domain_data())] ) # # or if we move domain data into Form instead: # integrals = [Integral(integrand, self.domain_type(), self.domain_id(), self.metadata())] # domain_data = { self.domain_type(): self.domain_data() } # return Form(integrals, domain_data) # TODO: How to represent all kinds of domain descriptions is still a bit unclear # Create form if we have a sufficient domain description elif (# We have a complete measure with domain description isinstance(self._domain_description, DomainDescription) # Is the measure in a basic state 'foo*dx'? or self._domain_description == Measure.DOMAIN_ID_UNIQUE # Is the measure over everywhere? or self._domain_description == Measure.DOMAIN_ID_EVERYWHERE # Is the measure in a state not allowed prior to preprocessing? or self._domain_description == Measure.DOMAIN_ID_OTHERWISE ): # Create and return a one-integral form from ufl.form import Form return Form( [Integral(integrand, self.domain_type(), self.domain_id(), self.metadata(), self.domain_data())] ) # Did we get several ids? elif isinstance(self._domain_description, tuple): # FIXME: Leave this analysis to preprocessing return sum(integrand*self.reconstruct(domain_id=d) for d in self._domain_description) # Did we get a name? elif isinstance(self._domain_description, str): # FIXME: Leave this analysis to preprocessing # Get all domains and regions from integrand to analyse domains = extract_domains(integrand) # Get domain or region with this name from integrand, error if multiple found name = self._domain_description candidates = set() for TD in domains: if TD.name() == name: candidates.add(TD) ufl_assert(len(candidates) > 0, "Found no domain with name '%s' in integrand." % name) ufl_assert(len(candidates) == 1, "Multiple distinct domains with same name encountered in integrand.") D, = candidates # Reconstruct measure with the found named domain or region measure = self.reconstruct(domain_id=D) return integrand*measure # Did we get a number? elif isinstance(self._domain_description, int): # FIXME: Leave this analysis to preprocessing # Get all top level domains from integrand to analyse domains = extract_top_domains(integrand) # Get domain from integrand, error if multiple found if len(domains) == 0: # This is the partially defined integral from dolfin expression mess cell = integrand.cell() D = None if cell is None else as_domain(cell) elif len(domains) == 1: D, = domains else: error("Ambiguous reference to integer subdomain with multiple top domains in integrand.") if D is None: # We have a number but not a domain? Leave it to preprocess... # This is the case with badly formed forms which can occur from dolfin # Create and return a one-integral form from ufl.form import Form return Form( [Integral(integrand, self.domain_type(), self.domain_id(), self.metadata(), self.domain_data())] ) else: # Reconstruct measure with the found numbered subdomain measure = self.reconstruct(domain_id=D[self._domain_description]) return integrand*measure # Provide error to user else: error("Invalid domain id %s." % str(self._domain_description))
def __init__(self, family, domain=None, degree=None, quad_scheme=None, form_degree=None): """Create finite element *Arguments* family (string) The finite element family domain The geometric domain degree (int) The polynomial degree (optional) quad_scheme The quadrature scheme (optional) form_degree (int) The form degree (FEEC notation, used when field is viewed as k-form) """ if domain is None: cell = None else: domain = as_domain(domain) cell = domain.cell() ufl_assert(cell is not None, "Missing cell in given domain.") # Check whether this family is an alias for something else if family in aliases: (name, cell, r) = aliases[family](family, cell, degree, form_degree) #info_blue("%s, is an alias for %s " % ( # (family, cell, degree, form_degree), # (name, cell, r))) # FIXME: Need to init here with domain instead of using cell from aliases, is that ok? ufl_assert(cell == domain.cell(), "Breaking assumption in element alias mapping.") self.__init__(name, domain, r, quad_scheme) return # Check that the element family exists ufl_assert(family in ufl_elements, 'Unknown finite element "%s".' % family) # Check that element data is valid (and also get common family name) (family, self._short_name, value_rank, krange, cellnames) =\ ufl_elements[family] # Validate cellname if a valid cell is specified cellname = None if cell is None else cell.cellname() ufl_assert( cellname in cellnames, 'Cellname "%s" invalid for "%s" finite element.' % (cellname, family)) # Validate degree if specified if degree is not None: ufl_assert(krange is not None, 'Degree "%s" invalid for "%s" finite element, '\ 'should be None.' % (degree, family)) kmin, kmax = krange ufl_assert(kmin is None or degree >= kmin, 'Degree "%s" invalid for "%s" finite element.' %\ (degree, family)) ufl_assert(kmax is None or degree <= kmax, 'Degree "%s" invalid for "%s" finite element.' %\ (istr(degree), family)) # Set value dimension (default to using geometric dimension in each axis) if value_rank == 0: value_shape = () else: ufl_assert( domain is not None, "Cannot infer shape of element without a domain with geometric dimension." ) dim = domain.geometric_dimension() value_shape = (dim, ) * value_rank # Initialize element data super(FiniteElement, self).__init__(family, domain, degree, quad_scheme, value_shape) # Cache repr string self._repr = "FiniteElement(%r, %r, %r, %r)" % ( self.family(), self.domain(), self.degree(), self.quadrature_scheme())
def __init__(self, family, domain, degree, shape=None, symmetry=None, quad_scheme=None): "Create tensor element (repeated mixed element with optional symmetries)" if domain is not None: domain = as_domain(domain) # Set default shape if not specified if shape is None: ufl_assert(domain is not None, "Cannot infer vector dimension without a domain.") dim = domain.geometric_dimension() shape = (dim, dim) # Construct default symmetry for matrix elements if symmetry == True: ufl_assert(len(shape) == 2 and shape[0] == shape[1], "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 ) # Validate indices in symmetry dict if isinstance(symmetry, dict): for i,j in symmetry.iteritems(): ufl_assert(len(i) == len(j), "Non-matching length of symmetry index tuples.") for k in range(len(i)): ufl_assert(i[k] >= 0 and j[k] >= 0 and i[k] < shape[k] and j[k] < shape[k], "Symmetry dimensions out of bounds.") else: ufl_assert(symmetry is None, "Expecting symmetry to be None, True, or dict.") # Compute all index combinations for given shape indices = compute_indices(shape) # Compute sub elements and mapping from indices # to sub elements, accounting for symmetry sub_element = FiniteElement(family, domain, degree, quad_scheme) sub_elements = [] sub_element_mapping = {} for index in indices: if symmetry and index in symmetry: continue sub_element_mapping[index] = len(sub_elements) sub_elements += [sub_element] # Update mapping for symmetry for index in indices: if symmetry and index in symmetry: sub_element_mapping[index] = sub_element_mapping[symmetry[index]] # Get common family name (checked in FiniteElement.__init__) family = sub_element.family() # Compute value shape value_shape = shape + sub_element.value_shape() # Initialize element data super(TensorElement, self).__init__(sub_elements, value_shape=value_shape) self._family = family self._degree = degree self._sub_element = sub_element self._shape = shape self._symmetry = symmetry self._sub_element_mapping = sub_element_mapping # Cache repr string self._repr = "TensorElement(%r, %r, %r, %r, %r, %r)" % \ (self._family, self._domain, self._degree, self._shape, self._symmetry, quad_scheme)
def __init__(self, family, domain=None, degree=None, quad_scheme=None, form_degree=None): """Create finite element *Arguments* family (string) The finite element family domain The geometric domain degree (int) The polynomial degree (optional) quad_scheme The quadrature scheme (optional) form_degree (int) The form degree (FEEC notation, used when field is viewed as k-form) """ if domain is None: cell = None else: domain = as_domain(domain) cell = domain.cell() ufl_assert(cell is not None, "Missing cell in given domain.") # Check whether this family is an alias for something else if family in aliases: (name, cell, r) = aliases[family](family, cell, degree, form_degree) #info_blue("%s, is an alias for %s " % ( # (family, cell, degree, form_degree), # (name, cell, r))) # FIXME: Need to init here with domain instead of using cell from aliases, is that ok? ufl_assert(cell == domain.cell(), "Breaking assumption in element alias mapping.") self.__init__(name, domain, r, quad_scheme) return # Check that the element family exists ufl_assert(family in ufl_elements, 'Unknown finite element "%s".' % family) # Check that element data is valid (and also get common family name) (family, self._short_name, value_rank, krange, cellnames) =\ ufl_elements[family] # Validate cellname if a valid cell is specified cellname = None if cell is None else cell.cellname() ufl_assert(cellname in cellnames, 'Cellname "%s" invalid for "%s" finite element.' % (cellname, family)) # Validate degree if specified if degree is not None: ufl_assert(krange is not None, 'Degree "%s" invalid for "%s" finite element, '\ 'should be None.' % (degree, family)) kmin, kmax = krange ufl_assert(kmin is None or degree >= kmin, 'Degree "%s" invalid for "%s" finite element.' %\ (degree, family)) ufl_assert(kmax is None or degree <= kmax, 'Degree "%s" invalid for "%s" finite element.' %\ (istr(degree), family)) # Set value dimension (default to using geometric dimension in each axis) if value_rank == 0: value_shape = () else: ufl_assert(domain is not None, "Cannot infer shape of element without a domain with geometric dimension.") dim = domain.geometric_dimension() value_shape = (dim,)*value_rank # Initialize element data super(FiniteElement, self).__init__(family, domain, degree, quad_scheme, value_shape) # Cache repr string self._repr = "FiniteElement(%r, %r, %r, %r)" % ( self.family(), self.domain(), self.degree(), self.quadrature_scheme())
def __rmul__(self, integrand): # Let other types implement multiplication with Measure # if they want to (to support the dolfin-adjoint TimeMeasure) if not isinstance(integrand, Expr): return NotImplemented # Allow only scalar integrands if not is_true_ufl_scalar(integrand): error("Trying to integrate expression of rank %d with free indices %r." \ % (integrand.rank(), integrand.free_indices())) # Is the measure in a state where multiplication is not allowed? if self._domain_description == Measure.DOMAIN_ID_UNDEFINED: error("Missing domain id. You need to select a subdomain, " +\ "e.g. M = f*dx(0) for subdomain 0.") #else: # TODO: Do it this way instead, and move all logic below into preprocess: # # Return a one-integral form: # from ufl.form import Form # return Form( [Integral(integrand, self.domain_type(), self.domain_id(), self.metadata(), self.domain_data())] ) # # or if we move domain data into Form instead: # integrals = [Integral(integrand, self.domain_type(), self.domain_id(), self.metadata())] # domain_data = { self.domain_type(): self.domain_data() } # return Form(integrals, domain_data) # TODO: How to represent all kinds of domain descriptions is still a bit unclear # Create form if we have a sufficient domain description elif ( # We have a complete measure with domain description isinstance(self._domain_description, DomainDescription) # Is the measure in a basic state 'foo*dx'? or self._domain_description == Measure.DOMAIN_ID_UNIQUE # Is the measure over everywhere? or self._domain_description == Measure.DOMAIN_ID_EVERYWHERE # Is the measure in a state not allowed prior to preprocessing? or self._domain_description == Measure.DOMAIN_ID_OTHERWISE): # Create and return a one-integral form from ufl.form import Form return Form([ Integral(integrand, self.domain_type(), self.domain_id(), self.metadata(), self.domain_data()) ]) # Did we get several ids? elif isinstance(self._domain_description, tuple): # FIXME: Leave this analysis to preprocessing return sum(integrand * self.reconstruct(domain_id=d) for d in self._domain_description) # Did we get a name? elif isinstance(self._domain_description, str): # FIXME: Leave this analysis to preprocessing # Get all domains and regions from integrand to analyse domains = extract_domains(integrand) # Get domain or region with this name from integrand, error if multiple found name = self._domain_description candidates = set() for TD in domains: if TD.name() == name: candidates.add(TD) ufl_assert( len(candidates) > 0, "Found no domain with name '%s' in integrand." % name) ufl_assert( len(candidates) == 1, "Multiple distinct domains with same name encountered in integrand." ) D, = candidates # Reconstruct measure with the found named domain or region measure = self.reconstruct(domain_id=D) return integrand * measure # Did we get a number? elif isinstance(self._domain_description, int): # FIXME: Leave this analysis to preprocessing # Get all top level domains from integrand to analyse domains = extract_top_domains(integrand) # Get domain from integrand, error if multiple found if len(domains) == 0: # This is the partially defined integral from dolfin expression mess cell = integrand.cell() D = None if cell is None else as_domain(cell) elif len(domains) == 1: D, = domains else: error( "Ambiguous reference to integer subdomain with multiple top domains in integrand." ) if D is None: # We have a number but not a domain? Leave it to preprocess... # This is the case with badly formed forms which can occur from dolfin # Create and return a one-integral form from ufl.form import Form return Form([ Integral(integrand, self.domain_type(), self.domain_id(), self.metadata(), self.domain_data()) ]) else: # Reconstruct measure with the found numbered subdomain measure = self.reconstruct( domain_id=D[self._domain_description]) return integrand * measure # Provide error to user else: error("Invalid domain id %s." % str(self._domain_description))