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 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
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)
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))
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
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]
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 __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__")
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
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
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
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")
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__()
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__()
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)
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}
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
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)