def _generate_physical_offsets(ufl_element, offset=0): """Generate offsets: i.e value offset for each basis function relative to a physical element representation.""" cell = ufl_element.cell() gdim = cell.geometric_dimension() tdim = cell.topological_dimension() # Refer to reference if gdim == tdim. This is a hack to support # more stuff (in particular restricted elements) if gdim == tdim: return _generate_reference_offsets(create_element(ufl_element)) if isinstance(ufl_element, ufl.MixedElement): offsets = [] for e in ufl_element.sub_elements(): offsets += _generate_physical_offsets(e, offset) # e is a ufl element, so value_size means the physical value size offset += e.value_size() return offsets elif isinstance(ufl_element, ufl.EnrichedElement): offsets = [] for e in ufl_element._elements: # TODO: Avoid private member access offsets += _generate_physical_offsets(e, offset) return offsets elif isinstance(ufl_element, ufl.FiniteElement): fiat_element = create_element(ufl_element) return [offset] * fiat_element.space_dimension() else: raise NotImplementedError("This element combination is not implemented")
def compute_shapes(form: ufl.Form): """Computes the shapes of the cell tensor, coefficient & coordinate arrays for a form""" # Cell tensor elements = tuple(arg.ufl_element() for arg in form.arguments()) fiat_elements = (create_element(element) for element in elements) element_dims = tuple(fe.space_dimension() for fe in fiat_elements) A_shape = element_dims # Coefficient arrays ws_shapes = [] for coefficient in form.coefficients(): w_element = coefficient.ufl_element() w_dim = create_element(w_element).space_dimension() ws_shapes.append((w_dim,)) if len(ws_shapes) > 0: max_w_dim = sorted(ws_shapes, key=lambda w_dim: np.prod(w_dim))[-1] w_full_shape = (len(ws_shapes), ) + max_w_dim else: w_full_shape = (0,) # Coordinate dofs array num_vertices_per_cell = form.ufl_cell().num_vertices() gdim = form.ufl_cell().geometric_dimension() coords_shape = (num_vertices_per_cell, gdim) return A_shape, w_full_shape, coords_shape
def _generate_physical_offsets(ufl_element, offset=0): """Generate offsets: i.e value offset for each basis function relative to a physical element representation.""" offsets = [] # Refer to reference if gdim == tdim. This is a hack to support # more stuff (in particular restricted elements) gdim = ufl_element.cell().geometric_dimension() tdim = ufl_element.cell().topological_dimension() if (gdim == tdim): return _generate_reference_offsets(create_element(ufl_element)) if isinstance(ufl_element, ufl.MixedElement): for e in ufl_element.sub_elements(): offsets += _generate_physical_offsets(e, offset) offset += _value_size(e) elif isinstance(ufl_element, ufl.EnrichedElement): for e in ufl_element._elements: offsets += _generate_physical_offsets(e, offset) elif isinstance(ufl_element, ufl.FiniteElement): element = create_element(ufl_element) offsets = [offset] * element.space_dimension() else: raise NotImplementedError, \ "This element combination is not implemented" return offsets
def _generate_physical_offsets(ufl_element, offset=0): """Generate offsets: i.e value offset for each basis function relative to a physical element representation.""" cell = ufl_element.cell() gdim = cell.geometric_dimension() tdim = cell.topological_dimension() # Refer to reference if gdim == tdim. This is a hack to support more # stuff (in particular restricted elements) if gdim == tdim: return _generate_reference_offsets(create_element(ufl_element)) if isinstance(ufl_element, ufl.MixedElement): offsets = [] for e in ufl_element.sub_elements(): offsets += _generate_physical_offsets(e, offset) # e is a ufl element, so value_size means the physical value size offset += e.value_size() return offsets elif isinstance(ufl_element, ufl.EnrichedElement): offsets = [] for e in ufl_element._elements: # TODO: Avoid private member access offsets += _generate_physical_offsets(e, offset) return offsets elif isinstance(ufl_element, ufl.FiniteElement): fiat_element = create_element(ufl_element) return [offset] * fiat_element.space_dimension() else: raise NotImplementedError( "This element combination is not implemented")
def _generate_physical_offsets(ufl_element, offset=0): """Generate offsets: i.e value offset for each basis function relative to a physical element representation.""" offsets = [] # Refer to reference if gdim == tdim. This is a hack to support # more stuff (in particular restricted elements) gdim = ufl_element.cell().geometric_dimension() tdim = ufl_element.cell().topological_dimension() if (gdim == tdim): return _generate_reference_offsets(create_element(ufl_element)) if isinstance(ufl_element, ufl.MixedElement): for e in ufl_element.sub_elements(): offsets += _generate_physical_offsets(e, offset) offset += _value_size(e) elif isinstance(ufl_element, ufl.EnrichedElement): for e in ufl_element._elements: offsets += _generate_physical_offsets(e, offset) elif isinstance(ufl_element, ufl.FiniteElement): element = create_element(ufl_element) offsets = [offset]*element.space_dimension() else: raise NotImplementedError, \ "This element combination is not implemented" return offsets
def compute_integral_ir(itg_data, form_data, form_id, element_numbers, parameters): "Compute intermediate represention of integral." info("Computing uflacs representation") # Initialise representation ir = initialize_integral_ir("uflacs", itg_data, form_data, form_id) # Sort integrals into a dict with quadrature degree and rule as key sorted_integrals = sort_integrals(itg_data.integrals, itg_data.metadata["quadrature_degree"], itg_data.metadata["quadrature_rule"]) # TODO: Might want to create the uflacs ir first and then create the tables we need afterwards! # Tabulate quadrature points and basis function values in these points integrals_dict, psi_tables, quadrature_rules = \ tabulate_basis(sorted_integrals, form_data, itg_data) # Store element numbers, needed for classnames ir["element_numbers"] = element_numbers # Delegate to flacs to build its intermediate representation and add to ir uflacs_ir = compute_uflacs_integral_ir(psi_tables, ir["entitytype"], integrals_dict, form_data, parameters) # Store uflacs generated part separately ir["uflacs"] = uflacs_ir # Create and save the optisation parameters # TODO: Define uflacs specific optimization parameters instead #ir["optimise_parameters"] = parse_optimise_parameters(parameters) # Save tables for quadrature weights and points ir["quadrature_rules"] = quadrature_rules # Create dimensions of primary indices, needed to reset the argument 'A' # given to tabulate_tensor() by the assembler. ir["prim_idims"] = [ create_element(ufl_element).space_dimension() for ufl_element in form_data.argument_elements ] # Added for uflacs, not sure if this is the best way to get this: ir["coeff_idims"] = [ create_element(ufl_element).space_dimension() for ufl_element in form_data.coefficient_elements ] return ir
def _compute_dofmap_ir(ufl_element, element_id, element_numbers): "Compute intermediate representation of dofmap." # Create FIAT element element = create_element(ufl_element) cell = ufl_element.cell() # Precompute repeatedly used items num_dofs_per_entity = _num_dofs_per_entity(element) facet_dofs = _tabulate_facet_dofs(element, cell) # Store id ir = {"id": element_id} # Compute data for each function ir["signature"] = "FFC dofmap for " + repr(ufl_element) ir["needs_mesh_entities"] = _needs_mesh_entities(element) ir["topological_dimension"] = cell.topological_dimension() ir["geometric_dimension"] = cell.geometric_dimension() ir["global_dimension"] = _global_dimension(element) ir["local_dimension"] = element.space_dimension() ir["num_facet_dofs"] = len(facet_dofs[0]) ir["num_entity_dofs"] = num_dofs_per_entity ir["tabulate_dofs"] = _tabulate_dofs(element, cell) ir["tabulate_facet_dofs"] = facet_dofs ir["tabulate_entity_dofs"] = (element.entity_dofs(), num_dofs_per_entity) ir["tabulate_coordinates"] = _tabulate_coordinates(ufl_element, element) ir["num_sub_dofmaps"] = ufl_element.num_sub_elements() ir["create_sub_dofmap"] = _create_sub_foo(ufl_element, element_numbers) #debug_ir(ir, "dofmap") return ir
def _compute_element_ir(ufl_element, element_id, element_numbers): "Compute intermediate representation of element." # Create FIAT element element = create_element(ufl_element) cell = ufl_element.cell() # Store id ir = {"id": element_id} # Compute data for each function ir["signature"] = repr(ufl_element) ir["cell_shape"] = cell.cellname() ir["topological_dimension"] = cell.topological_dimension() ir["geometric_dimension"] = cell.geometric_dimension() ir["space_dimension"] = element.space_dimension() ir["value_rank"] = len(ufl_element.value_shape()) ir["value_dimension"] = ufl_element.value_shape() ir["evaluate_basis"] = _evaluate_basis(ufl_element, element, cell) ir["evaluate_dof"] = _evaluate_dof(ufl_element, element, cell) ir["interpolate_vertex_values"] = _interpolate_vertex_values(ufl_element, element, cell) ir["num_sub_elements"] = ufl_element.num_sub_elements() ir["create_sub_element"] = _create_sub_foo(ufl_element, element_numbers) #debug_ir(ir, "finite_element") return ir
def _generate_offsets(ufl_element, reference_offset=0, physical_offset=0): """Generate offsets: i.e value offset for each basis function relative to a physical element representation.""" if isinstance(ufl_element, ufl.MixedElement): offsets = [] for e in ufl_element.sub_elements(): offsets += _generate_offsets(e, reference_offset, physical_offset) # e is a ufl element, so value_size means the physical value size reference_offset += e.reference_value_size() physical_offset += e.value_size() return offsets elif isinstance(ufl_element, ufl.EnrichedElement): offsets = [] for e in ufl_element._elements: # TODO: Avoid private member access offsets += _generate_offsets(e, reference_offset, physical_offset) return offsets elif isinstance(ufl_element, ufl.FiniteElement): fiat_element = create_element(ufl_element) return [(reference_offset, physical_offset) ] * fiat_element.space_dimension() else: # TODO: Support RestrictedElement, QuadratureElement, # TensorProductElement, etc.! and replace # _generate_{physical|reference}_offsets with this # function. raise NotImplementedError( "This element combination is not implemented")
def _generate_offsets(ufl_element, reference_offset=0, physical_offset=0): """Generate offsets: i.e value offset for each basis function relative to a physical element representation.""" if isinstance(ufl_element, ufl.MixedElement): offsets = [] for e in ufl_element.sub_elements(): offsets += _generate_offsets(e, reference_offset, physical_offset) # e is a ufl element, so value_size means the physical value size reference_offset += e.reference_value_size() physical_offset += e.value_size() return offsets elif isinstance(ufl_element, ufl.EnrichedElement): offsets = [] for e in ufl_element._elements: # TODO: Avoid private member access offsets += _generate_offsets(e, reference_offset, physical_offset) return offsets elif isinstance(ufl_element, ufl.FiniteElement): fiat_element = create_element(ufl_element) return [(reference_offset, physical_offset)] * fiat_element.space_dimension() else: # TODO: Support RestrictedElement, QuadratureElement, # TensorProductElement, etc.! and replace # _generate_{physical|reference}_offsets with this # function. raise NotImplementedError("This element combination is not implemented")
def cell_vertices(self, e, mt, tabledata, num_points): L = self.language # Get properties of domain domain = mt.terminal.ufl_domain() gdim = domain.geometric_dimension() coordinate_element = domain.ufl_coordinate_element() # Get dimension and dofmap of scalar element assert isinstance(coordinate_element, MixedElement) assert coordinate_element.value_shape() == (gdim,) ufl_scalar_element, = set(coordinate_element.sub_elements()) assert ufl_scalar_element.family() in ("Lagrange", "Q", "S") fiat_scalar_element = create_element(ufl_scalar_element) vertex_scalar_dofs = fiat_scalar_element.entity_dofs()[0] num_scalar_dofs = fiat_scalar_element.space_dimension() # Get dof and component dof, = vertex_scalar_dofs[mt.component[0]] component = mt.component[1] expr = self.symbols.domain_dof_access(dof, component, gdim, num_scalar_dofs, mt.restriction) return expr
def _extract_element_data(element_map, element_numbers): "Extract element data for psi_tables" # Iterate over map element_data = {} for elements in six.itervalues(element_map): for ufl_element, counter in six.iteritems(elements): # Create corresponding FIAT element fiat_element = create_element(ufl_element) # Compute value size value_size = product(ufl_element.value_shape()) # Get element number element_number = element_numbers.get(ufl_element) if element_number is None: # FIXME: Should not be necessary, we should always know the element number #warning("Missing element number, likely because vector elements are not yet supported in custom integrals.") pass # Store data element_data[counter] = { "value_size": value_size, "num_element_dofs": fiat_element.space_dimension(), "element_number": element_number } return element_data
def _init_table(arguments, domain_type, points, facet0, facet1): """Initialize table of basis functions and their derivatives at the given quadrature points for each element.""" # Compute maximum number of derivatives for each element num_derivatives = {} for v in arguments: ufl_element = v.element order = len(v.derivatives) if ufl_element in num_derivatives: num_derivatives[ufl_element] = max(order, num_derivatives[ufl_element]) else: num_derivatives[ufl_element] = order # Call FIAT to tabulate the basis functions for each element table = {} for (ufl_element, order) in num_derivatives.items(): fiat_element = create_element(ufl_element) if domain_type == Measure.CELL: table[(ufl_element, None)] = fiat_element.tabulate(order, points) elif domain_type == Measure.EXTERIOR_FACET: x = map_facet_points(points, facet0) table[(ufl_element, None)] = fiat_element.tabulate(order, x) elif domain_type == Measure.INTERIOR_FACET: x0 = map_facet_points(points, facet0) x1 = map_facet_points(points, facet1) table[(ufl_element, "+")] = fiat_element.tabulate(order, x0) table[(ufl_element, "-")] = fiat_element.tabulate(order, x1) return table
def _init_table(arguments, integral_type, points, facet0, facet1): """Initialize table of basis functions and their derivatives at the given quadrature points for each element.""" # Compute maximum number of derivatives for each element num_derivatives = {} for v in arguments: ufl_element = v.element order = len(v.derivatives) if ufl_element in num_derivatives: num_derivatives[ufl_element] = max(order, num_derivatives[ufl_element]) else: num_derivatives[ufl_element] = order # Call FIAT to tabulate the basis functions for each element table = {} for (ufl_element, order) in num_derivatives.items(): fiat_element = create_element(ufl_element) if integral_type == Measure.CELL: table[(ufl_element, None)] = fiat_element.tabulate(order, points) elif integral_type == Measure.EXTERIOR_FACET: x = map_facet_points(points, facet0) table[(ufl_element, None)] = fiat_element.tabulate(order, x) elif integral_type == Measure.INTERIOR_FACET: x0 = map_facet_points(points, facet0) x1 = map_facet_points(points, facet1) table[(ufl_element, "+")] = fiat_element.tabulate(order, x0) table[(ufl_element, "-")] = fiat_element.tabulate(order, x1) return table
def transform_component(component, offset, ufl_element): """ This function accounts for the fact that if the geometrical and topological dimension does not match, then for native vector elements, in particular the Piola-mapped ones, the physical value dimensions and the reference value dimensions are not the same. This has certain consequences for mixed elements, aka 'fun with offsets'. """ # This code is used for tensor/monomialtransformation.py and # quadrature/quadraturetransformerbase.py. cell = ufl_element.cell() gdim = cell.geometric_dimension() tdim = cell.topological_dimension() # Do nothing if we are not in a special case: The special cases # occur if we have piola mapped elements (for which value_shape != # ()), and if gdim != tdim) if gdim == tdim: return component, offset all_mappings = create_element(ufl_element).mapping() special_case = (any(['piola' in m for m in all_mappings]) and ufl_element.num_sub_elements() > 1) if not special_case: return component, offset # Extract lists of reference and physical value dimensions by # sub-element reference_value_dims = [] physical_value_dims = [] for sub_element in ufl_element.sub_elements(): assert (len(sub_element.value_shape()) < 2), \ "Vector-valued assumption failed" if sub_element.value_shape() == (): reference_value_dims += [1] physical_value_dims += [1] else: reference_value_dims += [sub_element.value_shape()[0] - (gdim - tdim)] physical_value_dims += [sub_element.value_shape()[0]] # Figure out which sub-element number 'component' is in, # 'sub_element_number' contains the result tot = physical_value_dims[0] for sub_element_number in range(len(physical_value_dims)): if component < tot: break else: tot += physical_value_dims[sub_element_number + 1] # Compute the new reference offset: reference_offset = sum(reference_value_dims[:sub_element_number]) physical_offset = sum(physical_value_dims[:sub_element_number]) shift = physical_offset - reference_offset # Compute the component relative to the reference frame reference_component = component - shift return reference_component, reference_offset
def transform_component(component, offset, ufl_element): """ This function accounts for the fact that if the geometrical and topological dimension does not match, then for native vector elements, in particular the Piola-mapped ones, the physical value dimensions and the reference value dimensions are not the same. This has certain consequences for mixed elements, aka 'fun with offsets'. """ # This code is used for tensor/monomialtransformation.py and # quadrature/quadraturetransformerbase.py. domain, = ufl_element.domains() # Assuming single domain gdim = domain.geometric_dimension() tdim = domain.topological_dimension() # Do nothing if we are not in a special case: The special cases # occur if we have piola mapped elements (for which value_shape != # ()), and if gdim != tdim) if gdim == tdim: return component, offset all_mappings = create_element(ufl_element).mapping() special_case = (any(['piola' in m for m in all_mappings]) and ufl_element.num_sub_elements() > 1) if not special_case: return component, offset # Extract lists of reference and physical value dimensions by # sub-element reference_value_dims = [] physical_value_dims = [] for sub_element in ufl_element.sub_elements(): assert (len(sub_element.value_shape()) < 2), \ "Vector-valued assumption failed" if sub_element.value_shape() == (): reference_value_dims += [1] physical_value_dims += [1] else: reference_value_dims += [sub_element.value_shape()[0] - (gdim - tdim)] physical_value_dims += [sub_element.value_shape()[0]] # Figure out which sub-element number 'component' is in, # 'sub_element_number' contains the result tot = physical_value_dims[0] for sub_element_number in range(len(physical_value_dims)): if component < tot: break else: tot += physical_value_dims[sub_element_number+1] # Compute the new reference offset: reference_offset = sum(reference_value_dims[:sub_element_number]) physical_offset = sum(physical_value_dims[:sub_element_number]) shift = physical_offset - reference_offset # Compute the component relative to the reference frame reference_component = component - shift return reference_component, reference_offset
def _compute_element_ir(ufl_element, element_id, element_numbers): "Compute intermediate representation of element." # Create FIAT element element = create_element(ufl_element) cell = ufl_element.cell() # Store id ir = {"id": element_id} # Compute data for each function ir["signature"] = repr(ufl_element) ir["cell_shape"] = cell.cellname() ir["topological_dimension"] = cell.topological_dimension() ir["geometric_dimension"] = cell.geometric_dimension() ir["space_dimension"] = element.space_dimension() ir["value_rank"] = len(ufl_element.value_shape()) ir["value_dimension"] = ufl_element.value_shape() ir["evaluate_basis"] = _evaluate_basis(ufl_element, element, cell) ir["evaluate_dof"] = _evaluate_dof(ufl_element, element, cell) ir["interpolate_vertex_values"] = _interpolate_vertex_values( ufl_element, element, cell) ir["num_sub_elements"] = ufl_element.num_sub_elements() ir["create_sub_element"] = _create_sub_foo(ufl_element, element_numbers) #debug_ir(ir, "finite_element") return ir
def _compute_dofmap_ir(ufl_element, element_id, element_numbers): "Compute intermediate representation of dofmap." # Create FIAT element element = create_element(ufl_element) cell = ufl_element.cell() # Precompute repeatedly used items num_dofs_per_entity = _num_dofs_per_entity(element) facet_dofs = _tabulate_facet_dofs(element, cell) # Store id ir = {"id": element_id} # Compute data for each function ir["signature"] = "FFC dofmap for " + repr(ufl_element) ir["needs_mesh_entities"] = _needs_mesh_entities(element) ir["topological_dimension"] = cell.topological_dimension() ir["geometric_dimension"] = cell.geometric_dimension() ir["global_dimension"] = _global_dimension(element) ir["local_dimension"] = element.space_dimension() ir["num_facet_dofs"] = len(facet_dofs[0]) ir["num_entity_dofs"] = num_dofs_per_entity ir["tabulate_dofs"] = _tabulate_dofs(element, cell) ir["tabulate_facet_dofs"] = facet_dofs ir["tabulate_entity_dofs"] = (element.entity_dofs(), num_dofs_per_entity) ir["tabulate_coordinates"] = _tabulate_coordinates(ufl_element, element) ir["num_sub_dofmaps"] = ufl_element.num_sub_elements() ir["create_sub_dofmap"] = _create_sub_foo(ufl_element, element_numbers) #debug_ir(ir, "dofmap") return ir
def _extract_element_data(element_map, element_numbers): "Extract element data for psi_tables" # Iterate over map element_data = {} for elements in six.itervalues(element_map): for ufl_element, counter in six.iteritems(elements): # Create corresponding FIAT element fiat_element = create_element(ufl_element) # Compute value size value_size = product(ufl_element.value_shape()) # Get element number element_number = element_numbers.get(ufl_element) if element_number is None: # FIXME: Should not be necessary, we should always know the element number #warning("Missing element number, likely because vector elements are not yet supported in custom integrals.") pass # Store data element_data[counter] = {"value_size": value_size, "num_element_dofs": fiat_element.space_dimension(), "element_number": element_number} return element_data
def _compute_element_ir(ufl_element, element_numbers, classnames, parameters): """Compute intermediate representation of element.""" # Create FIAT element fiat_element = create_element(ufl_element) cell = ufl_element.cell() cellname = cell.cellname() # Store id ir = {"id": element_numbers[ufl_element]} ir["classname"] = classnames["finite_element"][ufl_element] # Compute data for each function ir["signature"] = repr(ufl_element) ir["cell_shape"] = cellname ir["topological_dimension"] = cell.topological_dimension() ir["geometric_dimension"] = cell.geometric_dimension() ir["space_dimension"] = fiat_element.space_dimension() ir["value_shape"] = ufl_element.value_shape() ir["reference_value_shape"] = ufl_element.reference_value_shape() ir["degree"] = ufl_element.degree() ir["family"] = ufl_element.family() ir["evaluate_basis"] = _evaluate_basis(ufl_element, fiat_element, parameters["epsilon"]) ir["evaluate_dof"] = _evaluate_dof(ufl_element, fiat_element) ir["tabulate_dof_coordinates"] = _tabulate_dof_coordinates( ufl_element, fiat_element) ir["num_sub_elements"] = ufl_element.num_sub_elements() ir["create_sub_element"] = [ classnames["finite_element"][e] for e in ufl_element.sub_elements() ] return ir_element(**ir)
def _compute_dofmap_ir(ufl_element, element_numbers, classnames, parameters): """Compute intermediate representation of dofmap.""" # Create FIAT element fiat_element = create_element(ufl_element) cell = ufl_element.cell() # Precompute repeatedly used items num_dofs_per_entity = _num_dofs_per_entity(fiat_element) entity_dofs = fiat_element.entity_dofs() edge_permutations, face_permutations, cell_topology = _compute_dofmap_permutation_tables( fiat_element, cell) # Store id ir = {"id": element_numbers[ufl_element]} ir["classname"] = classnames["dofmap"][ufl_element] # Compute data for each function ir["signature"] = "FFC dofmap for " + repr(ufl_element) ir["num_global_support_dofs"] = _num_global_support_dofs(fiat_element) ir["num_element_support_dofs"] = fiat_element.space_dimension( ) - ir["num_global_support_dofs"] ir["num_entity_dofs"] = num_dofs_per_entity ir["tabulate_entity_dofs"] = (entity_dofs, num_dofs_per_entity) ir["num_sub_dofmaps"] = ufl_element.num_sub_elements() ir["create_sub_dofmap"] = [ classnames["dofmap"][e] for e in ufl_element.sub_elements() ] return ir_dofmap(**ir)
def compute_integral_ir(itg_data, form_data, form_id, element_numbers, parameters): "Compute intermediate represention of integral." info("Computing uflacs representation") # Initialise representation ir = initialize_integral_ir("uflacs", itg_data, form_data, form_id) # Sort integrals into a dict with quadrature degree and rule as key sorted_integrals = sort_integrals(itg_data.integrals, itg_data.metadata["quadrature_degree"], itg_data.metadata["quadrature_rule"]) # TODO: Might want to create the uflacs ir first and then create the tables we need afterwards! # Tabulate quadrature points and basis function values in these points integrals_dict, psi_tables, quadrature_rules = \ tabulate_basis(sorted_integrals, form_data, itg_data) # Store element numbers, needed for classnames ir["element_numbers"] = element_numbers # Delegate to flacs to build its intermediate representation and add to ir uflacs_ir = compute_uflacs_integral_ir(psi_tables, ir["entitytype"], integrals_dict, form_data, parameters) # Store uflacs generated part separately ir["uflacs"] = uflacs_ir # Create and save the optisation parameters # TODO: Define uflacs specific optimization parameters instead #ir["optimise_parameters"] = parse_optimise_parameters(parameters) # Save tables for quadrature weights and points ir["quadrature_rules"] = quadrature_rules # Create dimensions of primary indices, needed to reset the argument 'A' # given to tabulate_tensor() by the assembler. ir["prim_idims"] = [create_element(ufl_element).space_dimension() for ufl_element in form_data.argument_elements] # Added for uflacs, not sure if this is the best way to get this: ir["coeff_idims"] = [create_element(ufl_element).space_dimension() for ufl_element in form_data.coefficient_elements] return ir
def needs_oriented_jacobian(form_data): # Check whether this form needs an oriented jacobian (only forms # involgin contravariant piola mappings seem to need it) for ufl_element in form_data.unique_elements: element = create_element(ufl_element) if "contravariant piola" in element.mapping(): return True return False
def needs_oriented_jacobian(form_data): # Check whether this form needs an oriented jacobian (only forms # involgin contravariant piola mappings seem to need it) for ufl_element in form_data.unique_elements: element = create_element(ufl_element) if "contravariant piola" in element.mapping(): return True return False
def compute_integral_ir(itg_data, form_data, form_id, parameters): "Compute intermediate represention of integral." info("Computing quadrature representation") # Initialise representation ir = initialize_integral_ir("quadrature", itg_data, form_data, form_id) # Sort integrals into a dict with number of integral points as key sorted_integrals = _sort_integrals(itg_data.integrals, itg_data.metadata, form_data) # Tabulate quadrature points and basis function values in these points integrals_dict, psi_tables, quad_weights = \ _tabulate_basis(sorted_integrals, itg_data.domain_type, form_data) # Save tables for quadrature weights and points ir["quadrature_weights"] = quad_weights # Create dimensions of primary indices, needed to reset the argument 'A' # given to tabulate_tensor() by the assembler. ir["prim_idims"] = [create_element(ufl_element).space_dimension() for ufl_element in form_data.argument_elements] # Create and save the optisation parameters. ir["optimise_parameters"] = _parse_optimise_parameters(parameters) # Create transformer. if ir["optimise_parameters"]["optimisation"]: QuadratureTransformerClass = QuadratureTransformerOpt else: QuadratureTransformerClass = QuadratureTransformer transformer = QuadratureTransformerClass(psi_tables, quad_weights, form_data.geometric_dimension, form_data.topological_dimension, ir["entitytype"], form_data.function_replace_map, ir["optimise_parameters"]) # Transform integrals. ir["trans_integrals"] = _transform_integrals_by_type(ir, transformer, integrals_dict, itg_data.domain_type, form_data.cell) # Save tables populated by transformer ir["name_map"] = transformer.name_map ir["unique_tables"] = transformer.unique_tables # Basis values? # Save tables map, to extract table names for optimisation option -O. ir["psi_tables_map"] = transformer.psi_tables_map ir["additional_includes_set"] = transformer.additional_includes_set # Insert empty data which will be populated if optimization is turned on ir["geo_consts"] = {} return ir
def compute_integral_ir(itg_data, form_data, form_id, parameters): "Compute intermediate represention of integral." info("Computing uflacs representation") # Initialise representation ir = initialize_integral_ir("uflacs", itg_data, form_data, form_id) # Sort integrals into a dict with number of integral points as key sorted_integrals = _sort_integrals(itg_data.integrals, itg_data.metadata, form_data) # Tabulate quadrature points and basis function values in these points integrals_dict, psi_tables, quad_weights = \ _tabulate_basis(sorted_integrals, itg_data.domain_type, form_data) # Save tables for quadrature weights and points ir["quadrature_weights"] = quad_weights # Save tables for basis function values ir["psi_tables"] = psi_tables # Create dimensions of primary indices, needed to reset the argument 'A' # given to tabulate_tensor() by the assembler. ir["prim_idims"] = [ create_element(ufl_element).space_dimension() for ufl_element in form_data.argument_elements ] # Added for uflacs, not sure if this is the best way to get this: ir["coeff_idims"] = [ create_element(ufl_element).space_dimension() for ufl_element in form_data.coefficient_elements ] # Create and save the optisation parameters. ir["optimise_parameters"] = _parse_optimise_parameters(parameters) # Delegate to flacs to build its intermediate representation and add to ir import uflacs.backends.ffc uir = uflacs.backends.ffc.compute_tabulate_tensor_ir( ir, integrals_dict, form_data, parameters) ir.update(uir) return ir
def compute_integral_ir(itg_data, form_data, form_id, parameters): "Compute intermediate represention of integral." info("Computing quadrature representation") # Initialise representation ir = initialize_integral_ir("quadrature", itg_data, form_data, form_id) # Sort integrals into a dict with number of integral points as key sorted_integrals = _sort_integrals(itg_data.integrals, itg_data.metadata, form_data) # Tabulate quadrature points and basis function values in these points integrals_dict, psi_tables, quad_weights = \ _tabulate_basis(sorted_integrals, itg_data.domain_type, form_data) # Save tables for quadrature weights and points ir["quadrature_weights"] = quad_weights # Create dimensions of primary indices, needed to reset the argument 'A' # given to tabulate_tensor() by the assembler. ir["prim_idims"] = [ create_element(ufl_element).space_dimension() for ufl_element in form_data.argument_elements ] # Create and save the optisation parameters. ir["optimise_parameters"] = _parse_optimise_parameters(parameters) # Create transformer. if ir["optimise_parameters"]["optimisation"]: QuadratureTransformerClass = QuadratureTransformerOpt else: QuadratureTransformerClass = QuadratureTransformer transformer = QuadratureTransformerClass(psi_tables, quad_weights, form_data.geometric_dimension, form_data.topological_dimension, ir["entitytype"], form_data.function_replace_map, ir["optimise_parameters"]) # Transform integrals. ir["trans_integrals"] = _transform_integrals_by_type( ir, transformer, integrals_dict, itg_data.domain_type, form_data.cell) # Save tables populated by transformer ir["name_map"] = transformer.name_map ir["unique_tables"] = transformer.unique_tables # Basis values? # Save tables map, to extract table names for optimisation option -O. ir["psi_tables_map"] = transformer.psi_tables_map ir["additional_includes_set"] = transformer.additional_includes_set # Insert empty data which will be populated if optimization is turned on ir["geo_consts"] = {} return ir
def _get_auxiliary_variables(self, ufl_function, component, derivatives): "Helper function for both Coefficient and Argument." # Get UFL element. ufl_element = ufl_function.element() # Get subelement and the relative (flattened) component (in case we have mixed elements). local_comp, local_elem = ufl_element.extract_component(component) ffc_assert(len(local_comp) <= 1, "Assuming there are no tensor-valued basic elements.") local_comp = local_comp[0] if local_comp else 0 # Check that component != not () since the UFL component map will turn # it into 0, and () does not mean zeroth component in this context. if len(component): # Map component using component map from UFL. (TODO: inefficient use of this function) comp_map, comp_num = build_component_numbering(ufl_element.value_shape(), ufl_element.symmetry()) component = comp_map[component] # Map physical components into reference components component, dummy = transform_component(component, 0, ufl_element) # Compute the local offset (needed for non-affine mappings). local_offset = component - local_comp else: # Compute the local offset (needed for non-affine mappings). local_offset = 0 # Create FFC element. ffc_element = create_element(ufl_element) # Assuming that mappings for all basisfunctions are equal # (they should be). ffc_sub_element = create_element(local_elem) transformation = ffc_sub_element.mapping()[0] # Generate FFC multi index for derivatives. multiindices = FFCMultiIndex([range(self.tdim)]*len(derivatives)).indices #print "in create_auxiliary" #print "component = ", component return (component, local_elem, local_comp, local_offset, ffc_element, transformation, multiindices)
def num_coordinate_component_dofs(coordinate_element): """Get the number of dofs for a coordinate component for this degree. """ fiat_elements = create_element(coordinate_element).elements() # Extracting only first component degrees of freedom from FIAT fiat_element = fiat_elements[0] assert (all( isinstance(element, type(fiat_element)) for element in fiat_elements)) return fiat_element.space_dimension()
def numBasisFunctions(e): """Return the number of basis functions. e can be a form or an element - if e is a form, the element from the test function is used.""" if isinstance(e, FormData): # Use the element from the first argument, which should be the TestFunction e = e.arguments[0].element() element = create_element(e) if isinstance(element, FFCMixedElement): return len(element.entity_dofs()) * element.num_components() else: return element.get_nodal_basis().get_num_members()
def _compute_dofmap_ir(ufl_element, element_numbers, classnames, parameters, jit=False): "Compute intermediate representation of dofmap." # Create FIAT element fiat_element = create_element(ufl_element) cell = ufl_element.cell() # Precompute repeatedly used items num_dofs_per_entity = _num_dofs_per_entity(fiat_element) entity_dofs = fiat_element.entity_dofs() facet_dofs = _tabulate_facet_dofs(fiat_element, cell) entity_closure_dofs, num_dofs_per_entity_closure = \ _tabulate_entity_closure_dofs(fiat_element, cell) # Store id ir = {"id": element_numbers[ufl_element]} ir["classname"] = classnames["dofmap"][ufl_element] # Remember jit status ir["jit"] = jit # Compute data for each function ir["signature"] = "FFC dofmap for " + repr(ufl_element) ir["needs_mesh_entities"] = _needs_mesh_entities(fiat_element) ir["topological_dimension"] = cell.topological_dimension() ir["geometric_dimension"] = cell.geometric_dimension() ir["global_dimension"] = _global_dimension(fiat_element) ir["num_global_support_dofs"] = _num_global_support_dofs(fiat_element) ir["num_element_support_dofs"] = fiat_element.space_dimension( ) - ir["num_global_support_dofs"] ir["num_element_dofs"] = fiat_element.space_dimension() ir["num_facet_dofs"] = len(facet_dofs[0]) ir["num_entity_dofs"] = num_dofs_per_entity ir["num_entity_closure_dofs"] = num_dofs_per_entity_closure ir["tabulate_dofs"] = _tabulate_dofs(fiat_element, cell) ir["tabulate_facet_dofs"] = facet_dofs ir["tabulate_entity_dofs"] = (entity_dofs, num_dofs_per_entity) ir["tabulate_entity_closure_dofs"] = (entity_closure_dofs, entity_dofs, num_dofs_per_entity) ir["num_sub_dofmaps"] = ufl_element.num_sub_elements() ir["create_sub_dofmap"] = [ classnames["dofmap"][e] for e in ufl_element.sub_elements() ] return ir
def test_values(self, family, cell, degree, reference): # Create element element = create_element(FiniteElement(family, cell, degree)) # Get some points and check basis function values at points points = [random_point(element_coords(cell)) for i in range(5)] for x in points: table = element.tabulate(0, (x,)) basis = table[list(table.keys())[0]] for i in range(len(basis)): if not element.value_shape(): assert round(float(basis[i]) - reference[i](x), 10) == 0.0 else: for k in range(element.value_shape()[0]): assert round(basis[i][k][0] - reference[i](x)[k] , 10) == 0.0
def test_values(self, family, cell, degree, reference): # Create element element = create_element(FiniteElement(family, cell, degree)) # Get some points and check basis function values at points points = [random_point(element_coords(cell)) for i in range(5)] for x in points: table = element.tabulate(0, (x, )) basis = table[list(table.keys())[0]] for i in range(len(basis)): if not element.value_shape(): assert round(float(basis[i]) - reference[i](x), 10) == 0.0 else: for k in range(element.value_shape()[0]): assert round(basis[i][k][0] - reference[i](x)[k], 10) == 0.0
def facet_edge_vectors(self, e, mt, tabledata, num_points): L = self.language # Get properties of domain domain = mt.terminal.ufl_domain() cellname = domain.ufl_cell().cellname() gdim = domain.geometric_dimension() coordinate_element = domain.ufl_coordinate_element() if cellname in ("tetrahedron", "hexahedron"): pass elif cellname in ("interval", "triangle", "quadrilateral"): error( "The physical facet edge vectors doesn't make sense for {0} cell." .format(cellname)) else: error("Unhandled cell types {0}.".format(cellname)) # Get dimension and dofmap of scalar element assert isinstance(coordinate_element, MixedElement) assert coordinate_element.value_shape() == (gdim, ) ufl_scalar_element, = set(coordinate_element.sub_elements()) assert ufl_scalar_element.family() in ("Lagrange", "Q", "S") fiat_scalar_element = create_element(ufl_scalar_element) vertex_scalar_dofs = fiat_scalar_element.entity_dofs()[0] num_scalar_dofs = fiat_scalar_element.space_dimension() # Get edge vertices facet = self.symbols.entity("facet", mt.restriction) facet_edge = mt.component[0] facet_edge_vertices = L.Symbol( "{0}_facet_edge_vertices".format(cellname)) vertex0 = facet_edge_vertices[facet][facet_edge][0] vertex1 = facet_edge_vertices[facet][facet_edge][1] # Get dofs and component component = mt.component[1] assert coordinate_element.degree() == 1, "Assuming degree 1 element" dof0 = vertex0 dof1 = vertex1 expr = (self.symbols.domain_dof_access( dof0, component, gdim, num_scalar_dofs, mt.restriction) - self.symbols.domain_dof_access( dof1, component, gdim, num_scalar_dofs, mt.restriction)) return expr
def facet_edge_vectors(self, e, mt, tabledata, num_points): L = self.language # Get properties of domain domain = mt.terminal.ufl_domain() cellname = domain.ufl_cell().cellname() gdim = domain.geometric_dimension() coordinate_element = domain.ufl_coordinate_element() if cellname in ("tetrahedron", "hexahedron"): pass elif cellname in ("interval", "triangle", "quadrilateral"): error("The physical facet edge vectors doesn't make sense for {0} cell.".format(cellname)) else: error("Unhandled cell types {0}.".format(cellname)) # Get dimension and dofmap of scalar element assert isinstance(coordinate_element, MixedElement) assert coordinate_element.value_shape() == (gdim,) ufl_scalar_element, = set(coordinate_element.sub_elements()) assert ufl_scalar_element.family() in ("Lagrange", "Q", "S") fiat_scalar_element = create_element(ufl_scalar_element) vertex_scalar_dofs = fiat_scalar_element.entity_dofs()[0] num_scalar_dofs = fiat_scalar_element.space_dimension() # Get edge vertices facet = self.symbols.entity("facet", mt.restriction) facet_edge = mt.component[0] facet_edge_vertices = L.Symbol("{0}_facet_edge_vertices".format(cellname)) vertex0 = facet_edge_vertices[facet][facet_edge][0] vertex1 = facet_edge_vertices[facet][facet_edge][1] # Get dofs and component component = mt.component[1] assert coordinate_element.degree() == 1, "Assuming degree 1 element" dof0 = vertex0 dof1 = vertex1 expr = ( self.symbols.domain_dof_access(dof0, component, gdim, num_scalar_dofs, mt.restriction) - self.symbols.domain_dof_access(dof1, component, gdim, num_scalar_dofs, mt.restriction) ) return expr
def cell_edge_vectors(self, e, mt, tabledata, num_points): L = self.language # Get properties of domain domain = mt.terminal.ufl_domain() cellname = domain.ufl_cell().cellname() gdim = domain.geometric_dimension() coordinate_element = domain.ufl_coordinate_element() if cellname in ("triangle", "tetrahedron", "quadrilateral", "hexahedron"): pass elif cellname == "interval": error( "The physical cell edge vectors doesn't make sense for interval cell." ) else: error("Unhandled cell types {0}.".format(cellname)) # Get dimension and dofmap of scalar element assert isinstance(coordinate_element, MixedElement) assert coordinate_element.value_shape() == (gdim, ) ufl_scalar_element, = set(coordinate_element.sub_elements()) assert ufl_scalar_element.family() in ("Lagrange", "Q", "S") fiat_scalar_element = create_element(ufl_scalar_element) vertex_scalar_dofs = fiat_scalar_element.entity_dofs()[0] num_scalar_dofs = fiat_scalar_element.space_dimension() # Get edge vertices edge = mt.component[0] edge_vertices = fiat_scalar_element.get_reference_element( ).get_topology()[1][edge] vertex0, vertex1 = edge_vertices # Get dofs and component dof0, = vertex_scalar_dofs[vertex0] dof1, = vertex_scalar_dofs[vertex1] component = mt.component[1] expr = (self.symbols.domain_dof_access( dof0, component, gdim, num_scalar_dofs, mt.restriction) - self.symbols.domain_dof_access( dof1, component, gdim, num_scalar_dofs, mt.restriction)) return expr
def _compute_dofmap_ir(ufl_element, element_numbers, classnames, parameters, jit=False): "Compute intermediate representation of dofmap." # Create FIAT element fiat_element = create_element(ufl_element) cell = ufl_element.cell() # Precompute repeatedly used items num_dofs_per_entity = _num_dofs_per_entity(fiat_element) entity_dofs = fiat_element.entity_dofs() facet_dofs = _tabulate_facet_dofs(fiat_element, cell) entity_closure_dofs, num_dofs_per_entity_closure = \ _tabulate_entity_closure_dofs(fiat_element, cell) # Store id ir = {"id": element_numbers[ufl_element]} ir["classname"] = classnames["dofmap"][ufl_element] # Remember jit status ir["jit"] = jit # Compute data for each function ir["signature"] = "FFC dofmap for " + repr(ufl_element) ir["needs_mesh_entities"] = _needs_mesh_entities(fiat_element) ir["topological_dimension"] = cell.topological_dimension() ir["geometric_dimension"] = cell.geometric_dimension() ir["global_dimension"] = _global_dimension(fiat_element) ir["num_global_support_dofs"] = _num_global_support_dofs(fiat_element) ir["num_element_support_dofs"] = fiat_element.space_dimension() - ir["num_global_support_dofs"] ir["num_element_dofs"] = fiat_element.space_dimension() ir["num_facet_dofs"] = len(facet_dofs[0]) ir["num_entity_dofs"] = num_dofs_per_entity ir["num_entity_closure_dofs"] = num_dofs_per_entity_closure ir["tabulate_dofs"] = _tabulate_dofs(fiat_element, cell) ir["tabulate_facet_dofs"] = facet_dofs ir["tabulate_entity_dofs"] = (entity_dofs, num_dofs_per_entity) ir["tabulate_entity_closure_dofs"] = (entity_closure_dofs, entity_dofs, num_dofs_per_entity) ir["num_sub_dofmaps"] = ufl_element.num_sub_elements() ir["create_sub_dofmap"] = [classnames["dofmap"][e] for e in ufl_element.sub_elements()] return ir
def cell_edge_vectors(self, e, mt, tabledata, num_points): L = self.language # Get properties of domain domain = mt.terminal.ufl_domain() cellname = domain.ufl_cell().cellname() gdim = domain.geometric_dimension() coordinate_element = domain.ufl_coordinate_element() if cellname in ("triangle", "tetrahedron", "quadrilateral", "hexahedron"): pass elif cellname == "interval": error("The physical cell edge vectors doesn't make sense for interval cell.") else: error("Unhandled cell types {0}.".format(cellname)) # Get dimension and dofmap of scalar element assert isinstance(coordinate_element, MixedElement) assert coordinate_element.value_shape() == (gdim,) ufl_scalar_element, = set(coordinate_element.sub_elements()) assert ufl_scalar_element.family() in ("Lagrange", "Q", "S") fiat_scalar_element = create_element(ufl_scalar_element) vertex_scalar_dofs = fiat_scalar_element.entity_dofs()[0] num_scalar_dofs = fiat_scalar_element.space_dimension() # Get edge vertices edge = mt.component[0] edge_vertices = fiat_scalar_element.get_reference_element().get_topology()[1][edge] vertex0, vertex1 = edge_vertices # Get dofs and component dof0, = vertex_scalar_dofs[vertex0] dof1, = vertex_scalar_dofs[vertex1] component = mt.component[1] expr = ( self.symbols.domain_dof_access(dof0, component, gdim, num_scalar_dofs, mt.restriction) - self.symbols.domain_dof_access(dof1, component, gdim, num_scalar_dofs, mt.restriction) ) return expr
def cell_vertices(self, e, mt, tabledata, num_points): # Get properties of domain domain = mt.terminal.ufl_domain() gdim = domain.geometric_dimension() coordinate_element = domain.ufl_coordinate_element() # Get dimension and dofmap of scalar element assert isinstance(coordinate_element, MixedElement) assert coordinate_element.value_shape() == (gdim, ) ufl_scalar_element, = set(coordinate_element.sub_elements()) assert ufl_scalar_element.family() in ("Lagrange", "Q", "S") fiat_scalar_element = create_element(ufl_scalar_element) vertex_scalar_dofs = fiat_scalar_element.entity_dofs()[0] num_scalar_dofs = fiat_scalar_element.space_dimension() # Get dof and component dof, = vertex_scalar_dofs[mt.component[0]] component = mt.component[1] expr = self.symbols.domain_dof_access(dof, component, gdim, num_scalar_dofs, mt.restriction) return expr
def _compute_element_ir(ufl_element, element_numbers, classnames, parameters, jit): "Compute intermediate representation of element." # Create FIAT element fiat_element = create_element(ufl_element) cell = ufl_element.cell() cellname = cell.cellname() # Store id ir = {"id": element_numbers[ufl_element]} ir["classname"] = classnames["finite_element"][ufl_element] # Remember jit status ir["jit"] = jit # Compute data for each function ir["signature"] = repr(ufl_element) ir["cell_shape"] = cellname ir["topological_dimension"] = cell.topological_dimension() ir["geometric_dimension"] = cell.geometric_dimension() ir["space_dimension"] = fiat_element.space_dimension() ir["value_shape"] = ufl_element.value_shape() ir["reference_value_shape"] = ufl_element.reference_value_shape() ir["degree"] = ufl_element.degree() ir["family"] = ufl_element.family() ir["evaluate_basis"] = _evaluate_basis(ufl_element, fiat_element, parameters["epsilon"]) ir["evaluate_dof"] = _evaluate_dof(ufl_element, fiat_element) ir["interpolate_vertex_values"] = _interpolate_vertex_values(ufl_element, fiat_element) ir["tabulate_dof_coordinates"] = _tabulate_dof_coordinates(ufl_element, fiat_element) ir["num_sub_elements"] = ufl_element.num_sub_elements() ir["create_sub_element"] = [classnames["finite_element"][e] for e in ufl_element.sub_elements()] # debug_ir(ir, "finite_element") return ir
def _compute_element_ir(ufl_element, prefix, element_numbers): "Compute intermediate representation of element." # This hits unimplemented FIAT functionality for OPEs; the IR # is only required for function evaluation at a point, not integrals if isinstance(ufl_element.cell(), ufl.OuterProductCell): return None # Create FIAT element fiat_element = create_element(ufl_element) cell = ufl_element.cell() cellname = cell.cellname() # Store id ir = {"id": element_numbers[ufl_element]} ir["classname"] = make_classname(prefix, "finite_element", element_numbers[ufl_element]) # Compute data for each function ir["cell"] = cell ir["signature"] = repr(ufl_element) ir["cell_shape"] = cellname ir["topological_dimension"] = cell.topological_dimension() ir["geometric_dimension"] = cell.geometric_dimension() ir["space_dimension"] = fiat_element.space_dimension() ir["value_rank"] = len(ufl_element.value_shape()) ir["value_dimension"] = ufl_element.value_shape() ir["reference_value_dimension"] = ufl_element.reference_value_shape() ir["evaluate_basis"] = _evaluate_basis(ufl_element, fiat_element) ir["evaluate_dof"] = _evaluate_dof(ufl_element, fiat_element) ir["interpolate_vertex_values"] = _interpolate_vertex_values(ufl_element, fiat_element) ir["tabulate_dof_coordinates"] = _tabulate_dof_coordinates(ufl_element, fiat_element) ir["num_sub_elements"] = ufl_element.num_sub_elements() ir["create_sub_element"] = [make_classname(prefix, "finite_element", element_numbers[e]) for e in ufl_element.sub_elements()] #debug_ir(ir, "finite_element") return ir
def _compute_dofmap_ir(ufl_element, prefix, element_numbers): "Compute intermediate representation of dofmap." # This hits unimplemented FIAT functionality for OPEs; our # dofmaps are not produced by FFC anyway, AFAIK if isinstance(ufl_element.cell(), ufl.OuterProductCell): return None # Create FIAT element fiat_element = create_element(ufl_element) cell = ufl_element.cell() cellname = cell.cellname() # Precompute repeatedly used items num_dofs_per_entity = _num_dofs_per_entity(fiat_element) facet_dofs = _tabulate_facet_dofs(fiat_element, cell) # Store id ir = {"id": element_numbers[ufl_element]} ir["classname"] = make_classname(prefix, "dofmap", element_numbers[ufl_element]) # Compute data for each function ir["signature"] = "FFC dofmap for " + repr(ufl_element) ir["needs_mesh_entities"] = _needs_mesh_entities(fiat_element) ir["cell"] = cell ir["topological_dimension"] = cell.topological_dimension() ir["geometric_dimension"] = cell.geometric_dimension() ir["global_dimension"] = _global_dimension(fiat_element) ir["num_element_dofs"] = fiat_element.space_dimension() ir["num_facet_dofs"] = len(facet_dofs[0]) ir["num_entity_dofs"] = num_dofs_per_entity ir["tabulate_dofs"] = _tabulate_dofs(fiat_element, cell) ir["tabulate_facet_dofs"] = facet_dofs ir["tabulate_entity_dofs"] = (fiat_element.entity_dofs(), num_dofs_per_entity) ir["num_sub_dofmaps"] = ufl_element.num_sub_elements() ir["create_sub_dofmap"] = [make_classname(prefix, "dofmap", element_numbers[e]) for e in ufl_element.sub_elements()] return ir
def _tabulate_coordinate_mapping_basis(ufl_element): # TODO: Move this function to a table generation module? # Get scalar element, assuming coordinates are represented # with a VectorElement of scalar subelements selement = ufl_element.sub_elements()[0] fiat_element = create_element(selement) cell = selement.cell() tdim = cell.topological_dimension() tables = {} # Get points origo = (0.0, ) * tdim midpoint = cell_midpoint(cell) # Tabulate basis t0 = fiat_element.tabulate(1, [origo]) tm = fiat_element.tabulate(1, [midpoint]) # Get basis values at cell origo tables["x0"] = t0[(0, ) * tdim][:, 0] # Get basis values at cell midpoint tables["xm"] = tm[(0, ) * tdim][:, 0] # Single direction derivatives, e.g. [(1,0), (0,1)] in 2d derivatives = [(0, ) * i + (1, ) + (0, ) * (tdim - 1 - i) for i in range(tdim)] # Get basis derivative values at cell origo tables["J0"] = numpy.asarray([t0[d][:, 0] for d in derivatives]) # Get basis derivative values at cell midpoint tables["Jm"] = numpy.asarray([tm[d][:, 0] for d in derivatives]) return tables
def _extract_element_data(element_map, classnames): "Extract element data for psi_tables" # Iterate over map element_data = {} for elements in element_map.values(): for ufl_element, counter in elements.items(): # Create corresponding FIAT element fiat_element = create_element(ufl_element) # Compute value size value_size = product(ufl_element.value_shape()) # Get element classname element_classname = classnames["finite_element"][ufl_element] # Store data element_data[counter] = {"physical_value_size": value_size, "num_element_dofs": fiat_element.space_dimension(), "classname": element_classname} return element_data
def _tabulate_coordinate_mapping_basis(ufl_element): # TODO: Move this function to a table generation module? # Get scalar element, assuming coordinates are represented # with a VectorElement of scalar subelements selement = ufl_element.sub_elements()[0] fiat_element = create_element(selement) cell = selement.cell() tdim = cell.topological_dimension() tables = {} # Get points origo = (0.0,) * tdim midpoint = cell_midpoint(cell) # Tabulate basis t0 = fiat_element.tabulate(1, [origo]) tm = fiat_element.tabulate(1, [midpoint]) # Get basis values at cell origo tables["x0"] = t0[(0,) * tdim][:, 0] # Get basis values at cell midpoint tables["xm"] = tm[(0,) * tdim][:, 0] # Single direction derivatives, e.g. [(1,0), (0,1)] in 2d derivatives = [(0,) * i + (1,) + (0,) * (tdim - 1 - i) for i in range(tdim)] # Get basis derivative values at cell origo tables["J0"] = numpy.asarray([t0[d][:, 0] for d in derivatives]) # Get basis derivative values at cell midpoint tables["Jm"] = numpy.asarray([tm[d][:, 0] for d in derivatives]) return tables
def get_data(ufl_element): "Get needed data to run tests." # Create fiat element. element = create_element(ufl_element) # The derivative order that we are interested in is the degree of the element. if isinstance(element, FFCMixedElement): deriv_order = max([e.degree() for e in element.elements()]) else: deriv_order = element.degree() # Get coordinates of the reference cell. cell = ufl_element.cell() ref_coords = reference_cell(cell.cellname()).get_vertices() # Get the locations of the fiat element dofs. elem_points = [list(L.pt_dict.keys())[0] for L in element.dual_basis()] # Add some random points. geo_dim = cell.geometric_dimension() points = elem_points + random_points[geo_dim] return (element, points, geo_dim, ref_coords, deriv_order)
def get_data(ufl_element): "Get needed data to run tests." # Create fiat element. element = create_element(ufl_element) # The derivative order that we are interested in is the degree of the element. if isinstance(element, FFCMixedElement): deriv_order = max([e.degree() for e in element.elements()]) else: deriv_order = element.degree() # Get coordinates of the reference cell. cell = ufl_element.cell() ref_coords = reference_cell(cell.cellname()).get_vertices() # Get the locations of the fiat element dofs. elem_points = [list(L.pt_dict.keys())[0] for L in element.dual_basis()] # Add some random points. geo_dim = cell.geometric_dimension() points = elem_points + random_points[geo_dim] return (element, points, geo_dim, ref_coords, deriv_order)
def test_continuous_lagrange_quadrilateral(degree, expected_dim): "Test space dimensions of continuous TensorProduct elements (quadrilateral)." P = create_element(FiniteElement("Lagrange", "quadrilateral", degree)) assert P.space_dimension() == expected_dim
def test_discontinuous_lagrange(degree, expected_dim): "Test space dimensions of discontinuous Lagrange elements." P = create_element(FiniteElement("DG", "triangle", degree)) assert P.space_dimension() == expected_dim
def test_hhj(degree, expected_dim): "Test space dimensions of Hellan-Herrmann-Johnson element." P = create_element(FiniteElement("HHJ", "triangle", degree)) assert P.space_dimension() == expected_dim
def __init__(self, monomial): "Create transformed monomial from given monomial." # Reset monomial data self.float_value = monomial.float_value self.determinants = [] self.coefficients = [] self.transforms = [] self.arguments = [] # Reset index counters _reset_indices() # Initialize index map index_map = {} # Iterate over factors for f in monomial.factors: # Create FIAT element ufl_element = f.element() fiat_element = create_element(ufl_element) # Note nifty aspect here: when gdim != tdim, it might be # (in particular, is for H(div)/H(curl), that the value # dimension is different for the physical and reference # elements. # Get number of components # FIXME: Can't handle tensor-valued elements: vdim = shape[0] shape = ufl_element.value_shape() assert(len(shape) <= 1), \ "MonomialTransformation does not handle tensor-valued elements" if len(shape) == 0: vdim = 1 else: vdim = shape[0] # Extract dimensions sdim = fiat_element.space_dimension() cell = ufl_element.cell() gdim = cell.geometric_dimension() tdim = cell.topological_dimension() # Extract basis function index and coefficients if isinstance(f.function, Argument): vindex = MonomialIndex(index_type=MonomialIndex.PRIMARY, index_range=list(range(sdim)), index_id=f.index()) elif isinstance(f.function, Coefficient): vindex = MonomialIndex(index_range=list(range(sdim))) coefficient = MonomialCoefficient(vindex, f.index()) self.coefficients.append(coefficient) # Extract components components = self._extract_components(f, index_map, vdim) if len(components) > 1: raise MonomialException("Can only handle rank 0 or rank 1 tensors.") # Handle non-affine mappings (Piola) if len(components) > 0: # We can only handle rank 1 elements for now component = components[0] # Get mapping (all need to be equal) mappings = [] for i in component.index_range: (offset, ufl_sub_element) = ufl_element.extract_component(i) fiat_sub_element = create_element(ufl_sub_element) mappings.extend(fiat_sub_element.mapping()) if not all_equal(mappings): raise MonomialException("Mappings differ: " + str(mappings)) mapping = mappings[0] # Get component index relative to its sub element and its sub element (component_index, sub_element) = ufl_element.extract_component(component.index_range[0]) # Get offset if len(component_index) == 0: offset = 0 else: offset = component.index_range[0] - component_index[0] # MER: Need to handle mappings in special ways if gdim # != tdim and some Piolas are present. This could # probably be merged with the offset code above, but I # was not able to wrap my head around the offsets # always referring to component.index_range[0]. if (gdim != tdim): assert len(component.index_range) == 1, \ "Component transform not implemented for this case. Please request this feature." component, offset = transform_component(component.index_range[0], offset, ufl_element) component = MonomialIndex(index_type=MonomialIndex.FIXED, index_range=[component], index_id=None) components = [component, ] # Add transforms where appropriate if mapping == "contravariant piola": # phi(x) = (det J)^{-1} J Phi(X) index0 = component index1 = MonomialIndex(index_range=list(range(tdim))) + offset transform = MonomialTransform(index0, index1, MonomialTransform.J, f.restriction, offset) self.transforms.append(transform) determinant = MonomialDeterminant(power=-1, restriction=f.restriction) self.determinants.append(determinant) components[0] = index1 elif mapping == "covariant piola": # phi(x) = J^{-T} Phi(X) index0 = MonomialIndex(index_range=list(range(tdim))) + offset index1 = component transform = MonomialTransform(index0, index1, MonomialTransform.JINV, f.restriction, offset) self.transforms.append(transform) components[0] = index0 # Extract derivatives / transforms derivatives = [] for d in f.derivatives: index0 = MonomialIndex(index_range=list(range(tdim))) if d in index_map: index1 = index_map[d] elif isinstance(d, FixedIndex): index1 = MonomialIndex(index_type=MonomialIndex.FIXED, index_range=[int(d)], index_id=int(d)) else: index1 = MonomialIndex(index_range=list(range(gdim))) index_map[d] = index1 transform = MonomialTransform(index0, index1, MonomialTransform.JINV, f.restriction, 0) self.transforms.append(transform) derivatives.append(index0) # Extract restriction restriction = f.restriction # Create basis function v = MonomialArgument(ufl_element, vindex, components, derivatives, restriction) self.arguments.append(v) # Figure out secondary and auxiliary indices internal_indices = self._extract_internal_indices(None) external_indices = self._extract_external_indices(None) for i in internal_indices + external_indices: # Skip already visited indices if not i.index_type is None: continue # Set index type and id num_internal = len([j for j in internal_indices if j == i]) num_external = len([j for j in external_indices if j == i]) if num_internal == 1 and num_external == 1: i.index_type = MonomialIndex.SECONDARY i.index_id = _next_secondary_index() elif num_internal == 2 and num_external == 0: i.index_type = MonomialIndex.INTERNAL i.index_id = _next_internal_index() elif num_internal == 0 and num_external == 2: i.index_type = MonomialIndex.EXTERNAL i.index_id = _next_external_index() else: raise Exception("Summation index does not appear exactly twice: %s" % str(i))
def test_regge(degree, expected_dim): "Test space dimensions of generalized Regge element." P = create_element(FiniteElement("Regge", "triangle", degree)) assert P.space_dimension() == expected_dim
def test_discontinuous_lagrange(degree, expected_dim): "Test space dimensions of discontinuous Lagrange elements." P = create_element(FiniteElement("DG", "triangle", degree)) assert P.space_dimension() == expected_dim
def test_continuous_lagrange_quadrilateral(degree, expected_dim): "Test space dimensions of continuous TensorProduct elements (quadrilateral)." P = create_element(FiniteElement("Lagrange", "quadrilateral", degree)) assert P.space_dimension() == expected_dim
def test_regge(degree, expected_dim): "Test space dimensions of generalized Regge element." P = create_element(FiniteElement("Regge", "triangle", degree)) assert P.space_dimension() == expected_dim
def create_dof_models(element): "Create Soya3D models for dofs." # Flags for whether to flip and center arrows directional = {"PointScaledNormalEval": (True, False), "PointEdgeTangent": (False, True), "PointFaceTangent": (False, True)} # Elements not supported fully by FIAT unsupported = {"Argyris": argyris_dofs, "Arnold-Winther": arnold_winther_dofs, "Hermite": hermite_dofs, "Mardal-Tai-Winther": mardal_tai_winther_dofs, "Morley": morley_dofs} # Check if element is supported family = element.family() if not family in unsupported: # Create FIAT element and get dofs fiat_element = create_element(element) dofs = [(dof.get_type_tag(), dof.get_point_dict()) for dof in fiat_element.dual_basis()] else: # Bybass FIAT and set the dofs ourselves dofs = unsupported[family](element) # Iterate over dofs and add models models = [] num_moments = 0 for (dof_type, L) in dofs: # Check type of dof if dof_type == "PointEval": # Point evaluation, just get point points = list(L.keys()) if not len(points) == 1: error("Strange dof, single point expected.") x = points[0] # Generate model models.append(PointEvaluation(x)) elif dof_type == "PointDeriv": # Evaluation of derivatives at point points = list(L.keys()) if not len(points) == 1: error("Strange dof, single point expected.") x = points[0] # Generate model models.append(PointDerivative(x)) elif dof_type == "PointSecondDeriv": # Evaluation of derivatives at point points = list(L.keys()) if not len(points) == 1: error("Strange dof, single point expected.") x = points[0] # Generate model models.append(PointSecondDerivative(x)) elif dof_type in directional: # Normal evaluation, get point and normal points = list(L.keys()) if not len(points) == 1: error("Strange dof, single point expected.") x = points[0] n = [xx[0] for xx in L[x]] # Generate model flip, center = directional[dof_type] models.append(DirectionalEvaluation(x, n, flip, center)) elif dof_type == "PointNormalDeriv": # Evaluation of derivatives at point points = list(L.keys()) if not len(points) == 1: error("Strange dof, single point expected.") x = points[0] n = [xx[0] for xx in L[x]] # Generate model models.append(DirectionalDerivative(x, n)) elif dof_type in ("FrobeniusIntegralMoment", "IntegralMoment", "ComponentPointEval"): # Generate model models.append(IntegralMoment(element.cell().cellname(), num_moments)) # Count the number of integral moments num_moments += 1 else: error("Unable to plot dof, unhandled dof type: %s" % str(dof_type)) return models, num_moments
def test_hhj(degree, expected_dim): "Test space dimensions of Hellan-Herrmann-Johnson element." P = create_element(FiniteElement("HHJ", "triangle", degree)) assert P.space_dimension() == expected_dim
def tabulate_basis(sorted_integrals, form_data, itg_data): "Tabulate the basisfunctions and derivatives." # MER: Note to newbies: this code assumes that each integral in # the dictionary of sorted_integrals that enters here, has a # unique number of quadrature points ... # Initialise return values. quadrature_rules = {} psi_tables = {} integrals = {} avg_elements = {"cell": [], "facet": []} # Get some useful variables in short form integral_type = itg_data.integral_type cell = itg_data.domain.ufl_cell() cellname = cell.cellname() tdim = itg_data.domain.topological_dimension() entity_dim = integral_type_to_entity_dim(integral_type, tdim) num_entities = num_cell_entities[cellname][entity_dim] # Create canonical ordering of quadrature rules rules = sorted(sorted_integrals.keys()) # Loop the quadrature points and tabulate the basis values. for rule in rules: scheme, degree = rule # --------- Creating quadrature rule # Make quadrature rule and get points and weights. (points, weights) = create_quadrature_points_and_weights(integral_type, cell, degree, scheme) # The TOTAL number of weights/points num_points = None if weights is None else len(weights) # Add points and rules to dictionary if num_points in quadrature_rules: error("This number of points is already present in the weight table: " + repr(quadrature_rules)) quadrature_rules[num_points] = (weights, points) # --------- Store integral # Add the integral with the number of points as a key to the # return integrals. integral = sorted_integrals[rule] if num_points in integrals: error("This number of points is already present in the integrals: " + repr(integrals)) integrals[num_points] = integral # --------- Analyse UFL elements in integral # Get all unique elements in integral. ufl_elements = [form_data.element_replace_map[e] for e in extract_unique_elements(integral)] # Insert elements for x and J domain = integral.ufl_domain() # FIXME: For all domains to be sure? Better to rewrite though. x_element = domain.ufl_coordinate_element() if x_element not in ufl_elements: if integral_type in custom_integral_types: # FIXME: Not yet implemented, in progress # warning("Vector elements not yet supported in custom integrals so element for coordinate function x will not be generated.") pass else: ufl_elements.append(x_element) # Find all CellAvg and FacetAvg in integrals and extract # elements for avg, AvgType in (("cell", CellAvg), ("facet", FacetAvg)): expressions = extract_type(integral, AvgType) avg_elements[avg] = [form_data.element_replace_map[e] for expr in expressions for e in extract_unique_elements(expr)] # Find the highest number of derivatives needed for each element num_derivatives = _find_element_derivatives(integral.integrand(), ufl_elements, form_data.element_replace_map) # Need at least 1 for the Jacobian num_derivatives[x_element] = max(num_derivatives.get(x_element, 0), 1) # --------- Evaluate FIAT elements in quadrature points and # --------- store in tables # Add the number of points to the psi tables dictionary if num_points in psi_tables: error("This number of points is already present in the psi table: " + repr(psi_tables)) psi_tables[num_points] = {} # Loop FIAT elements and tabulate basis as usual. for ufl_element in ufl_elements: fiat_element = create_element(ufl_element) # Tabulate table of basis functions and derivatives in # points psi_table = _tabulate_psi_table(integral_type, cellname, tdim, fiat_element, num_derivatives[ufl_element], points) # Insert table into dictionary based on UFL elements # (None=not averaged) avg = None psi_tables[num_points][ufl_element] = { avg: psi_table } # Loop over elements found in CellAvg and tabulate basis averages num_points = 1 for avg in ("cell", "facet"): # Doesn't matter if it's exterior or interior if avg == "cell": avg_integral_type = "cell" elif avg == "facet": avg_integral_type = "exterior_facet" for element in avg_elements[avg]: fiat_element = create_element(element) # Make quadrature rule and get points and weights. (points, weights) = create_quadrature_points_and_weights(avg_integral_type, cell, element.degree(), "default") wsum = sum(weights) # Tabulate table of basis functions and derivatives in # points entity_psi_tables = _tabulate_psi_table(avg_integral_type, cellname, tdim, fiat_element, 0, points) rank = len(element.value_shape()) # Hack, duplicating table with per-cell values for each # facet in the case of cell_avg(f) in a facet integral if num_entities > len(entity_psi_tables): assert len(entity_psi_tables) == 1 assert avg_integral_type == "cell" assert "facet" in integral_type v, = sorted(entity_psi_tables.values()) entity_psi_tables = dict((e, v) for e in range(num_entities)) for entity, deriv_table in sorted(entity_psi_tables.items()): deriv, = sorted(deriv_table.keys()) # Not expecting derivatives of averages psi_table = deriv_table[deriv] if rank: # Compute numeric integral num_dofs, num_components, num_points = psi_table.shape if num_points != len(weights): error("Weights and table shape does not match.") avg_psi_table = numpy.asarray([[[numpy.dot(psi_table[j, k, :], weights) / wsum] for k in range(num_components)] for j in range(num_dofs)]) else: # Compute numeric integral num_dofs, num_points = psi_table.shape if num_points != len(weights): error("Weights and table shape does not match.") avg_psi_table = numpy.asarray([[numpy.dot(psi_table[j, :], weights) / wsum] for j in range(num_dofs)]) # Insert table into dictionary based on UFL elements insert_nested_dict(psi_tables, (num_points, element, avg, entity, deriv), avg_psi_table) return (integrals, psi_tables, quadrature_rules)