Example #1
0
 def build_rom(self, projected_operators, error_estimator):
     fom = self.fom
     return InstationaryModel(T=fom.T,
                              time_stepper=fom.time_stepper,
                              num_values=fom.num_values,
                              error_estimator=error_estimator,
                              **projected_operators)
Example #2
0
def discretize(n, nt, blocks):
    h = 1. / blocks
    ops = [WrappedDiffusionOperator.create(n, h * i, h * (i + 1)) for i in range(blocks)]
    pfs = [ProjectionParameterFunctional('diffusion_coefficients', blocks, i) for i in range(blocks)]
    operator = LincombOperator(ops, pfs)

    initial_data = operator.source.zeros()

    # use data property of WrappedVector to setup rhs
    # note that we cannot use the data property of ListVectorArray,
    # since ListVectorArray will always return a copy
    rhs_vec = operator.range.zeros()
    rhs_data = rhs_vec._list[0].to_numpy()
    rhs_data[:] = np.ones(len(rhs_data))
    rhs_data[0] = 0
    rhs_data[len(rhs_data) - 1] = 0
    rhs = VectorOperator(rhs_vec)

    # hack together a visualizer ...
    grid = OnedGrid(domain=(0, 1), num_intervals=n)
    visualizer = OnedVisualizer(grid)

    time_stepper = ExplicitEulerTimeStepper(nt)

    fom = InstationaryModel(T=1e-0, operator=operator, rhs=rhs, initial_data=initial_data,
                            time_stepper=time_stepper, num_values=20,
                            visualizer=visualizer, name='C++-Model')
    return fom
Example #3
0
 def build_rom(self, projected_operators, estimator):
     fom = self.fom
     return InstationaryModel(T=fom.T,
                              time_stepper=fom.time_stepper,
                              num_values=fom.num_values,
                              parameter_space=self.fom.parameter_space,
                              estimator=estimator,
                              **projected_operators)
Example #4
0
def discretize_instationary_cg(analytical_problem,
                               diameter=None,
                               domain_discretizer=None,
                               grid_type=None,
                               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 finite elements.

    Parameters
    ----------
    analytical_problem
        The |InstationaryProblem| 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.
    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.TimeStepperInterface>`
        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_cg(p.stationary_part,
                                       diameter=diameter,
                                       domain_discretizer=domain_discretizer,
                                       grid_type=grid_type,
                                       grid=grid,
                                       boundary_info=boundary_info)

    if p.initial_data.parametric:
        I = InterpolationOperator(data['grid'], p.initial_data)
    else:
        I = p.initial_data.evaluate(data['grid'].centers(data['grid'].dim))
        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)

    mass = m.l2_0_product

    m = InstationaryModel(operator=m.operator,
                          rhs=m.rhs,
                          mass=mass,
                          initial_data=I,
                          T=p.T,
                          products=m.products,
                          output_functional=m.output_functional,
                          time_stepper=time_stepper,
                          parameter_space=p.parameter_space,
                          visualizer=m.visualizer,
                          num_values=num_values,
                          name=f'{p.name}_CG')

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

    return m, data
Example #5
0
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
Example #6
0
def discretize_instationary_from_disk(parameter_file,
                                      T=None,
                                      steps=None,
                                      u0=None,
                                      time_stepper=None):
    """Load a linear affinely decomposed |InstationaryModel| from file.

    Similarly to :func:`discretize_stationary_from_disk`, the model is
    specified via an `ini.`-file of the following form ::

        [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)
        ...

        [mass-matrix]
        D.mat

        [initial-solution]
        u0: u0.mat

        [parameter]
        μ_1: a_1,b_1
        ...
        μ_n: a_n,b_n

        [products]
        Prod1: P_1.mat
        Prod2: P_2.mat
        ...

        [time]
        T: final time
        steps: number of time steps


    Parameters
    ----------
    parameter_file
        Path to the '.ini' parameter file.
    T
        End-time of desired solution. If `None`, the value specified in the
        parameter file is used.
    steps
        Number of time steps to. If `None`, the value specified in the
        parameter file is used.
    u0
        Initial solution. If `None` the initial solution is obtained
        from parameter file.
    time_stepper
        The desired :class:`time stepper <pymor.algorithms.timestepping.TimeStepper>`
        to use. If `None`, implicit Euler time stepping is used.

    Returns
    -------
    m
        The |InstationaryModel| that has been generated.
    """
    assert ".ini" == parameter_file[-4:], "Given file is not an .ini 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 'mass-matrix' in config.sections()
    assert 'rhs-vectors' in config.sections()
    assert 'parameter' in config.sections()

    system_mat = config.items('system-matrices')
    mass_mat = config.items('mass-matrix')
    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 mass matrix
    path = os.path.join(base_path, mass_mat[0][1])
    mass_operator = NumpyMatrixOperator.from_file(path,
                                                  source_id='STATE',
                                                  range_id='STATE')

    # Obtain initial solution if not given
    if u0 is None:
        u_0 = config.items('initial-solution')
        path = os.path.join(base_path, u_0[0][1])
        op = NumpyMatrixOperator.from_file(path, range_id='STATE')
        assert isinstance(op.matrix, np.ndarray)
        u0 = op.with_(matrix=op.matrix.reshape((-1, 1)))

    # 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

    # Further specifications
    if 'time' in config.sections():
        if T is None:
            assert 'T' in config.options('time')
            T = float(config.get('time', 'T'))
        if steps is None:
            assert 'steps' in config.options('time')
            steps = int(config.get('time', 'steps'))

    # Use implicit euler time stepper if no time-stepper given
    if time_stepper is None:
        time_stepper = ImplicitEulerTimeStepper(steps)
    else:
        time_stepper = time_stepper(steps)

    # Create and return instationary model
    return InstationaryModel(operator=system_lincombOperator,
                             rhs=rhs_lincombOperator,
                             parameter_space=parameter_space,
                             initial_data=u0,
                             T=T,
                             time_stepper=time_stepper,
                             mass=mass_operator,
                             products=products)