def unpicklable_misc_operator_with_arrays_and_products_factory(n): if n == 0: from pymor.operators.numpy import NumpyGenericOperator op, _, U, V, sp, rp = numpy_matrix_operator_with_arrays_and_products_factory(100, 20, 4, 3, n) mat = op.matrix op2 = NumpyGenericOperator(mapping=lambda U: mat.dot(U.T).T, adjoint_mapping=lambda U: mat.T.dot(U.T).T, dim_source=100, dim_range=20, linear=True) return op2, _, U, V, sp, rp else: assert False
def create_robin_solop(localizer, bilifo, source_space, omega_star_space): # Robin-Loesungsoperator def solve(va): g = localizer.to_space(NumpyVectorSpace.make_array(va), source_space, omega_star_space) solution = bilifo.apply_inverse(g) return solution.data cavesize = len(localizer.join_spaces(source_space)) rangesize = len(localizer.join_spaces(omega_star_space)) return NumpyGenericOperator(solve, dim_source=cavesize, dim_range=rangesize, linear=True)
def create_dirichlet_solop(localizer, local_op, rhsop, source_space, training_space): # Dirichlet-Loesungsoperator def solve(va): solution = local_op.apply_inverse( -rhsop.apply(NumpyVectorSpace.make_array(va))) return solution.data cavesize = len(localizer.join_spaces(source_space)) rangesize = len(localizer.join_spaces(training_space)) return NumpyGenericOperator(solve, dim_source=cavesize, dim_range=rangesize, linear=True)
def create_dirichlet_transfer(localizer, local_op, rhsop, source_space, training_space, range_space, pou): # Dirichlet-Transferoperator def transfer(va): range_solution = localizer.to_space( local_op.apply_inverse( -rhsop.apply(NumpyVectorSpace.make_array(va))), training_space, range_space) return pou[range_space](range_solution).data cavesize = len(localizer.join_spaces(source_space)) rangesize = len(localizer.join_spaces(range_space)) return NumpyGenericOperator(transfer, dim_source=cavesize, dim_range=rangesize, linear=True)
def create_robin_transfer(localizer, bilifo, source_space, omega_star_space, range_space, pou): # Robin-Transferoperator def transfer(va): g = localizer.to_space(NumpyVectorSpace.make_array(va), source_space, omega_star_space) solution = bilifo.apply_inverse(g) range_solution = localizer.to_space(solution, omega_star_space, range_space) return pou[range_space](range_solution).data cavesize = len(localizer.join_spaces(source_space)) rangesize = len(localizer.join_spaces(range_space)) return NumpyGenericOperator(transfer, dim_source=cavesize, dim_range=rangesize, linear=True)
def discretize_instationary_fv(analytical_problem, diameter=None, domain_discretizer=None, grid_type=None, num_flux='lax_friedrichs', lxf_lambda=1., eo_gausspoints=5, eo_intervals=1, grid=None, boundary_info=None, num_values=None, time_stepper=None, nt=None, preassemble=True): """Discretizes an |InstationaryProblem| with a |StationaryProblem| as stationary part using the finite volume method. Parameters ---------- analytical_problem The |InstationaryProblem| to discretize. diameter If not `None`, `diameter` is passed to the `domain_discretizer`. domain_discretizer Discretizer to be used for discretizing the analytical domain. This has to be a function `domain_discretizer(domain_description, diameter, ...)`. If further arguments should be passed to the discretizer, use :func:`functools.partial`. If `None`, |discretize_domain_default| is used. grid_type If not `None`, this parameter is forwarded to `domain_discretizer` to specify the type of the generated |Grid|. num_flux The numerical flux to use in the finite volume formulation. Allowed values are `'lax_friedrichs'`, `'engquist_osher'`, `'simplified_engquist_osher'` (see :mod:`pymor.discretizers.builtin.fv`). lxf_lambda The stabilization parameter for the Lax-Friedrichs numerical flux (ignored, if different flux is chosen). eo_gausspoints Number of Gauss points for the Engquist-Osher numerical flux (ignored, if different flux is chosen). eo_intervals Number of sub-intervals to use for integration when using Engquist-Osher numerical flux (ignored, if different flux is chosen). grid Instead of using a domain discretizer, the |Grid| can also be passed directly using this parameter. boundary_info A |BoundaryInfo| specifying the boundary types of the grid boundary entities. Must be provided if `grid` is specified. num_values The number of returned vectors of the solution trajectory. If `None`, each intermediate vector that is calculated is returned. time_stepper The :class:`time-stepper <pymor.algorithms.timestepping.TimeStepper>` to be used by :class:`~pymor.models.basic.InstationaryModel.solve`. nt If `time_stepper` is not specified, the number of time steps for implicit Euler time stepping. preassemble If `True`, preassemble all operators in the resulting |Model|. Returns ------- m The |Model| that has been generated. data Dictionary with the following entries: :grid: The generated |Grid|. :boundary_info: The generated |BoundaryInfo|. :unassembled_m: In case `preassemble` is `True`, the generated |Model| before preassembling operators. """ assert isinstance(analytical_problem, InstationaryProblem) assert isinstance(analytical_problem.stationary_part, StationaryProblem) assert grid is None or boundary_info is not None assert boundary_info is None or grid is not None assert grid is None or domain_discretizer is None assert (time_stepper is None) != (nt is None) p = analytical_problem m, data = discretize_stationary_fv(p.stationary_part, diameter=diameter, domain_discretizer=domain_discretizer, grid_type=grid_type, num_flux=num_flux, lxf_lambda=lxf_lambda, eo_gausspoints=eo_gausspoints, eo_intervals=eo_intervals, grid=grid, boundary_info=boundary_info) grid = data['grid'] if p.initial_data.parametric: def initial_projection(U, mu): I = p.initial_data.evaluate(grid.quadrature_points(0, order=2), mu).squeeze() I = np.sum(I * grid.reference_element.quadrature(order=2)[1], axis=1) * (1. / grid.reference_element.volume) I = m.solution_space.make_array(I) return I.lincomb(U).to_numpy() I = NumpyGenericOperator(initial_projection, dim_range=grid.size(0), linear=True, range_id=m.solution_space.id, parameter_type=p.initial_data.parameter_type) else: I = p.initial_data.evaluate(grid.quadrature_points(0, order=2)).squeeze() I = np.sum(I * grid.reference_element.quadrature(order=2)[1], axis=1) * (1. / grid.reference_element.volume) I = m.solution_space.make_array(I) if time_stepper is None: if p.stationary_part.diffusion is None: time_stepper = ExplicitEulerTimeStepper(nt=nt) else: time_stepper = ImplicitEulerTimeStepper(nt=nt) rhs = None if isinstance(m.rhs, ZeroOperator) else m.rhs m = InstationaryModel(operator=m.operator, rhs=rhs, mass=None, initial_data=I, T=p.T, products=m.products, time_stepper=time_stepper, parameter_space=p.parameter_space, visualizer=m.visualizer, num_values=num_values, name=f'{p.name}_FV') if preassemble: data['unassembled_m'] = m m = preassemble_(m) return m, data
def discretize_nonlinear_instationary_advection_fv(analytical_problem, diameter=None, nt=100, num_flux='lax_friedrichs', lxf_lambda=1., eo_gausspoints=5, eo_intervals=1, num_values=None, domain_discretizer=None, grid=None, boundary_info=None): """Discretizes an |InstationaryAdvectionProblem| using the finite volume method. Simple explicit Euler time-stepping is used for time-discretization. Parameters ---------- analytical_problem The |InstationaryAdvectionProblem| to discretize. diameter If not `None`, `diameter` is passed to the `domain_discretizer`. nt The number of time-steps. num_flux The numerical flux to use in the finite volume formulation. Allowed values are `'lax_friedrichs'`, `'engquist_osher'`, `'simplified_engquist_osher'`. (See :mod:`pymor.operators.fv`.) lxf_lambda The stabilization parameter for the Lax-Friedrichs numerical flux. (Ignored, if different flux is chosen.) eo_gausspoints Number of Gauss points for the Engquist-Osher numerical flux. (Ignored, if different flux is chosen.) eo_intervals Number of sub-intervals to use for integration when using Engquist-Osher numerical flux. (Ignored, if different flux is chosen.) num_values The number of returned vectors of the solution trajectory. If `None`, each intermediate vector that is calculated is returned. domain_discretizer Discretizer to be used for discretizing the analytical domain. This has to be a function `domain_discretizer(domain_description, diameter, ...)`. If further arguments should be passed to the discretizer, use :func:`functools.partial`. If `None`, |discretize_domain_default| is used. grid Instead of using a domain discretizer, the |Grid| can also be passed directly using this parameter. boundary_info A |BoundaryInfo| specifying the boundary types of the grid boundary entities. Must be provided if `grid` is specified. Returns ------- discretization The |Discretization| that has been generated. data Dictionary with the following entries: :grid: The generated |Grid|. :boundary_info: The generated |BoundaryInfo|. """ assert isinstance(analytical_problem, InstationaryAdvectionProblem) assert grid is None or boundary_info is not None assert boundary_info is None or grid is not None assert grid is None or domain_discretizer is None assert num_flux in ('lax_friedrichs', 'engquist_osher', 'simplified_engquist_osher') if grid is None: domain_discretizer = domain_discretizer or discretize_domain_default if diameter is None: grid, boundary_info = domain_discretizer(analytical_problem.domain) else: grid, boundary_info = domain_discretizer(analytical_problem.domain, diameter=diameter) p = analytical_problem if num_flux == 'lax_friedrichs': L = nonlinear_advection_lax_friedrichs_operator( grid, boundary_info, p.flux_function, dirichlet_data=p.dirichlet_data, lxf_lambda=lxf_lambda) elif num_flux == 'engquist_osher': L = nonlinear_advection_engquist_osher_operator( grid, boundary_info, p.flux_function, p.flux_function_derivative, gausspoints=eo_gausspoints, intervals=eo_intervals, dirichlet_data=p.dirichlet_data) else: L = nonlinear_advection_simplified_engquist_osher_operator( grid, boundary_info, p.flux_function, p.flux_function_derivative, dirichlet_data=p.dirichlet_data) F = None if p.rhs is None else L2ProductFunctional(grid, p.rhs) if p.initial_data.parametric: def initial_projection(U, mu): I = p.initial_data.evaluate(grid.quadrature_points(0, order=2), mu).squeeze() I = np.sum(I * grid.reference_element.quadrature(order=2)[1], axis=1) * (1. / grid.reference_element.volume) I = NumpyVectorArray(I, copy=False) return I.lincomb(U).data inject_sid( initial_projection, __name__ + '.discretize_nonlinear_instationary_advection_fv.initial_data', p.initial_data, grid) I = NumpyGenericOperator(initial_projection, dim_range=grid.size(0), linear=True, parameter_type=p.initial_data.parameter_type) else: I = p.initial_data.evaluate(grid.quadrature_points(0, order=2)).squeeze() I = np.sum(I * grid.reference_element.quadrature(order=2)[1], axis=1) * (1. / grid.reference_element.volume) I = NumpyVectorArray(I, copy=False) inject_sid( I, __name__ + '.discretize_nonlinear_instationary_advection_fv.initial_data', p.initial_data, grid) products = {'l2': L2Product(grid, boundary_info)} if grid.dim == 2: visualizer = PatchVisualizer(grid=grid, bounding_box=grid.domain, codim=0) elif grid.dim == 1: visualizer = Matplotlib1DVisualizer(grid, codim=0) else: visualizer = None parameter_space = p.parameter_space if hasattr(p, 'parameter_space') else None time_stepper = ExplicitEulerTimeStepper(nt=nt) discretization = InstationaryDiscretization( operator=L, rhs=F, initial_data=I, T=p.T, products=products, time_stepper=time_stepper, parameter_space=parameter_space, visualizer=visualizer, num_values=num_values, name='{}_FV'.format(p.name)) return discretization, {'grid': grid, 'boundary_info': boundary_info}
def discretize_parabolic_fv(analytical_problem, diameter=None, domain_discretizer=None, grid=None, boundary_info=None, num_values=None, time_stepper=None, nt=None): """Discretizes an |ParabolicProblem| using the finite volume method. Parameters ---------- analytical_problem The |ParabolicProblem| to discretize. diameter If not `None`, `diameter` is passed to the `domain_discretizer`. domain_discretizer Discretizer to be used for discretizing the analytical domain. This has to be a function `domain_discretizer(domain_description, diameter, ...)`. If further arguments should be passed to the discretizer, use :func:`functools.partial`. If `None`, |discretize_domain_default| is used. grid Instead of using a domain discretizer, the |Grid| can also be passed directly using this parameter. boundary_info A |BoundaryInfo| specifying the boundary types of the grid boundary entities. Must be provided if `grid` is specified. num_values The number of returned vectors of the solution trajectory. If `None`, each intermediate vector that is calculated is returned. time_stepper The time-stepper to be used by :class:`~pymor.discretizations.basic.InstationaryDiscretization.solve`. Has to satisfy the :class:`~pymor.algorithms.timestepping.TimeStepperInterface`. nt The number of time-steps. If provided implicit euler time-stepping is used. Returns ------- discretization The |Discretization| that has been generated. data Dictionary with the following entries: :grid: The generated |Grid|. :boundary_info: The generated |BoundaryInfo|. """ assert isinstance(analytical_problem, ParabolicProblem) assert grid is None or boundary_info is not None assert boundary_info is None or grid is not None assert grid is None or domain_discretizer is None assert time_stepper is None or nt is None p = analytical_problem d, data = discretize_elliptic_fv(p.elliptic_part(), diameter=diameter, domain_discretizer=domain_discretizer, grid=grid, boundary_info=boundary_info) if p.initial_data.parametric: def initial_projection(U, mu): I = p.initial_data.evaluate(grid.quadrature_points(0, order=2), mu).squeeze() I = np.sum(I * grid.reference_element.quadrature(order=2)[1], axis=1) * (1. / grid.reference_element.volume) I = NumpyVectorArray(I, copy=False) return I.lincomb(U).data I = NumpyGenericOperator(initial_projection, dim_range=grid.size(0), linear=True, parameter_type=p.initial_data.parameter_type) else: I = p.initial_data.evaluate(grid.quadrature_points(0, order=2)).squeeze() I = np.sum(I * grid.reference_element.quadrature(order=2)[1], axis=1) * (1. / grid.reference_element.volume) I = NumpyVectorArray(I, copy=False) if time_stepper is None: time_stepper = ImplicitEulerTimeStepper(nt=nt) discretization = InstationaryDiscretization(operator=d.operator, rhs=d.rhs, mass=None, initial_data=I, T=p.T, products=d.products, time_stepper=time_stepper, parameter_space=d.parameter_space, visualizer=d.visualizer, num_values=num_values, name='{}_FV'.format(p.name)) return discretization, data