示例#1
0
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
示例#2
0
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
示例#3
0
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
示例#4
0
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)
示例#5
0
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)
示例#6
0
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
示例#7
0
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
示例#10
0
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
示例#11
0
文件: analysis.py 项目: FEniCS/ffc
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