def with_(self, **kwargs): assert 'operators' in kwargs operators = kwargs.pop('operators') assert set(operators.keys()) == {'operator', 'rhs'} assert all(op.type_source == NumpyVectorArray for op in operators.itervalues()) assert all(op.type_range == NumpyVectorArray for op in operators.itervalues()) d = StationaryDiscretization(operator=operators['operator'], rhs=operators['rhs']) return d.with_(**kwargs)
def with_(self, **kwargs): assert 'operators' and 'functionals' in kwargs or kwargs.keys() == ['parameter_space'] assert 'vector_operators' not in kwargs or not kwargs['vector_operators'] if 'operators' in kwargs: operators = kwargs.pop('operators') functionals = kwargs.pop('functionals') assert set(operators.keys()) == {'operator'} assert set(functionals.keys()) == {'rhs'} operator = operators['operator'] rhs = functionals['rhs'] assert all(op.source.type == NumpyVectorArray or op.source.type == BlockVectorArray for op in (operator, rhs)) assert all(op.range.type == NumpyVectorArray or op.range.type == BlockVectorArray for op in (operator, rhs)) d = StationaryDiscretization(operator=operator, rhs=rhs) return d.with_(**kwargs) else: d = type(self)(self._impl) d.unlock() d.parameter_space = kwargs['parameter_space'] d.lock() return d
def discretize(grid_and_problem_data, polorder=1, solver_options=None): logger = getLogger('discretize_elliptic_swipdg.discretize') logger.info('discretizing ... ') over_integrate = 2 grid, boundary_info = grid_and_problem_data['grid'], grid_and_problem_data[ 'boundary_info'] _lambda, kappa, f = (grid_and_problem_data['lambda'], grid_and_problem_data['kappa'], grid_and_problem_data['f']) lambda_bar, lambda_bar = grid_and_problem_data[ 'lambda_bar'], grid_and_problem_data['lambda_bar'] mu_bar, mu_hat, parameter_range = ( grid_and_problem_data['mu_bar'], grid_and_problem_data['mu_hat'], grid_and_problem_data['parameter_range']) space = make_dg_space(grid) # prepare operators and functionals if isinstance(_lambda, dict): system_ops = [ make_elliptic_swipdg_matrix_operator(lambda_func, kappa, boundary_info, space, over_integrate) for lambda_func in _lambda['functions'] ] elliptic_ops = [ make_elliptic_matrix_operator(lambda_func, kappa, space, over_integrate) for lambda_func in _lambda['functions'] ] else: system_ops = [ make_elliptic_swipdg_matrix_operator(_lambda, kappa, boundary_info, space, over_integrate), ] elliptic_ops = [ make_elliptic_matrix_operator(_lambda, kappa, space, over_integrate), ] if isinstance(f, dict): rhs_functionals = [ make_l2_volume_vector_functional(f_func, space, over_integrate) for f_func in f['functions'] ] else: rhs_functionals = [ make_l2_volume_vector_functional(f, space, over_integrate), ] l2_matrix_with_system_pattern = system_ops[0].matrix().copy() l2_operator = make_l2_matrix_operator(l2_matrix_with_system_pattern, space) # assemble everything in one grid walk system_assembler = make_system_assembler(space) for op in system_ops: system_assembler.append(op) for op in elliptic_ops: system_assembler.append(op) for func in rhs_functionals: system_assembler.append(func) system_assembler.append(l2_operator) system_assembler.walk() # wrap everything if isinstance(_lambda, dict): op = LincombOperator([ DuneXTMatrixOperator(o.matrix(), dof_communicator=space.dof_communicator) for o in system_ops ], _lambda['coefficients']) elliptic_op = LincombOperator( [DuneXTMatrixOperator(o.matrix()) for o in elliptic_ops], _lambda['coefficients']) else: op = DuneXTMatrixOperator(system_ops[0].matrix()) elliptic_op = DuneXTMatrixOperator(elliptic_ops[0].matrix()) if isinstance(f, dict): rhs = LincombOperator([ VectorFunctional(op.range.make_array([func.vector()])) for func in rhs_functionals ], f['coefficients']) else: rhs = VectorFunctional( op.range.make_array([rhs_functionals[0].vector()])) operators = { 'l2': DuneXTMatrixOperator(l2_matrix_with_system_pattern), 'elliptic': elliptic_op, 'elliptic_mu_bar': DuneXTMatrixOperator(elliptic_op.assemble(mu=mu_bar).matrix) } d = StationaryDiscretization(op, rhs, operators=operators, visualizer=DuneGDTVisualizer(space)) d = d.with_(parameter_space=CubicParameterSpace( d.parameter_type, parameter_range[0], parameter_range[1])) return d, {'space': space}
def discretize_elliptic_cg(analytical_problem, diameter=None, domain_discretizer=None, grid=None, boundary_info=None): """Discretizes an |EllipticProblem| using finite elements. Parameters ---------- analytical_problem The |EllipticProblem| 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. 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, EllipticProblem) 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 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) assert isinstance(grid, (OnedGrid, TriaGrid, RectGrid)) if isinstance(grid, RectGrid): Operator = cg.DiffusionOperatorQ1 Functional = cg.L2ProductFunctionalQ1 else: Operator = cg.DiffusionOperatorP1 Functional = cg.L2ProductFunctionalP1 p = analytical_problem if p.diffusion_functionals is not None: L0 = Operator(grid, boundary_info, diffusion_constant=0, name='diffusion_boundary_part') Li = [ Operator(grid, boundary_info, diffusion_function=df, dirichlet_clear_diag=True, name='diffusion_{}'.format(i)) for i, df in enumerate(p.diffusion_functions) ] L = LincombOperator(operators=[L0] + Li, coefficients=[1.] + list(p.diffusion_functionals), name='diffusion') else: assert len(p.diffusion_functions) == 1 L = Operator(grid, boundary_info, diffusion_function=p.diffusion_functions[0], name='diffusion') F = Functional(grid, p.rhs, boundary_info, dirichlet_data=p.dirichlet_data, neumann_data=p.neumann_data) if isinstance(grid, (TriaGrid, RectGrid)): visualizer = PatchVisualizer(grid=grid, bounding_box=grid.domain, codim=2) else: visualizer = Matplotlib1DVisualizer(grid=grid, codim=1) empty_bi = EmptyBoundaryInfo(grid) l2_product = cg.L2ProductQ1(grid, empty_bi) if isinstance( grid, RectGrid) else cg.L2ProductP1(grid, empty_bi) h1_semi_product = Operator(grid, empty_bi) products = { 'h1': l2_product + h1_semi_product, 'h1_semi': h1_semi_product, 'l2': l2_product } parameter_space = p.parameter_space if hasattr(p, 'parameter_space') else None discretization = StationaryDiscretization(L, F, products=products, visualizer=visualizer, parameter_space=parameter_space, name='{}_CG'.format(p.name)) return discretization, {'grid': grid, 'boundary_info': boundary_info}
def discretize_elliptic_fv(analytical_problem, diameter=None, domain_discretizer=None, grid=None, boundary_info=None): """Discretizes an |EllipticProblem| using the finite volume method. Parameters ---------- analytical_problem The |EllipticProblem| 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. 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, EllipticProblem) 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 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 p.diffusion_functionals is not None: Li = [ fv.DiffusionOperator(grid, boundary_info, diffusion_function=df, name='diffusion_{}'.format(i)) for i, df in enumerate(p.diffusion_functions) ] L = LincombOperator(operators=Li, coefficients=list(p.diffusion_functionals), name='diffusion') F0 = fv.L2ProductFunctional(grid, p.rhs, boundary_info=boundary_info, neumann_data=p.neumann_data) if p.dirichlet_data is not None: Fi = [ fv.L2ProductFunctional(grid, None, boundary_info=boundary_info, dirichlet_data=p.dirichlet_data, diffusion_function=df, name='dirichlet_{}'.format(i)) for i, df in enumerate(p.diffusion_functions) ] F = LincombOperator(operators=[F0] + Fi, coefficients=[1.] + list(p.diffusion_functionals), name='rhs') else: F = F0 else: assert len(p.diffusion_functions) == 1 L = fv.DiffusionOperator(grid, boundary_info, diffusion_function=p.diffusion_functions[0], name='diffusion') F = fv.L2ProductFunctional(grid, p.rhs, boundary_info=boundary_info, dirichlet_data=p.dirichlet_data, diffusion_function=p.diffusion_functions[0], neumann_data=p.neumann_data) if isinstance(grid, (TriaGrid, RectGrid)): visualizer = PatchVisualizer(grid=grid, bounding_box=grid.domain, codim=0) elif isinstance(grid, (OnedGrid)): visualizer = Matplotlib1DVisualizer(grid=grid, codim=0) else: visualizer = None l2_product = fv.L2Product(grid) products = {'l2': l2_product} parameter_space = p.parameter_space if hasattr(p, 'parameter_space') else None discretization = StationaryDiscretization(L, F, products=products, visualizer=visualizer, parameter_space=parameter_space, name='{}_FV'.format(p.name)) return discretization, {'grid': grid, 'boundary_info': boundary_info}
def discretize_stationary_cg(analytical_problem, diameter=None, domain_discretizer=None, grid_type=None, grid=None, boundary_info=None, preassemble=True): """Discretizes an |StationaryProblem| using finite elements. Parameters ---------- analytical_problem The |StationaryProblem| to discretize. diameter If not `None`, `diameter` is passed as an argument 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 `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|. 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. preassemble If `True`, preassemble all operators in the resulting |Discretization|. Returns ------- d 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, 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 grid_type is None or grid is None p = analytical_problem if not (p.nonlinear_advection == p.nonlinear_advection_derivative == p.nonlinear_reaction == p.nonlinear_reaction_derivative == None): raise NotImplementedError if grid is None: domain_discretizer = domain_discretizer or discretize_domain_default if grid_type: domain_discretizer = partial(domain_discretizer, grid_type=grid_type) if diameter is None: grid, boundary_info = domain_discretizer(p.domain) else: grid, boundary_info = domain_discretizer(p.domain, diameter=diameter) assert grid.reference_element in (line, triangle, square) if grid.reference_element is square: DiffusionOperator = DiffusionOperatorQ1 AdvectionOperator = AdvectionOperatorQ1 ReactionOperator = L2ProductQ1 Functional = L2ProductFunctionalQ1 else: DiffusionOperator = DiffusionOperatorP1 AdvectionOperator = AdvectionOperatorP1 ReactionOperator = L2ProductP1 Functional = L2ProductFunctionalP1 Li = [ DiffusionOperator(grid, boundary_info, diffusion_constant=0, name='boundary_part') ] coefficients = [1.] # diffusion part if isinstance(p.diffusion, LincombFunction): Li += [ DiffusionOperator(grid, boundary_info, diffusion_function=df, dirichlet_clear_diag=True, name='diffusion_{}'.format(i)) for i, df in enumerate(p.diffusion.functions) ] coefficients += list(p.diffusion.coefficients) elif p.diffusion is not None: Li += [ DiffusionOperator(grid, boundary_info, diffusion_function=p.diffusion, dirichlet_clear_diag=True, name='diffusion') ] coefficients.append(1.) # advection part if isinstance(p.advection, LincombFunction): Li += [ AdvectionOperator(grid, boundary_info, advection_function=af, dirichlet_clear_diag=True, name='advection_{}'.format(i)) for i, af in enumerate(p.advection.functions) ] coefficients += list(p.advection.coefficients) elif p.advection is not None: Li += [ AdvectionOperator(grid, boundary_info, advection_function=p.advection, dirichlet_clear_diag=True, name='advection') ] coefficients.append(1.) # reaction part if isinstance(p.reaction, LincombFunction): Li += [ ReactionOperator(grid, boundary_info, coefficient_function=rf, dirichlet_clear_diag=True, name='reaction_{}'.format(i)) for i, rf in enumerate(p.reaction.functions) ] coefficients += list(p.reaction.coefficients) elif p.reaction is not None: Li += [ ReactionOperator(grid, boundary_info, coefficient_function=p.reaction, dirichlet_clear_diag=True, name='reaction') ] coefficients.append(1.) # robin boundaries if p.robin_data is not None: if grid.reference_element is square: raise NotImplementedError Li += [ RobinBoundaryOperator(grid, boundary_info, robin_data=p.robin_data, order=2, name='robin') ] coefficients.append(1.) L = LincombOperator(operators=Li, coefficients=coefficients, name='ellipticOperator') rhs = p.rhs or ConstantFunction(0., dim_domain=p.domain.dim) F = Functional(grid, rhs, boundary_info, dirichlet_data=p.dirichlet_data, neumann_data=p.neumann_data) if grid.reference_element in (triangle, square): visualizer = PatchVisualizer(grid=grid, bounding_box=grid.bounding_box(), codim=2) elif grid.reference_element is line: visualizer = OnedVisualizer(grid=grid, codim=1) else: visualizer = None Prod = L2ProductQ1 if grid.reference_element is square else L2ProductP1 empty_bi = EmptyBoundaryInfo(grid) l2_product = Prod(grid, empty_bi, name='l2') l2_0_product = Prod(grid, boundary_info, dirichlet_clear_columns=True, name='l2_0') h1_semi_product = DiffusionOperator(grid, empty_bi, name='h1_semi') h1_0_semi_product = DiffusionOperator(grid, boundary_info, dirichlet_clear_columns=True, name='h1_0_semi') products = { 'h1': l2_product + h1_semi_product, 'h1_semi': h1_semi_product, 'l2': l2_product, 'h1_0': l2_0_product + h1_0_semi_product, 'h1_0_semi': h1_0_semi_product, 'l2_0': l2_0_product } parameter_space = p.parameter_space if hasattr(p, 'parameter_space') else None d = StationaryDiscretization(L, F, products=products, visualizer=visualizer, parameter_space=parameter_space, name='{}_CG'.format(p.name)) data = {'grid': grid, 'boundary_info': boundary_info} if preassemble: data['unassembled_d'] = d d = preassemble_(d) return d, data
def _discretize_fenics(xblocks, yblocks, grid_num_intervals, element_order): # assemble system matrices - FEniCS code ######################################## import dolfin as df mesh = df.UnitSquareMesh(grid_num_intervals, grid_num_intervals, 'crossed') V = df.FunctionSpace(mesh, 'Lagrange', element_order) u = df.TrialFunction(V) v = df.TestFunction(V) diffusion = df.Expression( '(lower0 <= x[0]) * (open0 ? (x[0] < upper0) : (x[0] <= upper0)) *' + '(lower1 <= x[1]) * (open1 ? (x[1] < upper1) : (x[1] <= upper1))', lower0=0., upper0=0., open0=0, lower1=0., upper1=0., open1=0, element=df.FunctionSpace(mesh, 'DG', 0).ufl_element()) def assemble_matrix(x, y, nx, ny): diffusion.user_parameters['lower0'] = x / nx diffusion.user_parameters['lower1'] = y / ny diffusion.user_parameters['upper0'] = (x + 1) / nx diffusion.user_parameters['upper1'] = (y + 1) / ny diffusion.user_parameters['open0'] = (x + 1 == nx) diffusion.user_parameters['open1'] = (y + 1 == ny) return df.assemble( df.inner(diffusion * df.nabla_grad(u), df.nabla_grad(v)) * df.dx) mats = [ assemble_matrix(x, y, xblocks, yblocks) for x in range(xblocks) for y in range(yblocks) ] mat0 = mats[0].copy() mat0.zero() h1_mat = df.assemble(df.inner(df.nabla_grad(u), df.nabla_grad(v)) * df.dx) l2_mat = df.assemble(u * v * df.dx) f = df.Constant(1.) * v * df.dx F = df.assemble(f) bc = df.DirichletBC(V, 0., df.DomainBoundary()) for m in mats: bc.zero(m) bc.apply(mat0) bc.apply(h1_mat) bc.apply(F) # wrap everything as a pyMOR discretization ########################################### # FEniCS wrappers from pymor.gui.fenics import FenicsVisualizer from pymor.operators.fenics import FenicsMatrixOperator from pymor.vectorarrays.fenics import FenicsVector # generic pyMOR classes from pymor.discretizations.basic import StationaryDiscretization from pymor.operators.constructions import LincombOperator, VectorFunctional from pymor.parameters.functionals import ProjectionParameterFunctional from pymor.parameters.spaces import CubicParameterSpace from pymor.vectorarrays.list import ListVectorArray # define parameter functionals (same as in pymor.analyticalproblems.thermalblock) def parameter_functional_factory(x, y): return ProjectionParameterFunctional( component_name='diffusion', component_shape=(yblocks, xblocks), coordinates=(yblocks - y - 1, x), name='diffusion_{}_{}'.format(x, y)) parameter_functionals = tuple( parameter_functional_factory(x, y) for x in range(xblocks) for y in range(yblocks)) # wrap operators ops = [FenicsMatrixOperator(mat0, V, V) ] + [FenicsMatrixOperator(m, V, V) for m in mats] op = LincombOperator(ops, (1., ) + parameter_functionals) rhs = VectorFunctional(ListVectorArray([FenicsVector(F, V)])) h1_product = FenicsMatrixOperator(h1_mat, V, V, name='h1_0_semi') l2_product = FenicsMatrixOperator(l2_mat, V, V, name='l2') # build discretization visualizer = FenicsVisualizer(V) parameter_space = CubicParameterSpace(op.parameter_type, 0.1, 1.) d = StationaryDiscretization(op, rhs, products={ 'h1_0_semi': h1_product, 'l2': l2_product }, parameter_space=parameter_space, visualizer=visualizer) return d
def discretize_stationary_from_disk(parameter_file): """Generates stationary discretization only based on data loaded from files. The path and further specifications to these objects are given in an '.ini' parameter file (see example below). Suitable for discrete problems given by:: L(u, w) = F(w) with an operator L and a linear functional F with a parameter w given as system matrices and rhs vectors in an affine decomposition on the hard disk. Parameters ---------- parameterFile String containing the path to the .ini parameter file. Returns ------- discretization The |Discretization| that has been generated. Example ------- Following parameter file is suitable for a discrete elliptic problem with L(u, w) = (f_1(w)*K1 + f_2(w)*K2+...)*u and F(w) = g_1(w)*L1+g_2(w)*L2+... with parameter w_i in [a_i,b_i], where f_i(w) and g_i(w) are strings of valid python expressions. Optional products can be provided to introduce a dict of inner products on the discrete space. The content of the file is then given as:: [system-matrices] # path_to_object: parameter_functional_associated_with_object K1.mat: f_1(w_1,...,w_n) K2.mat: f_2(w_1,...,w_n) ... [rhs-vectors] L1.mat: g_1(w_1,...,w_n) L2.mat: g_2(w_1,...,w_n) ... [parameter] # Name: lower_bound,upper_bound w_1: a_1,b_1 ... w_n: a_n,b_n [products] # Name: path_to_object Prod1: S.mat Prod2: T.mat ... """ assert ".ini" == parameter_file[-4:], "Given file is not an .ini file" base_path = os.path.dirname(parameter_file) # Get input from parameter file config = configparser.ConfigParser() config.optionxform = str config.read(parameter_file) # Assert that all needed entries given assert 'system-matrices' in config.sections() assert 'rhs-vectors' in config.sections() assert 'parameter' in config.sections() system_mat = config.items('system-matrices') rhs_vec = config.items('rhs-vectors') parameter = config.items('parameter') # Dict of parameters types and ranges parameter_type = {} parameter_range = {} # get parameters for i in range(len(parameter)): parameter_name = parameter[i][0] parameter_list = tuple(float(j) for j in parameter[i][1].replace(" ", "").split(',')) parameter_range[parameter_name] = parameter_list # Assume scalar parameter dependence parameter_type[parameter_name] = 0 # Create parameter space parameter_space = CubicParameterSpace(parameter_type=parameter_type, ranges=parameter_range) # Assemble operators system_operators, system_functionals = [], [] # get parameter functionals and system matrices for i in range(len(system_mat)): path = os.path.join(base_path, system_mat[i][0]) expr = system_mat[i][1] parameter_functional = ExpressionParameterFunctional(expr, parameter_type=parameter_type) system_operators.append(NumpyMatrixOperator.from_file(path)) system_functionals.append(parameter_functional) system_lincombOperator = LincombOperator(system_operators, coefficients=system_functionals) # get rhs vectors rhs_operators, rhs_functionals = [], [] for i in range(len(rhs_vec)): path = os.path.join(base_path, rhs_vec[i][0]) expr = rhs_vec[i][1] parameter_functional = ExpressionParameterFunctional(expr, parameter_type=parameter_type) op = NumpyMatrixOperator.from_file(path) assert isinstance(op._matrix, np.ndarray) op = op.with_(matrix=op._matrix.reshape((1, -1))) rhs_operators.append(op) rhs_functionals.append(parameter_functional) rhs_lincombOperator = LincombOperator(rhs_operators, coefficients=rhs_functionals) # get products if given if 'products' in config.sections(): product = config.items('products') products = {} for i in range(len(product)): product_name = product[i][0] product_path = os.path.join(base_path, product[i][1]) products[product_name] = NumpyMatrixOperator.from_file(product_path) else: products = None # Create and return stationary discretization return StationaryDiscretization(operator=system_lincombOperator, rhs=rhs_lincombOperator, parameter_space=parameter_space, products=products)
def with_(self, **kwargs): assert 'vector_operators' not in kwargs or not kwargs['vector_operators'] if 'operators' in kwargs and 'functionals' in kwargs: operators = kwargs.pop('operators') functionals = kwargs.pop('functionals') assert set(operators.keys()) == {'operator'} assert set(functionals.keys()) == {'rhs'} operator = operators['operator'] rhs = functionals['rhs'] d = StationaryDiscretization(operator=operator, rhs=rhs, parameter_space=self.parameter_space) return d.with_(**kwargs) elif 'cache_region' in kwargs: d = type(self)(self._impl) d.unlock() d.enable_caching(kwargs.pop('cache_region')) d.lock() return d.with_(**kwargs) else: d = type(self)(self._impl) d.unlock() for attr in ('solver_options', 'parameter_space'): if attr in dir(self): setattr(d, attr, getattr(self, attr)) if 'parameter_space' in kwargs: d.parameter_space = kwargs.pop('parameter_space') assert len(kwargs) == 0 d.lock() return d
def discretize_stationary_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, preassemble=True): """Discretizes an |StationaryProblem| using the finite volume method. Parameters ---------- analytical_problem The |StationaryProblem| to discretize. diameter If not `None`, `diameter` is passed as an argument 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 `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.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). 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. preassemble If `True`, preassemble all operators in the resulting |Discretization|. 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, 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 grid_type is None or grid is None p = analytical_problem if analytical_problem.robin_data is not None: raise NotImplementedError if grid is None: domain_discretizer = domain_discretizer or discretize_domain_default if grid_type: domain_discretizer = partial(domain_discretizer, grid_type=grid_type) if diameter is None: grid, boundary_info = domain_discretizer(analytical_problem.domain) else: grid, boundary_info = domain_discretizer(analytical_problem.domain, diameter=diameter) L, L_coefficients = [], [] F, F_coefficients = [], [] if p.rhs is not None or p.neumann_data is not None: F += [ L2ProductFunctional(grid, p.rhs, boundary_info=boundary_info, neumann_data=p.neumann_data) ] F_coefficients += [1.] # diffusion part if isinstance(p.diffusion, LincombFunction): L += [ DiffusionOperator(grid, boundary_info, diffusion_function=df, name='diffusion_{}'.format(i)) for i, df in enumerate(p.diffusion.functions) ] L_coefficients += p.diffusion.coefficients if p.dirichlet_data is not None: F += [ L2ProductFunctional(grid, None, boundary_info=boundary_info, dirichlet_data=p.dirichlet_data, diffusion_function=df, name='dirichlet_{}'.format(i)) for i, df in enumerate(p.diffusion.functions) ] F_coefficients += p.diffusion.coefficients elif p.diffusion is not None: L += [ DiffusionOperator(grid, boundary_info, diffusion_function=p.diffusion, name='diffusion') ] L_coefficients += [1.] if p.dirichlet_data is not None: F += [ L2ProductFunctional(grid, None, boundary_info=boundary_info, dirichlet_data=p.dirichlet_data, diffusion_function=p.diffusion, name='dirichlet') ] F_coefficients += [1.] # advection part if isinstance(p.advection, LincombFunction): L += [ LinearAdvectionLaxFriedrichs(grid, boundary_info, af, name='advection_{}'.format(i)) for i, af in enumerate(p.advection.functions) ] L_coefficients += list(p.advection.coefficients) elif p.advection is not None: L += [ LinearAdvectionLaxFriedrichs(grid, boundary_info, p.advection, name='advection') ] L_coefficients.append(1.) # nonlinear advection part if p.nonlinear_advection is not None: if num_flux == 'lax_friedrichs': L += [ nonlinear_advection_lax_friedrichs_operator( grid, boundary_info, p.nonlinear_advection, dirichlet_data=p.dirichlet_data, lxf_lambda=lxf_lambda) ] elif num_flux == 'upwind': L += [ nonlinear_advection_upwind_operator( grid, boundary_info, p.nonlinear_advection, p.nonlinear_advection_derivative, dirichlet_data=p.dirichlet_data) ] elif num_flux == 'engquist_osher': L += [ nonlinear_advection_engquist_osher_operator( grid, boundary_info, p.nonlinear_advection, p.nonlinear_advection_derivative, gausspoints=eo_gausspoints, intervals=eo_intervals, dirichlet_data=p.dirichlet_data) ] elif num_flux == 'simplified_engquist_osher': L += [ nonlinear_advection_simplified_engquist_osher_operator( grid, boundary_info, p.nonlinear_advection, p.nonlinear_advection_derivative, dirichlet_data=p.dirichlet_data) ] else: raise NotImplementedError L_coefficients.append(1.) # reaction part if isinstance(p.reaction, LincombFunction): raise NotImplementedError elif p.reaction is not None: L += [ReactionOperator(grid, p.reaction, name='reaction')] L_coefficients += [1.] # nonlinear reaction part if p.nonlinear_reaction is not None: L += [ NonlinearReactionOperator(grid, p.nonlinear_reaction, p.nonlinear_reaction_derivative) ] L_coefficients += [1.] # system operator if len(L_coefficients) == 1 and L_coefficients[0] == 1.: L = L[0] else: L = LincombOperator(operators=L, coefficients=L_coefficients, name='elliptic_operator') # rhs if len(F_coefficients) == 0: F = ZeroOperator(L.range, NumpyVectorSpace(1)) elif len(F_coefficients) == 1 and F_coefficients[0] == 1.: F = F[0] else: F = LincombOperator(operators=F, coefficients=F_coefficients, name='rhs') if grid.reference_element in (triangle, square): visualizer = PatchVisualizer(grid=grid, bounding_box=grid.bounding_box(), codim=0) elif grid.reference_element is line: visualizer = OnedVisualizer(grid=grid, codim=0) else: visualizer = None l2_product = L2Product(grid, name='l2') products = {'l2': l2_product} parameter_space = p.parameter_space if hasattr(p, 'parameter_space') else None discretization = StationaryDiscretization(L, F, products=products, visualizer=visualizer, parameter_space=parameter_space, name='{}_FV'.format(p.name)) data = {'grid': grid, 'boundary_info': boundary_info} if preassemble: data['unassembled_discretization'] = discretization discretization = preassemble_(discretization) return discretization, data
def discretize_stationary_from_disk(parameter_file): """Load a linear affinely decomposed |StationaryDiscretization| from file. The discretization is defined via an `.ini`-style file as follows :: [system-matrices] L_1.mat: l_1(μ_1,...,μ_n) L_2.mat: l_2(μ_1,...,μ_n) ... [rhs-vectors] F_1.mat: f_1(μ_1,...,μ_n) F_2.mat: f_2(μ_1,...,μ_n) ... [parameter] μ_1: a_1,b_1 ... μ_n: a_n,b_n [products] Prod1: P_1.mat Prod2: P_2.mat ... Here, `L_1.mat`, `L_2.mat`, ..., `F_1.mat`, `F_2.mat`, ... are files containing matrices `L_1`, `L_2`, ... and vectors `F_1.mat`, `F_2.mat`, ... which correspond to the affine components of the operator and right-hand side functional. The respective coefficient functionals, are given via the string expressions `l_1(...)`, `l_2(...)`, ..., `f_1(...)` in the (scalar-valued) |Parameter| components `w_1`, ..., `w_n`. The allowed lower and upper bounds `a_i, b_i` for the component `μ_i` are specified in the `[parameters]` section. The resulting operator and right-hand side are then of the form :: L(μ) = l_1(μ)*L_1 + l_2(μ)*L_2+ ... F(μ) = f_1(μ)*F_1 + f_2(μ)*L_2+ ... In the `[products]` section, an optional list of inner products `Prod1`, `Prod2`, .. with corresponding matrices `P_1.mat`, `P_2.mat` can be specified. Example:: [system-matrices] matrix1.mat: 1. matrix2.mat: 1. - theta**2 [rhs-vectors] rhs.mat: 1. [parameter] theta: 0, 0.5 [products] h1: h1.mat l2: mass.mat Parameters ---------- parameter_file Path to the parameter file. Returns ------- discretization The |StationaryDiscretization| that has been generated. """ assert ".ini" == parameter_file[ -4:], 'Given file is not an .ini file: {}'.format(parameter_file) assert os.path.isfile(parameter_file) base_path = os.path.dirname(parameter_file) # Get input from parameter file config = configparser.ConfigParser() config.optionxform = str config.read(parameter_file) # Assert that all needed entries given assert 'system-matrices' in config.sections() assert 'rhs-vectors' in config.sections() assert 'parameter' in config.sections() system_mat = config.items('system-matrices') rhs_vec = config.items('rhs-vectors') parameter = config.items('parameter') # Dict of parameters types and ranges parameter_type = {} parameter_range = {} # get parameters for i in range(len(parameter)): parameter_name = parameter[i][0] parameter_list = tuple( float(j) for j in parameter[i][1].replace(" ", "").split(',')) parameter_range[parameter_name] = parameter_list # Assume scalar parameter dependence parameter_type[parameter_name] = 0 # Create parameter space parameter_space = CubicParameterSpace(parameter_type=parameter_type, ranges=parameter_range) # Assemble operators system_operators, system_functionals = [], [] # get parameter functionals and system matrices for i in range(len(system_mat)): path = os.path.join(base_path, system_mat[i][0]) expr = system_mat[i][1] parameter_functional = ExpressionParameterFunctional( expr, parameter_type=parameter_type) system_operators.append( NumpyMatrixOperator.from_file(path, source_id='STATE', range_id='STATE')) system_functionals.append(parameter_functional) system_lincombOperator = LincombOperator(system_operators, coefficients=system_functionals) # get rhs vectors rhs_operators, rhs_functionals = [], [] for i in range(len(rhs_vec)): path = os.path.join(base_path, rhs_vec[i][0]) expr = rhs_vec[i][1] parameter_functional = ExpressionParameterFunctional( expr, parameter_type=parameter_type) op = NumpyMatrixOperator.from_file(path, source_id='STATE') assert isinstance(op._matrix, np.ndarray) op = op.with_(matrix=op._matrix.reshape((1, -1))) rhs_operators.append(op) rhs_functionals.append(parameter_functional) rhs_lincombOperator = LincombOperator(rhs_operators, coefficients=rhs_functionals) # get products if given if 'products' in config.sections(): product = config.items('products') products = {} for i in range(len(product)): product_name = product[i][0] product_path = os.path.join(base_path, product[i][1]) products[product_name] = NumpyMatrixOperator.from_file( product_path, source_id='STATE', range_id='STATE') else: products = None # Create and return stationary discretization return StationaryDiscretization(operator=system_lincombOperator, rhs=rhs_lincombOperator, parameter_space=parameter_space, products=products)
param = {"lambda": [1.], "mu": [1.]} # u = cpp_disc.solve(param) parameter_type = Parameter(param).parameter_type # cpp_disc.visualize(u, "highdim_solution_cpp.vtk") lambda_fn, mu_fn = [GenericParameterFunctional(lambda mu: mu[n], Parameter({n: [1.]}).parameter_type) for n in ['lambda', 'mu']] LOW, HIGH = 1, 10 ops = [DealIIMatrixOperator(getattr(cpp_disc, name)()) for name in ['lambda_mat', 'mu_mat']] op = LincombOperator(ops, (lambda_fn, mu_fn)) rhs = VectorFunctional(ListVectorArray([DealIIVector(cpp_disc.rhs())])) viz = PyVis(cpp_disc) h1_op = DealIIMatrixOperator(cpp_disc.h1_mat(), "h1_0_semi") energy_op = DealIIMatrixOperator(cpp_disc.mu_mat(), "energy") py_disc = StationaryDiscretization(op, rhs, products={"energy": energy_op}, visualizer=viz, parameter_space=CubicParameterSpace(parameter_type, LOW, HIGH)) coercivity_estimator = ExpressionParameterFunctional("max(mu)", parameter_type) reductor = partial(reduce_stationary_coercive, error_product=energy_op, coercivity_estimator=coercivity_estimator) greedy_data = greedy(py_disc, reductor, py_disc.parameter_space.sample_uniformly(3), use_estimator=True, extension_algorithm=gram_schmidt_basis_extension, max_extensions=3) rb_disc, reconstructor = greedy_data['reduced_discretization'], greedy_data['reconstructor'] half = (HIGH - LOW) / 2. values = itertools.product((LOW, HIGH, half), (LOW, HIGH, half)) for new_param in ({"lambda": [a], "mu": [b]} for a, b in values): for disc, s in [(cpp_disc, 'cpp'), (py_disc, 'py'), (rb_disc, 'rb')]:
def discretize_elliptic_cg(analytical_problem, diameter=None, domain_discretizer=None, grid=None, boundary_info=None): """Discretizes an |EllipticProblem| using finite elements. Parameters ---------- analytical_problem The |EllipticProblem| 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. 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, EllipticProblem) 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 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) assert grid.reference_element in (line, triangle, square) if grid.reference_element is square: DiffusionOperator = cg.DiffusionOperatorQ1 AdvectionOperator = cg.AdvectionOperatorQ1 ReactionOperator = cg.L2ProductQ1 Functional = cg.L2ProductFunctionalQ1 else: DiffusionOperator = cg.DiffusionOperatorP1 AdvectionOperator = cg.AdvectionOperatorP1 ReactionOperator = cg.L2ProductP1 Functional = cg.L2ProductFunctionalP1 p = analytical_problem if p.diffusion_functionals is not None or p.advection_functionals is not None or p.reaction_functionals is not None: # parametric case Li = [ DiffusionOperator(grid, boundary_info, diffusion_constant=0, name='boundary_part') ] coefficients = [1.] # diffusion part if p.diffusion_functionals is not None: Li += [ DiffusionOperator(grid, boundary_info, diffusion_function=df, dirichlet_clear_diag=True, name='diffusion_{}'.format(i)) for i, df in enumerate(p.diffusion_functions) ] coefficients += list(p.diffusion_functionals) elif p.diffusion_functions is not None: assert len(p.diffusion_functions) == 1 Li += [ DiffusionOperator(grid, boundary_info, diffusion_function=p.diffusion_functions[0], dirichlet_clear_diag=True, name='diffusion') ] coefficients.append(1.) # advection part if p.advection_functionals is not None: Li += [ AdvectionOperator(grid, boundary_info, advection_function=af, dirichlet_clear_diag=True, name='advection_{}'.format(i)) for i, af in enumerate(p.advection_functions) ] coefficients += list(p.advection_functionals) elif p.advection_functions is not None: assert len(p.advection_functions) == 1 Li += [ AdvectionOperator(grid, boundary_info, advection_function=p.advection_functions[0], dirichlet_clear_diag=True, name='advection') ] coefficients.append(1.) # reaction part if p.reaction_functionals is not None: Li += [ ReactionOperator(grid, boundary_info, coefficient_function=rf, dirichlet_clear_diag=True, name='reaction_{}'.format(i)) for i, rf in enumerate(p.reaction_functions) ] coefficients += list(p.reaction_functionals) elif p.reaction_functions is not None: assert len(p.reaction_functions) == 1 Li += [ ReactionOperator(grid, boundary_info, coefficient_function=p.reaction_functions[0], dirichlet_clear_diag=True, name='reaction') ] coefficients.append(1.) # robin boundaries if p.robin_data is not None: Li += [ cg.RobinBoundaryOperator(grid, boundary_info, robin_data=p.robin_data, order=2, name='robin') ] coefficients.append(1.) L = LincombOperator(operators=Li, coefficients=coefficients, name='ellipticOperator') else: # unparametric case, not operator for boundary treatment Li = [] # only one operator has diagonal values, all subsequent operators have clear_diag dirichlet_clear_diag = False # diffusion part if p.diffusion_functions is not None: assert len(p.diffusion_functions) == 1 Li += [ DiffusionOperator(grid, boundary_info, diffusion_function=p.diffusion_functions[0], dirichlet_clear_diag=dirichlet_clear_diag, name='diffusion') ] dirichlet_clear_diag = True # advection part if p.advection_functions is not None: assert len(p.advection_functions) == 1 Li += [ AdvectionOperator(grid, boundary_info, advection_function=p.advection_functions[0], dirichlet_clear_diag=dirichlet_clear_diag, name='advection') ] dirichlet_clear_diag = True # reaction part if p.reaction_functions is not None: assert len(p.reaction_functions) == 1 Li += [ ReactionOperator(grid, boundary_info, coefficient_function=p.reaction_functions[0], dirichlet_clear_diag=dirichlet_clear_diag, name='reaction') ] dirichlet_clear_diag = True # robin boundaries if p.robin_data is not None: Li += [ cg.RobinBoundaryOperator(grid, boundary_info, robin_data=p.robin_data, order=2, name='robin') ] if len(Li) == 1: L = Li[0] else: L = LincombOperator(operators=Li, coefficients=[1.] * len(Li), name='ellipticOperator') F = Functional(grid, p.rhs, boundary_info, dirichlet_data=p.dirichlet_data, neumann_data=p.neumann_data) if grid.reference_element in (triangle, square): visualizer = PatchVisualizer(grid=grid, bounding_box=grid.bounding_box(), codim=2) elif grid.reference_element is line: visualizer = Matplotlib1DVisualizer(grid=grid, codim=1) else: visualizer = None Prod = cg.L2ProductQ1 if grid.reference_element is square else cg.L2ProductP1 empty_bi = EmptyBoundaryInfo(grid) l2_product = Prod(grid, empty_bi, name='l2') l2_0_product = Prod(grid, boundary_info, dirichlet_clear_columns=True, name='l2_0') h1_semi_product = DiffusionOperator(grid, empty_bi, name='h1_semi') h1_0_semi_product = DiffusionOperator(grid, boundary_info, dirichlet_clear_columns=True, name='h1_0_semi') products = { 'h1': l2_product + h1_semi_product, 'h1_semi': h1_semi_product, 'l2': l2_product, 'h1_0': l2_0_product + h1_0_semi_product, 'h1_0_semi': h1_0_semi_product, 'l2_0': l2_0_product } parameter_space = p.parameter_space if hasattr(p, 'parameter_space') else None discretization = StationaryDiscretization(L, F, products=products, visualizer=visualizer, parameter_space=parameter_space, name='{}_CG'.format(p.name)) return discretization, {'grid': grid, 'boundary_info': boundary_info}