def analyze_elements(elements, parameters): begin("Compiler stage 1: Analyzing form(s)") # Extract unique (sub)elements unique_elements = set(extract_sub_elements(elements)) # Sort elements unique_elements = sort_elements(unique_elements) # Build element map element_numbers = _compute_element_numbers(unique_elements) # Update scheme for QuadratureElements scheme = parameters["quadrature_rule"] if scheme == "auto": scheme = "default" for element in unique_elements: if element.family() == "Quadrature": element._quad_scheme = scheme end() form_datas = () unique_coordinate_elements = () return form_datas, unique_elements, element_numbers, unique_coordinate_elements
def _compute_element_mapping(form): "Compute element mapping for element replacement" # The element mapping is a slightly messy concept with two use # cases: # - Expression with missing cell or element TODO: Implement proper # Expression handling in UFL and get rid of this # - Constant with missing cell TODO: Fix anything that needs to be # worked around to drop this requirement # Extract all elements and include subelements of mixed elements elements = [ obj.ufl_element() for obj in chain(form.arguments(), form.coefficients()) ] elements = extract_sub_elements(elements) # Try to find a common degree for elements common_degree = _auto_select_degree(elements) # Compute element map element_mapping = {} for element in elements: # Flag for whether element needs to be reconstructed reconstruct = False # Set cell cell = element.cell() if cell is None: domains = form.ufl_domains() if not all(domains[0].ufl_cell() == d.ufl_cell() for d in domains): error( "Cannot replace unknown element cell without unique common cell in form." ) cell = domains[0].ufl_cell() info("Adjusting missing element cell to %s." % (cell, )) reconstruct = True # Set degree degree = element.degree() if degree is None: info("Adjusting missing element degree to %d" % (common_degree, )) degree = common_degree reconstruct = True # Reconstruct element and add to map if reconstruct: element_mapping[element] = element.reconstruct(cell=cell, degree=degree) else: element_mapping[element] = element return element_mapping
def _compute_element_mapping(form): "Compute element mapping for element replacement" # The element mapping is a slightly messy concept with two use # cases: # - Expression with missing cell or element TODO: Implement proper # Expression handling in UFL and get rid of this # - Constant with missing cell TODO: Fix anything that needs to be # worked around to drop this requirement # Extract all elements and include subelements of mixed elements elements = [obj.ufl_element() for obj in chain(form.arguments(), form.coefficients())] elements = extract_sub_elements(elements) # Try to find a common degree for elements common_degree = _auto_select_degree(elements) # Compute element map element_mapping = {} for element in elements: # Flag for whether element needs to be reconstructed reconstruct = False # Set cell cell = element.cell() if cell is None: domains = form.ufl_domains() if not all(domains[0].ufl_cell() == d.ufl_cell() for d in domains): error("Cannot replace unknown element cell without unique common cell in form.") cell = domains[0].ufl_cell() info("Adjusting missing element cell to %s." % (cell,)) reconstruct = True # Set degree degree = element.degree() if degree is None: info("Adjusting missing element degree to %d" % (common_degree,)) degree = common_degree reconstruct = True # Reconstruct element and add to map if reconstruct: element_mapping[element] = element.reconstruct(cell=cell, degree=degree) else: element_mapping[element] = element return element_mapping
def _compute_form_data_elements(self, arguments, coefficients, domains): self.argument_elements = tuple(f.ufl_element() for f in arguments) self.coefficient_elements = tuple(f.ufl_element() for f in coefficients) self.coordinate_elements = tuple(domain.ufl_coordinate_element() for domain in domains) # TODO: Include coordinate elements from argument and coefficient # domains as well? Can they differ? # Note: Removed self.elements and self.sub_elements to make sure # code that depends on the selection of argument + # coefficient elements blow up, as opposed to silently # almost working, with the introduction of the coordinate # elements here. all_elements = self.argument_elements + self.coefficient_elements + self.coordinate_elements all_sub_elements = extract_sub_elements(all_elements) self.unique_elements = unique_tuple(all_elements) self.unique_sub_elements = unique_tuple(all_sub_elements)
def _compute_form_data_elements(self, arguments, coefficients, domains): self.argument_elements = tuple(f.ufl_element() for f in arguments) self.coefficient_elements = tuple(f.ufl_element() for f in coefficients) self.coordinate_elements = tuple(domain.ufl_coordinate_element() for domain in domains) # TODO: Include coordinate elements from argument and coefficient # domains as well? Can they differ? # Note: Removed self.elements and self.sub_elements to make sure # code that depends on the selection of argument + # coefficient elements blow up, as opposed to silently # almost working, with the introduction of the coordinate # elements here. all_elements = self.argument_elements + self.coefficient_elements + self.coordinate_elements all_sub_elements = extract_sub_elements(all_elements) self.unique_elements = unique_tuple(all_elements) self.unique_sub_elements = unique_tuple(all_sub_elements)
def preprocess(form, object_names=None, common_cell=None, element_mapping=None): """ Preprocess raw input form to obtain form metadata, including a modified (preprocessed) form more easily manipulated by form compilers. The original form is left untouched. Currently, the following transformations are made to the preprocessed form: expand_compounds (side effect of calling expand_derivatives) expand_derivatives renumber arguments and coefficients and apply evt. element mapping """ tic = Timer('preprocess') # TODO: Reposition tic calls after refactoring. # Check that we get a form ufl_assert(isinstance(form, Form), "Expecting Form.") original_form = form # Object names is empty if not given object_names = object_names or {} # Element mapping is empty if not given element_mapping = element_mapping or {} # Create empty form data form_data = FormData() # Store copies of preprocess input data, for future validation if called again... form_data._input_object_names = dict(object_names) form_data._input_element_mapping = dict(element_mapping) #form_data._input_common_cell = no need to store this # Store name of form if given, otherwise empty string # such that automatic names can be assigned externally form_data.name = object_names.get(id(form), "") # Extract common cell common_cell = extract_common_cell(form, common_cell) # TODO: Split out expand_compounds from expand_derivatives # Expand derivatives tic('expand_derivatives') form = expand_derivatives(form, common_cell.geometric_dimension()) # EXPR # Propagate restrictions of interior facet integrals to the terminal nodes form = propagate_restrictions(form) # INTEGRAL, EXPR # --- BEGIN DOMAIN SPLITTING AND JOINING # Store domain metadata per domain type form_data.domain_data = extract_domain_data(form) # Split up integrals and group by domain type and domain id, # adding integrands with same domain and compiler data sub_integral_data = integral_dict_to_sub_integral_data( form.integral_groups()) # TODO: Replace integral_data with this through ufl and ffc? if 0: print_sub_integral_data(sub_integral_data) # Reconstruct form from these integrals in a more canonical representation form = reconstruct_form_from_sub_integral_data(sub_integral_data, form_data.domain_data) # Represent in the way ffc expects TODO: Change ffc? Fine for now. form_data.integral_data = convert_sub_integral_data_to_integral_data( sub_integral_data) # --- END DOMAIN SPLITTING AND JOINING # --- BEGIN FUNCTION ANALYSIS # --- BEGIN SPLIT EXPR JOIN # Replace arguments and coefficients with new renumbered objects tic('extract_arguments_and_coefficients') original_arguments, original_coefficients = \ extract_arguments_and_coefficients(form) tic('build_element_mapping') element_mapping = build_element_mapping(element_mapping, common_cell, original_arguments, original_coefficients) tic('build_argument_replace_map') # TODO: Remove renumbered ones? replace_map, renumbered_arguments, renumbered_coefficients = \ build_argument_replace_map(original_arguments, original_coefficients, element_mapping) # Note: This is the earliest point signature can be computed # Build mapping to original arguments and coefficients, which is # useful if the original arguments have data attached to them inv_replace_map = dict((w, v) for (v, w) in replace_map.iteritems()) original_arguments = [inv_replace_map[v] for v in renumbered_arguments] original_coefficients = [ inv_replace_map[w] for w in renumbered_coefficients ] # TODO: Build mapping from object to position instead? But we need mapped elements as well anyway. #argument_positions = { v: i } #coefficient_positions = { w: i } # Store data extracted by preprocessing form_data.original_arguments = original_arguments form_data.original_coefficients = original_coefficients # --- END SPLIT INTEGRAL JOIN # Mappings from elements and functions (coefficients and arguments) # that reside in form to objects with canonical numbering as well as # completed cells and elements # TODO: Create additional function mappings per integral, # to have different counts? Depends on future UFC design. form_data.element_replace_map = element_mapping form_data.function_replace_map = replace_map # Store some useful dimensions form_data.rank = len(form_data.original_arguments) form_data.num_coefficients = len(form_data.original_coefficients) # Store argument names form_data.argument_names = \ [object_names.get(id(form_data.original_arguments[i]), "v%d" % i) for i in range(form_data.rank)] # Store coefficient names form_data.coefficient_names = \ [object_names.get(id(form_data.original_coefficients[i]), "w%d" % i) for i in range(form_data.num_coefficients)] # --- END FUNCTION ANALYSIS # --- BEGIN SIGNATURE COMPUTATION # TODO: Compute signatures of each INTEGRAL and EXPR as well, perhaps compute it hierarchially from integral_data? # Store signature of form tic('signature') # TODO: Remove signature() from Form, not safe to cache with a replacement map #form_data.signature = form.signature(form_data.function_replace_map) form_data.signature = compute_form_signature( form, form_data.function_replace_map) # --- END SIGNATURE COMPUTATION # --- BEGIN CONSISTENCY CHECKS # Check that we don't have a mixed linear/bilinear form or anything like that ufl_assert( len(compute_form_arities(form)) == 1, "All terms in form must have same rank.") # --- END CONSISTENCY CHECKS # --- BEGIN ELEMENT DATA # Store elements, sub elements and element map tic('extract_elements') form_data.argument_elements = tuple(f.element() for f in renumbered_arguments) form_data.coefficient_elements = tuple(f.element() for f in renumbered_coefficients) form_data.elements = form_data.argument_elements + form_data.coefficient_elements form_data.unique_elements = unique_tuple(form_data.elements) form_data.sub_elements = extract_sub_elements(form_data.elements) form_data.unique_sub_elements = unique_tuple(form_data.sub_elements) # --- END ELEMENT DATA # --- BEGIN DOMAIN DATA # Store element domains (NB! This is likely to change!) # TODO: DOMAINS: What is a sensible way to store domains for a form? form_data.domains = tuple( sorted(set(element.domain() for element in form_data.unique_elements))) # Store toplevel domains (NB! This is likely to change!) # TODO: DOMAINS: What is a sensible way to store domains for a form? form_data.top_domains = tuple( sorted(set(domain.top_domain() for domain in form_data.domains))) # Store common cell form_data.cell = common_cell # Store data related to cell form_data.geometric_dimension = form_data.cell.geometric_dimension() form_data.topological_dimension = form_data.cell.topological_dimension() # Store number of domains for integral types form_data.num_sub_domains = extract_num_sub_domains(form) # --- END DOMAIN DATA # A coarse profiling implementation TODO: Add counting of nodes, Add memory usage tic.end() if preprocess.enable_profiling: print tic # Store preprocessed form and return form_data.preprocessed_form = form form_data.preprocessed_form._is_preprocessed = True # Attach signatures to original and preprocessed forms TODO: Avoid this? ufl_assert(form_data.preprocessed_form._signature is None, "") form_data.preprocessed_form._signature = form_data.signature ufl_assert(original_form._signature is None, "") original_form._signature = form_data.signature return form_data
def preprocess_expression(expr, object_names=None, common_cell=None, element_mapping=None): """ Preprocess raw input expression to obtain expression metadata, including a modified (preprocessed) expression more easily manipulated by expression compilers. The original expression is left untouched. Currently, the following transformations are made to the preprocessed form: expand_compounds (side effect of calling expand_derivatives) expand_derivatives renumber arguments and coefficients and apply evt. element mapping """ tic = Timer('preprocess_expression') # Check that we get an expression ufl_assert(isinstance(expr, Expr), "Expecting Expr.") # Object names is empty if not given object_names = object_names or {} # Element mapping is empty if not given element_mapping = element_mapping or {} # Create empty expression data expr_data = ExprData() # Store original expression expr_data.original_expr = expr # Store name of expr if given, otherwise empty string # such that automatic names can be assigned externally expr_data.name = object_names.get(id(expr), "") # TODO: Or default to 'expr'? # Extract common cell common_cell = extract_common_cell(expr, common_cell) # TODO: Split out expand_compounds from expand_derivatives # Expand derivatives tic('expand_derivatives') expr = expand_derivatives(expr, common_cell.geometric_dimension()) # Renumber indices #expr = renumber_indices(expr) # TODO: No longer needed? # Replace arguments and coefficients with new renumbered objects tic('extract_arguments_and_coefficients') original_arguments, original_coefficients = \ extract_arguments_and_coefficients(expr) tic('build_element_mapping') element_mapping = build_element_mapping(element_mapping, common_cell, original_arguments, original_coefficients) tic('build_argument_replace_map') replace_map, renumbered_arguments, renumbered_coefficients = \ build_argument_replace_map(original_arguments, original_coefficients, element_mapping) expr = replace(expr, replace_map) # Build mapping to original arguments and coefficients, which is # useful if the original arguments have data attached to them inv_replace_map = dict((w, v) for (v, w) in replace_map.iteritems()) original_arguments = [inv_replace_map[v] for v in renumbered_arguments] original_coefficients = [ inv_replace_map[w] for w in renumbered_coefficients ] # Store data extracted by preprocessing expr_data.arguments = renumbered_arguments # TODO: Needed? expr_data.coefficients = renumbered_coefficients # TODO: Needed? expr_data.original_arguments = original_arguments expr_data.original_coefficients = original_coefficients expr_data.renumbered_arguments = renumbered_arguments expr_data.renumbered_coefficients = renumbered_coefficients tic('replace') # Mappings from elements and functions (coefficients and arguments) # that reside in expr to objects with canonical numbering as well as # completed cells and elements expr_data.element_replace_map = element_mapping expr_data.function_replace_map = replace_map # Store signature of form tic('signature') expr_data.signature = compute_expression_signature( expr, expr_data.function_replace_map) # Store elements, sub elements and element map tic('extract_elements') expr_data.elements = tuple( f.element() for f in chain(renumbered_arguments, renumbered_coefficients)) expr_data.unique_elements = unique_tuple(expr_data.elements) expr_data.sub_elements = extract_sub_elements(expr_data.elements) expr_data.unique_sub_elements = unique_tuple(expr_data.sub_elements) # Store element domains (NB! This is likely to change!) # FIXME: DOMAINS: What is a sensible way to store domains for a expr? expr_data.domains = tuple( sorted(set(element.domain() for element in expr_data.unique_elements))) # Store toplevel domains (NB! This is likely to change!) # FIXME: DOMAINS: What is a sensible way to store domains for a expr? expr_data.top_domains = tuple( sorted(set(domain.top_domain() for domain in expr_data.domains))) # Store common cell expr_data.cell = common_cell # Store data related to cell expr_data.geometric_dimension = expr_data.cell.geometric_dimension() expr_data.topological_dimension = expr_data.cell.topological_dimension() # Store some useful dimensions expr_data.rank = len(expr_data.arguments) # TODO: Is this useful for expr? expr_data.num_coefficients = len(expr_data.coefficients) # Store argument names # TODO: Is this useful for expr? expr_data.argument_names = \ [object_names.get(id(expr_data.original_arguments[i]), "v%d" % i) for i in range(expr_data.rank)] # Store coefficient names expr_data.coefficient_names = \ [object_names.get(id(expr_data.original_coefficients[i]), "w%d" % i) for i in range(expr_data.num_coefficients)] # Store preprocessed expression expr_data.preprocessed_expr = expr tic.end() # A coarse profiling implementation # TODO: Add counting of nodes # TODO: Add memory usage if preprocess_expression.enable_profiling: print tic return expr_data
def preprocess(form, object_names=None, common_cell=None, element_mapping=None): """ Preprocess raw input form to obtain form metadata, including a modified (preprocessed) form more easily manipulated by form compilers. The original form is left untouched. Currently, the following transformations are made to the preprocessed form: expand_compounds (side effect of calling expand_derivatives) expand_derivatives renumber arguments and coefficients and apply evt. element mapping """ tic = Timer('preprocess') # TODO: Reposition tic calls after refactoring. # Check that we get a form ufl_assert(isinstance(form, Form), "Expecting Form.") original_form = form # Object names is empty if not given object_names = object_names or {} # Element mapping is empty if not given element_mapping = element_mapping or {} # Create empty form data form_data = FormData() # Store copies of preprocess input data, for future validation if called again... form_data._input_object_names = dict(object_names) form_data._input_element_mapping = dict(element_mapping) #form_data._input_common_cell = no need to store this # Store name of form if given, otherwise empty string # such that automatic names can be assigned externally form_data.name = object_names.get(id(form), "") # Extract common cell common_cell = extract_common_cell(form, common_cell) # TODO: Split out expand_compounds from expand_derivatives # Expand derivatives tic('expand_derivatives') form = expand_derivatives(form, common_cell.geometric_dimension()) # EXPR # Propagate restrictions of interior facet integrals to the terminal nodes form = propagate_restrictions(form) # INTEGRAL, EXPR # --- BEGIN DOMAIN SPLITTING AND JOINING # Store domain metadata per domain type form_data.domain_data = extract_domain_data(form) # Split up integrals and group by domain type and domain id, # adding integrands with same domain and compiler data sub_integral_data = integral_dict_to_sub_integral_data(form.integral_groups()) # TODO: Replace integral_data with this through ufl and ffc? if 0: print_sub_integral_data(sub_integral_data) # Reconstruct form from these integrals in a more canonical representation form = reconstruct_form_from_sub_integral_data(sub_integral_data, form_data.domain_data) # Represent in the way ffc expects TODO: Change ffc? Fine for now. form_data.integral_data = convert_sub_integral_data_to_integral_data(sub_integral_data) # --- END DOMAIN SPLITTING AND JOINING # --- BEGIN FUNCTION ANALYSIS # --- BEGIN SPLIT EXPR JOIN # Replace arguments and coefficients with new renumbered objects tic('extract_arguments_and_coefficients') original_arguments, original_coefficients = \ extract_arguments_and_coefficients(form) tic('build_element_mapping') element_mapping = build_element_mapping(element_mapping, common_cell, original_arguments, original_coefficients) tic('build_argument_replace_map') # TODO: Remove renumbered ones? replace_map, renumbered_arguments, renumbered_coefficients = \ build_argument_replace_map(original_arguments, original_coefficients, element_mapping) # Note: This is the earliest point signature can be computed # Build mapping to original arguments and coefficients, which is # useful if the original arguments have data attached to them inv_replace_map = dict((w,v) for (v,w) in replace_map.iteritems()) original_arguments = [inv_replace_map[v] for v in renumbered_arguments] original_coefficients = [inv_replace_map[w] for w in renumbered_coefficients] # TODO: Build mapping from object to position instead? But we need mapped elements as well anyway. #argument_positions = { v: i } #coefficient_positions = { w: i } # Store data extracted by preprocessing form_data.original_arguments = original_arguments form_data.original_coefficients = original_coefficients # --- END SPLIT INTEGRAL JOIN # Mappings from elements and functions (coefficients and arguments) # that reside in form to objects with canonical numbering as well as # completed cells and elements # TODO: Create additional function mappings per integral, # to have different counts? Depends on future UFC design. form_data.element_replace_map = element_mapping form_data.function_replace_map = replace_map # Store some useful dimensions form_data.rank = len(form_data.original_arguments) form_data.num_coefficients = len(form_data.original_coefficients) # Store argument names form_data.argument_names = \ [object_names.get(id(form_data.original_arguments[i]), "v%d" % i) for i in range(form_data.rank)] # Store coefficient names form_data.coefficient_names = \ [object_names.get(id(form_data.original_coefficients[i]), "w%d" % i) for i in range(form_data.num_coefficients)] # --- END FUNCTION ANALYSIS # --- BEGIN SIGNATURE COMPUTATION # TODO: Compute signatures of each INTEGRAL and EXPR as well, perhaps compute it hierarchially from integral_data? # Store signature of form tic('signature') # TODO: Remove signature() from Form, not safe to cache with a replacement map #form_data.signature = form.signature(form_data.function_replace_map) form_data.signature = compute_form_signature(form, form_data.function_replace_map) # --- END SIGNATURE COMPUTATION # --- BEGIN CONSISTENCY CHECKS # Check that we don't have a mixed linear/bilinear form or anything like that ufl_assert(len(compute_form_arities(form)) == 1, "All terms in form must have same rank.") # --- END CONSISTENCY CHECKS # --- BEGIN ELEMENT DATA # Store elements, sub elements and element map tic('extract_elements') form_data.argument_elements = tuple(f.element() for f in renumbered_arguments) form_data.coefficient_elements = tuple(f.element() for f in renumbered_coefficients) form_data.elements = form_data.argument_elements + form_data.coefficient_elements form_data.unique_elements = unique_tuple(form_data.elements) form_data.sub_elements = extract_sub_elements(form_data.elements) form_data.unique_sub_elements = unique_tuple(form_data.sub_elements) # --- END ELEMENT DATA # --- BEGIN DOMAIN DATA # Store element domains (NB! This is likely to change!) # TODO: DOMAINS: What is a sensible way to store domains for a form? form_data.domains = tuple(sorted(set(element.domain() for element in form_data.unique_elements))) # Store toplevel domains (NB! This is likely to change!) # TODO: DOMAINS: What is a sensible way to store domains for a form? form_data.top_domains = tuple(sorted(set(domain.top_domain() for domain in form_data.domains))) # Store common cell form_data.cell = common_cell # Store data related to cell form_data.geometric_dimension = form_data.cell.geometric_dimension() form_data.topological_dimension = form_data.cell.topological_dimension() # Store number of domains for integral types form_data.num_sub_domains = extract_num_sub_domains(form) # --- END DOMAIN DATA # A coarse profiling implementation TODO: Add counting of nodes, Add memory usage tic.end() if preprocess.enable_profiling: print tic # Store preprocessed form and return form_data.preprocessed_form = form form_data.preprocessed_form._is_preprocessed = True # Attach signatures to original and preprocessed forms TODO: Avoid this? ufl_assert(form_data.preprocessed_form._signature is None, "") form_data.preprocessed_form._signature = form_data.signature ufl_assert(original_form._signature is None, "") original_form._signature = form_data.signature return form_data
def preprocess_expression(expr, object_names=None, common_cell=None, element_mapping=None): """ Preprocess raw input expression to obtain expression metadata, including a modified (preprocessed) expression more easily manipulated by expression compilers. The original expression is left untouched. Currently, the following transformations are made to the preprocessed form: expand_compounds (side effect of calling expand_derivatives) expand_derivatives renumber arguments and coefficients and apply evt. element mapping """ tic = Timer('preprocess_expression') # Check that we get an expression ufl_assert(isinstance(expr, Expr), "Expecting Expr.") # Object names is empty if not given object_names = object_names or {} # Element mapping is empty if not given element_mapping = element_mapping or {} # Create empty expression data expr_data = ExprData() # Store original expression expr_data.original_expr = expr # Store name of expr if given, otherwise empty string # such that automatic names can be assigned externally expr_data.name = object_names.get(id(expr), "") # TODO: Or default to 'expr'? # Extract common cell common_cell = extract_common_cell(expr, common_cell) # TODO: Split out expand_compounds from expand_derivatives # Expand derivatives tic('expand_derivatives') expr = expand_derivatives(expr, common_cell.geometric_dimension()) # Renumber indices #expr = renumber_indices(expr) # TODO: No longer needed? # Replace arguments and coefficients with new renumbered objects tic('extract_arguments_and_coefficients') original_arguments, original_coefficients = \ extract_arguments_and_coefficients(expr) tic('build_element_mapping') element_mapping = build_element_mapping(element_mapping, common_cell, original_arguments, original_coefficients) tic('build_argument_replace_map') replace_map, renumbered_arguments, renumbered_coefficients = \ build_argument_replace_map(original_arguments, original_coefficients, element_mapping) expr = replace(expr, replace_map) # Build mapping to original arguments and coefficients, which is # useful if the original arguments have data attached to them inv_replace_map = dict((w,v) for (v,w) in replace_map.iteritems()) original_arguments = [inv_replace_map[v] for v in renumbered_arguments] original_coefficients = [inv_replace_map[w] for w in renumbered_coefficients] # Store data extracted by preprocessing expr_data.arguments = renumbered_arguments # TODO: Needed? expr_data.coefficients = renumbered_coefficients # TODO: Needed? expr_data.original_arguments = original_arguments expr_data.original_coefficients = original_coefficients expr_data.renumbered_arguments = renumbered_arguments expr_data.renumbered_coefficients = renumbered_coefficients tic('replace') # Mappings from elements and functions (coefficients and arguments) # that reside in expr to objects with canonical numbering as well as # completed cells and elements expr_data.element_replace_map = element_mapping expr_data.function_replace_map = replace_map # Store signature of form tic('signature') expr_data.signature = compute_expression_signature(expr, expr_data.function_replace_map) # Store elements, sub elements and element map tic('extract_elements') expr_data.elements = tuple(f.element() for f in chain(renumbered_arguments, renumbered_coefficients)) expr_data.unique_elements = unique_tuple(expr_data.elements) expr_data.sub_elements = extract_sub_elements(expr_data.elements) expr_data.unique_sub_elements = unique_tuple(expr_data.sub_elements) # Store element domains (NB! This is likely to change!) # FIXME: DOMAINS: What is a sensible way to store domains for a expr? expr_data.domains = tuple(sorted(set(element.domain() for element in expr_data.unique_elements))) # Store toplevel domains (NB! This is likely to change!) # FIXME: DOMAINS: What is a sensible way to store domains for a expr? expr_data.top_domains = tuple(sorted(set(domain.top_domain() for domain in expr_data.domains))) # Store common cell expr_data.cell = common_cell # Store data related to cell expr_data.geometric_dimension = expr_data.cell.geometric_dimension() expr_data.topological_dimension = expr_data.cell.topological_dimension() # Store some useful dimensions expr_data.rank = len(expr_data.arguments) # TODO: Is this useful for expr? expr_data.num_coefficients = len(expr_data.coefficients) # Store argument names # TODO: Is this useful for expr? expr_data.argument_names = \ [object_names.get(id(expr_data.original_arguments[i]), "v%d" % i) for i in range(expr_data.rank)] # Store coefficient names expr_data.coefficient_names = \ [object_names.get(id(expr_data.original_coefficients[i]), "w%d" % i) for i in range(expr_data.num_coefficients)] # Store preprocessed expression expr_data.preprocessed_expr = expr tic.end() # A coarse profiling implementation # TODO: Add counting of nodes # TODO: Add memory usage if preprocess_expression.enable_profiling: print tic return expr_data
def analyze_ufl_objects(ufl_objects, kind, parameters): """ Analyze ufl object(s), either forms, elements, or coordinate mappings, returning: form_datas - a tuple of form_data objects unique_elements - a tuple of unique elements across all forms element_numbers - a mapping to unique numbers for all elements """ begin("Compiler stage 1: Analyzing %s(s)" % (kind, )) form_datas = () unique_elements = set() unique_coordinate_elements = set() if kind == "form": forms = ufl_objects # Analyze forms form_datas = tuple(_analyze_form(form, parameters) for form in forms) # Extract unique elements accross all forms for form_data in form_datas: unique_elements.update(form_data.unique_sub_elements) # Extract coordinate elements across all forms for form_data in form_datas: unique_coordinate_elements.update(form_data.coordinate_elements) elif kind == "element": elements = ufl_objects # Extract unique (sub)elements unique_elements.update(extract_sub_elements(elements)) elif kind == "coordinate_mapping": meshes = ufl_objects # Extract unique (sub)elements unique_coordinate_elements = [ mesh.ufl_coordinate_element() for mesh in meshes ] # Make sure coordinate elements and their subelements are included unique_elements.update(extract_sub_elements(unique_coordinate_elements)) # Sort elements unique_elements = sort_elements(unique_elements) #unique_coordinate_elements = sort_elements(unique_coordinate_elements) unique_coordinate_elements = sorted(unique_coordinate_elements, key=lambda x: repr(x)) # Check for schemes for QuadratureElements for element in unique_elements: if element.family() == "Quadrature": qs = element.quadrature_scheme() if qs is None: error("Missing quad_scheme in quadrature element.") # Compute element numbers element_numbers = _compute_element_numbers(unique_elements) end() return form_datas, unique_elements, element_numbers, unique_coordinate_elements
def analyze_ufl_objects(ufl_objects, kind, parameters): """ Analyze ufl object(s), either forms, elements, or coordinate mappings, returning: form_datas - a tuple of form_data objects unique_elements - a tuple of unique elements across all forms element_numbers - a mapping to unique numbers for all elements """ begin("Compiler stage 1: Analyzing %s(s)" % (kind,)) form_datas = () unique_elements = set() unique_coordinate_elements = set() if kind == "form": forms = ufl_objects # Analyze forms form_datas = tuple(_analyze_form(form, parameters) for form in forms) # Extract unique elements accross all forms for form_data in form_datas: unique_elements.update(form_data.unique_sub_elements) # Extract coordinate elements across all forms for form_data in form_datas: unique_coordinate_elements.update(form_data.coordinate_elements) elif kind == "element": elements = ufl_objects # Extract unique (sub)elements unique_elements.update(extract_sub_elements(elements)) elif kind == "coordinate_mapping": meshes = ufl_objects # Extract unique (sub)elements unique_coordinate_elements = [mesh.ufl_coordinate_element() for mesh in meshes] # Make sure coordinate elements and their subelements are included unique_elements.update(extract_sub_elements(unique_coordinate_elements)) # Sort elements unique_elements = sort_elements(unique_elements) #unique_coordinate_elements = sort_elements(unique_coordinate_elements) unique_coordinate_elements = sorted(unique_coordinate_elements, key=lambda x: repr(x)) # Check for schemes for QuadratureElements for element in unique_elements: if element.family() == "Quadrature": qs = element.quadrature_scheme() if qs is None: error("Missing quad_scheme in quadrature element.") # Compute element numbers element_numbers = _compute_element_numbers(unique_elements) end() return form_datas, unique_elements, element_numbers, unique_coordinate_elements