Esempio n. 1
0
def reconstruct_solution(gq, lq, bases, silent=True):
    # Berechne reduzierte Loesung anhand gegebener Basis
    if not silent:
        print("reconstructing solution")
    op = gq["op"]
    rhs = gq["rhs"]
    localizer = gq["localizer"]
    spaces = gq["spaces"]
    operator_reductor = LRBOperatorProjection(op, rhs, localizer, spaces, bases, spaces, bases)
    rop = operator_reductor.get_reduced_operator()
    rrhs = operator_reductor.get_reduced_rhs()
    rd = StationaryModel(rop, rrhs, cache_region=None)
    ru = operator_reductor.reconstruct_source(rd.solve())
    return ru
Esempio n. 2
0
def discretize(dim, n, order):
    # ### problem definition
    import dolfin as df

    if dim == 2:
        mesh = df.UnitSquareMesh(n, n)
    elif dim == 3:
        mesh = df.UnitCubeMesh(n, n, n)
    else:
        raise NotImplementedError

    V = df.FunctionSpace(mesh, "CG", order)

    g = df.Constant(1.0)
    c = df.Constant(1.)

    class DirichletBoundary(df.SubDomain):
        def inside(self, x, on_boundary):
            return abs(x[0] - 1.0) < df.DOLFIN_EPS and on_boundary

    db = DirichletBoundary()
    bc = df.DirichletBC(V, g, db)

    u = df.Function(V)
    v = df.TestFunction(V)
    f = df.Expression("x[0]*sin(x[1])", degree=2)
    F = df.inner(
        (1 + c * u**2) * df.grad(u), df.grad(v)) * df.dx - f * v * df.dx

    df.solve(F == 0,
             u,
             bc,
             solver_parameters={"newton_solver": {
                 "relative_tolerance": 1e-6
             }})

    # ### pyMOR wrapping
    from pymor.bindings.fenics import FenicsVectorSpace, FenicsOperator, FenicsVisualizer
    from pymor.models.basic import StationaryModel
    from pymor.operators.constructions import VectorOperator

    space = FenicsVectorSpace(V)
    op = FenicsOperator(
        F,
        space,
        space,
        u, (bc, ),
        parameter_setter=lambda mu: c.assign(mu['c'].item()),
        parameters={'c': 1},
        solver_options={'inverse': {
            'type': 'newton',
            'rtol': 1e-6
        }})
    rhs = VectorOperator(op.range.zeros())

    fom = StationaryModel(op, rhs, visualizer=FenicsVisualizer(space))

    return fom
Esempio n. 3
0
def test_memory_region_safety():

    op = NumpyMatrixOperator(np.eye(1))
    rhs = op.range.make_array(np.array([1]))
    m = StationaryModel(op, rhs)
    m.enable_caching('memory')

    U = m.solve()
    del U[:]
    U = m.solve()
    assert len(U) == 1
    del U[:]
    U = m.solve()
    assert len(U) == 1
Esempio n. 4
0
 def build_rom(self, projected_operators, error_estimator):
     return StationaryModel(error_estimator=error_estimator, **projected_operators)
Esempio n. 5
0
def discretize_stationary_cg(analytical_problem,
                             diameter=None,
                             domain_discretizer=None,
                             grid_type=None,
                             grid=None,
                             boundary_info=None,
                             preassemble=True):
    """Discretizes a |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 |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, 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 is 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
        L2Functional = L2ProductFunctionalQ1
        BoundaryL2Functional = BoundaryL2ProductFunctional
    else:
        DiffusionOperator = DiffusionOperatorP1
        AdvectionOperator = AdvectionOperatorP1
        ReactionOperator = L2ProductP1
        L2Functional = L2ProductFunctionalP1
        BoundaryL2Functional = BoundaryL2ProductFunctional

    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=f'diffusion_{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=f'advection_{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=f'reaction_{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:
        assert isinstance(p.robin_data, tuple) and len(p.robin_data) == 2
        if isinstance(p.robin_data[0], LincombFunction):
            for i, rd in enumerate(p.robin_data[0].functions):
                robin_tuple = (rd, p.robin_data[1])
                Li += [
                    RobinBoundaryOperator(grid,
                                          boundary_info,
                                          robin_data=robin_tuple,
                                          name=f'robin_{i}')
                ]
            coefficients += list(p.robin_data[0].coefficients)
        else:
            Li += [
                RobinBoundaryOperator(grid,
                                      boundary_info,
                                      robin_data=p.robin_data,
                                      name=f'robin')
            ]
            coefficients.append(1.)

    L = LincombOperator(operators=Li,
                        coefficients=coefficients,
                        name='ellipticOperator')

    # right-hand side
    rhs = p.rhs or ConstantFunction(0., dim_domain=p.domain.dim)
    Fi = []
    coefficients_F = []
    if isinstance(p.rhs, LincombFunction):
        Fi += [
            L2Functional(grid,
                         rh,
                         dirichlet_clear_dofs=True,
                         boundary_info=boundary_info,
                         name=f'rhs_{i}')
            for i, rh in enumerate(p.rhs.functions)
        ]
        coefficients_F += list(p.rhs.coefficients)
    else:
        Fi += [
            L2Functional(grid,
                         rhs,
                         dirichlet_clear_dofs=True,
                         boundary_info=boundary_info,
                         name='rhs')
        ]
        coefficients_F.append(1.)

    if p.neumann_data is not None and boundary_info.has_neumann:
        if isinstance(p.neumann_data, LincombFunction):
            Fi += [
                BoundaryL2Functional(grid,
                                     -ne,
                                     boundary_info=boundary_info,
                                     boundary_type='neumann',
                                     dirichlet_clear_dofs=True,
                                     name=f'neumann_{i}')
                for i, ne in enumerate(p.neumann_data.functions)
            ]
            coefficients_F += list(p.neumann_data.coefficients)
        else:
            Fi += [
                BoundaryL2Functional(grid,
                                     -p.neumann_data,
                                     boundary_info=boundary_info,
                                     boundary_type='neumann',
                                     dirichlet_clear_dofs=True)
            ]
            coefficients_F.append(1.)

    if p.robin_data is not None and boundary_info.has_robin:
        if isinstance(p.robin_data[0], LincombFunction):
            Fi += [
                BoundaryL2Functional(grid,
                                     rob * p.robin_data[1],
                                     boundary_info=boundary_info,
                                     boundary_type='robin',
                                     dirichlet_clear_dofs=True,
                                     name=f'robin_{i}')
                for i, rob in enumerate(p.robin_data[0].functions)
            ]
            coefficients_F += list(p.robin_data[0].coefficients)
        else:
            Fi += [
                BoundaryL2Functional(grid,
                                     p.robin_data[0] * p.robin_data[1],
                                     boundary_info=boundary_info,
                                     boundary_type='robin',
                                     dirichlet_clear_dofs=True)
            ]
            coefficients_F.append(1.)

    if p.dirichlet_data is not None and boundary_info.has_dirichlet:
        if isinstance(p.dirichlet_data, LincombFunction):
            Fi += [
                BoundaryDirichletFunctional(grid,
                                            di,
                                            boundary_info,
                                            name=f'dirichlet{i}')
                for i, di in enumerate(p.dirichlet_data.functions)
            ]
            coefficients_F += list(p.dirichlet_data.coefficients)
        else:
            Fi += [
                BoundaryDirichletFunctional(grid, p.dirichlet_data,
                                            boundary_info)
            ]
            coefficients_F.append(1.)

    F = LincombOperator(operators=Fi,
                        coefficients=coefficients_F,
                        name='rhsOperator')

    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
    }

    # assemble additionals output functionals
    if p.outputs:
        if any(v[0] not in ('l2', 'l2_boundary') for v in p.outputs):
            raise NotImplementedError
        outputs = [
            L2Functional(grid, v[1], dirichlet_clear_dofs=False).H
            if v[0] == 'l2' else BoundaryL2Functional(
                grid, v[1], dirichlet_clear_dofs=False).H for v in p.outputs
        ]
        if len(outputs) > 1:
            from pymor.operators.block import BlockColumnOperator
            output_functional = BlockColumnOperator(outputs)
        else:
            output_functional = outputs[0]
    else:
        output_functional = None

    parameter_space = p.parameter_space if hasattr(p,
                                                   'parameter_space') else None

    m = StationaryModel(L,
                        F,
                        output_functional=output_functional,
                        products=products,
                        visualizer=visualizer,
                        parameter_space=parameter_space,
                        name=f'{p.name}_CG')

    data = {'grid': grid, 'boundary_info': boundary_info}

    if preassemble:
        data['unassembled_m'] = m
        m = preassemble_(m)

    return m, data
Esempio n. 6
0
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 a |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.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.
    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, 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 p.outputs:
        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=f'diffusion_{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=f'dirichlet_{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=f'advection_{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 == '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

    m = StationaryModel(L, F, products=products, visualizer=visualizer,
                        parameter_space=parameter_space, name=f'{p.name}_FV')

    data = {'grid': grid, 'boundary_info': boundary_info}

    if preassemble:
        data['unassembled_m'] = m
        m = preassemble_(m)

    return m, data
Esempio n. 7
0
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 model
    ##################################

    # FEniCS wrappers
    from pymor.bindings.fenics import FenicsVectorSpace, FenicsMatrixOperator, FenicsVisualizer

    # generic pyMOR classes
    from pymor.models.basic import StationaryModel
    from pymor.operators.constructions import LincombOperator, VectorOperator
    from pymor.parameters.functionals import ProjectionParameterFunctional
    from pymor.parameters.spaces import CubicParameterSpace

    # define parameter functionals (same as in pymor.analyticalproblems.thermalblock)
    def parameter_functional_factory(x, y):
        return ProjectionParameterFunctional(component_name='diffusion',
                                             component_shape=(yblocks, xblocks),
                                             index=(yblocks - y - 1, x),
                                             name=f'diffusion_{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 = VectorOperator(FenicsVectorSpace(V).make_array([F]))
    h1_product = FenicsMatrixOperator(h1_mat, V, V, name='h1_0_semi')
    l2_product = FenicsMatrixOperator(l2_mat, V, V, name='l2')

    # build model
    visualizer = FenicsVisualizer(FenicsVectorSpace(V))
    parameter_space = CubicParameterSpace(op.parameter_type, 0.1, 1.)
    fom = StationaryModel(op, rhs, products={'h1_0_semi': h1_product,
                                             'l2': l2_product},
                          parameter_space=parameter_space,
                          visualizer=visualizer)

    return fom
Esempio n. 8
0
 def build_rom(self, projected_operators, estimator):
     return StationaryModel(parameter_space=self.fom.parameter_space, estimator=estimator, **projected_operators)
Esempio n. 9
0
def discretize_stationary_from_disk(parameter_file):
    """Load a linear affinely decomposed |StationaryModel| from file.

    The model 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.  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
    -------
    m
        The |StationaryModel| that has been generated.
    """
    assert ".ini" == parameter_file[
        -4:], f'Given file is not an .ini file: {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, range_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 model
    return StationaryModel(operator=system_lincombOperator,
                           rhs=rhs_lincombOperator,
                           parameter_space=parameter_space,
                           products=products)