Ejemplo n.º 1
0
 def load(self, directory, filename):
     # Get full directory name
     full_directory = Folders.Folder(os.path.join(str(directory), filename))
     # Load problem corresponding to self._lhs, and update self._lhs accordingly
     assert self._lhs is None
     assert LHSIO.exists_file(full_directory, "lhs_problem_name")
     lhs_problem_name = LHSIO.load_file(full_directory, "lhs_problem_name")
     lhs_problem = get_problem_from_problem_name(lhs_problem_name)
     lhs_reduced_problem = get_reduced_problem_from_problem(lhs_problem)
     self._lhs = lhs_reduced_problem._riesz_solve_inner_product
     # Load problem corresponding to self._solution, and update self._solution accordingly
     assert self._solution is None
     assert SolutionIO.exists_file(full_directory, "solution_problem_name")
     solution_problem_name = SolutionIO.load_file(full_directory,
                                                  "solution_problem_name")
     solution_problem = get_problem_from_problem_name(solution_problem_name)
     solution_reduced_problem = get_reduced_problem_from_problem(
         solution_problem)
     self._solution = solution_reduced_problem._riesz_solve_storage
     # Load problem and operator corresponding to self._rhs, and update self._solution accordingly
     assert self._rhs is None
     assert RHSIO.exists_file(full_directory, "rhs_type")
     rhs_type = RHSIO.load_file(full_directory, "rhs_type")
     assert rhs_type in ("ParametrizedTensorFactory", "DelayedProduct")
     if rhs_type == "ParametrizedTensorFactory":
         assert RHSIO.exists_file(full_directory, "rhs_arg_0")
         (rhs_problem_name_0, rhs_term_0,
          rhs_index_0) = RHSIO.load_file(full_directory, "rhs_arg_0")
         rhs_problem_0 = get_problem_from_problem_name(rhs_problem_name_0)
         rhs_arg_0 = rhs_problem_0.operator[rhs_term_0][rhs_index_0]
         assert isinstance(rhs_arg_0, AbstractParametrizedTensorFactory)
         self._rhs = rhs_arg_0
     elif rhs_type == "DelayedProduct":
         assert RHSIO.exists_file(full_directory, "rhs_arg_0")
         rhs_arg_0 = RHSIO.load_file(full_directory, "rhs_arg_0")
         assert rhs_arg_0 == -1.0
         assert RHSIO.exists_file(full_directory, "rhs_arg_1")
         (rhs_problem_name_1, rhs_term_1,
          rhs_index_1) = RHSIO.load_file(full_directory, "rhs_arg_1")
         rhs_problem_1 = get_problem_from_problem_name(rhs_problem_name_1)
         rhs_arg_1 = rhs_problem_1.operator[rhs_term_1][rhs_index_1]
         assert isinstance(rhs_arg_1, AbstractParametrizedTensorFactory)
         assert RHSIO.exists_file(full_directory, "rhs_arg_2")
         (rhs_problem_name_2, rhs_component_2,
          rhs_index_2) = RHSIO.load_file(full_directory, "rhs_arg_2")
         rhs_problem_2 = get_problem_from_problem_name(rhs_problem_name_2)
         rhs_reduced_problem_2 = get_reduced_problem_from_problem(
             rhs_problem_2)
         if rhs_component_2 is not None:
             rhs_arg_2 = rhs_reduced_problem_2.basis_functions[
                 rhs_component_2][rhs_index_2]
         else:
             rhs_arg_2 = rhs_reduced_problem_2.basis_functions[rhs_index_2]
         rhs = DelayedProduct(rhs_arg_0)
         rhs *= rhs_arg_1
         rhs *= rhs_arg_2
         self._rhs = rhs
     else:
         raise TypeError("Invalid rhs")
     # Load problem corresponding to self._bcs, and update self._bcs accordingly
     assert self._bcs is None
     assert BCsIO.exists_file(full_directory, "bcs_problem_name")
     bcs_problem_name = BCsIO.load_file(full_directory, "bcs_problem_name")
     bcs_problem = get_problem_from_problem_name(bcs_problem_name)
     bcs_reduced_problem = get_reduced_problem_from_problem(bcs_problem)
     self._bcs = bcs_reduced_problem._riesz_solve_homogeneous_dirichlet_bc
     # Load parameters
     assert len(self._parameters) is 0
     assert ParametersIO.exists_file(full_directory, "parameters")
     self._parameters = ParametersIO.load_file(full_directory, "parameters")
     # Return
     return True
Ejemplo n.º 2
0
    def _basic_form_on_truth_function_space(form_wrapper, tensor=None):
        form = form_wrapper._form
        form_name = form_wrapper.name()
        mu = get_problem_from_parametrized_operator(form_wrapper).mu

        if form_name not in form_on_truth_function_space__reduced_problem_to_truth_solution_cache:
            visited = set()
            truth_problems = list()
            truth_problem_to_components = dict()
            truth_problem_to_exact_truth_problem = dict()
            truth_problem_to_truth_solution = dict()
            reduced_problem_to_components = dict()
            reduced_problem_to_truth_solution = dict()

            # Look for terminals on truth mesh
            for node in wrapping.form_iterator(form):
                if node in visited:
                    continue
                # ... problem solutions related to nonlinear terms
                elif wrapping.is_problem_solution_or_problem_solution_component_type(
                        node):
                    if wrapping.is_problem_solution_or_problem_solution_component(
                            node):
                        (preprocessed_node, component, truth_solution
                         ) = wrapping.solution_identify_component(node)
                        truth_problem = get_problem_from_solution(
                            truth_solution)
                        truth_problems.append(truth_problem)
                        # Store the solution
                        truth_problem_to_truth_solution[
                            truth_problem] = truth_solution
                        # Store the component
                        if truth_problem not in truth_problem_to_components:
                            truth_problem_to_components[truth_problem] = list()
                        truth_problem_to_components[truth_problem].append(
                            component)
                    else:
                        preprocessed_node = node
                    # Make sure to skip any parent solution related to this one
                    visited.add(node)
                    visited.add(preprocessed_node)
                    for parent_node in wrapping.solution_iterator(
                            preprocessed_node):
                        visited.add(parent_node)

            # Cache the resulting dicts
            form_on_truth_function_space__truth_problems_cache[
                form_name] = truth_problems
            form_on_truth_function_space__truth_problem_to_components_cache[
                form_name] = truth_problem_to_components
            form_on_truth_function_space__truth_problem_to_exact_truth_problem_cache[
                form_name] = truth_problem_to_exact_truth_problem
            form_on_truth_function_space__truth_problem_to_truth_solution_cache[
                form_name] = truth_problem_to_truth_solution
            form_on_truth_function_space__reduced_problem_to_components_cache[
                form_name] = reduced_problem_to_components
            form_on_truth_function_space__reduced_problem_to_truth_solution_cache[
                form_name] = reduced_problem_to_truth_solution

        # Extract from cache
        truth_problems = form_on_truth_function_space__truth_problems_cache[
            form_name]
        truth_problem_to_components = form_on_truth_function_space__truth_problem_to_components_cache[
            form_name]
        truth_problem_to_exact_truth_problem = form_on_truth_function_space__truth_problem_to_exact_truth_problem_cache[
            form_name]
        truth_problem_to_truth_solution = form_on_truth_function_space__truth_problem_to_truth_solution_cache[
            form_name]
        reduced_problem_to_components = form_on_truth_function_space__reduced_problem_to_components_cache[
            form_name]
        reduced_problem_to_truth_solution = form_on_truth_function_space__reduced_problem_to_truth_solution_cache[
            form_name]

        # Get list of truth and reduced problems that need to be solved, possibly updating cache
        required_truth_problems = list()
        required_reduced_problems = list()
        for truth_problem in truth_problems:
            truth_problem_is_solving = hasattr(truth_problem, "_is_solving")
            if is_training_started(truth_problem):
                reduced_problem = get_reduced_problem_from_problem(
                    truth_problem)
                reduced_problem_is_solving = hasattr(reduced_problem,
                                                     "_is_solving")
            else:
                reduced_problem = None
                reduced_problem_is_solving = False
            if not truth_problem_is_solving:
                if is_training_finished(truth_problem):
                    # Store the component
                    if reduced_problem not in reduced_problem_to_components:
                        reduced_problem_to_components[
                            reduced_problem] = truth_problem_to_components[
                                truth_problem]
                    # Store the solution
                    if reduced_problem not in reduced_problem_to_truth_solution:
                        reduced_problem_to_truth_solution[
                            reduced_problem] = truth_problem_to_truth_solution[
                                truth_problem]
                    # Append to list of required reduced problems
                    required_reduced_problems.append(
                        (reduced_problem, reduced_problem_is_solving))
                else:
                    if (hasattr(truth_problem,
                                "_apply_exact_evaluation_at_stages") and
                            not hasattr(truth_problem, "_apply_EIM_at_stages")
                            and not hasattr(truth_problem,
                                            "_apply_DEIM_at_stages")):
                        # Init truth problem (if required), as it may not have been initialized
                        truth_problem.init()
                        # Append to list of required truth problems which are not currently solving
                        required_truth_problems.append(
                            (truth_problem, False, reduced_problem_is_solving))
                    else:
                        # Store the corresponding exact truth problem
                        if truth_problem not in truth_problem_to_exact_truth_problem:
                            exact_truth_problem = exact_problem(truth_problem)
                            truth_problem_to_exact_truth_problem[
                                truth_problem] = exact_truth_problem
                            # Init exact truth problem (if required), as it may not have been initialized
                            exact_truth_problem.init()
                        else:
                            exact_truth_problem = truth_problem_to_exact_truth_problem[
                                truth_problem]
                        # Store the component
                        if exact_truth_problem not in truth_problem_to_components:
                            truth_problem_to_components[
                                exact_truth_problem] = truth_problem_to_components[
                                    truth_problem]
                        # Store the solution
                        if exact_truth_problem not in truth_problem_to_truth_solution:
                            truth_problem_to_truth_solution[
                                exact_truth_problem] = truth_problem_to_truth_solution[
                                    truth_problem]
                        # Append to list of required truth problems which are not currently solving
                        required_truth_problems.append(
                            (exact_truth_problem, False,
                             reduced_problem_is_solving))
            else:
                assert not reduced_problem_is_solving
                # Append to list of required truth problems which are currently solving
                required_truth_problems.append((truth_problem, True, False))

        # Solve truth problems (which have not been reduced yet) associated to nonlinear terms
        truth_problem_to_truth_solution_copy = dict()
        for (truth_problem, truth_problem_is_solving,
             reduced_problem_is_solving) in required_truth_problems:
            if not reduced_problem_is_solving:
                # Solve (if necessary) ...
                truth_problem.set_mu(mu)
                if not truth_problem_is_solving:
                    log(
                        PROGRESS,
                        "In form_on_truth_function_space, requiring truth problem solve for problem "
                        + truth_problem.name())
                    truth_problem.solve()
                else:
                    log(
                        PROGRESS,
                        "In form_on_truth_function_space, loading current truth problem solution for problem "
                        + truth_problem.name())
            else:
                reduced_problem = get_reduced_problem_from_problem(
                    truth_problem)
                log(
                    PROGRESS,
                    "In form_on_truth_function_space, replacing current truth problem solution with reduced solution for problem "
                    + reduced_problem.truth_problem.name())
            # ... and assign to truth_solution
            truth_solution = truth_problem_to_truth_solution[truth_problem]
            truth_problem_to_truth_solution_copy[truth_problem] = backend.copy(
                truth_solution)
            for component in truth_problem_to_components[truth_problem]:
                solution_to = _sub_from_tuple(truth_solution, component)
                if not reduced_problem_is_solving:
                    solution_from = _sub_from_tuple(truth_problem._solution,
                                                    component)
                else:
                    solution_from = _sub_from_tuple(
                        reduced_problem.basis_functions[:reduced_problem.
                                                        _solution.N] *
                        reduced_problem._solution, component)
                backend.assign(solution_to, solution_from)

        # Solve reduced problems associated to nonlinear terms
        reduced_problem_to_truth_solution_copy = dict()
        for (reduced_problem, is_solving) in required_reduced_problems:
            # Solve (if necessary) ...
            reduced_problem.set_mu(mu)
            if not is_solving:
                log(
                    PROGRESS,
                    "In form_on_truth_function_space, requiring reduced problem solve for problem "
                    + reduced_problem.truth_problem.name())
                reduced_problem.solve()
            else:
                log(
                    PROGRESS,
                    "In form_on_truth_function_space, loading current reduced problem solution for problem "
                    + reduced_problem.truth_problem.name())
            # ... and assign to truth_solution
            truth_solution = reduced_problem_to_truth_solution[reduced_problem]
            reduced_problem_to_truth_solution_copy[
                reduced_problem] = backend.copy(truth_solution)
            for component in reduced_problem_to_components[reduced_problem]:
                solution_to = _sub_from_tuple(truth_solution, component)
                solution_from = _sub_from_tuple(
                    reduced_problem.basis_functions[:reduced_problem._solution.
                                                    N] *
                    reduced_problem._solution, component)
                backend.assign(solution_to, solution_from)

        # Assemble
        assembled_form = wrapping.assemble(form, tensor)
        assembled_form.generator = form_wrapper  # for I/O
        form_rank = assembled_form.rank()

        # Undo any side effect of truth problem solves
        for (truth_problem, _, _) in required_truth_problems:
            truth_solution = truth_problem_to_truth_solution[truth_problem]
            truth_solution_copy = truth_problem_to_truth_solution_copy[
                truth_problem]
            for component in truth_problem_to_components[truth_problem]:
                solution_to = _sub_from_tuple(truth_solution, component)
                solution_from = _sub_from_tuple(truth_solution_copy, component)
                backend.assign(solution_to, solution_from)

        # Undo any side effect of reduced problem solves
        for (reduced_problem, _) in required_reduced_problems:
            truth_solution = reduced_problem_to_truth_solution[reduced_problem]
            truth_solution_copy = reduced_problem_to_truth_solution_copy[
                reduced_problem]
            for component in reduced_problem_to_components[reduced_problem]:
                solution_to = _sub_from_tuple(truth_solution, component)
                solution_from = _sub_from_tuple(truth_solution_copy, component)
                backend.assign(solution_to, solution_from)

        # Return
        return (assembled_form, form_rank)
Ejemplo n.º 3
0
    def _basic_expression_on_reduced_mesh(expression_wrapper, at):
        expression = expression_wrapper._expression
        expression_name = expression_wrapper.name()
        reduced_space = at.get_reduced_function_space()
        mu = get_problem_from_parametrized_expression(expression_wrapper).mu
        reduced_mesh = at.get_reduced_mesh()

        if (expression_name, reduced_mesh
            ) not in expression_on_reduced_mesh__expression_cache:
            visited = set()
            replacements = dict()
            truth_problems = list()
            truth_problem_to_components = dict()
            truth_problem_to_exact_truth_problem = dict()
            truth_problem_to_reduced_mesh_solution = dict()
            truth_problem_to_reduced_mesh_interpolator = dict()
            reduced_problem_to_components = dict()
            reduced_problem_to_reduced_mesh_solution = dict()
            reduced_problem_to_reduced_basis_functions = dict()

            # Look for terminals on truth mesh
            for node in wrapping.expression_iterator(expression):
                if node in visited:
                    continue
                # ... problem solutions related to nonlinear terms
                elif wrapping.is_problem_solution_or_problem_solution_component_type(
                        node):
                    if wrapping.is_problem_solution_or_problem_solution_component(
                            node):
                        (preprocessed_node, component, truth_solution
                         ) = wrapping.solution_identify_component(node)
                        truth_problem = get_problem_from_solution(
                            truth_solution)
                        truth_problems.append(truth_problem)
                        # Store the component
                        if truth_problem not in truth_problem_to_components:
                            truth_problem_to_components[truth_problem] = list()
                        truth_problem_to_components[truth_problem].append(
                            component)
                        # Get the function space corresponding to preprocessed_node on the reduced mesh
                        auxiliary_reduced_V = at.get_auxiliary_reduced_function_space(
                            truth_problem, component)
                        # Define and store the replacement
                        if truth_problem not in truth_problem_to_reduced_mesh_solution:
                            truth_problem_to_reduced_mesh_solution[
                                truth_problem] = list()
                        replacements[preprocessed_node] = backend.Function(
                            auxiliary_reduced_V)
                        truth_problem_to_reduced_mesh_solution[
                            truth_problem].append(
                                replacements[preprocessed_node])
                        # Get interpolator on reduced mesh
                        if truth_problem not in truth_problem_to_reduced_mesh_interpolator:
                            truth_problem_to_reduced_mesh_interpolator[
                                truth_problem] = list()
                        truth_problem_to_reduced_mesh_interpolator[
                            truth_problem].append(
                                at.get_auxiliary_function_interpolator(
                                    truth_problem, component))
                    else:
                        (
                            auxiliary_problem, component
                        ) = wrapping.get_auxiliary_problem_for_non_parametrized_function(
                            node)
                        preprocessed_node = node
                        # Get the function space corresponding to preprocessed_node on the reduced mesh
                        auxiliary_reduced_V = at.get_auxiliary_reduced_function_space(
                            auxiliary_problem, component)
                        # Get interpolator on reduced mesh
                        auxiliary_truth_problem_to_reduced_mesh_interpolator = at.get_auxiliary_function_interpolator(
                            auxiliary_problem, component)
                        # Define and store the replacement
                        replacements[
                            preprocessed_node] = auxiliary_truth_problem_to_reduced_mesh_interpolator(
                                preprocessed_node)
                    # Make sure to skip any parent solution related to this one
                    visited.add(node)
                    visited.add(preprocessed_node)
                    for parent_node in wrapping.solution_iterator(
                            preprocessed_node):
                        visited.add(parent_node)
                # ... geometric quantities
                elif isinstance(node, GeometricQuantity):
                    replacements[node] = type(node)(reduced_mesh)
                    visited.add(node)
            # ... and replace them
            replaced_expression = wrapping.expression_replace(
                expression, replacements)

            # Cache the resulting dicts
            expression_on_reduced_mesh__expression_cache[(
                expression_name, reduced_mesh)] = replaced_expression
            expression_on_reduced_mesh__truth_problems_cache[(
                expression_name, reduced_mesh)] = truth_problems
            expression_on_reduced_mesh__truth_problem_to_components_cache[(
                expression_name, reduced_mesh)] = truth_problem_to_components
            expression_on_reduced_mesh__truth_problem_to_exact_truth_problem_cache[
                (expression_name,
                 reduced_mesh)] = truth_problem_to_exact_truth_problem
            expression_on_reduced_mesh__truth_problem_to_reduced_mesh_solution_cache[
                (expression_name,
                 reduced_mesh)] = truth_problem_to_reduced_mesh_solution
            expression_on_reduced_mesh__truth_problem_to_reduced_mesh_interpolator_cache[
                (expression_name,
                 reduced_mesh)] = truth_problem_to_reduced_mesh_interpolator
            expression_on_reduced_mesh__reduced_problem_to_components_cache[(
                expression_name, reduced_mesh)] = reduced_problem_to_components
            expression_on_reduced_mesh__reduced_problem_to_reduced_mesh_solution_cache[
                (expression_name,
                 reduced_mesh)] = reduced_problem_to_reduced_mesh_solution
            expression_on_reduced_mesh__reduced_problem_to_reduced_basis_functions_cache[
                (expression_name,
                 reduced_mesh)] = reduced_problem_to_reduced_basis_functions

        # Extract from cache
        replaced_expression = expression_on_reduced_mesh__expression_cache[(
            expression_name, reduced_mesh)]
        truth_problems = expression_on_reduced_mesh__truth_problems_cache[(
            expression_name, reduced_mesh)]
        truth_problem_to_components = expression_on_reduced_mesh__truth_problem_to_components_cache[
            (expression_name, reduced_mesh)]
        truth_problem_to_exact_truth_problem = expression_on_reduced_mesh__truth_problem_to_exact_truth_problem_cache[
            (expression_name, reduced_mesh)]
        truth_problem_to_reduced_mesh_solution = expression_on_reduced_mesh__truth_problem_to_reduced_mesh_solution_cache[
            (expression_name, reduced_mesh)]
        truth_problem_to_reduced_mesh_interpolator = expression_on_reduced_mesh__truth_problem_to_reduced_mesh_interpolator_cache[
            (expression_name, reduced_mesh)]
        reduced_problem_to_components = expression_on_reduced_mesh__reduced_problem_to_components_cache[
            (expression_name, reduced_mesh)]
        reduced_problem_to_reduced_mesh_solution = expression_on_reduced_mesh__reduced_problem_to_reduced_mesh_solution_cache[
            (expression_name, reduced_mesh)]
        reduced_problem_to_reduced_basis_functions = expression_on_reduced_mesh__reduced_problem_to_reduced_basis_functions_cache[
            (expression_name, reduced_mesh)]

        # Get list of truth and reduced problems that need to be solved, possibly updating cache
        required_truth_problems = list()
        required_reduced_problems = list()
        for truth_problem in truth_problems:
            truth_problem_is_solving = hasattr(truth_problem, "_is_solving")
            if is_training_started(truth_problem):
                reduced_problem = get_reduced_problem_from_problem(
                    truth_problem)
                reduced_problem_is_solving = hasattr(reduced_problem,
                                                     "_is_solving")
            else:
                reduced_problem = None
                reduced_problem_is_solving = False
            if not truth_problem_is_solving:
                if is_training_finished(truth_problem):
                    # Store the component
                    if reduced_problem not in reduced_problem_to_components:
                        reduced_problem_to_components[
                            reduced_problem] = truth_problem_to_components[
                                truth_problem]
                    # Store the replacement
                    if reduced_problem not in reduced_problem_to_reduced_mesh_solution:
                        reduced_problem_to_reduced_mesh_solution[
                            reduced_problem] = truth_problem_to_reduced_mesh_solution[
                                truth_problem]
                    # Get reduced problem basis functions on reduced mesh
                    if reduced_problem not in reduced_problem_to_reduced_basis_functions:
                        reduced_problem_to_reduced_basis_functions[
                            reduced_problem] = list()
                        for component in reduced_problem_to_components[
                                reduced_problem]:
                            reduced_problem_to_reduced_basis_functions[
                                reduced_problem].append(
                                    at.get_auxiliary_basis_functions_matrix(
                                        truth_problem, reduced_problem,
                                        component))
                    # Append to list of required reduced problems
                    required_reduced_problems.append(
                        (reduced_problem, reduced_problem_is_solving))
                else:
                    if (hasattr(truth_problem,
                                "_apply_exact_evaluation_at_stages") and
                            not hasattr(truth_problem, "_apply_EIM_at_stages")
                            and not hasattr(truth_problem,
                                            "_apply_DEIM_at_stages")):
                        # Init truth problem (if required), as it may not have been initialized
                        truth_problem.init()
                        # Append to list of required truth problems which are not currently solving
                        required_truth_problems.append(
                            (truth_problem, False, reduced_problem_is_solving))
                    else:
                        # Store the corresponding exact truth problem
                        if truth_problem not in truth_problem_to_exact_truth_problem:
                            exact_truth_problem = exact_problem(truth_problem)
                            truth_problem_to_exact_truth_problem[
                                truth_problem] = exact_truth_problem
                            # Init exact truth problem (if required), as it may not have been initialized
                            exact_truth_problem.init()
                        else:
                            exact_truth_problem = truth_problem_to_exact_truth_problem[
                                truth_problem]
                        # Store the component
                        if exact_truth_problem not in truth_problem_to_components:
                            truth_problem_to_components[
                                exact_truth_problem] = truth_problem_to_components[
                                    truth_problem]
                        # Store the replacement
                        if exact_truth_problem not in truth_problem_to_reduced_mesh_solution:
                            truth_problem_to_reduced_mesh_solution[
                                exact_truth_problem] = truth_problem_to_reduced_mesh_solution[
                                    truth_problem]
                        # Get interpolator on reduced mesh
                        if exact_truth_problem not in truth_problem_to_reduced_mesh_interpolator:
                            truth_problem_to_reduced_mesh_interpolator[
                                exact_truth_problem] = list()
                            for component in truth_problem_to_components[
                                    exact_truth_problem]:
                                truth_problem_to_reduced_mesh_interpolator[
                                    exact_truth_problem].append(
                                        at.get_auxiliary_function_interpolator(
                                            exact_truth_problem, component))
                        # Append to list of required truth problems which are not currently solving
                        required_truth_problems.append(
                            (exact_truth_problem, False,
                             reduced_problem_is_solving))
            else:
                assert not reduced_problem_is_solving
                # Append to list of required truth problems which are currently solving
                required_truth_problems.append((truth_problem, True, False))

        # Solve truth problems (which have not been reduced yet) associated to nonlinear terms
        for (truth_problem, truth_problem_is_solving,
             reduced_problem_is_solving) in required_truth_problems:
            if not reduced_problem_is_solving:
                # Solve (if necessary) ...
                truth_problem.set_mu(mu)
                if not truth_problem_is_solving:
                    log(
                        PROGRESS,
                        "In expression_on_reduced_mesh, requiring truth problem solve for problem "
                        + truth_problem.name())
                    truth_problem.solve()
                else:
                    log(
                        PROGRESS,
                        "In expression_on_reduced_mesh, loading current truth problem solution for problem "
                        + truth_problem.name())
            else:
                reduced_problem = get_reduced_problem_from_problem(
                    truth_problem)
                log(
                    PROGRESS,
                    "In expression_on_reduced_mesh, replacing current truth problem solution with reduced solution for problem "
                    + reduced_problem.truth_problem.name())
            # ... and assign to reduced_mesh_solution
            for (reduced_mesh_solution, reduced_mesh_interpolator) in zip(
                    truth_problem_to_reduced_mesh_solution[truth_problem],
                    truth_problem_to_reduced_mesh_interpolator[truth_problem]):
                solution_to = reduced_mesh_solution
                if not reduced_problem_is_solving:
                    solution_from = reduced_mesh_interpolator(
                        truth_problem._solution)
                else:
                    solution_from = reduced_mesh_interpolator(
                        reduced_problem.basis_functions[:reduced_problem.
                                                        _solution.N] *
                        reduced_problem._solution)
                backend.assign(solution_to, solution_from)

        # Solve reduced problems associated to nonlinear terms
        for (reduced_problem, is_solving) in required_reduced_problems:
            # Solve (if necessary) ...
            reduced_problem.set_mu(mu)
            if not is_solving:
                log(
                    PROGRESS,
                    "In expression_on_reduced_mesh, requiring reduced problem solve for problem "
                    + reduced_problem.truth_problem.name())
                reduced_problem.solve()
            else:
                log(
                    PROGRESS,
                    "In expression_on_reduced_mesh, loading current reduced problem solution for problem "
                    + reduced_problem.truth_problem.name())
            # ... and assign to reduced_mesh_solution
            for (reduced_mesh_solution, reduced_basis_functions) in zip(
                    reduced_problem_to_reduced_mesh_solution[reduced_problem],
                    reduced_problem_to_reduced_basis_functions[reduced_problem]
            ):
                solution_to = reduced_mesh_solution
                solution_from_N = OnlineSizeDict()
                for c, v in reduced_problem._solution.N.items():
                    if c in reduced_basis_functions._components_name:
                        solution_from_N[c] = v
                solution_from = online_backend.OnlineFunction(solution_from_N)
                online_backend.online_assign(solution_from,
                                             reduced_problem._solution)
                solution_from = reduced_basis_functions[:solution_from_N] * solution_from
                backend.assign(solution_to, solution_from)

        # Evaluate and return
        reduced_function = backend.Function(reduced_space)
        wrapping.evaluate_expression(expression, reduced_function,
                                     replaced_expression)
        return reduced_function
Ejemplo n.º 4
0
 def load(self, directory, filename):
     from rbnics.backends import BasisFunctionsMatrix
     if self._type != "empty":  # avoid loading multiple times
         if self._type in ("basis_functions_matrix", "functions_list"):
             delayed_functions = self._content[self._type]
             it = NonAffineExpansionStorageContent_Iterator(
                 delayed_functions,
                 flags=["c_index", "multi_index", "refs_ok"],
                 op_flags=["readonly"])
             while not it.finished:
                 if isinstance(delayed_functions[it.multi_index],
                               DelayedFunctionsList):
                     assert self._type == "functions_list"
                     if len(
                             delayed_functions[it.multi_index]
                     ) > 0:  # ... unless it is an empty FunctionsList
                         return False
                 elif isinstance(delayed_functions[it.multi_index],
                                 DelayedBasisFunctionsMatrix):
                     assert self._type == "basis_functions_matrix"
                     if sum(
                             delayed_functions[it.multi_index].
                             _component_name_to_basis_component_length.
                             values()
                     ) > 0:  # ... unless it is an empty BasisFunctionsMatrix
                         return False
                 else:
                     raise TypeError("Invalid delayed functions")
                 it.iternext()
         else:
             return False
     # Get full directory name
     full_directory = Folders.Folder(os.path.join(str(directory), filename))
     # Detect trivial case
     assert TypeIO.exists_file(full_directory, "type")
     imported_type = TypeIO.load_file(full_directory, "type")
     self._type = imported_type
     assert self._type in ("basis_functions_matrix", "empty",
                           "error_estimation_operators_11",
                           "error_estimation_operators_21",
                           "error_estimation_operators_22",
                           "functions_list", "operators")
     if self._type in ("basis_functions_matrix", "functions_list"):
         # Load delayed functions
         assert self._type in self._content
         delayed_functions = self._content[self._type]
         it = NonAffineExpansionStorageContent_Iterator(
             delayed_functions, flags=["c_index", "multi_index", "refs_ok"])
         while not it.finished:
             delayed_function = delayed_functions[it.multi_index]
             delayed_function.load(full_directory,
                                   "delayed_functions_" + str(it.index))
             it.iternext()
     elif self._type == "empty":
         pass
     elif self._type in ("error_estimation_operators_11",
                         "error_estimation_operators_21",
                         "error_estimation_operators_22"):
         # Load delayed functions
         assert "delayed_functions" not in self._content
         self._content["delayed_functions"] = [
             NonAffineExpansionStorageContent_Base(self._shape[0],
                                                   dtype=object),
             NonAffineExpansionStorageContent_Base(self._shape[1],
                                                   dtype=object)
         ]
         for (index, delayed_functions) in enumerate(
                 self._content["delayed_functions"]):
             it = NonAffineExpansionStorageContent_Iterator(
                 delayed_functions, flags=["c_index", "refs_ok"])
             while not it.finished:
                 assert DelayedFunctionsTypeIO.exists_file(
                     full_directory, "delayed_functions_" + str(index) +
                     "_" + str(it.index) + "_type")
                 delayed_function_type = DelayedFunctionsTypeIO.load_file(
                     full_directory, "delayed_functions_" + str(index) +
                     "_" + str(it.index) + "_type")
                 assert DelayedFunctionsProblemNameIO.exists_file(
                     full_directory, "delayed_functions_" + str(index) +
                     "_" + str(it.index) + "_problem_name")
                 delayed_function_problem_name = DelayedFunctionsProblemNameIO.load_file(
                     full_directory, "delayed_functions_" + str(index) +
                     "_" + str(it.index) + "_problem_name")
                 delayed_function_problem = get_problem_from_problem_name(
                     delayed_function_problem_name)
                 assert delayed_function_type in (
                     "DelayedBasisFunctionsMatrix", "DelayedLinearSolver")
                 if delayed_function_type == "DelayedBasisFunctionsMatrix":
                     delayed_function = DelayedBasisFunctionsMatrix(
                         delayed_function_problem.V)
                     delayed_function.init(
                         delayed_function_problem.components)
                 elif delayed_function_type == "DelayedLinearSolver":
                     delayed_function = DelayedLinearSolver()
                 else:
                     raise ValueError("Invalid delayed function")
                 delayed_function.load(
                     full_directory, "delayed_functions_" + str(index) +
                     "_" + str(it.index) + "_content")
                 delayed_functions[it.index] = delayed_function
                 it.iternext()
         # Load inner product
         assert ErrorEstimationInnerProductIO.exists_file(
             full_directory, "inner_product_matrix_problem_name")
         inner_product_matrix_problem_name = ErrorEstimationInnerProductIO.load_file(
             full_directory, "inner_product_matrix_problem_name")
         inner_product_matrix_problem = get_problem_from_problem_name(
             inner_product_matrix_problem_name)
         inner_product_matrix_reduced_problem = get_reduced_problem_from_problem(
             inner_product_matrix_problem)
         self._content[
             "inner_product_matrix"] = inner_product_matrix_reduced_problem._error_estimation_inner_product
         # Recompute shape
         assert "delayed_functions_shape" not in self._content
         self._content["delayed_functions_shape"] = DelayedTransposeShape(
             (self._content["delayed_functions"][0][0],
              self._content["delayed_functions"][1][0]))
         # Prepare precomputed slices
         self._precomputed_slices = dict()
         self._prepare_trivial_precomputed_slice()
     elif self._type == "empty":
         pass
     elif self._type == "operators":
         # Load truth content
         assert "truth_operators" not in self._content
         self._content[
             "truth_operators"] = NonAffineExpansionStorageContent_Base(
                 self._shape, dtype=object)
         it = NonAffineExpansionStorageContent_Iterator(
             self._content["truth_operators"],
             flags=["c_index", "multi_index", "refs_ok"])
         while not it.finished:
             assert TruthContentItemIO.exists_file(
                 full_directory,
                 "truth_operator_" + str(it.index) + "_type")
             operator_type = TruthContentItemIO.load_file(
                 full_directory,
                 "truth_operator_" + str(it.index) + "_type")
             assert operator_type in ("NumericForm",
                                      "ParametrizedTensorFactory")
             if operator_type == "NumericForm":
                 assert TruthContentItemIO.exists_file(
                     full_directory, "truth_operator_" + str(it.index))
                 value = TruthContentItemIO.load_file(
                     full_directory, "truth_operator_" + str(it.index))
                 self._content["truth_operators"][
                     it.multi_index] = NumericForm(value)
             elif operator_type == "ParametrizedTensorFactory":
                 assert TruthContentItemIO.exists_file(
                     full_directory, "truth_operator_" + str(it.index))
                 (problem_name, term, index) = TruthContentItemIO.load_file(
                     full_directory, "truth_operator_" + str(it.index))
                 truth_problem = get_problem_from_problem_name(problem_name)
                 self._content["truth_operators"][
                     it.multi_index] = truth_problem.operator[term][index]
             else:
                 raise ValueError("Invalid operator type")
             it.iternext()
         assert "truth_operators_as_expansion_storage" not in self._content
         self._prepare_truth_operators_as_expansion_storage()
         # Load basis functions content
         assert BasisFunctionsContentLengthIO.exists_file(
             full_directory, "basis_functions_length")
         basis_functions_length = BasisFunctionsContentLengthIO.load_file(
             full_directory, "basis_functions_length")
         assert basis_functions_length in (0, 1, 2)
         assert "basis_functions" not in self._content
         self._content["basis_functions"] = list()
         for index in range(basis_functions_length):
             assert BasisFunctionsProblemNameIO.exists_file(
                 full_directory,
                 "basis_functions_" + str(index) + "_problem_name")
             basis_functions_problem_name = BasisFunctionsProblemNameIO.load_file(
                 full_directory,
                 "basis_functions_" + str(index) + "_problem_name")
             assert BasisFunctionsProblemNameIO.exists_file(
                 full_directory,
                 "basis_functions_" + str(index) + "_components_name")
             basis_functions_components_name = BasisFunctionsProblemNameIO.load_file(
                 full_directory,
                 "basis_functions_" + str(index) + "_components_name")
             basis_functions_problem = get_problem_from_problem_name(
                 basis_functions_problem_name)
             basis_functions_reduced_problem = get_reduced_problem_from_problem(
                 basis_functions_problem)
             basis_functions = BasisFunctionsMatrix(
                 basis_functions_reduced_problem.basis_functions.space,
                 basis_functions_components_name
                 if basis_functions_components_name !=
                 basis_functions_problem.components else None)
             basis_functions.init(basis_functions_components_name)
             basis_functions_loaded = basis_functions.load(
                 full_directory,
                 "basis_functions_" + str(index) + "_content")
             assert basis_functions_loaded
             self._content["basis_functions"].append(basis_functions)
         # Recompute shape
         self._content["basis_functions_shape"] = DelayedTransposeShape(
             self._content["basis_functions"])
         # Reset precomputed slices
         self._precomputed_slices = dict()
         self._prepare_trivial_precomputed_slice()
     else:
         raise ValueError("Invalid type")
     return True
Ejemplo n.º 5
0
    def _basic_form_on_reduced_function_space(form_wrapper, at):
        form = form_wrapper._form
        form_name = form_wrapper.name()
        mu = get_problem_from_parametrized_operator(form_wrapper).mu
        reduced_V = at.get_reduced_function_spaces()
        reduced_subdomain_data = at.get_reduced_subdomain_data()

        if (form_name,
                reduced_V) not in form_on_reduced_function_space__form_cache:
            visited = set()
            replacements = dict()
            truth_problems = list()
            truth_problem_to_components = dict()
            truth_problem_to_exact_truth_problem = dict()
            truth_problem_to_reduced_mesh_solution = dict()
            truth_problem_to_reduced_mesh_interpolator = dict()
            reduced_problem_to_components = dict()
            reduced_problem_to_reduced_mesh_solution = dict()
            reduced_problem_to_reduced_basis_functions = dict()

            # Look for terminals on truth mesh
            for node in wrapping.form_iterator(form, "nodes"):
                if node in visited:
                    continue
                # ... test and trial functions
                elif isinstance(node, Argument):
                    replacements[node] = wrapping.form_argument_replace(
                        node, reduced_V)
                    visited.add(node)
                # ... problem solutions related to nonlinear terms
                elif wrapping.is_problem_solution_or_problem_solution_component_type(
                        node):
                    if wrapping.is_problem_solution_or_problem_solution_component(
                            node):
                        (preprocessed_node, component, truth_solution
                         ) = wrapping.solution_identify_component(node)
                        truth_problem = get_problem_from_solution(
                            truth_solution)
                        truth_problems.append(truth_problem)
                        # Store the component
                        if truth_problem not in truth_problem_to_components:
                            truth_problem_to_components[truth_problem] = list()
                        truth_problem_to_components[truth_problem].append(
                            component)
                        # Get the function space corresponding to preprocessed_node on the reduced mesh
                        auxiliary_reduced_V = at.get_auxiliary_reduced_function_space(
                            truth_problem, component)
                        # Define and store the replacement
                        if truth_problem not in truth_problem_to_reduced_mesh_solution:
                            truth_problem_to_reduced_mesh_solution[
                                truth_problem] = list()
                        replacements[preprocessed_node] = backend.Function(
                            auxiliary_reduced_V)
                        truth_problem_to_reduced_mesh_solution[
                            truth_problem].append(
                                replacements[preprocessed_node])
                        # Get interpolator on reduced mesh
                        if truth_problem not in truth_problem_to_reduced_mesh_interpolator:
                            truth_problem_to_reduced_mesh_interpolator[
                                truth_problem] = list()
                        truth_problem_to_reduced_mesh_interpolator[
                            truth_problem].append(
                                at.get_auxiliary_function_interpolator(
                                    truth_problem, component))
                    else:
                        (
                            auxiliary_problem, component
                        ) = wrapping.get_auxiliary_problem_for_non_parametrized_function(
                            node)
                        preprocessed_node = node
                        # Get the function space corresponding to preprocessed_node on the reduced mesh
                        auxiliary_reduced_V = at.get_auxiliary_reduced_function_space(
                            auxiliary_problem, component)
                        # Get interpolator on reduced mesh
                        auxiliary_truth_problem_to_reduced_mesh_interpolator = at.get_auxiliary_function_interpolator(
                            auxiliary_problem, component)
                        # Define and store the replacement
                        replacements[
                            preprocessed_node] = auxiliary_truth_problem_to_reduced_mesh_interpolator(
                                preprocessed_node)
                    # Make sure to skip any parent solution related to this one
                    visited.add(node)
                    visited.add(preprocessed_node)
                    for parent_node in wrapping.solution_iterator(
                            preprocessed_node):
                        visited.add(parent_node)
                # ... geometric quantities
                elif isinstance(node, GeometricQuantity):
                    if len(reduced_V) == 2:
                        assert reduced_V[0].mesh().ufl_domain(
                        ) == reduced_V[1].mesh().ufl_domain()
                    replacements[node] = type(node)(reduced_V[0].mesh())
                    visited.add(node)
            # ... and replace them
            replaced_form = wrapping.form_replace(form, replacements, "nodes")

            # Look for measures ...
            if len(reduced_V) == 2:
                assert reduced_V[0].mesh().ufl_domain() == reduced_V[1].mesh(
                ).ufl_domain()
            measure_reduced_domain = reduced_V[0].mesh().ufl_domain()
            replacements_measures = dict()
            for integral in wrapping.form_iterator(replaced_form, "integrals"):
                # Prepare measure for the new form (from firedrake/mg/ufl_utils.py)
                integral_subdomain_data = integral.subdomain_data()
                if integral_subdomain_data is not None:
                    integral_reduced_subdomain_data = reduced_subdomain_data[
                        integral_subdomain_data]
                else:
                    integral_reduced_subdomain_data = None
                measure = Measure(
                    integral.integral_type(),
                    domain=measure_reduced_domain,
                    subdomain_id=integral.subdomain_id(),
                    subdomain_data=integral_reduced_subdomain_data,
                    metadata=integral.metadata())
                replacements_measures[integral.integrand(),
                                      integral.integral_type(),
                                      integral.subdomain_id()] = measure
            # ... and replace them
            replaced_form_with_replaced_measures = wrapping.form_replace(
                replaced_form, replacements_measures, "measures")

            # Cache the resulting dicts
            form_on_reduced_function_space__form_cache[(
                form_name, reduced_V)] = replaced_form_with_replaced_measures
            form_on_reduced_function_space__truth_problems_cache[(
                form_name, reduced_V)] = truth_problems
            form_on_reduced_function_space__truth_problem_to_components_cache[(
                form_name, reduced_V)] = truth_problem_to_components
            form_on_reduced_function_space__truth_problem_to_exact_truth_problem_cache[
                (form_name, reduced_V)] = truth_problem_to_exact_truth_problem
            form_on_reduced_function_space__truth_problem_to_reduced_mesh_solution_cache[
                (form_name,
                 reduced_V)] = truth_problem_to_reduced_mesh_solution
            form_on_reduced_function_space__truth_problem_to_reduced_mesh_interpolator_cache[
                (form_name,
                 reduced_V)] = truth_problem_to_reduced_mesh_interpolator
            form_on_reduced_function_space__reduced_problem_to_components_cache[
                (form_name, reduced_V)] = reduced_problem_to_components
            form_on_reduced_function_space__reduced_problem_to_reduced_mesh_solution_cache[
                (form_name,
                 reduced_V)] = reduced_problem_to_reduced_mesh_solution
            form_on_reduced_function_space__reduced_problem_to_reduced_basis_functions_cache[
                (form_name,
                 reduced_V)] = reduced_problem_to_reduced_basis_functions

        # Extract from cache
        replaced_form_with_replaced_measures = form_on_reduced_function_space__form_cache[
            (form_name, reduced_V)]
        truth_problems = form_on_reduced_function_space__truth_problems_cache[(
            form_name, reduced_V)]
        truth_problem_to_components = form_on_reduced_function_space__truth_problem_to_components_cache[
            (form_name, reduced_V)]
        truth_problem_to_exact_truth_problem = form_on_reduced_function_space__truth_problem_to_exact_truth_problem_cache[
            (form_name, reduced_V)]
        truth_problem_to_reduced_mesh_solution = form_on_reduced_function_space__truth_problem_to_reduced_mesh_solution_cache[
            (form_name, reduced_V)]
        truth_problem_to_reduced_mesh_interpolator = form_on_reduced_function_space__truth_problem_to_reduced_mesh_interpolator_cache[
            (form_name, reduced_V)]
        reduced_problem_to_components = form_on_reduced_function_space__reduced_problem_to_components_cache[
            (form_name, reduced_V)]
        reduced_problem_to_reduced_mesh_solution = form_on_reduced_function_space__reduced_problem_to_reduced_mesh_solution_cache[
            (form_name, reduced_V)]
        reduced_problem_to_reduced_basis_functions = form_on_reduced_function_space__reduced_problem_to_reduced_basis_functions_cache[
            (form_name, reduced_V)]

        # Get list of truth and reduced problems that need to be solved, possibly updating cache
        required_truth_problems = list()
        required_reduced_problems = list()
        for truth_problem in truth_problems:
            truth_problem_is_solving = hasattr(truth_problem, "_is_solving")
            if is_training_started(truth_problem):
                reduced_problem = get_reduced_problem_from_problem(
                    truth_problem)
                reduced_problem_is_solving = hasattr(reduced_problem,
                                                     "_is_solving")
            else:
                reduced_problem = None
                reduced_problem_is_solving = False
            if not truth_problem_is_solving:
                if is_training_finished(truth_problem):
                    # Store the component
                    if reduced_problem not in reduced_problem_to_components:
                        reduced_problem_to_components[
                            reduced_problem] = truth_problem_to_components[
                                truth_problem]
                    # Store the replacement
                    if reduced_problem not in reduced_problem_to_reduced_mesh_solution:
                        reduced_problem_to_reduced_mesh_solution[
                            reduced_problem] = truth_problem_to_reduced_mesh_solution[
                                truth_problem]
                    # Get reduced problem basis functions on reduced mesh
                    if reduced_problem not in reduced_problem_to_reduced_basis_functions:
                        reduced_problem_to_reduced_basis_functions[
                            reduced_problem] = list()
                        for component in reduced_problem_to_components[
                                reduced_problem]:
                            reduced_problem_to_reduced_basis_functions[
                                reduced_problem].append(
                                    at.get_auxiliary_basis_functions_matrix(
                                        truth_problem, reduced_problem,
                                        component))
                    # Append to list of required reduced problems
                    required_reduced_problems.append(
                        (reduced_problem, reduced_problem_is_solving))
                else:
                    if (hasattr(truth_problem,
                                "_apply_exact_evaluation_at_stages") and
                            not hasattr(truth_problem, "_apply_EIM_at_stages")
                            and not hasattr(truth_problem,
                                            "_apply_DEIM_at_stages")):
                        # Init truth problem (if required), as it may not have been initialized
                        truth_problem.init()
                        # Append to list of required truth problems which are not currently solving
                        required_truth_problems.append(
                            (truth_problem, False, reduced_problem_is_solving))
                    else:
                        # Store the corresponding exact truth problem
                        if truth_problem not in truth_problem_to_exact_truth_problem:
                            exact_truth_problem = exact_problem(truth_problem)
                            truth_problem_to_exact_truth_problem[
                                truth_problem] = exact_truth_problem
                            # Init exact truth problem (if required), as it may not have been initialized
                            exact_truth_problem.init()
                        else:
                            exact_truth_problem = truth_problem_to_exact_truth_problem[
                                truth_problem]
                        # Store the component
                        if exact_truth_problem not in truth_problem_to_components:
                            truth_problem_to_components[
                                exact_truth_problem] = truth_problem_to_components[
                                    truth_problem]
                        # Store the replacement
                        if exact_truth_problem not in truth_problem_to_reduced_mesh_solution:
                            truth_problem_to_reduced_mesh_solution[
                                exact_truth_problem] = truth_problem_to_reduced_mesh_solution[
                                    truth_problem]
                        # Get interpolator on reduced mesh
                        if exact_truth_problem not in truth_problem_to_reduced_mesh_interpolator:
                            truth_problem_to_reduced_mesh_interpolator[
                                exact_truth_problem] = list()
                            for component in truth_problem_to_components[
                                    exact_truth_problem]:
                                truth_problem_to_reduced_mesh_interpolator[
                                    exact_truth_problem].append(
                                        at.get_auxiliary_function_interpolator(
                                            exact_truth_problem, component))
                        # Append to list of required truth problems which are not currently solving
                        required_truth_problems.append(
                            (exact_truth_problem, False,
                             reduced_problem_is_solving))
            else:
                assert not reduced_problem_is_solving
                # Append to list of required truth problems which are currently solving
                required_truth_problems.append((truth_problem, True, False))

        # Solve truth problems (which have not been reduced yet) associated to nonlinear terms
        for (truth_problem, truth_problem_is_solving,
             reduced_problem_is_solving) in required_truth_problems:
            if not reduced_problem_is_solving:
                # Solve (if necessary) ...
                truth_problem.set_mu(mu)
                if not truth_problem_is_solving:
                    log(
                        PROGRESS,
                        "In form_on_reduced_function_space, requiring truth problem solve for problem "
                        + truth_problem.name())
                    truth_problem.solve()
                else:
                    log(
                        PROGRESS,
                        "In form_on_reduced_function_space, loading current truth problem solution for problem "
                        + truth_problem.name())
            else:
                reduced_problem = get_reduced_problem_from_problem(
                    truth_problem)
                log(
                    PROGRESS,
                    "In form_on_reduced_function_space, replacing current truth problem solution with reduced solution for problem "
                    + reduced_problem.truth_problem.name())
            # ... and assign to reduced_mesh_solution
            for (reduced_mesh_solution, reduced_mesh_interpolator) in zip(
                    truth_problem_to_reduced_mesh_solution[truth_problem],
                    truth_problem_to_reduced_mesh_interpolator[truth_problem]):
                solution_to = reduced_mesh_solution
                if not reduced_problem_is_solving:
                    solution_from = reduced_mesh_interpolator(
                        truth_problem._solution)
                else:
                    solution_from = reduced_mesh_interpolator(
                        reduced_problem.basis_functions[:reduced_problem.
                                                        _solution.N] *
                        reduced_problem._solution)
                backend.assign(solution_to, solution_from)

        # Solve reduced problems associated to nonlinear terms
        for (reduced_problem, is_solving) in required_reduced_problems:
            # Solve (if necessary) ...
            reduced_problem.set_mu(mu)
            if not is_solving:
                log(
                    PROGRESS,
                    "In form_on_reduced_function_space, requiring reduced problem solve for problem "
                    + reduced_problem.truth_problem.name())
                reduced_problem.solve()
            else:
                log(
                    PROGRESS,
                    "In form_on_reduced_function_space, loading current reduced problem solution for problem "
                    + reduced_problem.truth_problem.name())
            # ... and assign to reduced_mesh_solution
            for (reduced_mesh_solution, reduced_basis_functions) in zip(
                    reduced_problem_to_reduced_mesh_solution[reduced_problem],
                    reduced_problem_to_reduced_basis_functions[reduced_problem]
            ):
                solution_to = reduced_mesh_solution
                solution_from_N = OnlineSizeDict()
                for c, v in reduced_problem._solution.N.items():
                    if c in reduced_basis_functions._components_name:
                        solution_from_N[c] = v
                solution_from = online_backend.OnlineFunction(solution_from_N)
                online_backend.online_assign(solution_from,
                                             reduced_problem._solution)
                solution_from = reduced_basis_functions[:solution_from_N] * solution_from
                backend.assign(solution_to, solution_from)

        # Assemble and return
        assembled_replaced_form = wrapping.assemble(
            replaced_form_with_replaced_measures)
        form_rank = assembled_replaced_form.rank()
        return (assembled_replaced_form, form_rank)