Esempio n. 1
0
def test_lincomb_function():
    for steps in (1, 10):
        x = np.linspace(0, 1, num=steps)
        zero = ConstantFunction(0.0, dim_domain=steps)
        for zero in (ConstantFunction(0.0, dim_domain=steps),
                     GenericFunction(lambda X: np.zeros(X.shape[:-1]),
                                     dim_domain=steps)):
            for one in (ConstantFunction(1.0, dim_domain=steps),
                        GenericFunction(lambda X: np.ones(X.shape[:-1]),
                                        dim_domain=steps), 1.0):
                add = (zero + one) + 1 - 1
                add_ = 1 - 1 + (zero + one)
                sub = (zero - one) + np.zeros(())
                neg = -zero
                assert np.allclose(sub(x), [-1])
                assert np.allclose(add(x), [1.0])
                assert np.allclose(add_(x), [1.0])
                assert np.allclose(neg(x), [0.0])
                (repr(add), str(add), repr(one), str(one)
                 )  # just to cover the respective special funcs too
                mul = neg * 1. * 1.
                mul_ = 1. * 1. * neg
                assert np.allclose(mul(x), [0.0])
                assert np.allclose(mul_(x), [0.0])
        with pytest.raises(AssertionError):
            zero + ConstantFunction(dim_domain=steps + 1)
    with pytest.raises(AssertionError):
        ConstantFunction(dim_domain=0)
def elliptic_gmsh_demo(args):
    args['ANGLE'] = float(args['ANGLE'])
    args['NUM_POINTS'] = int(args['NUM_POINTS'])
    args['CLSCALE'] = float(args['CLSCALE'])

    problem = StationaryProblem(
        domain=CircularSectorDomain(args['ANGLE'], radius=1, num_points=args['NUM_POINTS']),
        diffusion=ConstantFunction(1, dim_domain=2),
        rhs=ConstantFunction(np.array(0.), dim_domain=2, name='rhs'),
        dirichlet_data=ExpressionFunction('sin(polar(x)[1] * pi/angle)', 2, (),
                                          {}, {'angle': args['ANGLE']}, name='dirichlet')
    )

    print('Discretize ...')
    m, data = discretize_stationary_cg(analytical_problem=problem, diameter=args['CLSCALE'])
    grid = data['grid']
    print(grid)
    print()

    print('Solve ...')
    U = m.solve()

    solution = ExpressionFunction('(lambda r, phi: r**(pi/angle) * sin(phi * pi/angle))(*polar(x))', 2, (),
                                  {}, {'angle': args['ANGLE']})
    U_ref = U.space.make_array(solution(grid.centers(2)))

    m.visualize((U, U_ref, U-U_ref),
                legend=('Solution', 'Analytical solution (circular boundary)', 'Error'),
                separate_colorbars=True)
Esempio n. 3
0
def burgers_problem_2d(vx=1.,
                       vy=1.,
                       torus=True,
                       initial_data_type='sin',
                       parameter_range=(1., 2.)):
    """Two-dimensional Burgers-type problem.

    The problem is to solve ::

        ∂_t u(x, t, μ)  +  ∇ ⋅ (v * u(x, t, μ)^μ) = 0
                                       u(x, 0, μ) = u_0(x)

    for u with t in [0, 0.3], x in [0, 2] x [0, 1].

    Parameters
    ----------
    vx
        The x component of the velocity vector v.
    vy
        The y component of the velocity vector v.
    torus
        If `True`, impose periodic boundary conditions. Otherwise,
        Dirichlet left and bottom, outflow top and right.
    initial_data_type
        Type of initial data (`'sin'` or `'bump'`).
    parameter_range
        The interval in which μ is allowed to vary.
    """

    assert initial_data_type in ('sin', 'bump')

    if initial_data_type == 'sin':
        initial_data = ExpressionFunction(
            "0.5 * (sin(2 * pi * x[..., 0]) * sin(2 * pi * x[..., 1]) + 1.)",
            2, ())
        dirichlet_data = ConstantFunction(dim_domain=2, value=0.5)
    else:
        initial_data = ExpressionFunction(
            "(x[..., 0] >= 0.5) * (x[..., 0] <= 1) * 1", 2, ())
        dirichlet_data = ConstantFunction(dim_domain=2, value=0.)

    return InstationaryProblem(
        StationaryProblem(
            domain=TorusDomain([[0, 0], [2, 1]])
            if torus else RectDomain([[0, 0], [2, 1]], right=None, top=None),
            dirichlet_data=dirichlet_data,
            rhs=None,
            nonlinear_advection=ExpressionFunction("abs(x)**exponent * v", 1,
                                                   (2, ), {'exponent': 1},
                                                   {'v': np.array([vx, vy])}),
            nonlinear_advection_derivative=ExpressionFunction(
                "exponent * abs(x)**(exponent-1) * sign(x) * v", 1, (2, ),
                {'exponent': 1}, {'v': np.array([vx, vy])}),
        ),
        initial_data=initial_data,
        T=0.3,
        parameter_ranges=parameter_range,
        name=f"burgers_problem_2d({vx}, {vy}, {torus}, '{initial_data_type}')")
Esempio n. 4
0
def elliptic_demo(args):
    args['PROBLEM-NUMBER'] = int(args['PROBLEM-NUMBER'])
    assert 0 <= args['PROBLEM-NUMBER'] <= 1, ValueError('Invalid problem number')
    args['DIRICHLET-NUMBER'] = int(args['DIRICHLET-NUMBER'])
    assert 0 <= args['DIRICHLET-NUMBER'] <= 2, ValueError('Invalid Dirichlet boundary number.')
    args['NEUMANN-NUMBER'] = int(args['NEUMANN-NUMBER'])
    assert 0 <= args['NEUMANN-NUMBER'] <= 2, ValueError('Invalid Neumann boundary number.')
    args['NEUMANN-COUNT'] = int(args['NEUMANN-COUNT'])
    assert 0 <= args['NEUMANN-COUNT'] <= 3, ValueError('Invalid Neumann boundary count.')

    rhss = [ExpressionFunction('ones(x.shape[:-1]) * 10', 2, ()),
            ExpressionFunction('(x[..., 0] - 0.5) ** 2 * 1000', 2, ())]
    dirichlets = [ExpressionFunction('zeros(x.shape[:-1])', 2, ()),
                  ExpressionFunction('ones(x.shape[:-1])', 2, ()),
                  ExpressionFunction('x[..., 0]', 2, ())]
    neumanns = [None,
                ConstantFunction(3., dim_domain=2),
                ExpressionFunction('50*(0.1 <= x[..., 1]) * (x[..., 1] <= 0.2)'
                                   '+50*(0.8 <= x[..., 1]) * (x[..., 1] <= 0.9)', 2, ())]
    domains = [RectDomain(),
               RectDomain(right='neumann'),
               RectDomain(right='neumann', top='neumann'),
               RectDomain(right='neumann', top='neumann', bottom='neumann')]

    rhs = rhss[args['PROBLEM-NUMBER']]
    dirichlet = dirichlets[args['DIRICHLET-NUMBER']]
    neumann = neumanns[args['NEUMANN-NUMBER']]
    domain = domains[args['NEUMANN-COUNT']]

    problem = StationaryProblem(
        domain=domain,
        diffusion=ConstantFunction(1, dim_domain=2),
        rhs=rhs,
        dirichlet_data=dirichlet,
        neumann_data=neumann
    )

    for n in [32, 128]:
        print('Discretize ...')
        discretizer = discretize_stationary_fv if args['--fv'] else discretize_stationary_cg
        m, data = discretizer(
            analytical_problem=problem,
            grid_type=RectGrid if args['--rect'] else TriaGrid,
            diameter=np.sqrt(2) / n if args['--rect'] else 1. / n
        )
        grid = data['grid']
        print(grid)
        print()

        print('Solve ...')
        U = m.solve()
        m.visualize(U, title=repr(grid))
        print()
Esempio n. 5
0
def burgers_problem(v=1.,
                    circle=True,
                    initial_data_type='sin',
                    parameter_range=(1., 2.)):
    """One-dimensional Burgers-type problem.

    The problem is to solve ::

        ∂_t u(x, t, μ)  +  ∂_x (v * u(x, t, μ)^μ) = 0
                                       u(x, 0, μ) = u_0(x)

    for u with t in [0, 0.3] and x in [0, 2].

    Parameters
    ----------
    v
        The velocity v.
    circle
        If `True`, impose periodic boundary conditions. Otherwise Dirichlet left,
        outflow right.
    initial_data_type
        Type of initial data (`'sin'` or `'bump'`).
    parameter_range
        The interval in which μ is allowed to vary.
    """

    assert initial_data_type in ('sin', 'bump')

    if initial_data_type == 'sin':
        initial_data = ExpressionFunction('0.5 * (sin(2 * pi * x) + 1.)', 1,
                                          ())
        dirichlet_data = ConstantFunction(dim_domain=1, value=0.5)
    else:
        initial_data = ExpressionFunction('(x >= 0.5) * (x <= 1) * 1.', 1, ())
        dirichlet_data = ConstantFunction(dim_domain=1, value=0.)

    return InstationaryProblem(
        StationaryProblem(
            domain=CircleDomain([0, 2]) if circle else LineDomain([0, 2],
                                                                  right=None),
            dirichlet_data=dirichlet_data,
            rhs=None,
            nonlinear_advection=ExpressionFunction('abs(x)**exponent[0] * v',
                                                   1, (1, ), {'exponent': 1},
                                                   {'v': v}),
            nonlinear_advection_derivative=ExpressionFunction(
                'exponent * abs(x)**(exponent[0]-1) * sign(x) * v', 1, (1, ),
                {'exponent': 1}, {'v': v}),
        ),
        T=0.3,
        initial_data=initial_data,
        parameter_ranges={'exponent': parameter_range},
        name=f"burgers_problem({v}, {circle}, '{initial_data_type}')")
Esempio n. 6
0
def helmholtz_problem(domain=RectDomain(), rhs=None, parameter_range=(0., 100.),
                      dirichlet_data=None, neumann_data=None):
    """Helmholtz equation problem.

    This problem is to solve the Helmholtz equation ::

      - ∆ u(x, k) - k^2 u(x, k) = f(x, k)

    on a given domain.

    Parameters
    ----------
    domain
        A |DomainDescription| of the domain the problem is posed on.
    rhs
        The |Function| f(x, μ).
    parameter_range
        A tuple `(k_min, k_max)` describing the interval in which k is allowd to vary.
    dirichlet_data
        |Function| providing the Dirichlet boundary values.
    neumann_data
        |Function| providing the Neumann boundary values.
    """

    return StationaryProblem(

        domain=domain,

        rhs=rhs or ConstantFunction(1., dim_domain=domain.dim),

        dirichlet_data=dirichlet_data,

        neumann_data=neumann_data,

        diffusion=ConstantFunction(1., dim_domain=domain.dim),

        reaction=LincombFunction([ConstantFunction(1., dim_domain=domain.dim)],
                                 [ExpressionParameterFunctional('-k[0]**2', {'k': 1})]),

        parameter_ranges={'k': parameter_range},

        name='helmholtz_problem'

    )
Esempio n. 7
0
def main(
    angle: float = Argument(..., help='The angle of the circular sector.'),
    num_points: int = Argument(
        ...,
        help='The number of points that form the arc of the circular sector.'),
    clscale: float = Argument(..., help='Mesh element size scaling factor.'),
):
    """Solves the Poisson equation in 2D on a circular sector domain of radius 1
    using an unstructured mesh.

    Note that Gmsh (http://geuz.org/gmsh/) is required for meshing.
    """

    problem = StationaryProblem(
        domain=CircularSectorDomain(angle, radius=1, num_points=num_points),
        diffusion=ConstantFunction(1, dim_domain=2),
        rhs=ConstantFunction(np.array(0.), dim_domain=2, name='rhs'),
        dirichlet_data=ExpressionFunction('sin(polar(x)[1] * pi/angle)',
                                          2, (), {}, {'angle': angle},
                                          name='dirichlet'))

    print('Discretize ...')
    m, data = discretize_stationary_cg(analytical_problem=problem,
                                       diameter=clscale)
    grid = data['grid']
    print(grid)
    print()

    print('Solve ...')
    U = m.solve()

    solution = ExpressionFunction(
        '(lambda r, phi: r**(pi/angle) * sin(phi * pi/angle))(*polar(x))', 2,
        (), {}, {'angle': angle})
    U_ref = U.space.make_array(solution(grid.centers(2)))

    m.visualize((U, U_ref, U - U_ref),
                legend=('Solution', 'Analytical solution (circular boundary)',
                        'Error'),
                separate_colorbars=True)
Esempio n. 8
0
def main(
    problem_number: int = Argument(
        ..., min=0, max=1, help='Selects the problem to solve [0 or 1].'),
    n: int = Argument(..., help='Grid interval count.'),
    fv: bool = Option(
        False,
        help='Use finite volume discretization instead of finite elements.'),
):
    """Solves the Poisson equation in 1D using pyMOR's builtin discreization toolkit."""

    rhss = [
        ExpressionFunction('ones(x.shape[:-1]) * 10', 1, ()),
        ExpressionFunction('(x - 0.5)**2 * 1000', 1, ())
    ]
    rhs = rhss[problem_number]

    d0 = ExpressionFunction('1 - x', 1, ())
    d1 = ExpressionFunction('x', 1, ())

    f0 = ProjectionParameterFunctional('diffusionl')
    f1 = 1.

    problem = StationaryProblem(domain=LineDomain(),
                                rhs=rhs,
                                diffusion=LincombFunction([d0, d1], [f0, f1]),
                                dirichlet_data=ConstantFunction(value=0,
                                                                dim_domain=1),
                                name='1DProblem')

    parameter_space = problem.parameters.space(0.1, 1)

    print('Discretize ...')
    discretizer = discretize_stationary_fv if fv else discretize_stationary_cg
    m, data = discretizer(problem, diameter=1 / n)
    print(data['grid'])
    print()

    print('Solve ...')
    U = m.solution_space.empty()
    for mu in parameter_space.sample_uniformly(10):
        U.append(m.solve(mu))
    m.visualize(U, title='Solution for diffusionl in [0.1, 1]')
Esempio n. 9
0
def elliptic_oned_demo(args):
    args['PROBLEM-NUMBER'] = int(args['PROBLEM-NUMBER'])
    assert 0 <= args['PROBLEM-NUMBER'] <= 1, ValueError(
        'Invalid problem number.')
    args['N'] = int(args['N'])

    rhss = [
        ExpressionFunction('ones(x.shape[:-1]) * 10', 1, ()),
        ExpressionFunction('(x - 0.5)**2 * 1000', 1, ())
    ]
    rhs = rhss[args['PROBLEM-NUMBER']]

    d0 = ExpressionFunction('1 - x', 1, ())
    d1 = ExpressionFunction('x', 1, ())

    f0 = ProjectionParameterFunctional('diffusionl')
    f1 = 1.

    problem = StationaryProblem(domain=LineDomain(),
                                rhs=rhs,
                                diffusion=LincombFunction([d0, d1], [f0, f1]),
                                dirichlet_data=ConstantFunction(value=0,
                                                                dim_domain=1),
                                name='1DProblem')

    parameter_space = problem.parameters.space(0.1, 1)

    print('Discretize ...')
    discretizer = discretize_stationary_fv if args[
        '--fv'] else discretize_stationary_cg
    m, data = discretizer(problem, diameter=1 / args['N'])
    print(data['grid'])
    print()

    print('Solve ...')
    U = m.solution_space.empty()
    for mu in parameter_space.sample_uniformly(10):
        U.append(m.solve(mu))
    m.visualize(U, title='Solution for diffusionl in [0.1, 1]')
Esempio n. 10
0
def main(
        diameter: float = Argument(
            0.1, help='Diameter option for the domain discretizer.'),
        r: int = Argument(5, help='Order of the ROMs.'),
):
    r"""2D heat equation demo.

    Discretization of the PDE:

    .. math::
        :nowrap:

        \begin{align*}
            \partial_t z(x, y, t) &= \Delta z(x, y, t),      & 0 < x, y < 1,\ t > 0 \\
            -\nabla z(0, y, t) \cdot n &= z(0, y, t) - u(t), & 0 < y < 1, t > 0 \\
            -\nabla z(1, y, t) \cdot n &= z(1, y, t),        & 0 < y < 1, t > 0 \\
            -\nabla z(0, x, t) \cdot n &= z(0, x, t),        & 0 < x < 1, t > 0 \\
            -\nabla z(1, x, t) \cdot n &= z(1, x, t),        & 0 < x < 1, t > 0 \\
            z(x, y, 0) &= 0                                  & 0 < x, y < 1 \\
            y(t) &= \int_0^1 z(1, y, t) dy,                  & t > 0 \\
        \end{align*}

    where :math:`u(t)` is the input and :math:`y(t)` is the output.
    """
    set_log_levels({'pymor.algorithms.gram_schmidt.gram_schmidt': 'WARNING'})

    p = InstationaryProblem(StationaryProblem(
        domain=RectDomain([[0., 0.], [1., 1.]],
                          left='robin',
                          right='robin',
                          top='robin',
                          bottom='robin'),
        diffusion=ConstantFunction(1., 2),
        robin_data=(ConstantFunction(1., 2),
                    ExpressionFunction('(x[...,0] < 1e-10) * 1.', 2)),
        outputs=[('l2_boundary',
                  ExpressionFunction('(x[...,0] > (1 - 1e-10)) * 1.', 2))]),
                            ConstantFunction(0., 2),
                            T=1.)

    fom, _ = discretize_instationary_cg(p, diameter=diameter, nt=100)

    fom.visualize(fom.solve())

    lti = fom.to_lti()

    print(f'order of the model = {lti.order}')
    print(f'number of inputs   = {lti.dim_input}')
    print(f'number of outputs  = {lti.dim_output}')

    # System poles
    poles = lti.poles()
    fig, ax = plt.subplots()
    ax.plot(poles.real, poles.imag, '.')
    ax.set_title('System poles')
    plt.show()

    # Magnitude plot of the full model
    w = np.logspace(-1, 3, 100)
    fig, ax = plt.subplots()
    lti.mag_plot(w, ax=ax)
    ax.set_title('Magnitude plot of the full model')
    plt.show()

    # Hankel singular values
    hsv = lti.hsv()
    fig, ax = plt.subplots()
    ax.semilogy(range(1, len(hsv) + 1), hsv, '.-')
    ax.set_title('Hankel singular values')
    plt.show()

    # Norms of the system
    print(f'FOM H_2-norm:    {lti.h2_norm():e}')
    if config.HAVE_SLYCOT:
        print(f'FOM H_inf-norm:  {lti.hinf_norm():e}')
    else:
        print('Skipped H_inf-norm calculation due to missing slycot.')
    print(f'FOM Hankel-norm: {lti.hankel_norm():e}')

    # Model order reduction
    run_mor_method(lti, w, BTReductor(lti), 'BT', r, tol=1e-5)
    run_mor_method(lti, w, LQGBTReductor(lti), 'LQGBT', r, tol=1e-5)
    run_mor_method(lti, w, BRBTReductor(lti), 'BRBT', r, tol=1e-5)
    run_mor_method(lti, w, IRKAReductor(lti), 'IRKA', r)
    run_mor_method(lti, w, TSIAReductor(lti), 'TSIA', r)
    run_mor_method(lti, w, OneSidedIRKAReductor(lti, 'V'), 'OS-IRKA', r)
Esempio n. 11
0
def elliptic2_demo(args):
    args['PROBLEM-NUMBER'] = int(args['PROBLEM-NUMBER'])
    assert 0 <= args['PROBLEM-NUMBER'] <= 1, ValueError('Invalid problem number.')
    args['N'] = int(args['N'])
    norm = args['NORM']
    norm = float(norm) if not norm.lower() in ('h1', 'l2') else norm.lower()

    rhss = [ExpressionFunction('ones(x.shape[:-1]) * 10', 2, ()),
              LincombFunction(
              [ExpressionFunction('ones(x.shape[:-1]) * 10', 2, ()), ConstantFunction(1.,2)],
              [ProjectionParameterFunctional('mu'), 0.1])]

    dirichlets = [ExpressionFunction('zeros(x.shape[:-1])', 2, ()),
                  LincombFunction(
                  [ExpressionFunction('2 * x[..., 0]', 2, ()), ConstantFunction(1.,2)],
                  [ProjectionParameterFunctional('mu'), 0.5])]

    neumanns = [None,
                  LincombFunction(
                  [ExpressionFunction('1 - x[..., 1]', 2, ()), ConstantFunction(1.,2)],
                  [ProjectionParameterFunctional('mu'), 0.5**2])]

    robins = [None,
                (LincombFunction(
                [ExpressionFunction('x[..., 1]', 2, ()), ConstantFunction(1.,2)],
                [ProjectionParameterFunctional('mu'), 1]),
                 ConstantFunction(1.,2))]

    domains = [RectDomain(),
               RectDomain(right='neumann', top='dirichlet', bottom='robin')]

    rhs = rhss[args['PROBLEM-NUMBER']]
    dirichlet = dirichlets[args['PROBLEM-NUMBER']]
    neumann = neumanns[args['PROBLEM-NUMBER']]
    domain = domains[args['PROBLEM-NUMBER']]
    robin = robins[args['PROBLEM-NUMBER']]
    
    problem = StationaryProblem(
        domain=domain,
        rhs=rhs,
        diffusion=LincombFunction(
            [ExpressionFunction('1 - x[..., 0]', 2, ()), ExpressionFunction('x[..., 0]', 2, ())],
            [ProjectionParameterFunctional('mu'), 1]
        ),
        dirichlet_data=dirichlet,
        neumann_data=neumann,
        robin_data=robin,
        parameter_ranges=(0.1, 1),
        name='2DProblem'
    )

    if isinstance(norm, float) and not args['--fv']:
        # use a random parameter to construct an energy product
        mu_bar = problem.parameters.parse(norm)
    else:
        mu_bar = None

    print('Discretize ...')
    if args['--fv']:
        m, data = discretize_stationary_fv(problem, diameter=1. / args['N'])
    else:
        m, data = discretize_stationary_cg(problem, diameter=1. / args['N'], mu_energy_product=mu_bar)
    print(data['grid'])
    print()

    print('Solve ...')
    U = m.solution_space.empty()
    for mu in problem.parameter_space.sample_uniformly(10):
        U.append(m.solve(mu))
    if mu_bar is not None:
        # use the given energy product
        norm_squared = U[-1].norm(m.products['energy'])[0]
        print('Energy norm of the last snapshot: ', np.sqrt(norm_squared))
    if not args['--fv']:
        if args['NORM'] == 'h1':
            norm_squared = U[-1].norm(m.products['h1_0_semi'])[0]
            print('H^1_0 semi norm of the last snapshot: ', np.sqrt(norm_squared))
        if args['NORM'] == 'l2':
            norm_squared = U[-1].norm(m.products['l2_0'])[0]
            print('L^2_0 norm of the last snapshot: ', np.sqrt(norm_squared))
    m.visualize(U, title='Solution for mu in [0.1, 1]')
def discretize_quadratic_pdeopt_stationary_cg(problem,
                                              diameter=np.sqrt(2) / 100.,
                                              weights=None,
                                              parameter_scales=None,
                                              domain_of_interest=None,
                                              desired_temperature=None,
                                              mu_for_u_d=None,
                                              mu_for_tikhonov=False,
                                              parameters_in_q=True,
                                              product='h1_l2_boundary',
                                              solver_options=None,
                                              use_corrected_functional=True,
                                              use_corrected_gradient=False,
                                              adjoint_approach=False):
    if use_corrected_functional:
        print('I am using the corrected functional!!')
    else:
        print('I am using the OLD functional!!')
    if use_corrected_gradient:
        print('I am using the corrected gradient!!')
    else:
        if adjoint_approach:
            print(
                'I am using the adjoint approach for computing the gradient!!')
        print('I am using the OLD gradient!!')

    mu_bar = _construct_mu_bar(problem)
    print(mu_bar)
    primal_fom, data = discretize_stationary_cg(problem,
                                                diameter=diameter,
                                                grid_type=RectGrid,
                                                energy_product=mu_bar)

    #Preassemble non parametric parts: simplify, put the constant part in only one function

    simplified_operators = [
        ZeroOperator(primal_fom.solution_space, primal_fom.solution_space)
    ]
    simplified_coefficients = [1]
    to_pre_assemble = ZeroOperator(primal_fom.solution_space,
                                   primal_fom.solution_space)

    if isinstance(primal_fom.operator, LincombOperator):
        for (i, coef) in enumerate(primal_fom.operator.coefficients):
            if isinstance(coef, Parametric):
                simplified_coefficients.append(coef)
                simplified_operators.append(primal_fom.operator.operators[i])
            else:
                to_pre_assemble += coef * primal_fom.operator.operators[i]
    else:
        to_pre_assemble += primal_fom.operator

    simplified_operators[0] += to_pre_assemble
    simplified_operators[0] = simplified_operators[0].assemble()

    lincomb_operator = LincombOperator(
        simplified_operators,
        simplified_coefficients,
        solver_options=primal_fom.operator.solver_options)

    simplified_rhs = [
        ZeroOperator(primal_fom.solution_space, NumpyVectorSpace(1))
    ]
    simplified_rhs_coefficients = [1]
    to_pre_assemble = ZeroOperator(primal_fom.solution_space,
                                   NumpyVectorSpace(1))

    if isinstance(primal_fom.rhs, LincombOperator):
        for (i, coef) in enumerate(primal_fom.rhs.coefficients):
            if isinstance(coef, Parametric):
                simplified_rhs_coefficients.append(coef)
                simplified_rhs.append(primal_fom.rhs.operators[i])
            else:
                to_pre_assemble += coef * primal_fom.rhs.operators[i]
    else:
        to_pre_assemble += primal_fom.rhs

    simplified_rhs[0] += to_pre_assemble
    simplified_rhs[0] = simplified_rhs[0].assemble()
    lincomb_rhs = LincombOperator(simplified_rhs, simplified_rhs_coefficients)

    primal_fom = primal_fom.with_(operator=lincomb_operator, rhs=lincomb_rhs)

    grid = data['grid']
    d = grid.dim

    # prepare data functions
    if desired_temperature is not None:
        u_desired = ConstantFunction(desired_temperature, d)
    if domain_of_interest is None:
        domain_of_interest = ConstantFunction(1., d)
    if mu_for_u_d is not None:
        domain_of_interest = ConstantFunction(1., d)
        modifified_mu = mu_for_u_d.copy()
        for key in mu_for_u_d.keys():
            if len(mu_for_u_d[key]) == 0:
                modifified_mu.pop(key)
        u_d = primal_fom.solve(modifified_mu)
    else:
        assert desired_temperature is not None
        u_d = InterpolationOperator(grid, u_desired).as_vector()

    if grid.reference_element is square:
        L2_OP = L2ProductQ1
    else:
        L2_OP = L2ProductP1

    Restricted_L2_OP = L2_OP(grid,
                             data['boundary_info'],
                             dirichlet_clear_rows=False,
                             coefficient_function=domain_of_interest)

    l2_u_d_squared = Restricted_L2_OP.apply2(u_d, u_d)[0][0]
    constant_part = 0.5 * l2_u_d_squared

    # assemble output functional
    from pdeopt.theta import build_output_coefficient
    if weights is not None:
        weight_for_J = weights.pop('state')
    else:
        weight_for_J = 1.
    if isinstance(weight_for_J, dict):
        assert len(
            weight_for_J
        ) == 4, 'you need to give all derivatives including second order'
        state_functional = ExpressionParameterFunctional(
            weight_for_J['function'],
            weight_for_J['parameter_type'],
            derivative_expressions=weight_for_J['derivative'],
            second_derivative_expressions=weight_for_J['second_derivatives'])
    elif isinstance(weight_for_J, float) or isinstance(weight_for_J, int):
        state_functional = ConstantParameterFunctional(weight_for_J)
    else:
        assert 0, 'state weight needs to be an integer or a dict with derivatives'

    if mu_for_tikhonov:
        if mu_for_u_d is not None:
            mu_for_tikhonov = mu_for_u_d
        else:
            assert isinstance(mu_for_tikhonov, dict)
        output_coefficient = build_output_coefficient(
            primal_fom.parameter_type, weights, mu_for_tikhonov,
            parameter_scales, state_functional, constant_part)
    else:
        output_coefficient = build_output_coefficient(
            primal_fom.parameter_type, weights, None, parameter_scales,
            state_functional, constant_part)

    output_functional = {}

    output_functional['output_coefficient'] = output_coefficient
    output_functional['linear_part'] = LincombOperator(
        [VectorOperator(Restricted_L2_OP.apply(u_d))],
        [-state_functional])  # j(.)
    output_functional['bilinear_part'] = LincombOperator(
        [Restricted_L2_OP], [0.5 * state_functional])  # k(.,.)
    output_functional['d_u_linear_part'] = LincombOperator(
        [VectorOperator(Restricted_L2_OP.apply(u_d))],
        [-state_functional])  # j(.)
    output_functional['d_u_bilinear_part'] = LincombOperator(
        [Restricted_L2_OP], [state_functional])  # 2k(.,.)

    l2_boundary_product = RobinBoundaryOperator(
        grid,
        data['boundary_info'],
        robin_data=(ConstantFunction(1, 2), ConstantFunction(1, 2)),
        name='l2_boundary_product')

    # choose product
    if product == 'h1_l2_boundary':
        opt_product = primal_fom.h1_semi_product + l2_boundary_product  # h1_semi + l2_boundary
    elif product == 'fixed_energy':
        opt_product = primal_fom.energy_product  # energy w.r.t. mu_bar (see above)
    else:
        assert 0, 'product: {} is not nown'.format(product)
    print('my product is {}'.format(product))

    primal_fom = primal_fom.with_(
        products=dict(opt=opt_product,
                      l2_boundary=l2_boundary_product,
                      **primal_fom.products))
    pde_opt_fom = QuadraticPdeoptStationaryModel(
        primal_fom,
        output_functional,
        opt_product=opt_product,
        use_corrected_functional=use_corrected_functional,
        use_corrected_gradient=use_corrected_gradient)
    return pde_opt_fom, data, mu_bar
def discretize_fin_pdeopt_stationary_cg(problem,
                                        grid,
                                        boundary_info,
                                        mu_for_u_d,
                                        product='h1_l2_boundary',
                                        use_corrected_functional=True,
                                        use_corrected_gradient=False,
                                        add_constant_term=False):
    if use_corrected_functional:
        print('I am using the corrected functional!!')
    else:
        print('I am using the OLD functional!!')
    if use_corrected_gradient:
        print('I am using the corrected gradient!!')
    else:
        print('I am using the OLD gradient!!')
    mu_bar = _construct_mu_bar(problem)
    print(mu_bar)
    primal_fom, data = discretize_stationary_cg(problem,
                                                grid=grid,
                                                boundary_info=boundary_info,
                                                energy_product=mu_bar)

    u_d = primal_fom.solve(mu_for_u_d)

    Boundary_Functional = primal_fom.rhs.operators[1]
    T_root_d = Boundary_Functional.apply_adjoint(u_d)
    T_root_d_squared = T_root_d.to_numpy()[0][0]**2

    # assemble output functional
    from pdeopt.theta import build_output_coefficient
    weights = {}
    mu_for_tikhonov = {}
    parameter_scales = {}
    for key, item in mu_for_u_d.items():
        if isinstance(item, list):
            weights[key] = 1. / item[0]**2
        else:
            weights[key] = 1. / item**2
        mu_for_tikhonov[key] = mu_for_u_d[key]
        parameter_scales[key] = 1.
    if add_constant_term:
        state_functional = ConstantParameterFunctional(1.)
        output_coefficient = build_output_coefficient(
            primal_fom.parameter_type,
            weights,
            mu_for_tikhonov,
            parameter_scales,
            state_functional=state_functional,
            constant_part=0.5 * T_root_d_squared)
    else:
        output_coefficient = build_output_coefficient(
            primal_fom.parameter_type, weights, mu_for_tikhonov,
            parameter_scales)

    output_functional = {}

    class Boundary_squared_half(ImmutableObject):
        def __init__(self, source, range):
            self.__auto_init(locals())
            self.linear = False

        def apply2(self, u, v, mu=None):
            return Boundary_Functional.apply_adjoint(u).to_numpy(
            ) * Boundary_Functional.apply_adjoint(v).to_numpy() * 0.5

    class Boundary_squared(ImmutableObject):
        def __init__(self, source, range):
            self.__auto_init(locals())
            self.linear = False

        def apply2(self, u, v, mu=None):
            return Boundary_Functional.apply_adjoint(u).to_numpy(
            ) * Boundary_Functional.apply_adjoint(v).to_numpy()

        def apply(self, u, mu=None):
            b = (Boundary_Functional.apply_adjoint(u).to_numpy()[0][0] *
                 Boundary_Functional).as_vector()
            return b

    source_ = Boundary_Functional.source
    range_ = Boundary_Functional.range
    output_functional['output_coefficient'] = output_coefficient
    output_functional[
        'linear_part'] = -1 * Boundary_Functional * T_root_d.to_numpy()[0][
            0]  # j(.)
    output_functional['bilinear_part'] = Boundary_squared_half(
        range_, range_)  # k(.,.)
    output_functional[
        'd_u_linear_part'] = -1 * Boundary_Functional * T_root_d.to_numpy()[0][
            0]  # j(.)
    output_functional['d_u_bilinear_part'] = Boundary_squared(
        range_, range_)  # 2k(.,.)

    # choose product
    l2_boundary_product = RobinBoundaryOperator(
        grid,
        data['boundary_info'],
        robin_data=(ConstantFunction(1, 2), ConstantFunction(1, 2)),
        name='l2_boundary_product')
    # choose product
    if product == 'h1_l2_boundary':
        opt_product = primal_fom.h1_semi_product + l2_boundary_product  # h1_semi + l2_boundary
    elif product == 'fixed_energy':
        opt_product = primal_fom.energy_product  # energy w.r.t. mu_bar (see above)
    else:
        assert 0, 'product: {} is not known'.format(product)
    print('my product is {}'.format(product))

    primal_fom = primal_fom.with_(
        products=dict(opt=opt_product,
                      l2_boundary=l2_boundary_product,
                      **primal_fom.products))
    pde_opt_fom = QuadraticPdeoptStationaryModel(
        primal_fom,
        output_functional,
        opt_product=opt_product,
        fin_model=True,
        use_corrected_functional=use_corrected_functional,
        use_corrected_gradient=use_corrected_gradient)
    return pde_opt_fom, data, mu_bar
Esempio n. 14
0
def elliptic2_demo(args):
    args['PROBLEM-NUMBER'] = int(args['PROBLEM-NUMBER'])
    assert 0 <= args['PROBLEM-NUMBER'] <= 1, ValueError(
        'Invalid problem number.')
    args['N'] = int(args['N'])

    rhss = [
        ExpressionFunction('ones(x.shape[:-1]) * 10', 2, ()),
        LincombFunction([
            ExpressionFunction('ones(x.shape[:-1]) * 10', 2, ()),
            ConstantFunction(1., 2)
        ], [ProjectionParameterFunctional('mu'), 0.1])
    ]

    dirichlets = [
        ExpressionFunction('zeros(x.shape[:-1])', 2, ()),
        LincombFunction([
            ExpressionFunction('2 * x[..., 0]', 2, ()),
            ConstantFunction(1., 2)
        ], [ProjectionParameterFunctional('mu'), 0.5])
    ]

    neumanns = [
        None,
        LincombFunction([
            ExpressionFunction('1 - x[..., 1]', 2, ()),
            ConstantFunction(1., 2)
        ], [ProjectionParameterFunctional('mu'), 0.5**2])
    ]

    robins = [
        None,
        (LincombFunction(
            [ExpressionFunction('x[..., 1]', 2, ()),
             ConstantFunction(1., 2)],
            [ProjectionParameterFunctional('mu'), 1]), ConstantFunction(1., 2))
    ]

    domains = [
        RectDomain(),
        RectDomain(right='neumann', top='dirichlet', bottom='robin')
    ]

    rhs = rhss[args['PROBLEM-NUMBER']]
    dirichlet = dirichlets[args['PROBLEM-NUMBER']]
    neumann = neumanns[args['PROBLEM-NUMBER']]
    domain = domains[args['PROBLEM-NUMBER']]
    robin = robins[args['PROBLEM-NUMBER']]

    problem = StationaryProblem(domain=domain,
                                rhs=rhs,
                                diffusion=LincombFunction([
                                    ExpressionFunction('1 - x[..., 0]', 2, ()),
                                    ExpressionFunction('x[..., 0]', 2, ())
                                ], [ProjectionParameterFunctional('mu'), 1]),
                                dirichlet_data=dirichlet,
                                neumann_data=neumann,
                                robin_data=robin,
                                parameter_ranges=(0.1, 1),
                                name='2DProblem')

    print('Discretize ...')
    discretizer = discretize_stationary_fv if args[
        '--fv'] else discretize_stationary_cg
    m, data = discretizer(problem, diameter=1. / args['N'])
    print(data['grid'])
    print()

    print('Solve ...')
    U = m.solution_space.empty()
    for mu in problem.parameter_space.sample_uniformly(10):
        U.append(m.solve(mu))
    m.visualize(U, title='Solution for mu in [0.1, 1]')
Esempio n. 15
0
def main(
    problem_number: int = Argument(..., min=0, max=1, help='Selects the problem to solve [0 or 1].'),
    n: int = Argument(..., help='Triangle count per direction'),
    norm: str = Argument(
        ...,
        help="h1: compute the h1-norm of the last snapshot.\n\n"
             "l2: compute the l2-norm of the last snapshot.\n\n"
             "k: compute the energy norm of the last snapshot, where the energy-product"
             "is constructed with a parameter {'mu': k}."
    ),

    fv: bool = Option(False, help='Use finite volume discretization instead of finite elements.'),
):
    """Solves the Poisson equation in 2D using pyMOR's builtin discreization toolkit."""
    norm = float(norm) if not norm.lower() in ('h1', 'l2') else norm.lower()

    rhss = [ExpressionFunction('ones(x.shape[:-1]) * 10', 2, ()),
            LincombFunction(
                [ExpressionFunction('ones(x.shape[:-1]) * 10', 2, ()), ConstantFunction(1., 2)],
                [ProjectionParameterFunctional('mu'), 0.1])]

    dirichlets = [ExpressionFunction('zeros(x.shape[:-1])', 2, ()),
                  LincombFunction(
                  [ExpressionFunction('2 * x[..., 0]', 2, ()), ConstantFunction(1., 2)],
                  [ProjectionParameterFunctional('mu'), 0.5])]

    neumanns = [None,
                LincombFunction(
                    [ExpressionFunction('1 - x[..., 1]', 2, ()), ConstantFunction(1., 2)],
                    [ProjectionParameterFunctional('mu'), 0.5**2])]

    robins = [None,
              (LincombFunction(
                  [ExpressionFunction('x[..., 1]', 2, ()), ConstantFunction(1., 2)],
                  [ProjectionParameterFunctional('mu'), 1]), ConstantFunction(1., 2))]

    domains = [RectDomain(),
               RectDomain(right='neumann', top='dirichlet', bottom='robin')]

    rhs = rhss[problem_number]
    dirichlet = dirichlets[problem_number]
    neumann = neumanns[problem_number]
    domain = domains[problem_number]
    robin = robins[problem_number]

    problem = StationaryProblem(
        domain=domain,
        rhs=rhs,
        diffusion=LincombFunction(
            [ExpressionFunction('1 - x[..., 0]', 2, ()), ExpressionFunction('x[..., 0]', 2, ())],
            [ProjectionParameterFunctional('mu'), 1]
        ),
        dirichlet_data=dirichlet,
        neumann_data=neumann,
        robin_data=robin,
        parameter_ranges=(0.1, 1),
        name='2DProblem'
    )

    if isinstance(norm, float) and not fv:
        # use a random parameter to construct an energy product
        mu_bar = problem.parameters.parse(norm)
    else:
        mu_bar = None

    print('Discretize ...')
    if fv:
        m, data = discretize_stationary_fv(problem, diameter=1. / n)
    else:
        m, data = discretize_stationary_cg(problem, diameter=1. / n, mu_energy_product=mu_bar)
    print(data['grid'])
    print()

    print('Solve ...')
    U = m.solution_space.empty()
    for mu in problem.parameter_space.sample_uniformly(10):
        U.append(m.solve(mu))
    if mu_bar is not None:
        # use the given energy product
        norm_squared = U[-1].norm(m.products['energy'])[0]
        print('Energy norm of the last snapshot: ', np.sqrt(norm_squared))
    if not fv:
        if norm == 'h1':
            norm_squared = U[-1].norm(m.products['h1_0_semi'])[0]
            print('H^1_0 semi norm of the last snapshot: ', np.sqrt(norm_squared))
        if norm == 'l2':
            norm_squared = U[-1].norm(m.products['l2_0'])[0]
            print('L^2_0 norm of the last snapshot: ', np.sqrt(norm_squared))
    m.visualize(U, title='Solution for mu in [0.1, 1]')
Esempio n. 16
0
# This file is part of the pyMOR project (http://www.pymor.org).
# Copyright 2013-2020 pyMOR developers and contributors. All rights reserved.
# License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

import numpy as np

import pytest

from pymor.analyticalproblems.functions import ConstantFunction, GenericFunction, ExpressionFunction


constant_functions = \
    [ConstantFunction(),
     ConstantFunction(np.array([1., 2., 3.]), dim_domain=7),
     ConstantFunction(np.eye(27), dim_domain=2),
     ConstantFunction(np.array(3), dim_domain=1)]


def importable_function(x):
    return (x[..., 0] * x[..., 1])[..., np.newaxis]


class A:
    @staticmethod
    def unimportable_function(x):
        return np.max(x, axis=-1)


def get_function_with_closure(y):
    def function_with_closure(x):
        return np.concatenate((x + y, x - y), axis=-1)
Esempio n. 17
0
def main(
        problem_number: int = Argument(
            ..., min=0, max=1, help='Selects the problem to solve [0 or 1].'),
        dirichlet_number: int = Argument(
            ...,
            min=0,
            max=2,
            help='Selects the Dirichlet data function [0 to 2].'),
        neumann_number: int = Argument(
            ..., min=0, max=2, help='Selects the Neumann data function.'),
        neumann_count: int = Argument(
            ...,
            min=0,
            max=3,
            help='0: no neumann boundary\n\n'
            '1: right edge is neumann boundary\n\n'
            '2: right+top edges are neumann boundary\n\n'
            '3: right+top+bottom edges are neumann boundary\n\n'),
        fv: bool = Option(
            False,
            help='Use finite volume discretization instead of finite elements.'
        ),
        rect: bool = Option(False, help='Use RectGrid instead of TriaGrid.'),
):
    """Solves the Poisson equation in 2D using pyMOR's builtin discreization toolkit."""

    rhss = [
        ExpressionFunction('ones(x.shape[:-1]) * 10', 2, ()),
        ExpressionFunction('(x[..., 0] - 0.5) ** 2 * 1000', 2, ())
    ]
    dirichlets = [
        ExpressionFunction('zeros(x.shape[:-1])', 2, ()),
        ExpressionFunction('ones(x.shape[:-1])', 2, ()),
        ExpressionFunction('x[..., 0]', 2, ())
    ]
    neumanns = [
        None,
        ConstantFunction(3., dim_domain=2),
        ExpressionFunction(
            '50*(0.1 <= x[..., 1]) * (x[..., 1] <= 0.2)'
            '+50*(0.8 <= x[..., 1]) * (x[..., 1] <= 0.9)', 2, ())
    ]
    domains = [
        RectDomain(),
        RectDomain(right='neumann'),
        RectDomain(right='neumann', top='neumann'),
        RectDomain(right='neumann', top='neumann', bottom='neumann')
    ]

    rhs = rhss[problem_number]
    dirichlet = dirichlets[dirichlet_number]
    neumann = neumanns[neumann_number]
    domain = domains[neumann_count]

    problem = StationaryProblem(domain=domain,
                                diffusion=ConstantFunction(1, dim_domain=2),
                                rhs=rhs,
                                dirichlet_data=dirichlet,
                                neumann_data=neumann)

    for n in [32, 128]:
        print('Discretize ...')
        discretizer = discretize_stationary_fv if fv else discretize_stationary_cg
        m, data = discretizer(analytical_problem=problem,
                              grid_type=RectGrid if rect else TriaGrid,
                              diameter=np.sqrt(2) / n if rect else 1. / n)
        grid = data['grid']
        print(grid)
        print()

        print('Solve ...')
        U = m.solve()
        m.visualize(U, title=repr(grid))
        print()
Esempio n. 18
0

thermalblock_problems = picklable_thermalblock_problems + non_picklable_thermalblock_problems


burgers_problems = \
    [burgers_problem(),
     burgers_problem(v=0.2, circle=False),
     burgers_problem(v=0.4, initial_data_type='bump'),
     burgers_problem(parameter_range=(1., 1.3)),
     burgers_problem_2d(),
     burgers_problem_2d(torus=False, initial_data_type='bump', parameter_range=(1.3, 1.5))]


picklable_elliptic_problems = \
    [StationaryProblem(domain=RectDomain(), rhs=ConstantFunction(dim_domain=2, value=1.)),
     helmholtz_problem()]


non_picklable_elliptic_problems = \
    [StationaryProblem(domain=RectDomain(),
                     rhs=ConstantFunction(dim_domain=2, value=21.),
                     diffusion=LincombFunction(
                         [GenericFunction(dim_domain=2, mapping=lambda X, p=p: X[..., 0]**p)
                          for p in range(5)],
                         [ExpressionParameterFunctional(f'max(mu["exp"], {m})', parameters={'exp': 1})
                          for m in range(5)]
                     ))]


elliptic_problems = picklable_thermalblock_problems + non_picklable_elliptic_problems
Esempio n. 19
0
def text_problem(text='pyMOR', font_name=None):
    import numpy as np
    from PIL import Image, ImageDraw, ImageFont
    from tempfile import NamedTemporaryFile

    font_list = [font_name] if font_name else [
        'DejaVuSansMono.ttf', 'VeraMono.ttf', 'UbuntuMono-R.ttf', 'Arial.ttf'
    ]
    font = None
    for filename in font_list:
        try:
            font = ImageFont.truetype(
                filename, 64)  # load some font from file of given size
        except (OSError, IOError):
            pass
    if font is None:
        raise ValueError('Could not load TrueType font')

    size = font.getsize(text)  # compute width and height of rendered text
    size = (size[0] + 20, size[1] + 20
            )  # add a border of 10 pixels around the text

    def make_bitmap_function(
            char_num
    ):  # we need to genereate a BitmapFunction for each character
        img = Image.new('L',
                        size)  # create new Image object of given dimensions
        d = ImageDraw.Draw(img)  # create ImageDraw object for the given Image

        # in order to position the character correctly, we first draw all characters from the first
        # up to the wanted character
        d.text((10, 10), text[:char_num + 1], font=font, fill=255)

        # next we erase all previous character by drawing a black rectangle
        if char_num > 0:
            d.rectangle(
                ((0, 0), (font.getsize(text[:char_num])[0] + 10, size[1])),
                fill=0,
                outline=0)

        # open a new temporary file
        with NamedTemporaryFile(
                suffix='.png'
        ) as f:  # after leaving this 'with' block, the temporary
            # file is automatically deleted
            img.save(f, format='png')
            return BitmapFunction(f.name,
                                  bounding_box=[(0, 0), size],
                                  range=[0., 1.])

    # create BitmapFunctions for each character
    dfs = [make_bitmap_function(n) for n in range(len(text))]

    # create an indicator function for the background
    background = ConstantFunction(1., 2) - LincombFunction(
        dfs, np.ones(len(dfs)))

    # form the linear combination
    dfs = [background] + dfs
    coefficients = [1] + [
        ProjectionParameterFunctional('diffusion', len(text), i)
        for i in range(len(text))
    ]
    diffusion = LincombFunction(dfs, coefficients)

    return StationaryProblem(domain=RectDomain(dfs[1].bounding_box,
                                               bottom='neumann'),
                             neumann_data=ConstantFunction(-1., 2),
                             diffusion=diffusion,
                             parameter_ranges=(0.1, 1.))
Esempio n. 20
0
def thermal_block_problem(num_blocks=(3, 3), parameter_range=(0.1, 1)):
    """Analytical description of a 2D 'thermal block' diffusion problem.

    The problem is to solve the elliptic equation ::

      - ∇ ⋅ [ d(x, μ) ∇ u(x, μ) ] = f(x, μ)

    on the domain [0,1]^2 with Dirichlet zero boundary values. The domain is
    partitioned into nx x ny blocks and the diffusion function d(x, μ) is
    constant on each such block (i,j) with value μ_ij. ::

           ----------------------------
           |        |        |        |
           |  μ_11  |  μ_12  |  μ_13  |
           |        |        |        |
           |---------------------------
           |        |        |        |
           |  μ_21  |  μ_22  |  μ_23  |
           |        |        |        |
           ----------------------------

    Parameters
    ----------
    num_blocks
        The tuple `(nx, ny)`
    parameter_range
        A tuple `(μ_min, μ_max)`. Each |Parameter| component μ_ij is allowed
        to lie in the interval [μ_min, μ_max].
    """

    def parameter_functional_factory(ix, iy):
        return ProjectionParameterFunctional(component_name='diffusion',
                                             component_shape=(num_blocks[1], num_blocks[0]),
                                             index=(num_blocks[1] - iy - 1, ix),
                                             name=f'diffusion_{ix}_{iy}')

    def diffusion_function_factory(ix, iy):
        if ix + 1 < num_blocks[0]:
            X = '(x[..., 0] >= ix * dx) * (x[..., 0] < (ix + 1) * dx)'
        else:
            X = '(x[..., 0] >= ix * dx)'
        if iy + 1 < num_blocks[1]:
            Y = '(x[..., 1] >= iy * dy) * (x[..., 1] < (iy + 1) * dy)'
        else:
            Y = '(x[..., 1] >= iy * dy)'
        return ExpressionFunction(f'{X} * {Y} * 1.',
                                  2, (), {}, {'ix': ix, 'iy': iy, 'dx': 1. / num_blocks[0], 'dy': 1. / num_blocks[1]},
                                  name=f'diffusion_{ix}_{iy}')

    return StationaryProblem(

        domain=RectDomain(),

        rhs=ConstantFunction(dim_domain=2, value=1.),

        diffusion=LincombFunction([diffusion_function_factory(ix, iy)
                                   for ix, iy in product(range(num_blocks[0]), range(num_blocks[1]))],
                                  [parameter_functional_factory(ix, iy)
                                   for ix, iy in product(range(num_blocks[0]), range(num_blocks[1]))],
                                  name='diffusion'),

        parameter_space=CubicParameterSpace({'diffusion': (num_blocks[1], num_blocks[0])}, *parameter_range),

        name=f'ThermalBlock({num_blocks})'

    )
Esempio n. 21
0
def main(
        diameter: float = Argument(
            0.01, help='Diameter option for the domain discretizer.'),
        r: int = Argument(5, help='Order of the ROMs.'),
):
    """Parametric 1D heat equation example."""
    set_log_levels({'pymor.algorithms.gram_schmidt.gram_schmidt': 'WARNING'})

    # Model
    p = InstationaryProblem(StationaryProblem(
        domain=LineDomain([0., 1.], left='robin', right='robin'),
        diffusion=LincombFunction([
            ExpressionFunction('(x[...,0] <= 0.5) * 1.', 1),
            ExpressionFunction('(0.5 < x[...,0]) * 1.', 1)
        ], [1, ProjectionParameterFunctional('diffusion')]),
        robin_data=(ConstantFunction(1., 1),
                    ExpressionFunction('(x[...,0] < 1e-10) * 1.', 1)),
        outputs=(('l2_boundary',
                  ExpressionFunction('(x[...,0] > (1 - 1e-10)) * 1.', 1)), ),
    ),
                            ConstantFunction(0., 1),
                            T=3.)

    fom, _ = discretize_instationary_cg(p, diameter=diameter, nt=100)

    fom.visualize(fom.solve(mu=0.1))
    fom.visualize(fom.solve(mu=1))
    fom.visualize(fom.solve(mu=10))

    lti = fom.to_lti()

    print(f'order of the model = {lti.order}')
    print(f'number of inputs   = {lti.dim_input}')
    print(f'number of outputs  = {lti.dim_output}')

    mu_list = [0.1, 1, 10]
    w_list = np.logspace(-1, 3, 100)

    # System poles
    fig, ax = plt.subplots()
    for mu in mu_list:
        poles = lti.poles(mu=mu)
        ax.plot(poles.real, poles.imag, '.', label=fr'$\mu = {mu}$')
    ax.set_title('System poles')
    ax.legend()
    plt.show()

    # Magnitude plots
    fig, ax = plt.subplots()
    for mu in mu_list:
        lti.mag_plot(w_list, ax=ax, mu=mu, label=fr'$\mu = {mu}$')
    ax.set_title('Magnitude plot of the full model')
    ax.legend()
    plt.show()

    # Hankel singular values
    fig, ax = plt.subplots()
    for mu in mu_list:
        hsv = lti.hsv(mu=mu)
        ax.semilogy(range(1, len(hsv) + 1), hsv, label=fr'$\mu = {mu}$')
    ax.set_title('Hankel singular values')
    ax.legend()
    plt.show()

    # System norms
    for mu in mu_list:
        print(f'mu = {mu}:')
        print(f'    H_2-norm of the full model:    {lti.h2_norm(mu=mu):e}')
        if config.HAVE_SLYCOT:
            print(
                f'    H_inf-norm of the full model:  {lti.hinf_norm(mu=mu):e}')
        print(f'    Hankel-norm of the full model: {lti.hankel_norm(mu=mu):e}')

    # Model order reduction
    run_mor_method_param(lti, r, w_list, mu_list, BTReductor, 'BT')
    run_mor_method_param(lti, r, w_list, mu_list, LQGBTReductor, 'LQGBT')
    run_mor_method_param(lti, r, w_list, mu_list, BRBTReductor, 'BRBT')
    run_mor_method_param(lti, r, w_list, mu_list, IRKAReductor, 'IRKA')
    run_mor_method_param(lti, r, w_list, mu_list, TSIAReductor, 'TSIA')
    run_mor_method_param(lti,
                         r,
                         w_list,
                         mu_list,
                         OneSidedIRKAReductor,
                         'OS-IRKA',
                         version='V')