Esempio n. 1
0
 def __init__(self, N, content=None):
     assert isinstance(N, (int, dict))
     if isinstance(N, dict):
         N_sum = sum(N.values())
     else:
         N_sum = N
     self.N = N
     if content is None:
         self.content = VectorBaseType(N_sum)
     else:
         self.content = content
     # Auxiliary attributes related to basis functions matrix
     if isinstance(N, dict):
         if len(N) > 1:
             # ordering (stored by OnlineSizeDict, which inherits from OrderedDict) is important
             # in the definition of attributes
             assert isinstance(N, OnlineSizeDict)
         else:
             self.N = N = OnlineSizeDict(N)
         self._component_name_to_basis_component_index = ComponentNameToBasisComponentIndexDict()
         self._component_name_to_basis_component_length = OnlineSizeDict()
         for (component_index, (component_name, component_length)) in enumerate(N.items()):
             self._component_name_to_basis_component_index[component_name] = component_index
             self._component_name_to_basis_component_length[component_name] = component_length
     else:
         self._component_name_to_basis_component_index = None
         self._component_name_to_basis_component_length = None
Esempio n. 2
0
def slice_to_size(obj, key, length_dict):
    key = _check_key(obj, key)
    length_dict = _check_length_dict(key, length_dict)

    size = list()
    for (slice_index, slice_) in enumerate(key):
        assert isinstance(slice_.start, (int, OnlineSizeDict))
        assert slice_.step is None
        assert isinstance(slice_.stop, (int, OnlineSizeDict))
        assert isinstance(slice_.start, int) == isinstance(slice_.stop, int)
        if isinstance(slice_.stop, int):
            assert isinstance(
                length_dict[slice_index],
                OnlineSizeDict) or length_dict[slice_index] is None
            if length_dict[slice_index] is None:
                size.append(slice_.stop - slice_.start)
            else:
                assert len(length_dict[slice_index]) == 1
                for (component_name, _) in length_dict[slice_index].items():
                    break
                current_size = OnlineSizeDict()
                current_size[component_name] = slice_.stop - slice_.start
                size.append(current_size)
        else:
            assert isinstance(length_dict[slice_index], OnlineSizeDict)
            assert length_dict[slice_index].keys() == slice_.start.keys()
            assert length_dict[slice_index].keys() == slice_.stop.keys()
            current_size = OnlineSizeDict()
            for component_name in length_dict[slice_index].keys():
                current_size[component_name] = slice_.stop[
                    component_name] - slice_.start[component_name]
            size.append(current_size)
    return size
Esempio n. 3
0
 def __init__(self, M, N, content=None):
     assert isinstance(M, (int, dict))
     assert isinstance(N, (int, dict))
     assert isinstance(M, dict) == isinstance(N, dict)
     if isinstance(M, dict):
         M_sum = sum(M.values())
         N_sum = sum(N.values())
     else:
         M_sum = M
         N_sum = N
     self.M = M
     self.N = N
     if content is None:
         self.content = MatrixBaseType(M_sum, N_sum)
     else:
         self.content = content
     # Auxiliary attributes related to basis functions matrix
     if isinstance(M, dict):
         if len(M) > 1:
             # ordering (stored by OnlineSizeDict, which inherits from OrderedDict) is important
             # in the definition of attributes
             assert isinstance(M, OnlineSizeDict)
         else:
             self.M = M = OnlineSizeDict(M)
         if len(N) > 1:
             # ordering (stored by OnlineSizeDict, which inherits from OrderedDict) is important
             # in the definition of attributes
             assert isinstance(N, OnlineSizeDict)
         else:
             self.N = N = OnlineSizeDict(N)
         component_name_to_basis_component_index_0 = ComponentNameToBasisComponentIndexDict(
         )
         component_name_to_basis_component_length_0 = OnlineSizeDict()
         for (component_index,
              (component_name,
               component_length)) in enumerate(M.items()):
             component_name_to_basis_component_index_0[
                 component_name] = component_index
             component_name_to_basis_component_length_0[
                 component_name] = component_length
         component_name_to_basis_component_index_1 = ComponentNameToBasisComponentIndexDict(
         )
         component_name_to_basis_component_length_1 = OnlineSizeDict()
         for (component_index,
              (component_name,
               component_length)) in enumerate(N.items()):
             component_name_to_basis_component_index_1[
                 component_name] = component_index
             component_name_to_basis_component_length_1[
                 component_name] = component_length
         self._component_name_to_basis_component_index = (
             component_name_to_basis_component_index_0,
             component_name_to_basis_component_index_1)
         self._component_name_to_basis_component_length = (
             component_name_to_basis_component_length_0,
             component_name_to_basis_component_length_1)
     else:
         self._component_name_to_basis_component_index = (None, None)
         self._component_name_to_basis_component_length = (None, None)
Esempio n. 4
0
 def __call__(self, object_to, object_from):
     if object_from is not object_to:
         assert isinstance(object_to.vector().N, (dict, int))
         assert isinstance(object_from.vector().N, (dict, int))
         if isinstance(object_from.vector().N, dict) and isinstance(
                 object_to.vector().N, dict):
             from_N_keys = set(object_from.vector().N.keys())
             to_N_keys = set(object_to.vector().N.keys())
             components_in_both = from_N_keys & to_N_keys
             for c in components_in_both:
                 assert object_to.vector().N[c] == object_from.vector(
                 ).N[c]
             components_only_in_from = from_N_keys - to_N_keys
             components_only_in_to = to_N_keys - from_N_keys
             from_N_dict = OnlineSizeDict()
             to_N_dict = OnlineSizeDict()
             for c in components_in_both:
                 from_N_dict[c] = object_from.vector().N[c]
                 to_N_dict[c] = object_to.vector().N[c]
             for c in components_only_in_from:
                 from_N_dict[c] = 0
             for c in components_only_in_to:
                 to_N_dict[c] = 0
             object_to.vector()[:to_N_dict] = object_from.vector(
             )[:from_N_dict]
             self._preserve_vector_attributes(
                 object_to.vector(), object_from.vector(),
                 len(components_only_in_from) > 0,
                 len(components_only_in_to) > 0)
         elif isinstance(object_from.vector().N, int) and isinstance(
                 object_to.vector().N, dict):
             assert len(object_to.vector().N) == 1
             raise ValueError(
                 "Refusing to assign a dict dimension N to an int dimension N"
             )
         elif isinstance(object_from.vector().N, dict) and isinstance(
                 object_to.vector().N, int):
             assert len(object_from.vector().N) == 1
             for (c, N_c) in object_from.vector().N.items():
                 break
             assert N_c == object_to.vector().N
             N = OnlineSizeDict()
             N[c] = N_c
             object_to.vector().N = N
             object_to.vector()[:] = object_from.vector()
             self._preserve_vector_attributes(object_to.vector(),
                                              object_from.vector())
         else:  # isinstance(object_from.vector().N, int) and isinstance(object_to.vector().N, int):
             assert object_to.vector().N == object_from.vector().N
             object_to.vector()[:] = object_from.vector()
             self._preserve_vector_attributes(object_to.vector(),
                                              object_from.vector())
 def __init__(self, space, component=None):
     if component is not None:
         self.space = wrapping.get_function_subspace(space, component)
     else:
         self.space = space
     self.mpi_comm = wrapping.get_mpi_comm(space)
     self._components = dict()  # of FunctionsList
     self._precomputed_sub_components = Cache(
     )  # from tuple to FunctionsList
     self._precomputed_slices = Cache()  # from tuple to FunctionsList
     self._components_name = list()  # filled in by init
     self._component_name_to_basis_component_index = ComponentNameToBasisComponentIndexDict(
     )  # filled in by init
     self._component_name_to_basis_component_length = OnlineSizeDict()
 def _precompute_slice(self, N_start, _):
     N_stop = OnlineSizeDict()
     for component_name in self._components_name:
         N_stop[
             component_name] = self._component_name_to_basis_component_length[
                 component_name]
     return self._precompute_slice(N_start, len(self))
Esempio n. 7
0
 def __init__(self, space):
     self.space = space
     self._components_name = list()
     self._component_name_to_basis_component_index = ComponentNameToBasisComponentIndexDict()
     self._component_name_to_basis_component_length = OnlineSizeDict()
     self._enrich_memory = Cache()
     self._precomputed_slices = Cache() # from tuple to FunctionsList
Esempio n. 8
0
def read_basis_functions(W, N):
    basis_functions = BasisFunctionsMatrix(W)
    basis_functions.init(components)
    loaded = basis_functions.load("basis", "basis")
    assert loaded
    N_dict = OnlineSizeDict()
    for c in components:
        N_dict[c] = N
    return basis_functions[:N_dict]
Esempio n. 9
0
 def __getitem__(self, key):
     if (isinstance(key, slice)  # vector[:5]
             or isinstance(key,
                           (list, tuple))  # vector[[0, 1, 2, 3, 4]]
         ):
         if isinstance(key, slice):  # vector[:5]
             output_content = self.content[wrapping.Slicer(
                 slice_to_array(
                     self, key,
                     self._component_name_to_basis_component_length,
                     self._component_name_to_basis_component_index))]
             output_size = slice_to_size(
                 self, key,
                 self._component_name_to_basis_component_length)
         elif isinstance(key, (list, tuple)):  # vector[[0, 1, 2, 3, 4]]
             output_content = self.content[wrapping.Slicer(key)]
             output_size = (len(key), )
         # Prepare output
         assert len(output_size) == 1
         output = Vector_Class.__new__(type(self), output_size[0],
                                       output_content)
         output.__init__(output_size[0], output_content)
         # Preserve auxiliary attributes related to basis functions matrix
         output._component_name_to_basis_component_index = self._component_name_to_basis_component_index
         if self._component_name_to_basis_component_length is None:
             output._component_name_to_basis_component_length = None
         else:
             if isinstance(key, slice):  # vector[:5]
                 output._component_name_to_basis_component_length = output_size[
                     0]
             elif isinstance(key,
                             (list, tuple)):  # vector[[0, 1, 2, 3, 4]]
                 if len(self._component_name_to_basis_component_length
                        ) == 1:
                     for (
                             component_name, _
                     ) in self._component_name_to_basis_component_length.items(
                     ):
                         break
                     component_name_to_basis_component_length = OnlineSizeDict(
                     )
                     component_name_to_basis_component_length[
                         component_name] = len(key)
                     output._component_name_to_basis_component_length = component_name_to_basis_component_length
                 else:
                     raise NotImplementedError(
                         "Vector.__getitem__ with list or tuple input arguments has not been implemented yet"
                         + " for the case of multiple components")
         return output
     elif isinstance(key, int):  # vector[5]
         output = self.content[key]
         assert isinstance(output, Number)
         return output
     else:
         raise TypeError("Unsupported key type in Vector.__getitem__")
Esempio n. 10
0
 def __getitem__(self, key):
     assert isinstance(key, tuple)
     assert len(key) == 2
     key_is_tuple_of_slices = all([isinstance(key_i, slice) for key_i in key])
     key_is_tuple_of_tuples_or_lists = all([isinstance(key_i, (list, tuple)) for key_i in key])
     key_is_tuple_of_int = all([isinstance(key_i, int) for key_i in key])
     if (
         key_is_tuple_of_slices  # matrix[:5, :5]
         or key_is_tuple_of_tuples_or_lists  # matrix[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]
     ):
         assert key_is_tuple_of_slices is not key_is_tuple_of_tuples_or_lists
         if key_is_tuple_of_slices:  # matrix[:5, :5]
             output_content = self.content[
                 wrapping.Slicer(*slice_to_array(self, key, self._component_name_to_basis_component_length,
                                                 self._component_name_to_basis_component_index))]
             output_size = slice_to_size(self, key, self._component_name_to_basis_component_length)
         elif key_is_tuple_of_tuples_or_lists:  # matrix[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]
             output_content = self.content[wrapping.Slicer(*key)]
             output_size = (len(key[0]), len(key[1]))
         # Prepare output
         assert len(output_size) == 2
         output = Matrix_Class.__new__(type(self), output_size[0], output_size[1], output_content)
         output.__init__(output_size[0], output_size[1], output_content)
         # Preserve auxiliary attributes related to basis functions matrix
         output._component_name_to_basis_component_index = self._component_name_to_basis_component_index
         if (
             self._component_name_to_basis_component_length[0] is None
             and self._component_name_to_basis_component_length[1] is None
         ):
             output._component_name_to_basis_component_length = (None, None)
         else:
             if key_is_tuple_of_slices:  # matrix[:5, :5]
                 output._component_name_to_basis_component_length = tuple(output_size)
             elif key_is_tuple_of_tuples_or_lists:  # matrix[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]
                 component_name_to_basis_component_length = [None, None]
                 for i in range(2):
                     if len(self._component_name_to_basis_component_length[i]) == 1:
                         for (component_name, _) in self._component_name_to_basis_component_length[i].items():
                             break
                         component_name_to_basis_component_length_i = OnlineSizeDict()
                         component_name_to_basis_component_length_i[component_name] = len(key[i])
                         component_name_to_basis_component_length[i] = component_name_to_basis_component_length_i
                     else:
                         raise NotImplementedError(
                             "Matrix.__getitem__ with list or tuple input arguments"
                             + " has not been implemented yet for the case of multiple components")
                 output._component_name_to_basis_component_length = tuple(
                     component_name_to_basis_component_length)
         return output
     elif key_is_tuple_of_int:  # matrix[5, 5]
         output = self.content[key]
         assert isinstance(output, Number)
         return output
     else:
         raise TypeError("Unsupported key type in Matrix.__getitem__")
Esempio n. 11
0
 def solve_supremizer(self, solution):
     N_us = OnlineSizeDict(solution.N) # create a copy
     del N_us["p"]
     cache_key = self._supremizer_cache_key_from_N_and_kwargs(N_us)
     self._supremizer = OnlineFunction(N_us)
     if "RAM" in self.cache_config and cache_key in self._supremizer_cache:
         log(PROGRESS, "Loading reduced supremizer from cache")
         assign(self._supremizer, self._supremizer_cache[cache_key])
     else:
         log(PROGRESS, "Solving supremizer reduced problem")
         self._solve_supremizer(solution)
         if "RAM" in self.cache_config:
             self._supremizer_cache[cache_key] = copy(self._supremizer)
     return self._supremizer
Esempio n. 12
0
 def solve_supremizer(self, solution):
     N_us = OnlineSizeDict(solution.N)  # create a copy
     del N_us["p"]
     kwargs = self._latest_solve_kwargs
     self._supremizer = OnlineFunction(N_us)
     try:
         assign(self._supremizer, self._supremizer_cache[
             self.mu, N_us,
             kwargs])  # **kwargs is not supported by __getitem__
     except KeyError:
         self._solve_supremizer(solution)
         self._supremizer_cache[self.mu, N_us,
                                kwargs] = copy(self._supremizer)
     return self._supremizer
Esempio n. 13
0
def _check_key(obj, key):
    if not isinstance(key, tuple):
        key = (key, )
    assert isinstance(key, tuple)
    assert all([isinstance(key_i, slice) for key_i in key])

    def shape_attribute(slice_index):
        return getattr(obj, _slice_shape_attribute[len(key)][slice_index])

    converted_key = list()
    for (slice_index, slice_) in enumerate(key):
        shape_index = shape_attribute(slice_index)
        assert isinstance(slice_.start,
                          (int, OnlineSizeDict)) or slice_.start is None
        if ((isinstance(slice_.start, int) and slice_.start == 0)
                or slice_.start is None):
            assert isinstance(shape_index, (int, OnlineSizeDict))
            if isinstance(shape_index, int):
                start = 0
            elif isinstance(shape_index, OnlineSizeDict):
                start = OnlineSizeDict()
                for component_name in shape_index.keys():
                    start[component_name] = 0
            else:
                raise TypeError("Invalid shape")
        else:
            start = slice_.start
        assert slice_.step is None
        step = slice_.step
        assert isinstance(slice_.stop,
                          (int, OnlineSizeDict)) or slice_.stop is None
        if ((isinstance(slice_.stop, int) and slice_.stop == sys.maxsize)
                or slice_.stop is None):
            stop = shape_index
        else:
            stop = slice_.stop
        converted_slice = slice(start, stop, step)
        converted_key.append(converted_slice)
    return converted_key
Esempio n. 14
0
def preserve_solution_attributes(lhs, solution, rhs):
    # We should be solving a square system
    assert lhs.M == lhs.N
    assert lhs.N == rhs.N
    # Make sure that solution preserves auxiliary attributes related to basis functions matrix
    assert (solution.vector()._component_name_to_basis_component_index is None
            ) == (solution.vector()._component_name_to_basis_component_length
                  is None)
    if solution.vector()._component_name_to_basis_component_index is None:
        solution.vector(
        )._component_name_to_basis_component_index = lhs._component_name_to_basis_component_index[
            0]
        solution.vector(
        )._component_name_to_basis_component_length = lhs._component_name_to_basis_component_length[
            0]
    else:
        assert lhs._component_name_to_basis_component_index[
            0] == solution.vector()._component_name_to_basis_component_index
        assert lhs._component_name_to_basis_component_length[
            0] == solution.vector()._component_name_to_basis_component_length
    # If solving a problem with one component, update solution.vector().N to be a dict
    if (solution.vector()._component_name_to_basis_component_index is not None
            and len(solution.vector()._component_name_to_basis_component_index)
            == 1):
        assert isinstance(solution.vector().N, (dict, int))
        if isinstance(solution.vector().N, dict):
            assert set(solution.vector().
                       _component_name_to_basis_component_index.keys()) == set(
                           solution.vector().N.keys())
        elif isinstance(solution.vector().N, int):
            for component_name in solution.vector(
            )._component_name_to_basis_component_index:
                break
            N_int = solution.vector().N
            N = OnlineSizeDict()
            N[component_name] = N_int
            solution.vector().N = N
        else:
            raise TypeError("Invalid solution dimension")
Esempio n. 15
0
    class _BasisFunctionsMatrix(AbstractBasisFunctionsMatrix):
        def __init__(self, space, component=None):
            if component is not None:
                self.space = wrapping.get_function_subspace(space, component)
            else:
                self.space = space
            self.mpi_comm = wrapping.get_mpi_comm(space)
            self._components = dict()  # of FunctionsList
            self._precomputed_sub_components = Cache(
            )  # from tuple to FunctionsList
            self._precomputed_slices = Cache()  # from tuple to FunctionsList
            self._components_name = list()  # filled in by init
            self._component_name_to_basis_component_index = ComponentNameToBasisComponentIndexDict(
            )  # filled in by init
            self._component_name_to_basis_component_length = OnlineSizeDict()

        def init(self, components_name):
            if self._components_name != components_name:  # Do nothing if it was already initialized with the same dicts
                # Store components name
                self._components_name = components_name
                # Initialize components FunctionsList
                self._components.clear()
                for component_name in components_name:
                    self._components[component_name] = backend.FunctionsList(
                        self.space)
                # Prepare len components
                self._component_name_to_basis_component_length.clear()
                for component_name in components_name:
                    self._component_name_to_basis_component_length[
                        component_name] = 0
                # Intialize the component_name_to_basis_component_index dict
                self._component_name_to_basis_component_index.clear()
                for (basis_component_index,
                     component_name) in enumerate(components_name):
                    self._component_name_to_basis_component_index[
                        component_name] = basis_component_index
                # Reset precomputed sub components
                self._precomputed_sub_components.clear()
                # Reset precomputed slices
                self._precomputed_slices.clear()

                # Patch FunctionsList.enrich() to update internal attributes
                def patch_functions_list_enrich(component_name,
                                                functions_list):
                    original_functions_list_enrich = functions_list.enrich

                    def patched_functions_list_enrich(self_,
                                                      functions,
                                                      component=None,
                                                      weights=None,
                                                      copy=True):
                        # Append to storage
                        original_functions_list_enrich(functions, component,
                                                       weights, copy)
                        # Update component name to basis component length
                        if component is not None:
                            if isinstance(component, dict):
                                assert len(component) == 1
                                for (_, component_to) in component.items():
                                    break
                                assert component_name == component_to
                            else:
                                assert component_name == component
                        self._update_component_name_to_basis_component_length(
                            component_name)
                        # Reset precomputed sub components
                        self._precomputed_sub_components.clear()
                        # Prepare trivial precomputed sub components
                        self._prepare_trivial_precomputed_sub_components()
                        # Reset precomputed slices
                        self._precomputed_slices.clear()
                        # Prepare trivial precomputed slice
                        self._prepare_trivial_precomputed_slice()

                    functions_list.enrich_patch = PatchInstanceMethod(
                        functions_list, "enrich",
                        patched_functions_list_enrich)
                    functions_list.enrich_patch.patch()

                for component_name in components_name:
                    patch_functions_list_enrich(
                        component_name, self._components[component_name])

        def enrich(self, functions, component=None, weights=None, copy=True):
            assert copy is True
            # Append to storage
            self._enrich(functions, component, weights, copy)

        @overload(
            object, None, (None, list_of(Number)), bool
        )  # the first argument is object in order to handle FunctionsList's AdditionalFunctionType
        def _enrich(self, functions, component, weights, copy):
            assert len(self._components) == 1
            assert len(self._components_name) == 1
            component_0 = self._components_name[0]
            self._components[component_0].enrich(functions, None, weights,
                                                 copy)

        @overload(
            object, str, (None, list_of(Number)), bool
        )  # the first argument is object in order to handle FunctionsList's AdditionalFunctionType
        def _enrich(self, functions, component, weights, copy):
            assert component in self._components
            self._components[component].enrich(functions, component, weights,
                                               copy)

        @overload(
            object, dict_of(str, str), (None, list_of(Number)), bool
        )  # the first argument is object in order to handle FunctionsList's AdditionalFunctionType
        def _enrich(self, functions, component, weights, copy):
            assert len(component) == 1
            for (_, component_to) in component.items():
                break
            assert component_to in self._components
            self._components[component_to].enrich(functions, component,
                                                  weights)

        @overload(None)
        def _update_component_name_to_basis_component_length(self, component):
            assert len(self._components) == 1
            assert len(self._components_name) == 1
            component_0 = self._components_name[0]
            self._component_name_to_basis_component_length[component_0] = len(
                self._components[component_0])

        @overload(str)
        def _update_component_name_to_basis_component_length(self, component):
            self._component_name_to_basis_component_length[component] = len(
                self._components[component])

        @overload(dict_of(str, str))
        def _update_component_name_to_basis_component_length(self, component):
            assert len(component) == 1
            for (_, component_to) in component.items():
                break
            assert component_to in self._components
            self._component_name_to_basis_component_length[component_to] = len(
                self._components[component_to])

        def _prepare_trivial_precomputed_sub_components(self):
            self._precomputed_sub_components[tuple(
                self._components_name)] = self

        def _prepare_trivial_precomputed_slice(self):
            if len(self._components) == 1:
                assert len(self._components_name) == 1
                component_0 = self._components_name[0]
                precomputed_slice_key_start = 0
                precomputed_slice_key_stop = self._component_name_to_basis_component_length[
                    component_0]
            else:
                precomputed_slice_key_start = list()
                precomputed_slice_key_stop = list()
                for component_name in self._components_name:
                    precomputed_slice_key_start.append(0)
                    precomputed_slice_key_stop.append(
                        self._component_name_to_basis_component_length[
                            component_name])
                precomputed_slice_key_start = tuple(
                    precomputed_slice_key_start)
                precomputed_slice_key_stop = tuple(precomputed_slice_key_stop)
            self._precomputed_slices[precomputed_slice_key_start,
                                     precomputed_slice_key_stop] = self

        def clear(self):
            components_name = self._components_name
            # Trick _init into re-initializing everything
            self._components_name = None
            self.init(components_name)

        def save(self, directory, filename):
            if len(self._components) > 1:

                def filename_and_component(component_name):
                    return filename + "_" + component_name
            else:

                def filename_and_component(component_name):
                    return filename

            for (component_name, functions_list) in self._components.items():
                functions_list.save(directory,
                                    filename_and_component(component_name))

        def load(self, directory, filename):
            return_value = True
            assert len(self._components) > 0
            if len(self._components) > 1:

                def filename_and_component(component_name):
                    return filename + "_" + component_name
            else:

                def filename_and_component(component_name):
                    return filename

            for (component_name, functions_list) in self._components.items():
                # Skip updating internal attributes while reading in basis functions, we will do that
                # only once at the end
                assert hasattr(functions_list, "enrich_patch")
                functions_list.enrich_patch.unpatch()
                # Load each component
                return_value_component = functions_list.load(
                    directory, filename_and_component(component_name))
                return_value = return_value and return_value_component
                # Populate component length
                self._update_component_name_to_basis_component_length(
                    component_name)
                # Restore patched enrich method
                functions_list.enrich_patch.patch()
            # Reset precomputed sub components
            self._precomputed_sub_components.clear()
            # Prepare trivial precomputed sub components
            self._prepare_trivial_precomputed_sub_components()
            # Reset precomputed slices
            self._precomputed_slices.clear()
            # Prepare trivial precomputed slice
            self._prepare_trivial_precomputed_slice()
            # Return
            return return_value

        @overload(
            online_backend.OnlineMatrix.Type(), )
        def __mul__(self, other):
            if isinstance(other.M, dict):
                assert set(other.M.keys()) == set(self._components_name)

            def BasisFunctionsMatrixWithInit(space):
                output = _BasisFunctionsMatrix.__new__(type(self), space)
                output.__init__(space)
                output.init(self._components_name)
                return output

            return wrapping.basis_functions_matrix_mul_online_matrix(
                self, other, BasisFunctionsMatrixWithInit)

        @overload(
            online_backend.OnlineFunction.Type(), )
        def __mul__(self, other):
            return self.__mul__(online_wrapping.function_to_vector(other))

        @overload(
            online_backend.OnlineVector.Type(), )
        def __mul__(self, other):
            if isinstance(other.N, dict):
                assert set(other.N.keys()) == set(self._components_name)
            return wrapping.basis_functions_matrix_mul_online_vector(
                self, other)

        @overload(
            ThetaType, )
        def __mul__(self, other):
            return wrapping.basis_functions_matrix_mul_online_vector(
                self, other)

        def __len__(self):
            assert len(self._components_name) == 1
            assert len(self._component_name_to_basis_component_length) == 1
            return self._component_name_to_basis_component_length[
                self._components_name[0]]

        @overload(int)
        def __getitem__(self, key):
            # spare the user an obvious extraction of the first component return basis function number key
            assert len(self._components) == 1
            assert len(self._components_name) == 1
            component_0 = self._components_name[0]
            return self._components[component_0][key]

        @overload(str)
        def __getitem__(self, key):
            # return all basis functions for each component, then the user may use __getitem__ of FunctionsList to extract a single basis function
            return self._components[key]

        @overload(list_of(str))
        def __getitem__(self, key):
            return self._precompute_sub_components(key)

        @overload(slice)  # e.g. key = :N, return the first N functions
        def __getitem__(self, key):
            assert key.step is None
            return self._precompute_slice(key.start, key.stop)

        @overload(
            int, object
        )  # the second argument is object in order to handle FunctionsList's AdditionalFunctionType
        def __setitem__(self, key, item):
            assert len(
                self._components
            ) == 1, "Cannot set components, only single functions. Did you mean to call __getitem__ to extract a component and __setitem__ of a single function on that component?"
            assert len(self._components_name) == 1
            self._components[self._components_name[0]][key] = item

        @overload(None, int)
        def _precompute_slice(self, _, N_stop):
            return self._precompute_slice(0, N_stop)

        @overload(int, None)
        def _precompute_slice(self, N_start, _):
            return self._precompute_slice(N_start, len(self))

        @overload(int, int)
        def _precompute_slice(self, N_start, N_stop):
            if (N_start, N_stop) not in self._precomputed_slices:
                assert len(self._components) == 1
                output = _BasisFunctionsMatrix.__new__(type(self), self.space)
                output.__init__(self.space)
                output.init(self._components_name)
                for component_name in self._components_name:
                    output._components[component_name].enrich(
                        self._components[component_name][N_start:N_stop],
                        copy=False)
                self._precomputed_slices[N_start, N_stop] = output
            return self._precomputed_slices[N_start, N_stop]

        @overload(None, OnlineSizeDict)
        def _precompute_slice(self, _, N_stop):
            N_start = OnlineSizeDict()
            for component_name in self._components_name:
                N_start[component_name] = 0
            return self._precompute_slice(N_start, N_stop)

        @overload(OnlineSizeDict, None)
        def _precompute_slice(self, N_start, _):
            N_stop = OnlineSizeDict()
            for component_name in self._components_name:
                N_stop[
                    component_name] = self._component_name_to_basis_component_length[
                        component_name]
            return self._precompute_slice(N_start, len(self))

        @overload(OnlineSizeDict, OnlineSizeDict)
        def _precompute_slice(self, N_start, N_stop):
            assert set(N_start.keys()) == set(self._components_name)
            assert set(N_stop.keys()) == set(self._components_name)
            N_start_key = tuple(N_start[component_name]
                                for component_name in self._components_name)
            N_stop_key = tuple(N_stop[component_name]
                               for component_name in self._components_name)
            if (N_start_key, N_stop_key) not in self._precomputed_slices:
                output = _BasisFunctionsMatrix.__new__(type(self), self.space)
                output.__init__(self.space)
                output.init(self._components_name)
                for component_name in self._components_name:
                    output._components[component_name].enrich(
                        self._components[component_name]
                        [N_start[component_name]:N_stop[component_name]],
                        copy=False)
                self._precomputed_slices[N_start_key, N_stop_key] = output
            return self._precomputed_slices[N_start_key, N_stop_key]

        def _precompute_sub_components(self, sub_components):
            sub_components_key = tuple(sub_components)
            if sub_components_key not in self._precomputed_sub_components:
                assert set(sub_components).issubset(self._components_name)
                output = _BasisFunctionsMatrix.__new__(type(self), self.space,
                                                       sub_components)
                output.__init__(self.space, sub_components)
                output.init(sub_components)
                for component_name in sub_components:
                    output._components[component_name].enrich(
                        self._components[component_name],
                        component=component_name,
                        copy=True)
                self._precomputed_sub_components[sub_components_key] = output
            return self._precomputed_sub_components[sub_components_key]

        def __iter__(self):
            assert len(self._components) == 1
            assert len(self._components_name) == 1
            component_0 = self._components_name[0]
            return self._components[component_0].__iter__()
Esempio n. 16
0
    class Vector_Class(object):
        def __init__(self, N, content=None):
            assert isinstance(N, (int, dict))
            if isinstance(N, dict):
                N_sum = sum(N.values())
            else:
                N_sum = N
            self.N = N
            if content is None:
                self.content = VectorBaseType(N_sum)
            else:
                self.content = content
            # Auxiliary attributes related to basis functions matrix
            if isinstance(N, dict):
                if len(N) > 1:
                    # ordering (stored by OnlineSizeDict, which inherits from OrderedDict) is important
                    # in the definition of attributes
                    assert isinstance(N, OnlineSizeDict)
                else:
                    self.N = N = OnlineSizeDict(N)
                self._component_name_to_basis_component_index = ComponentNameToBasisComponentIndexDict()
                self._component_name_to_basis_component_length = OnlineSizeDict()
                for (component_index, (component_name, component_length)) in enumerate(N.items()):
                    self._component_name_to_basis_component_index[component_name] = component_index
                    self._component_name_to_basis_component_length[component_name] = component_length
            else:
                self._component_name_to_basis_component_index = None
                self._component_name_to_basis_component_length = None

        def __getitem__(self, key):
            if (
                isinstance(key, slice)  # vector[:5]
                or isinstance(key, (list, tuple))  # vector[[0, 1, 2, 3, 4]]
            ):
                if isinstance(key, slice):  # vector[:5]
                    output_content = self.content[
                        wrapping.Slicer(slice_to_array(
                            self, key, self._component_name_to_basis_component_length,
                            self._component_name_to_basis_component_index))]
                    output_size = slice_to_size(self, key, self._component_name_to_basis_component_length)
                elif isinstance(key, (list, tuple)):  # vector[[0, 1, 2, 3, 4]]
                    output_content = self.content[wrapping.Slicer(key)]
                    output_size = (len(key), )
                # Prepare output
                assert len(output_size) == 1
                output = Vector_Class.__new__(type(self), output_size[0], output_content)
                output.__init__(output_size[0], output_content)
                # Preserve auxiliary attributes related to basis functions matrix
                output._component_name_to_basis_component_index = self._component_name_to_basis_component_index
                if self._component_name_to_basis_component_length is None:
                    output._component_name_to_basis_component_length = None
                else:
                    if isinstance(key, slice):  # vector[:5]
                        output._component_name_to_basis_component_length = output_size[0]
                    elif isinstance(key, (list, tuple)):  # vector[[0, 1, 2, 3, 4]]
                        if len(self._component_name_to_basis_component_length) == 1:
                            for (component_name, _) in self._component_name_to_basis_component_length.items():
                                break
                            component_name_to_basis_component_length = OnlineSizeDict()
                            component_name_to_basis_component_length[component_name] = len(key)
                            output._component_name_to_basis_component_length = component_name_to_basis_component_length
                        else:
                            raise NotImplementedError(
                                "Vector.__getitem__ with list or tuple input arguments has not been implemented yet"
                                + " for the case of multiple components")
                return output
            elif isinstance(key, int):  # vector[5]
                output = self.content[key]
                assert isinstance(output, Number)
                return output
            else:
                raise TypeError("Unsupported key type in Vector.__getitem__")

        def __setitem__(self, key, value):
            if (
                isinstance(key, slice)  # vector[:5]
                or isinstance(key, (list, tuple))  # vector[[0, 1, 2, 3, 4]]
            ):
                if isinstance(key, slice):  # vector[:5]
                    converted_key = wrapping.Slicer(
                        slice_to_array(self, key, self._component_name_to_basis_component_length,
                                       self._component_name_to_basis_component_index))
                elif isinstance(key, (list, tuple)):  # vector[[0, 1, 2, 3, 4]]
                    converted_key = wrapping.Slicer(key)
                if isinstance(value, type(self)):
                    value = value.content
                self.content[converted_key] = value
            elif isinstance(key, int):  # vector[5]
                self.content[key] = value
            else:
                raise TypeError("Unsupported key type in Vector.__setitem__")

        def __abs__(self):
            self._arithmetic_operations_assert_attributes(None, other_order=0)
            output_content = self.content.__abs__()
            output_size = self.N
            output = Vector_Class.__new__(type(self), output_size, output_content)
            output.__init__(output_size, output_content)
            self._arithmetic_operations_preserve_attributes(output, other_order=0)
            return output

        def __neg__(self):
            self._arithmetic_operations_assert_attributes(None, other_order=0)
            output_content = self.content.__neg__()
            output_size = self.N
            output = Vector_Class.__new__(type(self), output_size, output_content)
            output.__init__(output_size, output_content)
            self._arithmetic_operations_preserve_attributes(output, other_order=0)
            return output

        def __add__(self, other):
            if isinstance(other, type(self)):
                self._arithmetic_operations_assert_attributes(other)
                output_content = self.content.__add__(other.content)
                output_size = self.N
                output = Vector_Class.__new__(type(self), output_size, output_content)
                output.__init__(output_size, output_content)
                self._arithmetic_operations_preserve_attributes(output)
                return output
            else:
                return NotImplemented

        def __iadd__(self, other):
            if isinstance(other, type(self)):
                self._arithmetic_operations_assert_attributes(other)
                self.content.__iadd__(other.content)
                return self
            else:
                return NotImplemented

        def __sub__(self, other):
            if isinstance(other, type(self)):
                self._arithmetic_operations_assert_attributes(other)
                output_content = self.content.__sub__(other.content)
                output_size = self.N
                output = Vector_Class.__new__(type(self), output_size, output_content)
                output.__init__(output_size, output_content)
                self._arithmetic_operations_preserve_attributes(output)
                return output
            else:
                return NotImplemented

        def __isub__(self, other):
            if isinstance(other, type(self)):
                self._arithmetic_operations_assert_attributes(other)
                self.content.__isub__(other.content)
                return self
            else:
                return NotImplemented

        def __mul__(self, other):
            if isinstance(other, Number):
                self._arithmetic_operations_assert_attributes(other, other_order=0)
                output_content = self.content.__mul__(other)
                output_size = self.N
                output = Vector_Class.__new__(type(self), output_size, output_content)
                output.__init__(output_size, output_content)
                self._arithmetic_operations_preserve_attributes(output, other_order=0)
                return output
            else:
                return NotImplemented

        def __rmul__(self, other):
            if isinstance(other, Number):
                self._arithmetic_operations_assert_attributes(other, other_order=0)
                output_content = self.content.__rmul__(other)
                output_size = self.N
                output = Vector_Class.__new__(type(self), output_size, output_content)
                output.__init__(output_size, output_content)
                self._arithmetic_operations_preserve_attributes(output, other_order=0)
                return output
            else:
                return NotImplemented

        def __imul__(self, other):
            if isinstance(other, Number):
                self._arithmetic_operations_assert_attributes(other, other_order=0)
                self.content.__imul__(other)
                return self
            else:
                return NotImplemented

        def __truediv__(self, other):
            if isinstance(other, Number):
                self._arithmetic_operations_assert_attributes(other, other_order=0)
                output_content = self.content.__truediv__(other)
                output_size = self.N
                output = Vector_Class.__new__(type(self), output_size, output_content)
                output.__init__(output_size, output_content)
                self._arithmetic_operations_preserve_attributes(output, other_order=0)
                return output
            else:
                return NotImplemented

        def __itruediv__(self, other):
            if isinstance(other, Number):
                self._arithmetic_operations_assert_attributes(other, other_order=0)
                self.content.__itruediv__(other)
                return self
            else:
                return NotImplemented

        def _arithmetic_operations_assert_attributes(self, other, other_order=1):
            assert other_order in (0, 1)
            if other_order == 1:
                assert self.N == other.N
                assert self._component_name_to_basis_component_index == other._component_name_to_basis_component_index
                assert self._component_name_to_basis_component_length == other._component_name_to_basis_component_length

        def _arithmetic_operations_preserve_attributes(self, output, other_order=1):
            assert other_order in (0, 1)
            output._component_name_to_basis_component_index = self._component_name_to_basis_component_index
            output._component_name_to_basis_component_length = self._component_name_to_basis_component_length

        def __str__(self):
            return str(self.content)

        def __iter__(self):
            return self.content.__iter__()
Esempio n. 17
0
    def _init_basis_functions(self, current_stage="online"):
        """
        Basis functions are initialized. Internal method.
        """
        assert current_stage in ("online", "offline")
        # Initialize basis functions mappings
        if self.basis_functions is None:  # avoid re-initializing basis functions matrix multiple times
            self.basis_functions = BasisFunctionsMatrix(self.truth_problem.V)
            self.basis_functions.init(self.components)
        # Get number of components
        n_components = len(self.components)
        # Get helper strings depending on the number of basis components
        if n_components > 1:
            dirichlet_bc_string = "dirichlet_bc_{c}"

            def has_non_homogeneous_dirichlet_bc(component):
                return self.dirichlet_bc[
                    component] and not self.dirichlet_bc_are_homogeneous[
                        component]

            def get_basis_functions(component):
                return self.basis_functions[component]
        else:
            dirichlet_bc_string = "dirichlet_bc"

            def has_non_homogeneous_dirichlet_bc(component):
                return self.dirichlet_bc and not self.dirichlet_bc_are_homogeneous

            def get_basis_functions(component):
                return self.basis_functions

        # Detect how many theta terms are related to boundary conditions
        assert (self.dirichlet_bc is
                None) == (self.dirichlet_bc_are_homogeneous is None)
        if self.dirichlet_bc is None:  # init was not called already
            dirichlet_bc = dict()
            for component in self.components:
                try:
                    theta_bc = self.compute_theta(
                        dirichlet_bc_string.format(c=component))
                except ValueError:  # there were no Dirichlet BCs to be imposed by lifting
                    dirichlet_bc[component] = False
                else:
                    dirichlet_bc[component] = True
            if n_components == 1:
                self.dirichlet_bc = dirichlet_bc[self.components[0]]
            else:
                self.dirichlet_bc = dirichlet_bc
            self.dirichlet_bc_are_homogeneous = self.truth_problem.dirichlet_bc_are_homogeneous
            assert self._combined_and_homogenized_dirichlet_bc is None
            self._combined_and_homogenized_dirichlet_bc = self._combine_and_homogenize_all_dirichlet_bcs(
            )
        # Load basis functions
        if current_stage == "online":
            basis_functions_loaded = self.basis_functions.load(
                self.folder["basis"], "basis")
            # To properly initialize N and N_bc, detect how many theta terms
            # are related to boundary conditions
            if basis_functions_loaded:
                N = OnlineSizeDict()
                N_bc = OnlineSizeDict()
                for component in self.components:
                    if has_non_homogeneous_dirichlet_bc(component):
                        theta_bc = self.compute_theta(
                            dirichlet_bc_string.format(c=component))
                        N[component] = len(
                            get_basis_functions(component)) - len(theta_bc)
                        N_bc[component] = len(theta_bc)
                    else:
                        N[component] = len(get_basis_functions(component))
                        N_bc[component] = 0
                assert len(N) == len(N_bc)
                assert len(N) > 0
                if len(N) == 1:
                    self.N = N[self.components[0]]
                    self.N_bc = N_bc[self.components[0]]
                else:
                    self.N = N
                    self.N_bc = N_bc
        elif current_stage == "offline":
            # Store the lifting functions in self.basis_functions
            for component in self.components:
                self.assemble_operator(
                    dirichlet_bc_string.format(c=component), "offline"
                )  # no return value from assemble_operator in this case
            # Save basis functions matrix, that contains up to now only lifting functions
            self.basis_functions.save(self.folder["basis"], "basis")
            # Properly fill in self.N_bc
            if n_components == 1:
                self.N = 0
                self.N_bc = len(self.basis_functions)
            else:
                N = OnlineSizeDict()
                N_bc = OnlineSizeDict()
                for component in self.components:
                    N[component] = 0
                    N_bc[component] = len(self.basis_functions[component])
                self.N = N
                self.N_bc = N_bc
            # Note that, however, self.N is not increased, so it will actually contain the number
            # of basis functions without the lifting ones.
        else:
            raise ValueError("Invalid stage in _init_basis_functions().")
 def _precompute_slice(self, _, N_stop):
     N_start = OnlineSizeDict()
     for component_name in self._components_name:
         N_start[component_name] = 0
     return self._precompute_slice(N_start, N_stop)
    def _basic_form_on_reduced_function_space(form_wrapper, at):
        form = form_wrapper._form
        form_name = form_wrapper.name()
        form_problem = get_problem_from_parametrized_operator(form_wrapper)
        reduced_V = at.get_reduced_function_spaces()
        reduced_subdomain_data = at.get_reduced_subdomain_data()
        mu = form_problem.mu
        if hasattr(form_problem, "set_time"):
            t = form_problem.t
        else:
            t = None

        if (form_name, reduced_V) not in form_cache:
            visited = set()
            replacements = dict()
            truth_problems = list()
            truth_problem_to_components = {  # outer dict index over time derivative
                0: dict(),
                1: dict()
            }
            truth_problem_to_exact_truth_problem = dict()
            truth_problem_to_reduced_mesh_solution = dict()
            truth_problem_to_reduced_mesh_solution_dot = dict()
            truth_problem_to_reduced_mesh_interpolator = {  # outer dict index over time derivative
                0: dict(),
                1: dict()
            }
            reduced_problem_to_components = {  # outer dict index over time derivative
                0: dict(),
                1: dict()
            }
            reduced_problem_to_reduced_mesh_solution = dict()
            reduced_problem_to_reduced_mesh_solution_dot = dict()
            reduced_problem_to_reduced_basis_functions = {  # outer dict index over time derivative
                0: dict(),
                1: dict()
            }

            # Look for terminals on truth mesh
            logger.log(DEBUG, "Traversing terminals of form " + form_name)
            for node in wrapping.form_iterator(form, "nodes"):
                if node in visited:
                    continue
                # ... test and trial functions
                elif isinstance(node, Argument):
                    logger.log(
                        DEBUG, "\tFound argument, number: " +
                        str(node.number()) + ", part: " + str(node.part()))
                    replacements[node] = wrapping.form_argument_replace(
                        node, reduced_V)
                    visited.add(node)
                # ... problem solutions related to nonlinear terms
                elif wrapping.is_problem_solution_type(node):
                    node_is_problem_solution = wrapping.is_problem_solution(
                        node)
                    node_is_problem_solution_dot = wrapping.is_problem_solution_dot(
                        node)
                    if node_is_problem_solution or node_is_problem_solution_dot:
                        if node_is_problem_solution:
                            (preprocessed_node, component, truth_solution
                             ) = wrapping.solution_identify_component(node)
                            truth_problem = get_problem_from_solution(
                                truth_solution)
                            logger.log(
                                DEBUG,
                                "\tFound problem solution of truth problem " +
                                truth_problem.name() +
                                " (exact problem decorator: " +
                                str(hasattr(truth_problem, "__is_exact__")) +
                                ", component: " + str(component) + ")")
                            # Time derivative key for components and interpolator dicts
                            time_derivative = 0
                        elif node_is_problem_solution_dot:
                            (preprocessed_node, component, truth_solution_dot
                             ) = wrapping.solution_dot_identify_component(node)
                            truth_problem = get_problem_from_solution_dot(
                                truth_solution_dot)
                            logger.log(
                                DEBUG,
                                "\tFound problem solution dot of truth problem "
                                + truth_problem.name() +
                                " (exact problem decorator: " +
                                str(hasattr(truth_problem, "__is_exact__")) +
                                ", component: " + str(component) + ")")
                            # Time derivative key for components and interpolator dicts
                            time_derivative = 1
                        # Store truth problem
                        if truth_problem not in truth_problems:
                            truth_problems.append(truth_problem)
                        # Store the component
                        if truth_problem not in truth_problem_to_components[
                                time_derivative]:
                            truth_problem_to_components[time_derivative][
                                truth_problem] = list()
                        if component not in truth_problem_to_components[
                                time_derivative][truth_problem]:
                            truth_problem_to_components[time_derivative][
                                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
                            assert preprocessed_node not in replacements  # as it is related to a new truth solution component
                            replacements[preprocessed_node] = backend.Function(
                                auxiliary_reduced_V)
                            if time_derivative == 0:
                                if truth_problem not in truth_problem_to_reduced_mesh_solution:
                                    truth_problem_to_reduced_mesh_solution[
                                        truth_problem] = list()
                                truth_problem_to_reduced_mesh_solution[
                                    truth_problem].append(
                                        replacements[preprocessed_node])
                            elif time_derivative == 1:
                                if truth_problem not in truth_problem_to_reduced_mesh_solution_dot:
                                    truth_problem_to_reduced_mesh_solution_dot[
                                        truth_problem] = list()
                                truth_problem_to_reduced_mesh_solution_dot[
                                    truth_problem].append(
                                        replacements[preprocessed_node])
                            # Get interpolator on reduced mesh
                            if truth_problem not in truth_problem_to_reduced_mesh_interpolator[
                                    time_derivative]:
                                truth_problem_to_reduced_mesh_interpolator[
                                    time_derivative][truth_problem] = list()
                            truth_problem_to_reduced_mesh_interpolator[
                                time_derivative][truth_problem].append(
                                    at.get_auxiliary_function_interpolator(
                                        truth_problem, component))
                    else:
                        (
                            preprocessed_node, component, auxiliary_problem
                        ) = wrapping.get_auxiliary_problem_for_non_parametrized_function(
                            node)
                        logger.log(
                            DEBUG, "\tFound non parametrized function " +
                            str(preprocessed_node) +
                            " associated to auxiliary problem " +
                            str(auxiliary_problem.name()) + ", component: " +
                            str(component))
                        if preprocessed_node not in replacements:
                            # 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):
                    logger.log(DEBUG,
                               "\tFound geometric quantity " + str(node))
                    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)
                else:
                    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_cache[(form_name,
                        reduced_V)] = replaced_form_with_replaced_measures
            truth_problems_cache[(form_name, reduced_V)] = truth_problems
            truth_problem_to_components_cache[(
                form_name, reduced_V)] = truth_problem_to_components
            truth_problem_to_exact_truth_problem_cache[(
                form_name, reduced_V)] = truth_problem_to_exact_truth_problem
            truth_problem_to_reduced_mesh_solution_cache[(
                form_name, reduced_V)] = truth_problem_to_reduced_mesh_solution
            truth_problem_to_reduced_mesh_solution_dot_cache[(
                form_name,
                reduced_V)] = truth_problem_to_reduced_mesh_solution_dot
            truth_problem_to_reduced_mesh_interpolator_cache[(
                form_name,
                reduced_V)] = truth_problem_to_reduced_mesh_interpolator
            reduced_problem_to_components_cache[(
                form_name, reduced_V)] = reduced_problem_to_components
            reduced_problem_to_reduced_mesh_solution_cache[(
                form_name,
                reduced_V)] = reduced_problem_to_reduced_mesh_solution
            reduced_problem_to_reduced_mesh_solution_dot_cache[(
                form_name,
                reduced_V)] = reduced_problem_to_reduced_mesh_solution_dot
            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_cache[(form_name,
                                                           reduced_V)]
        truth_problems = truth_problems_cache[(form_name, reduced_V)]
        truth_problem_to_components = truth_problem_to_components_cache[(
            form_name, reduced_V)]
        truth_problem_to_exact_truth_problem = truth_problem_to_exact_truth_problem_cache[
            (form_name, reduced_V)]
        truth_problem_to_reduced_mesh_solution = truth_problem_to_reduced_mesh_solution_cache[
            (form_name, reduced_V)]
        truth_problem_to_reduced_mesh_solution_dot = truth_problem_to_reduced_mesh_solution_dot_cache[
            (form_name, reduced_V)]
        truth_problem_to_reduced_mesh_interpolator = truth_problem_to_reduced_mesh_interpolator_cache[
            (form_name, reduced_V)]
        reduced_problem_to_components = reduced_problem_to_components_cache[(
            form_name, reduced_V)]
        reduced_problem_to_reduced_mesh_solution = reduced_problem_to_reduced_mesh_solution_cache[
            (form_name, reduced_V)]
        reduced_problem_to_reduced_mesh_solution_dot = reduced_problem_to_reduced_mesh_solution_dot_cache[
            (form_name, reduced_V)]
        reduced_problem_to_reduced_basis_functions = 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):
                    logger.log(
                        DEBUG, "Truth problem " + truth_problem.name() +
                        " (exact problem decorator: " +
                        str(hasattr(truth_problem, "__is_exact__")) +
                        ") is not currently solving, and its offline stage has finished: truth problem will be replaced by reduced problem"
                    )
                    # Store the replacement for solution
                    if (reduced_problem
                            not in reduced_problem_to_reduced_mesh_solution
                            and truth_problem
                            in truth_problem_to_reduced_mesh_solution):
                        reduced_problem_to_reduced_mesh_solution[
                            reduced_problem] = truth_problem_to_reduced_mesh_solution[
                                truth_problem]
                        # Store the component
                        assert reduced_problem not in reduced_problem_to_components[
                            0]
                        assert truth_problem in truth_problem_to_components[0]
                        reduced_problem_to_components[0][
                            reduced_problem] = truth_problem_to_components[0][
                                truth_problem]
                        # Get reduced problem basis functions on reduced mesh
                        assert reduced_problem not in reduced_problem_to_reduced_basis_functions[
                            0]
                        reduced_problem_to_reduced_basis_functions[0][
                            reduced_problem] = [
                                at.get_auxiliary_basis_functions_matrix(
                                    truth_problem, component) for component in
                                reduced_problem_to_components[0]
                                [reduced_problem]
                            ]
                    # Store the replacement for solution_dot
                    if (reduced_problem
                            not in reduced_problem_to_reduced_mesh_solution_dot
                            and truth_problem
                            in truth_problem_to_reduced_mesh_solution_dot):
                        reduced_problem_to_reduced_mesh_solution_dot[
                            reduced_problem] = truth_problem_to_reduced_mesh_solution_dot[
                                truth_problem]
                        # Store the component
                        assert reduced_problem not in reduced_problem_to_components[
                            1]
                        assert truth_problem in truth_problem_to_components[1]
                        reduced_problem_to_components[1][
                            reduced_problem] = truth_problem_to_components[1][
                                truth_problem]
                        # Get reduced problem basis functions on reduced mesh
                        assert reduced_problem not in reduced_problem_to_reduced_basis_functions[
                            1]
                        reduced_problem_to_reduced_basis_functions[1][
                            reduced_problem] = [
                                at.get_auxiliary_basis_functions_matrix(
                                    truth_problem, component) for component in
                                reduced_problem_to_components[1]
                                [reduced_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")):
                        logger.log(
                            DEBUG, "Truth problem " + truth_problem.name() +
                            " (exact problem decorator: " +
                            str(hasattr(truth_problem, "__is_exact__")) +
                            ") is not currently solving, its offline stage has not finished, and only @ExactParametrizedFunctions has been used: truth solve of this truth problem instance will be called"
                        )
                        # 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:
                        logger.log(
                            DEBUG, "Truth problem " + truth_problem.name() +
                            " (exact problem decorator: " +
                            str(hasattr(truth_problem, "__is_exact__")) +
                            ") is not currently solving, its offline stage has not finished, and either @ExactParametrizedFunctions has not been used or it has been used in combination with @DEIM or @EIM: truth solve on an auxiliary instance (with exact problem decorator) will be called, to prevent early initialization of DEIM/EIM data structures"
                        )
                        # 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 replacement for solution
                        if (exact_truth_problem
                                not in truth_problem_to_reduced_mesh_solution
                                and truth_problem
                                in truth_problem_to_reduced_mesh_solution):
                            truth_problem_to_reduced_mesh_solution[
                                exact_truth_problem] = truth_problem_to_reduced_mesh_solution[
                                    truth_problem]
                            # Store the component
                            assert exact_truth_problem not in truth_problem_to_components[
                                0]
                            assert truth_problem in truth_problem_to_components[
                                0]
                            truth_problem_to_components[0][
                                exact_truth_problem] = truth_problem_to_components[
                                    0][truth_problem]
                            # Get interpolator on reduced mesh
                            assert exact_truth_problem not in truth_problem_to_reduced_mesh_interpolator[
                                0]
                            assert truth_problem in truth_problem_to_reduced_mesh_interpolator[
                                0]
                            truth_problem_to_reduced_mesh_interpolator[0][
                                exact_truth_problem] = truth_problem_to_reduced_mesh_interpolator[
                                    0][truth_problem]
                        # Store the replacement for solution_dot
                        if (exact_truth_problem not in
                                truth_problem_to_reduced_mesh_solution_dot
                                and truth_problem
                                in truth_problem_to_reduced_mesh_solution_dot):
                            truth_problem_to_reduced_mesh_solution_dot[
                                exact_truth_problem] = truth_problem_to_reduced_mesh_solution_dot[
                                    truth_problem]
                            # Store the component
                            assert exact_truth_problem not in truth_problem_to_components[
                                1]
                            assert truth_problem in truth_problem_to_components[
                                1]
                            truth_problem_to_components[1][
                                exact_truth_problem] = truth_problem_to_components[
                                    1][truth_problem]
                            # Get interpolator on reduced mesh
                            assert exact_truth_problem not in truth_problem_to_reduced_mesh_interpolator[
                                1]
                            assert truth_problem in truth_problem_to_reduced_mesh_interpolator[
                                1]
                            truth_problem_to_reduced_mesh_interpolator[1][
                                exact_truth_problem] = truth_problem_to_reduced_mesh_interpolator[
                                    1][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:
                logger.log(
                    DEBUG, "Truth problem " + truth_problem.name() +
                    " (exact problem decorator: " +
                    str(hasattr(truth_problem, "__is_exact__")) +
                    ") is currently solving: current truth solution will be loaded"
                )
                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:
                    logger.log(
                        DEBUG, "Requiring truth problem solve for problem " +
                        truth_problem.name() + " (exact problem decorator: " +
                        str(hasattr(truth_problem, "__is_exact__")) + ")")
                    truth_problem.solve()
                else:
                    logger.log(
                        DEBUG,
                        "Loading current truth problem solution for problem " +
                        truth_problem.name() + " (exact problem decorator: " +
                        str(hasattr(truth_problem, "__is_exact__")) + ")")
            else:
                reduced_problem = get_reduced_problem_from_problem(
                    truth_problem)
                logger.log(
                    DEBUG,
                    "Replacing current truth problem solution with reduced solution for problem "
                    + reduced_problem.truth_problem.name())
            # Assign to reduced_mesh_solution
            if truth_problem in truth_problem_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[0]
                    [truth_problem]):
                    solution_to = reduced_mesh_solution
                    if t is None:
                        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)
                    else:
                        if not reduced_problem_is_solving:
                            if not truth_problem_is_solving:
                                solution_from = reduced_mesh_interpolator(
                                    truth_problem._solution_over_time.at(t))
                            else:
                                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)
            # Assign to reduced_mesh_solution_dot
            if truth_problem in truth_problem_to_reduced_mesh_solution_dot:
                for (reduced_mesh_solution_dot,
                     reduced_mesh_interpolator) in zip(
                         truth_problem_to_reduced_mesh_solution_dot[
                             truth_problem],
                         truth_problem_to_reduced_mesh_interpolator[1]
                         [truth_problem]):
                    solution_dot_to = reduced_mesh_solution_dot
                    assert t is not None
                    if not reduced_problem_is_solving:
                        if not truth_problem_is_solving:
                            solution_dot_from = reduced_mesh_interpolator(
                                truth_problem._solution_dot_over_time.at(t))
                        else:
                            solution_dot_from = reduced_mesh_interpolator(
                                truth_problem._solution_dot)
                    else:
                        solution_dot_from = reduced_mesh_interpolator(
                            reduced_problem.basis_functions[:reduced_problem.
                                                            _solution_dot.N] *
                            reduced_problem._solution_dot)
                    backend.assign(solution_dot_to, solution_dot_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:
                logger.log(
                    DEBUG, "Requiring reduced problem solve for problem " +
                    reduced_problem.truth_problem.name())
                reduced_problem.solve()
            else:
                logger.log(
                    DEBUG,
                    "Loading current reduced problem solution for problem " +
                    reduced_problem.truth_problem.name())
            # Assign to reduced_mesh_solution
            if reduced_problem in reduced_problem_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[0]
                    [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)
                    if t is None or is_solving:
                        online_backend.online_assign(solution_from,
                                                     reduced_problem._solution)
                    else:
                        online_backend.online_assign(
                            solution_from,
                            reduced_problem._solution_over_time.at(t))
                    solution_from = reduced_basis_functions[:solution_from_N] * solution_from
                    backend.assign(solution_to, solution_from)
            # Assign to reduced_mesh_solution_dot
            if reduced_problem in reduced_problem_to_reduced_mesh_solution_dot:
                for (reduced_mesh_solution_dot,
                     reduced_basis_functions) in zip(
                         reduced_problem_to_reduced_mesh_solution_dot[
                             reduced_problem],
                         reduced_problem_to_reduced_basis_functions[1]
                         [reduced_problem]):
                    solution_dot_to = reduced_mesh_solution_dot
                    solution_dot_from_N = OnlineSizeDict()
                    for c, v in reduced_problem._solution_dot.N.items():
                        if c in reduced_basis_functions._components_name:
                            solution_dot_from_N[c] = v
                    solution_dot_from = online_backend.OnlineFunction(
                        solution_dot_from_N)
                    assert t is not None
                    if is_solving:
                        online_backend.online_assign(
                            solution_dot_from, reduced_problem._solution_dot)
                    else:
                        online_backend.online_assign(
                            solution_dot_from,
                            reduced_problem._solution_dot_over_time.at(t))
                    solution_dot_from = reduced_basis_functions[:
                                                                solution_dot_from_N] * solution_dot_from
                    backend.assign(solution_dot_to, solution_dot_from)

        # Assemble and return
        assembled_replaced_form = wrapping.assemble(
            replaced_form_with_replaced_measures)
        if not isinstance(assembled_replaced_form, Number):
            form_rank = assembled_replaced_form.rank()
        else:
            form_rank = 0
        return (assembled_replaced_form, form_rank)
Esempio n. 20
0
 def _online_size_from_kwargs(self, N, **kwargs):
     return OnlineSizeDict.generate_from_N_and_kwargs(
         self.components, self.N, N, **kwargs)
def N_generator():
    N = min(reduced_stokes_problem.N.values())
    n = OnlineSizeDict()
    for n_int in range(2, N + 1, 2):
        n["u"] = n["s"] = n["p"] = n_int
        yield {n_int: n}
Esempio n. 22
0
 def _basic_expression_on_reduced_mesh(expression_wrapper, at):
     expression = expression_wrapper._expression
     expression_name = expression_wrapper.name()
     expression_problem = get_problem_from_parametrized_expression(expression_wrapper)
     reduced_space = at.get_reduced_function_space()
     reduced_mesh = at.get_reduced_mesh()
     mu = expression_problem.mu
     if hasattr(expression_problem, "set_time"):
         t = expression_problem.t
     else:
         t = None
     
     if (expression_name, reduced_mesh) not in expression_cache:
         visited = set()
         replacements = dict()
         truth_problems = list()
         truth_problem_to_components = { # outer dict index over time derivative
             0: dict(),
             1: dict()
         }
         truth_problem_to_exact_truth_problem = dict()
         truth_problem_to_reduced_mesh_solution = dict()
         truth_problem_to_reduced_mesh_solution_dot = dict()
         truth_problem_to_reduced_mesh_interpolator = { # outer dict index over time derivative
             0: dict(),
             1: dict()
         }
         reduced_problem_to_components = { # outer dict index over time derivative
             0: dict(),
             1: dict()
         }
         reduced_problem_to_reduced_mesh_solution = dict()
         reduced_problem_to_reduced_mesh_solution_dot = dict()
         reduced_problem_to_reduced_basis_functions = { # outer dict index over time derivative
             0: dict(),
             1: 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_type(node):
                 node_is_problem_solution = wrapping.is_problem_solution(node)
                 node_is_problem_solution_dot = wrapping.is_problem_solution_dot(node)
                 if node_is_problem_solution or node_is_problem_solution_dot:
                     if node_is_problem_solution:
                         (preprocessed_node, component, truth_solution) = wrapping.solution_identify_component(node)
                         truth_problem = get_problem_from_solution(truth_solution)
                         # Time derivative key for components and interpolator dicts
                         time_derivative = 0
                     elif node_is_problem_solution_dot:
                         (preprocessed_node, component, truth_solution_dot) = wrapping.solution_dot_identify_component(node)
                         truth_problem = get_problem_from_solution_dot(truth_solution_dot)
                         # Time derivative key for components and interpolator dicts
                         time_derivative = 1
                     # Store truth problem
                     if truth_problem not in truth_problems:
                         truth_problems.append(truth_problem)
                     # Store the component
                     if truth_problem not in truth_problem_to_components[time_derivative]:
                         truth_problem_to_components[time_derivative][truth_problem] = list()
                     if component not in truth_problem_to_components[time_derivative][truth_problem]:
                         truth_problem_to_components[time_derivative][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
                         assert preprocessed_node not in replacements # as it is related to a new truth solution component
                         replacements[preprocessed_node] = backend.Function(auxiliary_reduced_V)
                         if time_derivative is 0:
                             if truth_problem not in truth_problem_to_reduced_mesh_solution:
                                 truth_problem_to_reduced_mesh_solution[truth_problem] = list()
                             truth_problem_to_reduced_mesh_solution[truth_problem].append(replacements[preprocessed_node])
                         elif time_derivative is 1:
                             if truth_problem not in truth_problem_to_reduced_mesh_solution_dot:
                                 truth_problem_to_reduced_mesh_solution_dot[truth_problem] = list()
                             truth_problem_to_reduced_mesh_solution_dot[truth_problem].append(replacements[preprocessed_node])
                         # Get interpolator on reduced mesh
                         if truth_problem not in truth_problem_to_reduced_mesh_interpolator[time_derivative]:
                             truth_problem_to_reduced_mesh_interpolator[time_derivative][truth_problem] = list()
                         truth_problem_to_reduced_mesh_interpolator[time_derivative][truth_problem].append(at.get_auxiliary_function_interpolator(truth_problem, component))
                 else:
                     (preprocessed_node, component, auxiliary_problem) = wrapping.get_auxiliary_problem_for_non_parametrized_function(node)
                     if preprocessed_node not in replacements:
                         # 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)
             else:
                 visited.add(node)
         # ... and replace them
         replaced_expression = wrapping.expression_replace(expression, replacements)
         
         # Cache the resulting dicts
         expression_cache[(expression_name, reduced_mesh)] = replaced_expression
         truth_problems_cache[(expression_name, reduced_mesh)] = truth_problems
         truth_problem_to_components_cache[(expression_name, reduced_mesh)] = truth_problem_to_components
         truth_problem_to_exact_truth_problem_cache[(expression_name, reduced_mesh)] = truth_problem_to_exact_truth_problem
         truth_problem_to_reduced_mesh_solution_cache[(expression_name, reduced_mesh)] = truth_problem_to_reduced_mesh_solution
         truth_problem_to_reduced_mesh_solution_dot_cache[(expression_name, reduced_mesh)] = truth_problem_to_reduced_mesh_solution_dot
         truth_problem_to_reduced_mesh_interpolator_cache[(expression_name, reduced_mesh)] = truth_problem_to_reduced_mesh_interpolator
         reduced_problem_to_components_cache[(expression_name, reduced_mesh)] = reduced_problem_to_components
         reduced_problem_to_reduced_mesh_solution_cache[(expression_name, reduced_mesh)] = reduced_problem_to_reduced_mesh_solution
         reduced_problem_to_reduced_mesh_solution_dot_cache[(expression_name, reduced_mesh)] = reduced_problem_to_reduced_mesh_solution_dot
         reduced_problem_to_reduced_basis_functions_cache[(expression_name, reduced_mesh)] = reduced_problem_to_reduced_basis_functions
         
     # Extract from cache
     replaced_expression = expression_cache[(expression_name, reduced_mesh)]
     truth_problems = truth_problems_cache[(expression_name, reduced_mesh)]
     truth_problem_to_components = truth_problem_to_components_cache[(expression_name, reduced_mesh)]
     truth_problem_to_exact_truth_problem = truth_problem_to_exact_truth_problem_cache[(expression_name, reduced_mesh)]
     truth_problem_to_reduced_mesh_solution = truth_problem_to_reduced_mesh_solution_cache[(expression_name, reduced_mesh)]
     truth_problem_to_reduced_mesh_solution_dot = truth_problem_to_reduced_mesh_solution_dot_cache[(expression_name, reduced_mesh)]
     truth_problem_to_reduced_mesh_interpolator = truth_problem_to_reduced_mesh_interpolator_cache[(expression_name, reduced_mesh)]
     reduced_problem_to_components = reduced_problem_to_components_cache[(expression_name, reduced_mesh)]
     reduced_problem_to_reduced_mesh_solution = reduced_problem_to_reduced_mesh_solution_cache[(expression_name, reduced_mesh)]
     reduced_problem_to_reduced_mesh_solution_dot = reduced_problem_to_reduced_mesh_solution_dot_cache[(expression_name, reduced_mesh)]
     reduced_problem_to_reduced_basis_functions = 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 replacement for solution
                 if (
                     reduced_problem not in reduced_problem_to_reduced_mesh_solution
                         and
                     truth_problem in truth_problem_to_reduced_mesh_solution
                 ):
                     reduced_problem_to_reduced_mesh_solution[reduced_problem] = truth_problem_to_reduced_mesh_solution[truth_problem]
                     # Store the component
                     assert reduced_problem not in reduced_problem_to_components[0]
                     assert truth_problem in truth_problem_to_components[0]
                     reduced_problem_to_components[0][reduced_problem] = truth_problem_to_components[0][truth_problem]
                     # Get reduced problem basis functions on reduced mesh
                     assert reduced_problem not in reduced_problem_to_reduced_basis_functions[0]
                     reduced_problem_to_reduced_basis_functions[0][reduced_problem] = [at.get_auxiliary_basis_functions_matrix(truth_problem, component) for component in reduced_problem_to_components[0][reduced_problem]]
                 # Store the replacement for solution_dot
                 if (
                     reduced_problem not in reduced_problem_to_reduced_mesh_solution_dot
                         and
                     truth_problem in truth_problem_to_reduced_mesh_solution_dot
                 ):
                     reduced_problem_to_reduced_mesh_solution_dot[reduced_problem] = truth_problem_to_reduced_mesh_solution_dot[truth_problem]
                     # Store the component
                     assert reduced_problem not in reduced_problem_to_components[1]
                     assert truth_problem in truth_problem_to_components[1]
                     reduced_problem_to_components[1][reduced_problem] = truth_problem_to_components[1][truth_problem]
                     # Get reduced problem basis functions on reduced mesh
                     assert reduced_problem not in reduced_problem_to_reduced_basis_functions[1]
                     reduced_problem_to_reduced_basis_functions[1][reduced_problem] = [at.get_auxiliary_basis_functions_matrix(truth_problem, component) for component in reduced_problem_to_components[1][reduced_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 replacement for solution
                     if (
                         exact_truth_problem not in truth_problem_to_reduced_mesh_solution
                             and
                         truth_problem in truth_problem_to_reduced_mesh_solution
                     ):
                         truth_problem_to_reduced_mesh_solution[exact_truth_problem] = truth_problem_to_reduced_mesh_solution[truth_problem]
                         # Store the component
                         assert exact_truth_problem not in truth_problem_to_components[0]
                         assert truth_problem in truth_problem_to_components[0]
                         truth_problem_to_components[0][exact_truth_problem] = truth_problem_to_components[0][truth_problem]
                         # Get interpolator on reduced mesh
                         assert exact_truth_problem not in truth_problem_to_reduced_mesh_interpolator[0]
                         assert truth_problem in truth_problem_to_reduced_mesh_interpolator[0]
                         truth_problem_to_reduced_mesh_interpolator[0][exact_truth_problem] = truth_problem_to_reduced_mesh_interpolator[0][truth_problem]
                     # Store the replacement for solution_dot
                     if (
                         exact_truth_problem not in truth_problem_to_reduced_mesh_solution_dot
                             and
                         truth_problem in truth_problem_to_reduced_mesh_solution_dot
                     ):
                         truth_problem_to_reduced_mesh_solution_dot[exact_truth_problem] = truth_problem_to_reduced_mesh_solution_dot[truth_problem]
                         # Store the component
                         assert exact_truth_problem not in truth_problem_to_components[1]
                         assert truth_problem in truth_problem_to_components[1]
                         truth_problem_to_components[1][exact_truth_problem] = truth_problem_to_components[1][truth_problem]
                         # Get interpolator on reduced mesh
                         assert exact_truth_problem not in truth_problem_to_reduced_mesh_interpolator[1]
                         assert truth_problem in truth_problem_to_reduced_mesh_interpolator[1]
                         truth_problem_to_reduced_mesh_interpolator[1][exact_truth_problem] = truth_problem_to_reduced_mesh_interpolator[1][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
     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())
         # Assign to reduced_mesh_solution
         if truth_problem in truth_problem_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[0][truth_problem]):
                 solution_to = reduced_mesh_solution
                 if t is None:
                     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)
                 else:
                     if not reduced_problem_is_solving:
                         if not truth_problem_is_solving:
                             solution_from = reduced_mesh_interpolator(truth_problem._solution_over_time.at(t))
                         else:
                             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)
         # Assign to reduced_mesh_solution_dot
         if truth_problem in truth_problem_to_reduced_mesh_solution_dot:
             for (reduced_mesh_solution_dot, reduced_mesh_interpolator) in zip(truth_problem_to_reduced_mesh_solution_dot[truth_problem], truth_problem_to_reduced_mesh_interpolator[1][truth_problem]):
                 solution_dot_to = reduced_mesh_solution_dot
                 assert t is not None
                 if not reduced_problem_is_solving:
                     if not truth_problem_is_solving:
                         solution_dot_from = reduced_mesh_interpolator(truth_problem._solution_dot_over_time.at(t))
                     else:
                         solution_dot_from = reduced_mesh_interpolator(truth_problem._solution_dot)
                 else:
                     solution_dot_from = reduced_mesh_interpolator(reduced_problem.basis_functions[:reduced_problem._solution_dot.N]*reduced_problem._solution_dot)
                 backend.assign(solution_dot_to, solution_dot_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())
         # Assign to reduced_mesh_solution
         if reduced_problem in reduced_problem_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[0][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)
                 if t is None or is_solving:
                     online_backend.online_assign(solution_from, reduced_problem._solution)
                 else:
                     online_backend.online_assign(solution_from, reduced_problem._solution_over_time.at(t))
                 solution_from = reduced_basis_functions[:solution_from_N]*solution_from
                 backend.assign(solution_to, solution_from)
         # Assign to reduced_mesh_solution_dot
         if reduced_problem in reduced_problem_to_reduced_mesh_solution_dot:
             for (reduced_mesh_solution_dot, reduced_basis_functions) in zip(reduced_problem_to_reduced_mesh_solution_dot[reduced_problem], reduced_problem_to_reduced_basis_functions[1][reduced_problem]):
                 solution_dot_to = reduced_mesh_solution_dot
                 solution_dot_from_N = OnlineSizeDict()
                 for c, v in reduced_problem._solution_dot.N.items():
                     if c in reduced_basis_functions._components_name:
                         solution_dot_from_N[c] = v
                 solution_dot_from = online_backend.OnlineFunction(solution_dot_from_N)
                 assert t is not None
                 if is_solving:
                     online_backend.online_assign(solution_dot_from, reduced_problem._solution_dot)
                 else:
                     online_backend.online_assign(solution_dot_from, reduced_problem._solution_dot_over_time.at(t))
                 solution_dot_from = reduced_basis_functions[:solution_dot_from_N]*solution_dot_from
                 backend.assign(solution_dot_to, solution_dot_from)
     
     # Evaluate and return
     reduced_function = backend.Function(reduced_space)
     wrapping.evaluate_expression(expression, reduced_function, replaced_expression)
     return reduced_function
Esempio n. 23
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)