def coordinate_derivative(self, o): from ufl.algorithms import extract_unique_elements spaces = set(c.family() for c in extract_unique_elements(o)) unsupported_spaces = {"Argyris", "Bell", "Hermite", "Morley"} if spaces & unsupported_spaces: error("CoordinateDerivative is not supported for elements of type %s. " "This is because their pullback is not implemented in UFL." % unsupported_spaces) f, w, v, cd = o.ufl_operands f = self(f) # transform f rules = CoordinateDerivativeRuleset(w, v, cd) return map_expr_dag(rules, f)
def coordinate_derivative(self, o, f, w, v, cd): from ufl.algorithms import extract_unique_elements spaces = set(c.family() for c in extract_unique_elements(o)) unsupported_spaces = {"Argyris", "Bell", "Hermite", "Morley"} if spaces & unsupported_spaces: error("CoordinateDerivative is not supported for elements of type %s. " "This is because their pullback is not implemented in UFL." % unsupported_spaces) _, w, v, cd = o.ufl_operands rules = CoordinateDerivativeRuleset(w, v, cd) key = (CoordinateDerivativeRuleset, w, v, cd) return map_expr_dag(rules, f, vcache=self.vcache[key], rcache=self.rcache[key])
def test_extract_elements_and_extract_unique_elements(forms): b = forms[2] integrals = b.integrals_by_type("cell") integrand = integrals[0].integrand() element1 = FiniteElement("CG", triangle, 1) element2 = FiniteElement("CG", triangle, 1) v = TestFunction(element1) u = TrialFunction(element2) a = u * v * dx assert extract_elements(a) == (element1, element2) assert extract_unique_elements(a) == (element1,)
def test_extract_elements_and_extract_unique_elements(forms): b = forms[2] integrals = b.integrals_by_type("cell") integrand = integrals[0].integrand() element1 = FiniteElement("CG", triangle, 1) element2 = FiniteElement("CG", triangle, 1) v = TestFunction(element1) u = TrialFunction(element2) a = u * v * dx assert extract_elements(a) == (element1, element2) assert extract_unique_elements(a) == (element1, )
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)
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)
def _tabulate_basis(sorted_integrals, domain_type, form_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_weights = {} psi_tables = {} integrals = {} avg_elements = { "cell": [], "facet": [] } # Loop the quadrature points and tabulate the basis values. for pr, integral in sorted_integrals.iteritems(): # Extract number of points and the rule. degree, rule = pr # Get all unique elements in integral. ufl_elements = [form_data.element_replace_map[e] for e in extract_unique_elements(integral)] # 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)] # Create a list of equivalent FIAT elements (with same # ordering of elements). fiat_elements = [create_element(e) for e in ufl_elements] # Make quadrature rule and get points and weights. (points, weights) = _create_quadrature_points_and_weights(domain_type, form_data.cell, degree, rule) # The TOTAL number of weights/points len_weights = len(weights) # Assert that this is unique ffc_assert(len_weights not in quadrature_weights, \ "This number of points is already present in the weight table: " + repr(quadrature_weights)) ffc_assert(len_weights not in psi_tables, \ "This number of points is already present in the psi table: " + repr(psi_tables)) ffc_assert(len_weights not in integrals, \ "This number of points is already present in the integrals: " + repr(integrals)) # Add points and rules to dictionary. quadrature_weights[len_weights] = (weights, points) # Add the number of points to the psi tables dictionary. psi_tables[len_weights] = {} # Add the integral with the number of points as a key to the return integrals. integrals[len_weights] = integral # Find the highest number of derivatives needed for each element num_derivatives = _find_element_derivatives(integral.integrand(), ufl_elements, form_data.element_replace_map) # Loop FIAT elements and tabulate basis as usual. for i, element in enumerate(fiat_elements): # Tabulate table of basis functions and derivatives in points psi_table = _tabulate_psi_table(domain_type, form_data.cell, element, num_derivatives[ufl_elements[i]], points) # Insert table into dictionary based on UFL elements. (None=not averaged) psi_tables[len_weights][ufl_elements[i]] = { None: psi_table } # Loop over elements found in CellAvg and tabulate basis averages len_weights = 1 for avg in ("cell", "facet"): # Doesn't matter if it's exterior or interior if avg == "cell": avg_domain_type = "cell" elif avg == "facet": avg_domain_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_domain_type, form_data.cell, element.degree(), "default") wsum = sum(weights) # Tabulate table of basis functions and derivatives in points entity_psi_tables = _tabulate_psi_table(avg_domain_type, form_data.cell, 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 actual_entities = _tabulate_entities(domain_type, form_data.cell) if len(actual_entities) > len(entity_psi_tables): assert len(entity_psi_tables) == 1 assert avg_domain_type == "cell" assert "facet" in domain_type v, = entity_psi_tables.values() entity_psi_tables = dict((e, v) for e in actual_entities) for entity, deriv_table in entity_psi_tables.items(): deriv, = list(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 ffc_assert(num_points == len(weights), "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 ffc_assert(num_points == len(weights), "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, (len_weights, element, avg, entity, deriv), avg_psi_table) return (integrals, psi_tables, quadrature_weights)
def _tabulate_basis(sorted_integrals, domain_type, form_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_weights = {} psi_tables = {} integrals = {} avg_elements = {"cell": [], "facet": []} # Loop the quadrature points and tabulate the basis values. for pr, integral in sorted_integrals.iteritems(): # Extract number of points and the rule. degree, rule = pr # Get all unique elements in integral. ufl_elements = [ form_data.element_replace_map[e] for e in extract_unique_elements(integral) ] # 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) ] # Create a list of equivalent FIAT elements (with same # ordering of elements). fiat_elements = [create_element(e) for e in ufl_elements] # Make quadrature rule and get points and weights. (points, weights) = _create_quadrature_points_and_weights( domain_type, form_data.cell, degree, rule) # The TOTAL number of weights/points len_weights = len(weights) # Assert that this is unique ffc_assert(len_weights not in quadrature_weights, \ "This number of points is already present in the weight table: " + repr(quadrature_weights)) ffc_assert(len_weights not in psi_tables, \ "This number of points is already present in the psi table: " + repr(psi_tables)) ffc_assert(len_weights not in integrals, \ "This number of points is already present in the integrals: " + repr(integrals)) # Add points and rules to dictionary. quadrature_weights[len_weights] = (weights, points) # Add the number of points to the psi tables dictionary. psi_tables[len_weights] = {} # Add the integral with the number of points as a key to the return integrals. integrals[len_weights] = integral # Find the highest number of derivatives needed for each element num_derivatives = _find_element_derivatives( integral.integrand(), ufl_elements, form_data.element_replace_map) # Loop FIAT elements and tabulate basis as usual. for i, element in enumerate(fiat_elements): # Tabulate table of basis functions and derivatives in points psi_table = _tabulate_psi_table(domain_type, form_data.cell, element, num_derivatives[ufl_elements[i]], points) # Insert table into dictionary based on UFL elements. (None=not averaged) psi_tables[len_weights][ufl_elements[i]] = {None: psi_table} # Loop over elements found in CellAvg and tabulate basis averages len_weights = 1 for avg in ("cell", "facet"): # Doesn't matter if it's exterior or interior if avg == "cell": avg_domain_type = "cell" elif avg == "facet": avg_domain_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_domain_type, form_data.cell, element.degree(), "default") wsum = sum(weights) # Tabulate table of basis functions and derivatives in points entity_psi_tables = _tabulate_psi_table(avg_domain_type, form_data.cell, 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 actual_entities = _tabulate_entities(domain_type, form_data.cell) if len(actual_entities) > len(entity_psi_tables): assert len(entity_psi_tables) == 1 assert avg_domain_type == "cell" assert "facet" in domain_type v, = entity_psi_tables.values() entity_psi_tables = dict((e, v) for e in actual_entities) for entity, deriv_table in entity_psi_tables.items(): deriv, = list(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 ffc_assert(num_points == len(weights), "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 ffc_assert(num_points == len(weights), "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, (len_weights, element, avg, entity, deriv), avg_psi_table) return (integrals, psi_tables, quadrature_weights)