Exemplo n.º 1
0
 def action_IdentityOperator(self, ops):
     coeff = sum(self.coefficients)
     if coeff == 0:
         return ZeroOperator(ops[0].source, ops[0].source, name=self.name)
     else:
         return LincombOperator([IdentityOperator(ops[0].source, name=self.name)],
                                [coeff],
                                name=self.name)
Exemplo n.º 2
0
 def __init__(self, block_space, component):
     assert isinstance(block_space, BlockVectorSpace)
     assert 0 <= component < len(block_space.subspaces)
     blocks = [
         ZeroOperator(space, space)
         if i != component else IdentityOperator(space)
         for i, space in enumerate(block_space.subspaces)
     ]
     super().__init__(blocks)
Exemplo n.º 3
0
 def action_ZeroOperator(self, op):
     range_basis, source_basis = self.range_basis, self.source_basis
     if source_basis is not None and range_basis is not None:
         from pymor.operators.numpy import NumpyMatrixOperator
         return NumpyMatrixOperator(np.zeros((len(range_basis), len(source_basis))),
                                    name=op.name)
     else:
         new_source = NumpyVectorSpace(len(source_basis)) if source_basis is not None else op.source
         new_range = NumpyVectorSpace(len(range_basis)) if range_basis is not None else op.range
         return ZeroOperator(new_range, new_source, name=op.name)
Exemplo n.º 4
0
 def action_ZeroOperator(self, ops):
     without_zero = [(op, coeff)
                     for op, coeff in zip(ops, self.coefficients)
                     if not isinstance(op, ZeroOperator)]
     if len(without_zero) == 0:
         return ZeroOperator(ops[0].range, ops[0].source, name=self.name)
     else:
         new_ops, new_coeffs = zip(*without_zero)
         return assemble_lincomb(new_ops, new_coeffs,
                                 solver_options=self.solver_options, name=self.name)
Exemplo n.º 5
0
    def jacobian(self, U, mu=None):
        mu = self.parse_parameter(mu)
        options = self.solver_options.get(
            'jacobian') if self.solver_options else None

        if len(self.interpolation_dofs) == 0:
            if isinstance(self.source, NumpyVectorSpace) and isinstance(
                    self.range, NumpyVectorSpace):
                return NumpyMatrixOperator(np.zeros(
                    (self.range.dim, self.source.dim)),
                                           solver_options=options,
                                           source_id=self.source.id,
                                           range_id=self.range.id,
                                           name=self.name + '_jacobian')
            else:
                return ZeroOperator(self.source,
                                    self.range,
                                    name=self.name + '_jacobian')
        elif hasattr(self, 'operator'):
            return EmpiricalInterpolatedOperator(self.operator.jacobian(U,
                                                                        mu=mu),
                                                 self.interpolation_dofs,
                                                 self.collateral_basis,
                                                 self.triangular,
                                                 solver_options=options,
                                                 name=self.name + '_jacobian')
        else:
            restricted_source = self.restricted_operator.source
            U_components = restricted_source.make_array(
                U.components(self.source_dofs))
            JU = self.restricted_operator.jacobian(U_components, mu=mu) \
                                         .apply(restricted_source.make_array(np.eye(len(self.source_dofs))))
            try:
                if self.triangular:
                    interpolation_coefficients = solve_triangular(
                        self.interpolation_matrix,
                        JU.data.T,
                        lower=True,
                        unit_diagonal=True).T
                else:
                    interpolation_coefficients = np.linalg.solve(
                        self.interpolation_matrix, JU.data.T).T
            except ValueError:  # this exception occurs when AU contains NaNs ...
                interpolation_coefficients = np.empty(
                    (len(JU), len(self.collateral_basis))) + np.nan
            J = self.collateral_basis.lincomb(interpolation_coefficients)
            if isinstance(J.space, NumpyVectorSpace):
                J = NumpyMatrixOperator(J.data.T, range_id=self.range.id)
            else:
                J = VectorArrayOperator(J)
            return Concatenation(J,
                                 ComponentProjection(self.source_dofs,
                                                     self.source),
                                 solver_options=options,
                                 name=self.name + '_jacobian')
Exemplo n.º 6
0
 def action_zero_coeff(self, ops):
     if all(coeff != 0 for coeff in self.coefficients):
         raise RuleNotMatchingError
     without_zero = [(op, coeff)
                     for op, coeff in zip(ops, self.coefficients)
                     if coeff != 0]
     if len(without_zero) == 0:
         return ZeroOperator(ops[0].range, ops[0].source, name=self.name)
     else:
         new_ops, new_coeffs = zip(*without_zero)
         return assemble_lincomb(new_ops, new_coeffs,
                                 solver_options=self.solver_options, name=self.name)
Exemplo n.º 7
0
    def action_EmpiricalInterpolatedOperator(self, op):
        range_basis, source_basis = self.range_basis, self.source_basis
        if len(op.interpolation_dofs) == 0:
            return self.apply(ZeroOperator(op.range, op.source, op.name))
        elif not hasattr(op, 'restricted_operator') or source_basis is None:
            raise RuleNotMatchingError('Has no restricted operator or source_basis is None')
        if range_basis is not None:
            projected_collateral_basis = NumpyVectorSpace.make_array(op.collateral_basis.dot(range_basis))
        else:
            projected_collateral_basis = op.collateral_basis

        return ProjectedEmpiciralInterpolatedOperator(op.restricted_operator, op.interpolation_matrix,
                                                      NumpyVectorSpace.make_array(source_basis.dofs(op.source_dofs)),
                                                      projected_collateral_basis, op.triangular, None, op.name)
Exemplo n.º 8
0
 def action_ZeroOperator(self, op, range_basis, source_basis, product=None):
     if source_basis is not None and range_basis is not None:
         from pymor.operators.numpy import NumpyMatrixOperator
         return NumpyMatrixOperator(np.zeros(
             (len(range_basis), len(source_basis))),
                                    source_id=op.source.id,
                                    range_id=op.range.id,
                                    name=op.name)
     else:
         new_source = (NumpyVectorSpace(len(source_basis), op.source.id)
                       if source_basis is not None else op.source)
         new_range = (NumpyVectorSpace(len(range_basis), op.range.id)
                      if range_basis is not None else op.range)
         return ZeroOperator(new_source, new_range, name=op.name)
Exemplo n.º 9
0
    def __init__(self, blocks):
        blocks = np.array(blocks)
        assert 1 <= blocks.ndim <= 2
        if self.blocked_source and self.blocked_range:
            assert blocks.ndim == 2
        elif self.blocked_source:
            if blocks.ndim == 1:
                blocks.shape = (1, len(blocks))
        else:
            if blocks.ndim == 1:
                blocks.shape = (len(blocks), 1)
        self.blocks = blocks
        assert all(
            isinstance(op, OperatorInterface) or op is None
            for op in self._operators())

        # check if every row/column contains at least one operator
        assert all(
            any(blocks[i, j] is not None for j in range(blocks.shape[1]))
            for i in range(blocks.shape[0]))
        assert all(
            any(blocks[i, j] is not None for i in range(blocks.shape[0]))
            for j in range(blocks.shape[1]))

        # find source/range spaces for every column/row
        source_spaces = [None for j in range(blocks.shape[1])]
        range_spaces = [None for i in range(blocks.shape[0])]
        for (i, j), op in np.ndenumerate(blocks):
            if op is not None:
                assert source_spaces[j] is None or op.source == source_spaces[j]
                source_spaces[j] = op.source
                assert range_spaces[i] is None or op.range == range_spaces[i]
                range_spaces[i] = op.range

        # turn Nones to ZeroOperators
        for (i, j) in np.ndindex(blocks.shape):
            if blocks[i, j] is None:
                self.blocks[i, j] = ZeroOperator(range_spaces[i],
                                                 source_spaces[j])

        self.source = BlockVectorSpace(
            source_spaces) if self.blocked_source else source_spaces[0]
        self.range = BlockVectorSpace(
            range_spaces) if self.blocked_range else range_spaces[0]
        self.num_source_blocks = len(source_spaces)
        self.num_range_blocks = len(range_spaces)
        self.linear = all(op.linear for op in self._operators())
        self.build_parameter_type(*self._operators())
Exemplo n.º 10
0
    def d_mu(self, parameter, index=0):
        """Return the operator's derivative with respect to a given parameter.

        Parameters
        ----------
        parameter
            The parameter w.r.t. which to return the derivative.
        index
            Index of the parameter's component w.r.t which to return the derivative.

        Returns
        -------
        New |Operator| representing the partial derivative.
        """
        if parameter in self.parameters:
            raise NotImplementedError
        else:
            from pymor.operators.constructions import ZeroOperator
            return ZeroOperator(self.range, self.source, name=self.name + '_d_mu')
Exemplo n.º 11
0
    def __init__(self,
                 T,
                 initial_data,
                 operator,
                 rhs,
                 mass=None,
                 time_stepper=None,
                 num_values=None,
                 output_functional=None,
                 products=None,
                 error_estimator=None,
                 visualizer=None,
                 name=None):

        if isinstance(rhs, VectorArray):
            assert rhs in operator.range
            rhs = VectorOperator(rhs, name='rhs')
        if isinstance(initial_data, VectorArray):
            assert initial_data in operator.source
            initial_data = VectorOperator(initial_data, name='initial_data')
        mass = mass or IdentityOperator(operator.source)
        rhs = rhs or ZeroOperator(operator.source, NumpyVectorSpace(1))

        assert isinstance(time_stepper, TimeStepper)
        assert initial_data.source.is_scalar
        assert operator.source == initial_data.range
        assert rhs.linear and rhs.range == operator.range and rhs.source.is_scalar
        assert mass.linear and mass.source == mass.range == operator.source
        assert output_functional is None or output_functional.source == operator.source

        super().__init__(products=products,
                         error_estimator=error_estimator,
                         visualizer=visualizer,
                         name=name)

        self.parameters_internal = {'t': 1}
        self.__auto_init(locals())
        self.solution_space = operator.source
        self.linear = operator.linear and (output_functional is None
                                           or output_functional.linear)
        if output_functional is not None:
            self.dim_output = output_functional.range.dim
Exemplo n.º 12
0
    def d_mu(self, component, index=()):
        """Return the operator's derivative with respect to an index of a parameter component.

        Parameters
        ----------
        component
            Parameter component
        index
            index in the parameter component

        Returns
        -------
        New |Operator| representing the partial derivative.
        """
        if self.parametric:
            raise NotImplementedError
        else:
            from pymor.operators.constructions import ZeroOperator
            return ZeroOperator(self.range,
                                self.source,
                                name=self.name + '_d_mu')
Exemplo n.º 13
0
Arquivo: ei.py Projeto: simon-ca/pymor
    def projected(self, range_basis, source_basis, product=None, name=None):
        assert source_basis is None or source_basis in self.source
        assert range_basis is None or range_basis in self.range
        assert product is None or product.source == product.range == self.range

        if len(self.interpolation_dofs) == 0:
            return ZeroOperator(self.source, self.range, self.name).projected(range_basis, source_basis, product, name)
        elif not hasattr(self, 'restricted_operator') or source_basis is None:
            return super().projected(range_basis, source_basis, product, name)
        else:
            name = name or self.name + '_projected'

            if range_basis is not None:
                if product is None:
                    projected_collateral_basis = NumpyVectorArray(self.collateral_basis.dot(range_basis))
                else:
                    projected_collateral_basis = NumpyVectorArray(product.apply2(self.collateral_basis, range_basis))
            else:
                projected_collateral_basis = self.collateral_basis

            return ProjectedEmpiciralInterpolatedOperator(self.restricted_operator, self.interpolation_matrix,
                                                          NumpyVectorArray(source_basis.components(self.source_dofs),
                                                                           copy=False),
                                                          projected_collateral_basis, self.triangular, None, name)
Exemplo n.º 14
0
def thermalblock_zero_factory(xblocks, yblocks, diameter, seed):
    from pymor.operators.constructions import ZeroOperator
    _, _, U, V, sp, rp = thermalblock_factory(xblocks, yblocks, diameter, seed)
    return ZeroOperator(V.space, U.space), None, U, V, sp, rp
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
Exemplo n.º 16
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
Exemplo n.º 17
0
        def restricted(self, dofs):
            from pymor.tools.mpi import parallel
            if parallel:
                raise NotImplementedError('SubMesh does not work in parallel')
            with self.logger.block(
                    f'Restricting operator to {len(dofs)} dofs ...'):
                if len(dofs) == 0:
                    return ZeroOperator(NumpyVectorSpace(0),
                                        NumpyVectorSpace(0)), np.array(
                                            [], dtype=np.int)

                if self.source.V.mesh().id() != self.range.V.mesh().id():
                    raise NotImplementedError

                self.logger.info('Computing affected cells ...')
                mesh = self.source.V.mesh()
                range_dofmap = self.range.V.dofmap()
                affected_cell_indices = set()
                for c in df.cells(mesh):
                    cell_index = c.index()
                    local_dofs = range_dofmap.cell_dofs(cell_index)
                    for ld in local_dofs:
                        if ld in dofs:
                            affected_cell_indices.add(cell_index)
                            continue
                affected_cell_indices = list(sorted(affected_cell_indices))

                if any(i.integral_type() not in ('cell', 'exterior_facet')
                       for i in self.form.integrals()):
                    # enlarge affected_cell_indices if needed
                    raise NotImplementedError

                self.logger.info('Computing source DOFs ...')
                source_dofmap = self.source.V.dofmap()
                source_dofs = set()
                for cell_index in affected_cell_indices:
                    local_dofs = source_dofmap.cell_dofs(cell_index)
                    source_dofs.update(local_dofs)
                source_dofs = np.array(sorted(source_dofs), dtype=np.intc)

                self.logger.info('Building submesh ...')
                subdomain = df.MeshFunction('size_t', mesh,
                                            mesh.geometry().dim())
                for ci in affected_cell_indices:
                    subdomain.set_value(ci, 1)
                submesh = df.SubMesh(mesh, subdomain, 1)

                self.logger.info('Building UFL form on submesh ...')
                form_r, V_r_source, V_r_range, source_function_r = self._restrict_form(
                    submesh, source_dofs)

                self.logger.info('Building DirichletBCs on submesh ...')
                bc_r = self._restrict_dirichlet_bcs(submesh, source_dofs,
                                                    V_r_source)

                self.logger.info('Computing source DOF mapping ...')
                restricted_source_dofs = self._build_dof_map(
                    self.source.V, V_r_source, source_dofs)

                self.logger.info('Computing range DOF mapping ...')
                restricted_range_dofs = self._build_dof_map(
                    self.range.V, V_r_range, dofs)

                op_r = FenicsOperator(form_r,
                                      FenicsVectorSpace(V_r_source),
                                      FenicsVectorSpace(V_r_range),
                                      source_function_r,
                                      dirichlet_bcs=bc_r,
                                      parameter_setter=self.parameter_setter,
                                      parameters=self.parameters)

                return (RestrictedFenicsOperator(op_r, restricted_range_dofs),
                        source_dofs[np.argsort(restricted_source_dofs)])
Exemplo n.º 18
0
def test_d_mu_of_LincombOperator():
    dict_of_d_mus = {'mu': ['100', '2 * mu[0]'], 'nu': 'cos(nu)'}

    dict_of_second_derivative = {
        'mu': [{
            'mu': ['0', '2'],
            'nu': '0'
        }, {
            'mu': ['2', '0'],
            'nu': '0'
        }],
        'nu': {
            'mu': ['0', '0'],
            'nu': '-sin(nu)'
        }
    }

    pf = ProjectionParameterFunctional('mu', (2, ), (0, ))
    epf = ExpressionParameterFunctional(
        '100 * mu[0] + 2 * mu[1] * mu[0] + sin(nu)', {
            'mu': (2, ),
            'nu': ()
        }, 'functional_with_derivative', dict_of_d_mus,
        dict_of_second_derivative)

    mu = {'mu': (10, 2), 'nu': 0}

    space = NumpyVectorSpace(1)
    zero_op = ZeroOperator(space, space)
    operators = [zero_op, zero_op, zero_op]
    coefficients = [1., pf, epf]

    operator = LincombOperator(operators, coefficients)

    op_sensitivity_to_first_mu = operator.d_mu('mu', 0)
    op_sensitivity_to_second_mu = operator.d_mu('mu', 1)
    op_sensitivity_to_nu = operator.d_mu('nu', ())

    eval_mu_1 = op_sensitivity_to_first_mu.evaluate_coefficients(mu)
    eval_mu_2 = op_sensitivity_to_second_mu.evaluate_coefficients(mu)
    eval_nu = op_sensitivity_to_nu.evaluate_coefficients(mu)

    second_derivative_first_mu_first_mu = operator.d_mu('mu', 0).d_mu('mu', 0)
    second_derivative_first_mu_second_mu = operator.d_mu('mu', 0).d_mu('mu', 1)
    second_derivative_first_mu_nu = operator.d_mu('mu', 0).d_mu('nu')
    second_derivative_second_mu_first_mu = operator.d_mu('mu', 1).d_mu('mu', 0)
    second_derivative_second_mu_second_mu = operator.d_mu('mu',
                                                          1).d_mu('mu', 1)
    second_derivative_second_mu_nu = operator.d_mu('mu', 1).d_mu('nu')
    second_derivative_nu_first_mu = operator.d_mu('nu').d_mu('mu', 0)
    second_derivative_nu_second_mu = operator.d_mu('nu').d_mu('mu', 1)
    second_derivative_nu_nu = operator.d_mu('nu').d_mu('nu')

    hes_mu_1_mu_1 = second_derivative_first_mu_first_mu.evaluate_coefficients(
        mu)
    hes_mu_1_mu_2 = second_derivative_first_mu_second_mu.evaluate_coefficients(
        mu)
    hes_mu_1_nu = second_derivative_first_mu_nu.evaluate_coefficients(mu)
    hes_mu_2_mu_1 = second_derivative_second_mu_first_mu.evaluate_coefficients(
        mu)
    hes_mu_2_mu_2 = second_derivative_second_mu_second_mu.evaluate_coefficients(
        mu)
    hes_mu_2_nu = second_derivative_second_mu_nu.evaluate_coefficients(mu)
    hes_nu_mu_1 = second_derivative_nu_first_mu.evaluate_coefficients(mu)
    hes_nu_mu_2 = second_derivative_nu_second_mu.evaluate_coefficients(mu)
    hes_nu_nu = second_derivative_nu_nu.evaluate_coefficients(mu)

    assert operator.evaluate_coefficients(mu) == [1., 10, 1040.]
    assert eval_mu_1 == [0., 1., 100.]
    assert eval_mu_2 == [0., 0., 2. * 10]
    assert eval_nu == [0., 0., 1.]

    assert hes_mu_1_mu_1 == [0., 0., 0.]
    assert hes_mu_1_mu_2 == [0., 0., 2]
    assert hes_mu_1_nu == [0., 0., 0]
    assert hes_mu_2_mu_1 == [0., 0., 2]
    assert hes_mu_2_mu_2 == [0., 0., 0]
    assert hes_mu_2_nu == [0., 0., 0]
    assert hes_nu_mu_1 == [0., 0., 0]
    assert hes_nu_mu_2 == [0., 0., 0]
    assert hes_nu_nu == [0., 0., -0]